/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.glassfish.pfl.dynamic.codegen.impl;

import java.util.List ;
import java.util.Set ;
import java.util.HashSet ;
import java.util.IdentityHashMap ;
import java.util.Arrays ;
import java.util.ArrayList ;

import org.glassfish.pfl.dynamic.codegen.spi.Type ;
import org.glassfish.pfl.dynamic.codegen.spi.Signature ;
import org.glassfish.pfl.dynamic.codegen.spi.Variable ;
import org.glassfish.pfl.dynamic.codegen.spi.ClassInfo ;
import org.glassfish.pfl.dynamic.codegen.spi.Expression;
import org.glassfish.pfl.dynamic.codegen.spi.FieldInfo ;

import org.glassfish.pfl.dynamic.copyobject.spi.Copy ;
import org.glassfish.pfl.dynamic.copyobject.spi.CopyType ;


Used to create all expressions. BlockStatement is used as the factory for creating instances of ExpressionFactory. All statements created by an ExpressionFactory have the BlockStatement that created this ExpressionFactory as their parent. An ExpressionFactory should be used only to create Expression instances in statements inside the creating BlockStatement. Each subtype of Expression is defined as a static inner class in ExpressionFactory.
/** Used to create all expressions. BlockStatement is used as the * factory for creating instances of ExpressionFactory. All statements * created by an ExpressionFactory have the BlockStatement that * created this ExpressionFactory as their parent. An ExpressionFactory * should be used only to create Expression instances in statements * inside the creating BlockStatement. Each subtype of Expression is * defined as a static inner class in ExpressionFactory. */
public final class ExpressionFactory { private final Node efparent ; private final IdentityHashMap<Expression,Boolean> unusedExpressions ; public final Node efparent() { return this.efparent ; } public final IdentityHashMap<Expression,Boolean> unusedExpressions() { return unusedExpressions ; } public ExpressionFactory( Node parent ) { this.efparent = parent ; unusedExpressions = new IdentityHashMap<Expression,Boolean>() ; } /* A type safe method for copying a List<Expression>. * This may be the only way this can be done, since there * is no way to create a List<Expression>.class constant * to pass to a T copy( Class<T> ) call on NodeBase. * A cast to List<Expression> is not type safe, so it * would create a compiler warning, although never would * result in a runtime exception. */ static List<Expression> copyExpressionList( Node newParent, List<Expression> exprs ) { List<Expression> result = new ArrayList<Expression>() ; for (Expression expr : exprs) result.add( ((ExpressionInternal)expr).copy( (ExpressionInternal)newParent, ExpressionInternal.class) ) ; return result ; } public static abstract class ExpressionBase extends NodeBase implements ExpressionInternal { @Copy( CopyType.IDENTITY ) private ExpressionFactory expressionFactory ; public ExpressionBase( ExpressionFactory ef ) { super( ef.efparent() ) ; this.expressionFactory = ef ; ef.unusedExpressions().put( this, true ) ; } // Override in the subclasses that are assignable. public boolean isAssignable() { return false ; } @Override public <T extends Node> T copy( Class<T> cls ) { throw new IllegalArgumentException( "Need to use copy(Node,Class) to copy an expression" ) ; } @Override public <T extends Node> T copy( Node newParent, Class<T> cls ) { if (expressionFactory.unusedExpressions().containsKey( this )) expressionFactory.unusedExpressions().remove( this ) ; // Only copy expressions in which all local definitions // are still in scope. Util.checkScope( this ) ; return super.copy( newParent, cls ) ; } // Every subclass must define accept( Visitor ) and type(). // For debugging purposes, subclasses should also define // toString. Just as in // Statement subclasses, we will not define hashCode or equals // in subclasses of ExpressionBase. @Override public abstract void accept( Visitor v ) ; } //--------------- CONSTANT EXPRESSIONS ----------------------------------------
Class that represents a constant value of any primitive type, a String, or a Class.
/** Class that represents a constant value of any primitive type, * a String, or a Class. */
public static final class ConstantExpression extends ExpressionBase { private Type type ; private Object value ; ConstantExpression( ExpressionFactory ef, Type type, Object value ) { super( ef ) ; this.type = type ; this.value = value ; } public Object value() { return this.value ; } @Override public String toString() { String valueStr = value == null ? "null" : value.toString() ; return "ConstantExpression" + Util.getNodeIdString(this) + "[" + type.name() + ":" + valueStr + "]" ; } public Type type() { return this.type ; } @Override public void accept( Visitor visitor ) { visitor.visitConstantExpression( this ) ; } } public ExpressionInternal _null() { return new ConstantExpression( this, Type._null(), null ) ; } public ExpressionInternal _const( boolean c ) { return new ConstantExpression( this, Type._boolean(), c ) ; } public ExpressionInternal _const( char c ) { return new ConstantExpression( this, Type._char(), c ) ; } public ExpressionInternal _const( byte c ) { return new ConstantExpression( this, Type._byte(), c ) ; } public ExpressionInternal _const( short c ) { return new ConstantExpression( this, Type._short(), c ) ; } public ExpressionInternal _const( int c ) { return new ConstantExpression( this, Type._int(), c ) ; } public ExpressionInternal _const( long c ) { return new ConstantExpression( this, Type._long(), c ) ; } public ExpressionInternal _const( float c ) { return new ConstantExpression( this, Type._float(), c ) ; } public ExpressionInternal _const( double c ) { return new ConstantExpression( this, Type._double(), c ) ; } public ExpressionInternal _const( String c ) { return new ConstantExpression( this, Type._String(), c ) ; } public ExpressionInternal _const( Type c ) { return new ConstantExpression( this, Type._Class(), c ) ; } //--------------- VOID EXPRESSION ----------------------------------------
Class that represents a void expression.
/** Class that represents a void expression. */
public static final class VoidExpression extends ExpressionBase { VoidExpression( ExpressionFactory ef ) { super( ef ) ; } public Type type() { return Type._void() ; } @Override public void accept( Visitor visitor ) { visitor.visitVoidExpression( this ) ; } @Override public String toString() { return "VoidExpression" + Util.getNodeIdString(this) + "[]" ; } } public ExpressionInternal _void() { return new VoidExpression( this ); } //--------------- THIS EXPRESSION ----------------------------------------
Class used to represent the current object ("this" in java).
/** Class used to represent the current object ("this" in java). */
public static final class ThisExpression extends ExpressionBase { ThisExpression( ExpressionFactory ef ) { super( ef ) ; } public Type type() { // The most derived type of "this" is unknown, so // we should type it as the static type of the defining // class. This can be determined by walking up the // parent chain until we find the class. ClassGeneratorImpl cg = getAncestor( ClassGeneratorImpl.class ) ; if (cg == null) throw new IllegalStateException( "No ClassGenerator found!" ) ; Type cgType = Type._classGenerator( cg ) ; return cgType ; } @Override public void accept( Visitor visitor ) { visitor.visitThisExpression( this ) ; } @Override public String toString() { return "ThisExpression" + Util.getNodeIdString(this) + "[]" ; } } public ExpressionInternal _this() { return new ThisExpression( this ) ; } //--------------- CALL EXPRESSION ----------------------------------------
Representation of any sort of method call other than a constructor invocation. There are two main cases here: static calls, represented by CallExpression, and non-static calls, represented by CallExpression. This abstract base class has two concrete subclasses, one for static, and one for non-static calls.

The call type is determined as follows:

  • If isStatic is true, the call is static.
  • If isStatic is false, and the target's type is an interface, the call is an interface call.
  • If isStatic is false, and the target's type is not an interface, the call is virtual.
/** Representation of any sort of method call other than a * constructor invocation. There are two main cases here: * static calls, represented by CallExpression<Type>, and * non-static calls, represented by CallExpression<ExpressionInternal>. * This abstract base class has two concrete subclasses, one * for static, and one for non-static calls. * <P> * The call type is determined as follows: * <ul> * <li>If isStatic is true, the call is static. * <li>If isStatic is false, and the target's type is an interface, * the call is an interface call. * <li>If isStatic is false, and the target's type is not an interface, * the call is virtual. * </ul> */
public static abstract class CallExpression<T> extends ExpressionBase { private T target ; private String ident ; private Signature signature ; private List<Expression> args ; // Defined in subclass to indicate static or non-static call public abstract boolean isStatic() ; // Construct a call expression for a call CallExpression( ExpressionFactory ef, String ident, Signature signature, List<Expression> args ) { super( ef ) ; this.ident = ident ; this.signature = signature ; this.args = copyExpressionList( this, args ) ; } public final T target() { return this.target ; } public final void target( T arg ) { this.target = arg ; } public final String ident() { return this.ident ; } public final Signature signature() { return this.signature ; } public final List<Expression> args() { return this.args ; } public final Type type() { return signature.returnType() ; } // every subclass must define accept( Visitor ). } public static final class StaticCallExpression extends CallExpression<Type> { StaticCallExpression( ExpressionFactory ef, Type target, String ident, Signature signature, List<Expression> args ) { super( ef, ident, signature, args ) ; target( target ) ; } @Override public boolean isStatic() { return true ; } @Override public void accept( Visitor visitor ) { visitor.visitStaticCallExpression( this ) ; } @Override public String toString() { return "StaticCallExpression" + Util.getNodeIdString(this) + "[target=" + target() + " " + "ident=" + ident() + " " + "signature=" + signature() + "]" ; } } public static final class NonStaticCallExpression extends CallExpression<Expression> { NonStaticCallExpression( ExpressionFactory ef, Expression target, String ident, Signature signature, List<Expression> args ) { super( ef, ident, signature, args ) ; target( ((ExpressionInternal)target).copy( this, ExpressionInternal.class ) ) ; } @Override public boolean isStatic() { return false ; } @Override public void accept( Visitor visitor ) { visitor.visitNonStaticCallExpression( this ) ; } @Override public String toString() { return "NonStaticCallExpression" + Util.getNodeIdString(this) + "[ident=" + ident() + " " + "signature=" + signature() + "]" ; } }
Construct a representation of a non-static method invocation.
/** Construct a representation of a non-static method invocation. */
public Expression call( Expression target, String ident, Signature signature, List<Expression> exprs ) { signature.checkCompatibility( ((ExpressionInternal)target).type(), ident, exprs ) ; return new NonStaticCallExpression( this, target, ident, signature, exprs ) ; }
Shorthand form to construct invocation that looks up Signature based on the types of the expressions in exprs. Can probably be used in most circumstances.
/** Shorthand form to construct invocation that looks up Signature based * on the types of the expressions in exprs. Can probably be used in most * circumstances. */
public Expression call( Expression target, String ident, List<Expression> exprs ) { Signature sig = Signature.fromCall( ((ExpressionInternal)target).type(), ident, exprs ) ; return new NonStaticCallExpression( this, target, ident, sig, exprs ) ; }
Construct a representation of a static method invocation.
/** Construct a representation of a static method invocation. */
public Expression staticCall( Type target, String ident, Signature signature, List<Expression> exprs ) { signature.checkStaticCompatibility( target, ident, exprs ) ; if (target.isPrimitive() || target.isArray()) throw new IllegalArgumentException( "The target for a static call must be a reference type" ) ; return new StaticCallExpression( this, target, ident, signature, exprs ) ; }
Shorthand form to construct invocation that looks up Signature based on the types of the expressions in exprs. Can probably be used in most circumstances.
/** Shorthand form to construct invocation that looks up Signature based * on the types of the expressions in exprs. Can probably be used in most * circumstances. */
public Expression staticCall( Type target, String ident, List<Expression> exprs ) { if (target.isPrimitive() || target.isArray()) throw new IllegalArgumentException( "The target for a static call must be a reference type" ) ; Signature sig = Signature.fromStaticCall( target, ident, exprs ) ; return new StaticCallExpression( this, target, ident, sig, exprs ) ; } //--------------- UNARY OPERATOR EXPRESSION ----------------------------------------
Operators that apply to a single expression. The only unary operator that we support at present is ! (NOT) because this is very useful in constructing boolean expressions for while loops and conditionals.
/** Operators that apply to a single expression. * The only unary operator that we support at present is ! (NOT) * because this is very useful in constructing boolean expressions * for while loops and conditionals. */
public enum UnaryOperator{ NOT( "!" ) { public void checkType( Expression arg ) { Type type = ((ExpressionInternal)arg).type() ; if (type != Type._boolean()) throw new IllegalArgumentException( "! expects a boolean type, found " + type ) ; } } ; private final String javaRepresentation ; public String javaRepresentation() { return javaRepresentation ; } public abstract void checkType( Expression arg ) ; UnaryOperator( String javaRepresentation ) { this.javaRepresentation = javaRepresentation ; } }
Representation of the application of a UnaryOperator to an Expression.
/** Representation of the application of a UnaryOperator to an * Expression. */
public static final class UnaryOperatorExpression extends ExpressionBase { private UnaryOperator op ; private Expression expr ; UnaryOperatorExpression( ExpressionFactory ef, UnaryOperator op, Expression expr ) { super( ef ) ; this.op = op ; this.expr = ((ExpressionInternal)expr).copy( this, ExpressionInternal.class); } public UnaryOperator operator() { return op ; } public Expression expr() { return expr ; } public Type type() { return Type._boolean() ; } @Override public void accept( Visitor visitor ) { visitor.visitUnaryOperatorExpression( this ) ; } @Override public String toString() { return "UnaryOperatorExpression" + Util.getNodeIdString(this) + "[" + op + "]" ; } } public Expression unaryOp( UnaryOperator op, Expression expr ) { return new UnaryOperatorExpression( this, op, expr ) ; } //--------------- BINARY OPERATOR EXPRESSION ---------------------------------------- public enum BinaryOperatorKind { RELATIONAL, NUMERIC, BOOLEAN } ;
Representation of binary operators. We only support a limited set of operators as follows:
  • Basic arithmetic: PLUS, MINUS, TIMES, DIV, REM
  • Relational operators (LT, GT, LE, GE, EQ, NE)
  • == and != on references (e.g. obj == null) and primitives.
  • AND and OR on booleans
/** Representation of binary operators. * We only support a limited set of operators as follows: * <ul> * <li>Basic arithmetic: PLUS, MINUS, TIMES, DIV, REM * <li>Relational operators (LT, GT, LE, GE, EQ, NE) * <li>== and != on references (e.g. obj == null) and * primitives. * <li>AND and OR on booleans * </ul> */
public enum BinaryOperator{ PLUS( "+" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } @Override public BinaryOperatorKind kind() { return BinaryOperatorKind.NUMERIC ; } }, TIMES( "*" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } @Override public BinaryOperatorKind kind() { return BinaryOperatorKind.NUMERIC ; } }, DIV( "/" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } @Override public BinaryOperatorKind kind() { return BinaryOperatorKind.NUMERIC ; } }, MINUS( "-" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } @Override public BinaryOperatorKind kind() { return BinaryOperatorKind.NUMERIC ; } }, REM( "%" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } @Override public BinaryOperatorKind kind() { return BinaryOperatorKind.NUMERIC ; } }, GT( ">" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } }, GE( ">=" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } }, LT( "<" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } }, LE( "<=" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createNumericExpression( this, ef, left, right ) ; } }, EQ( "==" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createEqualityExpression( this, ef, left, right ) ; } }, NE( "!=" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { return createEqualityExpression( this, ef, left, right ) ; } }, AND( "&&" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { if (!(left.equals( Type._boolean())) || !(right.equals( Type._boolean()))) throw new IllegalArgumentException( this.javaRepresentation() + " requires boolean expressions" ) ; return new IfExpression( ef, left, right, ef._const( false ) ) ; } @Override public BinaryOperatorKind kind() { return BinaryOperatorKind.BOOLEAN ; } }, OR( "||" ) { public Expression create( ExpressionFactory ef, Expression left, Expression right ) { if (!(left.equals( Type._boolean())) || !(right.equals( Type._boolean()))) throw new IllegalArgumentException( this.javaRepresentation() + " requires boolean expressions" ) ; return ef.ifExpression( left, ef._const( true ), right ) ; } @Override public BinaryOperatorKind kind() { return BinaryOperatorKind.BOOLEAN ; } } ; private final String javaRepresentation ; private static Expression createNumericExpression( final BinaryOperator op, final ExpressionFactory ef, final Expression left, final Expression right ) { Expression lb = left ; Type ltype = ((ExpressionInternal)left).type() ; Expression rb = right ; Type rtype = ((ExpressionInternal)right).type() ; Type ctype = ltype.binaryPromotion( rtype ) ; if (!ctype.equals( ltype )) lb = ef.cast( ctype, lb ) ; if (!ctype.equals( rtype )) rb = ef.cast( ctype, rb ) ; return new BinaryOperatorExpression( ef, ctype, lb, op, rb ) ; } // See JLS 15.20 private static Expression createEqualityExpression( final BinaryOperator op, final ExpressionFactory ef, final Expression left, final Expression right ) { Type ltype = ((ExpressionInternal)left).type() ; Type rtype = ((ExpressionInternal)right).type() ; if (rtype.equals(Type._boolean()) && ltype.equals(Type._boolean())) { return new BinaryOperatorExpression( ef, Type._boolean(), left, op, right ) ; } else if (ltype.isNumber() && rtype.isNumber()) { Expression lb = left ; Expression rb = right ; Type ctype = ltype.binaryPromotion( rtype ) ; if (!ctype.equals( ltype )) lb = ef.cast( ctype, lb ) ; if (!ctype.equals( rtype )) rb = ef.cast( ctype, rb ) ; return new BinaryOperatorExpression( ef, Type._boolean(), lb, op, rb ) ; } else { boolean lok = !ltype.isPrimitive() || ltype.equals( Type._null() ) ; boolean rok = !rtype.isPrimitive() || rtype.equals( Type._null() ) ; if (lok && rok) return new BinaryOperatorExpression( ef, Type._boolean(), left, op, right ) ; else throw new IllegalArgumentException( "Both arguments to " + op.javaRepresentation() + " must be of reference or null type. left type = " + ltype.name() + " right type = " + rtype.name() ) ; } } public String javaRepresentation() { return javaRepresentation ; } public abstract Expression create( ExpressionFactory ef, Expression left, Expression right ) ; public BinaryOperatorKind kind() { return BinaryOperatorKind.RELATIONAL ; } BinaryOperator( String javaRepresentation ) { this.javaRepresentation = javaRepresentation ; } } // Note that left and right can be replaced, in order to re-write the // tree for numeric type conversions public static final class BinaryOperatorExpression extends ExpressionBase { private Expression left ; private BinaryOperator op ; private Expression right ; private Type type ; BinaryOperatorExpression( ExpressionFactory ef, Type type, Expression left, BinaryOperator op, Expression right ) { super( ef ) ; this.type = type ; this.left = ((ExpressionInternal)left).copy(this, ExpressionInternal.class); this.op = op ; this.right = ((ExpressionInternal)right).copy(this, ExpressionInternal.class); } public BinaryOperator operator() { return op ; } public Expression left() { return left ; } public Expression right() { return right ; } public Type type() { return type ; } @Override public void accept( Visitor visitor ) { visitor.visitBinaryOperatorExpression( this ) ; } @Override public String toString() { return "BinaryOperatorExpression" + Util.getNodeIdString(this) + "[" + op + "]" ; } } public Expression binaryOperator( Expression left, BinaryOperator op, Expression right ) { return op.create( this, left, right ) ; } //--------------- CAST EXPRESSION ---------------------------------------- public static final class CastExpression extends ExpressionBase { private Type type ; private Expression expr ; CastExpression( ExpressionFactory ef, Type type, Expression expr ) { super( ef ) ; this.type = type ; this.expr = ((ExpressionInternal)expr).copy(this, ExpressionInternal.class); } public Expression expr() { return expr ; } public Type type() { return type ; } @Override public void accept( Visitor visitor ) { visitor.visitCastExpression( this ) ; } @Override public String toString() { return "CastExpression" + Util.getNodeIdString(this) + "[" + type.name() + "]" ; } } public Expression cast( Type type, Expression expr ) { return new CastExpression( this, type, expr ) ; } //--------------- INSTOF EXPRESSION ---------------------------------------- public static final class InstofExpression extends ExpressionBase { private Expression expr ; private Type itype ; InstofExpression( ExpressionFactory ef, Expression expr, Type type ) { super( ef ) ; this.expr = ((ExpressionInternal)expr).copy(this, ExpressionInternal.class); this.itype = type ; } public Expression expr() { return expr ; } public Type itype() { return itype ; } public Type type() { return Type._boolean() ; } @Override public void accept( Visitor visitor ) { visitor.visitInstofExpression( this ) ; } @Override public String toString() { return "InstofExpression" + Util.getNodeIdString(this) + "[" + itype.name() + "]" ; } } public Expression instof( Expression expr, Type type ) { return new InstofExpression( this, expr, type ) ; } //--------------- NEWOBJ EXPRESSION ---------------------------------------- public static final class NewObjExpression extends ExpressionBase { private Type type ; private Signature signature ; private List<Expression> args ; NewObjExpression( ExpressionFactory ef, Type type, Signature signature, List<Expression> args ) { super( ef ) ; this.type = type ; this.signature = signature ; if (!signature.returnType().equals(Type._void())) throw new IllegalArgumentException( "The signature of a new call to a constructor must have a void return type" ) ; this.args = copyExpressionList(this, args) ; } public final Signature signature() { return this.signature ; } public final List<Expression> args() { return this.args ; } public Type type() { return type ; } @Override public void accept( Visitor visitor ) { visitor.visitNewObjExpression( this ) ; } @Override public String toString() { return "NewObjExpression" + Util.getNodeIdString(this) + "[" + type.name() + " " + signature + "]" ; } } public Expression newObj( Type type, Signature signature, List<Expression> args ) { signature.checkConstructorCompatibility( type, args ) ; return new NewObjExpression( this, type, signature, args ) ; } public Expression newObj( Type type, List<Expression> exprs ) { Signature signature = Signature.fromConstructor( type, exprs ) ; return new NewObjExpression( this, type, signature, exprs ) ; } //--------------- NEWARR EXPRESSION ---------------------------------------- public static final class NewArrExpression extends ExpressionBase { private Type ctype ; private Expression size ; private List<Expression> exprs ; NewArrExpression( ExpressionFactory ef, Type ctype, Expression size, List<Expression> exprs ) { super( ef ) ; this.ctype = ctype ; this.size = ((ExpressionInternal)size).copy( this, ExpressionInternal.class ) ; this.exprs = copyExpressionList( this, exprs ) ; } public Type ctype() { return ctype ; } public Expression size() { return size ; } public List<Expression> exprs() { return exprs ; } public Type type() { return Type._array( ctype ) ; } @Override public void accept( Visitor visitor ) { visitor.visitNewArrExpression( this ) ; } @Override public String toString() { return "NewArrExpression" + Util.getNodeIdString(this) + "[" + ctype.name() + "]" ; } } public Expression newArrInit( Type type, List<Expression> exprs ) { Expression size = _const( exprs.size() ) ; return new NewArrExpression( this, type, size, exprs ) ; } public Expression newArr( Type type, Expression size ) { return new NewArrExpression( this, type, size, null ) ; } //--------------- SUPER CALL EXPRESSION ---------------------------------------- public static final class SuperCallExpression extends ExpressionBase { private String ident ; private Signature signature ; private List<Expression> exprs ; SuperCallExpression( ExpressionFactory ef, String ident, Signature signature, List<Expression> exprs ) { super( ef ) ; this.ident = ident ; this.signature = signature ; this.exprs = copyExpressionList( this, exprs ) ; } public String ident() { return ident ; } public Signature signature() { return signature ; } public List<Expression> exprs() { return exprs ; } public Type type() { return signature.returnType() ; } @Override public void accept( Visitor visitor ) { visitor.visitSuperCallExpression( this ) ; } @Override public String toString() { return "SuperCallExpression" + Util.getNodeIdString(this) + "[" + ident + " " + signature + "]" ; } } public Expression superCall( String ident, Signature signature, List<Expression> exprs ) { return new SuperCallExpression( this, ident, signature, exprs ) ; } public Expression superCall( String ident, List<Expression> exprs ) { ClassGeneratorImpl cg = efparent().getAncestor(ClassGeneratorImpl.class) ; if (cg == null) throw new IllegalStateException( "No ClassGenerator found!" ) ; Type type = cg.superType() ; Signature signature = Signature.fromCall( type, ident, exprs ) ; return new SuperCallExpression( this, ident, signature, exprs ) ; } //--------------- SUPER OBJ EXPRESSION (super at start of constructor) ---------- public static final class SuperObjExpression extends ExpressionBase { private Signature signature ; private List<Expression> exprs ; SuperObjExpression( ExpressionFactory ef, Signature signature, List<Expression> exprs ) { super( ef ) ; this.signature = signature ; this.exprs = copyExpressionList( this, exprs ) ; } public Signature signature() { return signature ; } public List<Expression> exprs() { return exprs ; } public Type type() { return Type._void() ; } @Override public void accept( Visitor visitor ) { visitor.visitSuperObjExpression( this ) ; } @Override public String toString() { return "SuperObjExpression" + Util.getNodeIdString(this) + "[" + signature + "]" ; } }
Call to superclass constructor. Must be first in the method.
/** Call to superclass constructor. Must be first in the method. */
public Expression superObj( Signature signature, List<Expression> exprs ) { return new SuperObjExpression( this, signature, exprs ) ; }
Call to superclass constructor. Must be first in the method. This is a shorthand form that computes the Signature directly from the Expression list exprs.
/** Call to superclass constructor. Must be first in the method. * This is a shorthand form that computes the Signature directly * from the Expression list exprs. */
public Expression superObj( List<Expression> exprs ) { ClassGeneratorImpl cg = efparent().getAncestor(ClassGeneratorImpl.class) ; if (cg == null) throw new IllegalStateException( "No ClassGenerator found!" ) ; Type type = cg.superType() ; Signature signature = Signature.fromConstructor( type, exprs ) ; return new SuperObjExpression( this, signature, exprs ) ; } //--------------- THIS OBJ EXPRESSION (this at start of constructor) ---------- public static final class ThisObjExpression extends ExpressionBase { private Signature signature ; private List<Expression> exprs ; ThisObjExpression( ExpressionFactory ef, Signature signature, List<Expression> exprs ) { super( ef ) ; this.signature = signature ; this.exprs = copyExpressionList( this, exprs ) ; } public Signature signature() { return signature ; } public List<Expression> exprs() { return exprs ; } public Type type() { return Type._void() ; } @Override public void accept( Visitor visitor ) { visitor.visitThisObjExpression( this ) ; } @Override public String toString() { return "ThisObjExpression" + Util.getNodeIdString(this) + "[" + signature + "]" ; } }
Call to another constructor. Must be first in the method.
/** Call to another constructor. Must be first in the method. */
public Expression thisObj( Signature signature, List<Expression> exprs ) { return new ThisObjExpression( this, signature, exprs ) ; }
Call to another constructor. Must be first in the method. This is a shorthand form that computes the Signature directly from the Expression list exprs.
/** Call to another constructor. Must be first in the method. * This is a shorthand form that computes the Signature directly * from the Expression list exprs. */
public Expression thisObj( List<Expression> exprs ) { ClassGeneratorImpl cg = efparent().getAncestor(ClassGeneratorImpl.class) ; if (cg == null) throw new IllegalStateException( "No ClassGenerator found!" ) ; Type type = cg.thisType() ; Signature signature = Signature.fromConstructor( type, exprs ) ; return new ThisObjExpression( this, signature, exprs ) ; } //--------------- Field Access Expression ------------------------------------- public static abstract class FieldAccessExpressionBase<T> extends ExpressionBase { private T target ; private String fieldName ; FieldAccessExpressionBase( ExpressionFactory ef, String fieldName ) { super( ef ) ; this.fieldName = fieldName ; } @Override public boolean isAssignable() { // XXX What if this field is final? return true ; } abstract boolean isStatic() ; abstract Type targetType() ; public T target() { return target ; } public void target( T arg ) { this.target = arg ; } public String fieldName() { return fieldName ; } public Type type() { ClassInfo cinfo = targetType().classInfo() ; FieldInfo fld = cinfo.findFieldInfo( fieldName) ; if (fld == null) throw new IllegalStateException( "Type " + targetType().name() + " does not contain field " + fieldName ) ; ClassGeneratorImpl defClass = getAncestor( ClassGeneratorImpl.class ) ; if (fld.isAccessibleInContext( defClass, cinfo )) return fld.type() ; else throw new IllegalStateException( "Field " + fieldName + " in type " + targetType().name() + "is not accessible in context " + defClass.name() ) ; } } public static final class NonStaticFieldAccessExpression extends FieldAccessExpressionBase<Expression> { NonStaticFieldAccessExpression( ExpressionFactory ef, Expression target, String fieldName ) { super( ef, fieldName ) ; target( ((ExpressionInternal)target).copy(this, ExpressionInternal.class) ) ; } @Override public boolean isStatic() { return false ; } @Override public Type targetType() { return ((ExpressionInternal)target()).type() ; } @Override public void accept( Visitor visitor ) { visitor.visitNonStaticFieldAccessExpression( this ) ; } @Override public String toString() { return "NonStaticFieldAccessExpression" + Util.getNodeIdString(this) + "[" + fieldName() + "]" ; } } public static final class StaticFieldAccessExpression extends FieldAccessExpressionBase<Type> { StaticFieldAccessExpression( ExpressionFactory ef, Type target, String fieldName ) { super( ef, fieldName ) ; target( target ) ; } @Override public boolean isStatic() { return true ; } @Override public Type targetType() { return target() ; } @Override public void accept( Visitor visitor ) { visitor.visitStaticFieldAccessExpression( this ) ; } @Override public String toString() { return "StaticFieldAccessExpression" + Util.getNodeIdString(this) + "[" + target().name() + " " + fieldName() + "]" ; } } public Expression fieldAccess( Expression target, String fieldName ) { return new NonStaticFieldAccessExpression( this, target, fieldName ) ; } public Expression fieldAccess( Type target, String fieldName ) { return new StaticFieldAccessExpression( this, target, fieldName ) ; } //--------------- Array Index Expression ------------------------------------- public static final class ArrayIndexExpression extends ExpressionBase { private Expression expr ; private Expression index ; ArrayIndexExpression( ExpressionFactory ef, Expression expr, Expression index ) { super( ef ) ; this.expr = ((ExpressionInternal)expr).copy(this, ExpressionInternal.class); this.index = ((ExpressionInternal)index).copy(this, ExpressionInternal.class); } @Override public boolean isAssignable() { return true ; } public Expression expr() { return expr ; } public Expression index() { return index ; } public Type type() { Type atype = ((ExpressionInternal)expr).type().memberType() ; return atype ; } @Override public void accept( Visitor visitor ) { visitor.visitArrayIndexExpression( this ) ; } @Override public String toString() { return "ArrayIndexExpression" + Util.getNodeIdString(this) + "[]" ; } } public Expression arrayIndex( Expression expr, Expression index ) { return new ArrayIndexExpression( this, expr, index ) ; } //--------------- Array Length Expression ------------------------------------- public static final class ArrayLengthExpression extends ExpressionBase { private Expression expr ; ArrayLengthExpression( ExpressionFactory ef, Expression expr ) { super( ef ) ; this.expr = ((ExpressionInternal)expr).copy(this, ExpressionInternal.class); } public Expression expr() { return expr ; } public Type type() { return Type._int() ; } @Override public void accept( Visitor visitor ) { visitor.visitArrayLengthExpression( this ) ; } @Override public String toString() { return "ArrayLengthExpression" + Util.getNodeIdString(this) + "[]" ; } } public Expression arrayLength( Expression expr ) { return new ArrayLengthExpression( this, expr ) ; } //--------------- If expression ------------------------------------- public static final class IfExpression extends ExpressionBase { private Expression condition ; private Expression truePart ; private Expression falsePart ; private Type type ; IfExpression( final ExpressionFactory ef, final Expression condition, final Expression truePart, final Expression falsePart ) { super( ef ) ; this.condition = ((ExpressionInternal)condition).copy( this, ExpressionInternal.class ) ; this.truePart = ((ExpressionInternal)truePart).copy( this, ExpressionInternal.class ) ; this.falsePart = ((ExpressionInternal)falsePart).copy( this, ExpressionInternal.class ) ; // See section 15.24 to compute the type of the conditional expression final Type ttype = ((ExpressionInternal)truePart).type() ; final Type ftype = ((ExpressionInternal)falsePart).type() ; if (ttype.equals( ftype )) { type = ttype ; } else if (ttype.isNumber() && ftype.isNumber()) { Set<Type> special = new HashSet<Type>( Arrays.asList( Type._byte(), Type._short() ) ) ; Set<Type> argTypes = new HashSet<Type>( Arrays.asList( ttype, ftype ) ) ; if (special.equals( argTypes )) { type = Type._short() ; } else { type = ttype.binaryPromotion( ftype ) ; if (!ttype.equals( type )) this.truePart = ef.cast( type, this.truePart ) ; if (!ftype.equals( type )) this.falsePart = ef.cast( type, this.falsePart ) ; } } else { // handle the reference cases if (ttype.equals(Type._null()) && !ftype.isPrimitive()) { type = ftype ; } else if (ftype.equals(Type._null()) && !ttype.isPrimitive()) { type = ttype ; } else { // both types are reference types if (ttype.isAssignmentConvertibleFrom( ftype )) type = ttype ; else if (ftype.isAssignmentConvertibleFrom( ttype )) type = ftype ; } } } public Expression condition() { return condition ; } public Expression truePart() { return this.truePart ; } public Expression falsePart() { return this.falsePart ; } public Type type() { return type ; } @Override public void accept( Visitor visitor ) { visitor.visitIfExpression( this ) ; } @Override public String toString() { return "IfExpression" + Util.getNodeIdString(this) + "[type=" + type.name() + "]" ; } } public Expression ifExpression( Expression condition, Expression truePart, Expression falsePart ) { return new IfExpression( this, condition, truePart, falsePart ) ; } //----------------Variable--------------------------------------------- // public static final class VariableImpl extends ExpressionFactory.ExpressionBase implements VariableInternal { private Type type ; private String ident ; private boolean available = true ; VariableImpl( ExpressionFactory ef, Type type, String ident ) { super( ef ) ; if (!Identifier.isValidIdentifier( ident )) throw new IllegalArgumentException( ident + " is not a valid Java identifier name" ) ; this.type = type ; this.ident = ident ; } @Override public boolean isAssignable() { return true ; } public String ident() { return ident ; } public boolean isAvailable() { return available ; } public void close() { available = false ; } @Override public int hashCode() { return type.hashCode() ^ ident.hashCode() ; } @Override public boolean equals( Object obj ) { if (!(obj instanceof Variable)) return false ; if (obj == this) return true ; VariableInternal other = VariableInternal.class.cast( obj ) ; return type.equals(other.type()) && ident.equals(other.ident()) ; } @Override public String toString() { return "VariableImpl" + Util.getNodeIdString(this) + "[" + type.name() + " " + ident + "]" ; } public Type type() { return type ; } @Override public void accept( Visitor visitor ) { visitor.visitVariable( this ) ; } } public Variable variable( Type type, String ident ) { return new VariableImpl( this, type, ident ) ; } }