![JAR search and dependency download from the Maven repository](/logo.png)
org.glassfish.pfl.dynamic.codegen.spi.Wrapper Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.pfl.dynamic.codegen.spi;
import java.io.PrintStream ;
import java.io.IOException ;
import java.util.Properties ;
import java.util.List ;
import java.util.Stack ;
import static java.util.Arrays.asList ;
import java.security.ProtectionDomain ;
import java.security.AccessController ;
import java.security.PrivilegedAction ;
import org.glassfish.pfl.dynamic.copyobject.impl.ClassCopierOrdinaryImpl ;
import org.glassfish.pfl.basic.fsm.State ;
import org.glassfish.pfl.basic.fsm.Input ;
import org.glassfish.pfl.basic.fsm.FSM ;
import org.glassfish.pfl.basic.fsm.FSMImpl ;
import org.glassfish.pfl.basic.fsm.Runner ;
import org.glassfish.pfl.basic.fsm.StateEngine ;
import org.glassfish.pfl.dynamic.codegen.impl.BlockStatement ;
import org.glassfish.pfl.dynamic.codegen.impl.ClassGeneratorImpl ;
import org.glassfish.pfl.dynamic.codegen.impl.CurrentClassLoader ;
import org.glassfish.pfl.dynamic.codegen.impl.CodeGenerator ;
import org.glassfish.pfl.dynamic.codegen.impl.CodeGeneratorUtil ;
import org.glassfish.pfl.dynamic.codegen.impl.ExpressionFactory ;
import org.glassfish.pfl.dynamic.codegen.impl.Identifier ;
import org.glassfish.pfl.dynamic.codegen.impl.ImportListImpl ;
import org.glassfish.pfl.dynamic.codegen.impl.IfStatement ;
import org.glassfish.pfl.dynamic.codegen.impl.MethodGenerator ;
import org.glassfish.pfl.dynamic.codegen.impl.SwitchStatement ;
import org.glassfish.pfl.dynamic.codegen.impl.TryStatement ;
import org.glassfish.pfl.dynamic.codegen.impl.Util ;
import org.glassfish.pfl.dynamic.codegen.impl.FieldGenerator ;
import org.glassfish.pfl.dynamic.codegen.impl.VariableInternal;
import org.glassfish.pfl.dynamic.codegen.impl.WhileStatement ;
import org.glassfish.pfl.basic.contain.Pair;
/** Main API for runtime code generation.
* This API generates bytecode dynamically at runtime, allowing direct construction
* of Class instances from the generated bytecodes. Such classes can then
* be instantiated and used in a running program. This can be used for a variety of
* advanced applications aimed at extending the Java language or providing
* significant performance enhancements.
*
* The supported language is best thought of as a subset of Java 1.0.2.
* The following features from Java 5 and earlier are currently NOT supported:
*
* - Generics.
*
- Annotations (this may be added at some point).
*
- For loops (of any sort, but this may be added through extension at some
* point).
*
- Enums.
*
- Autoboxing.
*
- Varargs methods.
*
- Nested classes.
*
- Compiler generated default constructors.
*
- Compiler generated calls to super() in a constructor.
*
- Anonymous classes.
*
- do loops.
*
- Static fields in interfaces.
*
- Labels, or labelled break or continue.
*
* The intent is that dynamically generated code should be a simplified form of
* Java, much like the original Java 1.0 definition. This moves dynamic code
* generation to a level much closer to Java than to raw bytecode manipulation.
*
* As much as possible, this class uses standard Java keywords prefixed by "_" as
* method names. This helps to remember what the method name is for creating
* an if statement (_if of course). All public methods are static, and
* using static imports for this class is advisable: simple use
*
* import static org.glassfish.dynamic.codegen.spi.Wrapper.*
*
* to get easy access to all of the _xxx methods.
* A typical use of this class looks something like:
*
* _clear() ; // clean up any state from previous uses
* // optional:
* _setClassLoader(cl) ; // If you need a specific ClassLoader, set it early
// so that your generated code can be checked against
// those classes that it references.
* _package( "YYY" ) ; // set the package to use for the generated code
* _import( "AAA.BBB" ) ; // repeat as needed. As in Java, this makes "BBB"
* // a synonym for "AAA.BBB". Collisions are not
* // permitted.
* _class( ... ) ; // _interface is used for interfaces.
* _data( ... ) ; // define the class data members (repeat as needed)
* _initializer() ; // define a static initializer
*
*
* _method( ... ) ; // define a method (use _constructor for a constructor)
* _arg( ... ) ; // repeat as needed for the method arguments.
* _body() ; // begin the method body definition.
* // define the contents of the body using any of the available
* // statements.
* _end() ; // of method
* _end() ; // of class
* _end() ; // of package
* Class> newClass = _generate( ... ) ;
*
* Alternatively, the last line could be
*
* GenericClass gc = _generate( T.class, props ) ;
*
* which makes it easy to create an instance of the generated class
* by calling:
*
* T instance = gc.create( ) ;
*
*
* Currently only one class can be defined at a time.
* There is a grammar defined below that gives more detail.
* One small note: it is necessary to call _expr( expr ) in order to
* convert expr into a statement that is incorporated into a body.
* If this call is omitted, the generated code will NOT contain expr,
* leading to a difficult to find bug. I will probably fix this
* eventually, and treat all dangling expressions as errors.
*
* This class provides many short
* utility methods that operate against a current context that
* is maintained in a ThreadLocal. This removes the
* bookkeeping that would otherwise be needed to keep track
* of various internal factories needed for generating statements and expressions.
* Note that this class is designed to be statically imported.
*
* The point of view of the API of this class is that calls to create
* expressions are nested, while calls to create statements are not.
* That is, constructing an expression
* will often lead to nested method calls, but constructing a
* statement is done with a sequence of method calls. Note that
* everything could be done as a single nested method call per
* class, but this is unnatural and hard to debug in
* Java (Java is not Lisp, but you could make it look sort of
* like Lisp if you tried hard enough).
*
* All of the expression methods can be called any place where
* an expression is valid, which basically means anywhere a
* statement can be defined. The other methods can only be called
* if the sequence of method calls is contained in the language
* defined by the following grammar:
*
*
* START : _package IMPORTS CLASS _end ;
*
* IMPORTS : _import IMPORTS
* | empty ;
*
* CLASS : _class CDECLS _end ;
*
* CDECLS : CDECL CDECLS
* | empty ;
*
* CDECL : _data
* | _initializer STMTS _end
* | METHOD
* | CONSTRUCTOR ;
*
* METHOD : _method ARGS _body STMTS _end ;
*
* CONSTRUCTOR : _constructor ARGS _body STMTS _end ;
*
* ARGS : _arg ARGS
* | empty ;
*
* STMTS : STMT STMTS
* | empty ;
*
* STMT : IF
* | TRY
* | SWITCH
* | WHILE
* | SIMPLE ;
*
* IF : _if STMTS _end
* | _if STMTS _else STMTS _end ;
*
* TRY : _try STMTS CATCHES _end
* | _try STMTS _finally STMTS _end
* | _try STMTS CATCHES _finally STMTS _end ;
*
* CATCHES : _catch STMTS CATCHES
* | empty ;
*
* SWITCH : _switch CASES
* | _switch CASES _default STMTS _end ;
*
* CASES : _case STMTS CASES
* | empty ;
* XXX modify this to support multiple case labels per statement list
*
* WHILE : _while STMTS _end ;
*
* SIMPLE : _assign
* | _define
* | _return
* | _throw
* | _expr ;
*
*
* Any method that requires an expression can use any expression so long as
* all variables references in the expression are still in scope. This means
* that:
*
* - Variables representing data members can be referenced anywhere
* between the _class _body and _end.
*
- Variables representing method parameters can be referenced anywhere
* between the _method _body and _end.
*
- Variables representing _define statements can be referenced with in the
* scope of their block (that is, until the corresponding "}" in java. Here we
* don't use "{}" to delimit scope in the generated code).
*
- Variables representing _catch statements can be referenced until the next
* corresponding _catch, _finally, or _end.
* Any attempt to use an Expression that references a Variable that is out of scope
* will result in an IllegalStateException.
*
*
* The _classGenerator() method is used here to get the ClassGeneratorImpl,
* which can then be used in the CodeGenerator API to create source
* code or byte code directly. Also note that Util.display can be used
* to dump the contents of the ClassGeneratorImpl for debugging purposes.
*
* For convenience, methods are provided to display the AST (@see _displayAST),
* generate source code (@see _sourceCode), and generate byteCode
* (@see _byteCode).
*/
public final class Wrapper {
private Wrapper() {}
// Checking the sequence of operations in the class
// is equivalent to parsing a sentence in the grammar defined
// above. Some productions in the grammar have side effects
// such as updating the current ExpressionFactory or
// BlockStatement that is used in other places. Probably
// the simplest implementation here would be a recursive
// decent parser, but this assumes that the parser controls
// the call flow, and simply asks for the next token from
// a lexical analyzer in the usual way. But here the parser
// is not in control: the external program is.
//
// The implementation I have chosen here is to define a FSM
// with a stack that can effectively parse the above grammar.
// J2SE 5.0 provides some useful facilities (notably enums)
// that can be used in conjunction with the ORB FSM framework.
// This defines enums that implement the FSM state interface that
// can be used in the FSM
private enum Operation implements Input{
PACKAGE, // _package method
IMPORT, // _import method
CLASS, // _class method
DATA, // _data method
INITIALIZER, // _initializer method
METHOD, // _method method
ARG, // _arg method
BODY, // _body method
IF, // _if method
ELSE, // _else method
TRY, // _try method
CATCH, // _catch method
FINALLY, // _finally method
SWITCH, // _switch method
CASE, // _case method
DEFAULT, // _default method
WHILE, // _while method
SIMPLE, // _return, _throw, _assign, _define,
// and _expr methods
END } ; // _end method
// SIMPLE represents simple statements: return, throw, expr, assign
// and define.
// Note that the state objects must extend State, so we cannot
// use enum here.
private static final State S_INIT = new State( "S_INIT", State.Kind.INITIAL ) ;
private static final State S_DONE = new State( "S_DONE", State.Kind.FINAL ) ;
private static final State S_PACKAGE = new State( "S_PACKAGE" ) ;
private static final State S_CLASS = new State( "S_CLASS", State.Kind.INITIAL ) ;
private static final State S_INITIALIZER = new State( "S_INITIALIZER" ) ;
private static final State S_METHOD = new State( "S_METHOD", State.Kind.INITIAL ) ;
private static final State S_BODY = new State( "S_BODY", State.Kind.INITIAL ) ;
private static final State S_IF = new State( "S_IF", State.Kind.INITIAL ) ;
private static final State S_ELSE = new State( "S_ELSE" ) ;
private static final State S_TRY = new State( "S_TRY", State.Kind.INITIAL ) ;
private static final State S_FINAL = new State( "S_FINAL" ) ;
private static final State S_SWITCH = new State( "S_SWITCH", State.Kind.INITIAL ) ;
private static final State S_DEFAULT = new State( "S_DEFAULT" ) ;
private static final StateEngine engine = StateEngine.create() ;
// This set of transitions is used in several states,
// so we use this method to avoid repetition.
private static void addCommonTransitions( State state ) {
engine.add( state, Operation.SIMPLE, null, state ) ;
engine.add( state, Operation.IF, null, state ) ;
engine.add( state, Operation.TRY, null, state ) ;
engine.add( state, Operation.SWITCH, null, state ) ;
engine.add( state, Operation.WHILE, null, state ) ;
engine.add( state, Operation.END, null, S_DONE ) ;
}
static {
// Table of legal state transitions in each state:
// Any input not in the table is illegal.
// No transitions are legal in S_DONE.
//
// XXX We should provide a default action that prints out an appropriate
// error message (rather than the default FSM-specific one).
//
// State Input Action New State
engine.add( S_INIT, Operation.PACKAGE, null, S_PACKAGE ) ;
engine.add( S_PACKAGE, Operation.IMPORT, null, S_PACKAGE ) ;
engine.add( S_PACKAGE, Operation.CLASS, null, S_CLASS ) ;
engine.add( S_CLASS, Operation.DATA, null, S_CLASS ) ;
engine.add( S_CLASS, Operation.INITIALIZER, null, S_CLASS ) ;
engine.add( S_CLASS, Operation.METHOD, null, S_CLASS ) ;
engine.add( S_CLASS, Operation.END, null, S_DONE ) ;
engine.add( S_METHOD, Operation.BODY, null, S_BODY ) ;
engine.add( S_METHOD, Operation.ARG, null, S_METHOD ) ;
engine.add( S_METHOD, Operation.END, null, S_DONE ) ;
addCommonTransitions( S_BODY ) ;
addCommonTransitions( S_IF ) ;
engine.add( S_IF, Operation.ELSE, null, S_ELSE ) ;
addCommonTransitions( S_ELSE ) ;
addCommonTransitions( S_TRY ) ;
engine.add( S_TRY, Operation.CATCH, null, S_TRY ) ;
engine.add( S_TRY, Operation.FINALLY, null, S_FINAL ) ;
addCommonTransitions( S_FINAL ) ;
addCommonTransitions( S_SWITCH ) ;
engine.add( S_SWITCH, Operation.CASE, null, S_SWITCH ) ;
engine.add( S_SWITCH, Operation.DEFAULT, null, S_DEFAULT ) ;
addCommonTransitions( S_DEFAULT ) ;
}
// We need to represent the current state as a stack of contexts.
// The contexts are stacked as follows: class, method or body
// (for static initializers), statement*
// (any number of statement contexts can be nested).
// The context stack is used to manage ExpressionFactories and
// to support lookup of variable identifiers.
//
// We will not handle the push/pop interaction in the FSM.
// Instead, each Environment method that needs to push or
// pop will first update the current state machine, then (assuming
// there is no error) construct the type-specific context node.
// The constructor of the abstract base class Context actually
// pushes the Context onto the stack.
//
// Note that the sole purpose of the state machine is to make
// sure that operations are called in the correct order.
//
// Context Design
//
// All contexts are constructed with a reference to the Environment
// They are stacked in the following order:
// 1. ClassContext
// 2. MethodContext (or just a BodyContext for a static initializer)
// 3. If/Try/Switch/While StatementContext as needed.
//
private static abstract class Context {
private final Runner runner ;
private final Context parent ;
protected final Stack contexts ;
private ExpressionFactory expressionFactory ;
private BlockStatement blockStatement ;
public final ExpressionFactory ef() {
if (expressionFactory == null)
throw new IllegalStateException(
"No ExpressionFactory is currently available" ) ;
return expressionFactory ;
}
public final BlockStatement bs() {
if (blockStatement == null)
throw new IllegalStateException(
"No BlockStatement is currently available" ) ;
return blockStatement ;
}
protected final void setBlockStatement( BlockStatement bs ) {
blockStatement = bs ;
if (bs == null)
expressionFactory = null ;
else
expressionFactory = bs.exprFactory() ;
}
public Context( Stack contexts, State start ) {
FSM fsm = new FSMImpl( engine, start ) ;
this.runner = new Runner( fsm ) ;
this.contexts = contexts ;
if (contexts.empty())
this.parent = null ;
else
this.parent = contexts.peek() ;
contexts.push( this ) ;
expressionFactory = null ;
blockStatement = null ;
}
public final void stateTransition( Operation op ) {
runner.doIt( op ) ;
}
public final Context parent() {
return parent ;
}
// Overridden in subclasses that have other places to
// find variables besides the BlockStatement
protected Expression alternateLookup( String ident ) {
return null ;
}
// The main method used to search for variables.
// This works for all types of contexts. First,
// we look in the BlockStatement, if present.
// Some subclasses of Context override alternate
// lookup, which is called next. If the local
// call fails, we delegate to the parent (if any).
// Once all options fail, an exception is thrown.
public Expression getVariable( String ident ) {
Expression result = null ;
if (blockStatement != null)
result = blockStatement.getVar( ident ) ;
if (result == null)
result = alternateLookup( ident ) ;
if ((result == null) && (parent != null))
result = parent.getVariable( ident ) ;
if (result == null)
throw new IllegalArgumentException(
"Identifier " + ident + " not found." ) ;
return result ;
}
public void _end() {
contexts.pop() ;
}
}
// Context used for _package and _import.
private static final class PackageContext extends Context {
public PackageContext( Stack contexts ) {
// start of no-codegen copier
super( contexts, S_INIT ) ;
ClassCopierOrdinaryImpl.setCodegenCopierAllowed( false ) ;
}
}
// Context used for _class until
// we start defining methods or static initializers.
private static class ClassContext extends Context {
private final ClassGeneratorImpl cg ;
public ClassGeneratorImpl classGenerator() {
return cg ;
}
public ClassContext( Stack contexts, ClassGeneratorImpl cg ) {
super( contexts, S_CLASS ) ;
this.cg = cg ;
}
public FieldGenerator _data( int modifiers, Type type, String name ) {
return cg.addField( modifiers, type, name ) ;
}
public void _initializer() {
new BodyContext( contexts, cg.initializer() ) ;
}
public void _method( int modifiers, Type type, String name,
List exceptions ) {
MethodGenerator mg = cg.startMethod( modifiers, type, name,
exceptions) ;
new MethodContext( contexts, mg ) ;
}
public void _constructor( int modifiers, List exceptions ) {
MethodGenerator mg = cg.startConstructor( modifiers, exceptions ) ;
new MethodContext( contexts, mg ) ;
// XXX somewhere we need to force the first statement in
// a constructor to be an expression that is either this or super.
}
// This method returns a field access expression. This is the
// case of a variable lookup that resolves to a static or
// non-static field access expression. This just finds the field;
// access checks are handled elsewhere.
@Override
protected Expression alternateLookup( String ident ) {
FieldInfo fld = cg.findFieldInfo(ident) ;
if (fld == null)
throw new IllegalArgumentException( ident
+ " not found in " + cg.name() ) ;
return FieldGenerator.class.cast(fld).getExpression() ;
}
@Override
public void _end() {
super._end() ;
// end of no-codegen copier
ClassCopierOrdinaryImpl.setCodegenCopierAllowed( true ) ;
}
}
// Context used for all methods and constructors.
private static class MethodContext extends Context {
private MethodGenerator mg ;
public MethodGenerator methodGenerator() {
return mg ;
}
public MethodContext( Stack contexts, MethodGenerator mg ) {
super( contexts, S_METHOD ) ;
this.mg = mg ;
setBlockStatement( null ) ;
}
public Expression _arg( Type type, String ident ) {
return mg.addArgument( type, ident ) ;
}
public void _body() {
setBlockStatement( mg.body() ) ;
}
@Override
protected Expression alternateLookup( String ident ) {
for (Variable var : mg.arguments())
if (ident.equals( ((VariableInternal)var).ident()))
return var ;
return null ;
}
@Override
public void _end() {
super._end() ;
ClassGeneratorImpl cg = ClassGeneratorImpl.class.cast( mg.parent() ) ;
cg.methodComplete( mg ) ;
}
}
// Context used for static initializers.
private static class BodyContext extends Context {
public BodyContext( Stack contexts, BlockStatement bs ) {
super( contexts, S_BODY ) ;
setBlockStatement( bs ) ;
}
}
// Context used for if statements.
private static class IfStatementContext extends Context {
private final IfStatement ifstmt ;
public IfStatementContext( Stack contexts,
Expression expr ) {
super( contexts, S_IF ) ;
this.ifstmt = parent().bs().addIf( expr ) ;
setBlockStatement( ifstmt.truePart() ) ;
}
public void _else() {
setBlockStatement( ifstmt.falsePart() ) ;
}
}
// Context used for switch statements.
private static class SwitchStatementContext extends Context {
private final SwitchStatement swstmt ;
public SwitchStatementContext( Stack contexts,
Expression expr ) {
super( contexts, S_SWITCH ) ;
this.swstmt = parent().bs().addSwitch( expr ) ;
setBlockStatement( null ) ;
}
public void _case( int value ) {
setBlockStatement( swstmt.addCase( value ) ) ;
}
public void _default() {
setBlockStatement( swstmt.defaultCase() ) ;
}
}
// Context used for try statements.
private static class TryStatementContext extends Context {
private final TryStatement trystmt ;
private Variable currentCaseVariable ;
public TryStatementContext( Stack contexts ) {
super( contexts, S_TRY ) ;
this.trystmt = parent().bs().addTry() ;
currentCaseVariable = null ;
setBlockStatement( trystmt.bodyPart() ) ;
}
public Expression _catch( Type type, String name ) {
Pair pair =
trystmt.addCatch( type, name ) ;
setBlockStatement( pair.second() ) ;
currentCaseVariable = pair.first() ;
return currentCaseVariable ;
}
public void _finally() {
setBlockStatement( trystmt.finalPart() ) ;
currentCaseVariable = null ;
}
@Override
protected Expression alternateLookup( String ident ) {
if (currentCaseVariable != null)
if (ident.equals(
((VariableInternal)currentCaseVariable).ident()))
return currentCaseVariable ;
return null ;
}
@Override
public void _end() {
super._end() ;
if (trystmt.catches().entrySet().isEmpty() &&
trystmt.finalPart().isEmpty())
throw new IllegalStateException(
"A try statement must have at least one catch clause or a final part" ) ;
}
}
// Context used for while statements.
private static class WhileStatementContext extends Context {
private final WhileStatement whilestmt ;
public WhileStatementContext( Stack contexts,
Expression expr ) {
super( contexts, S_BODY ) ;
this.whilestmt = parent().bs().addWhile( expr ) ;
setBlockStatement(whilestmt.body()) ;
}
}
// The Environment is stored in a ThreadLocal and used for
// all of the Wrapper public methods.
private static class Environment {
private Stack contexts ;
private ImportList imports ;
private String _package ;
private ClassGeneratorImpl root ;
public ImportList imports() {
return imports ;
}
private T top( Class cls ) {
return cls.cast( contexts.peek() ) ;
}
public Environment() {
_clear() ;
}
void _clear() {
contexts = new Stack() ;
contexts.push( new PackageContext( contexts ) ) ;
imports = new ImportListImpl() ;
_package = "" ;
root = null ;
}
public Type _t( String name ) {
// look up the type in the table of imports.
// If not found, treat as a fully qualified name.
Type type = imports.lookup( name ) ;
if (type == null)
return Type._class( name ) ;
else
return type ;
}
public Expression _v( String name ) {
return contexts.peek().getVariable( name ) ;
}
public ClassGeneratorImpl classGenerator() {
return root ;
}
public Type _thisClass() {
return root.thisType() ;
}
public ExpressionFactory ef() {
return contexts.peek().ef() ;
}
public BlockStatement bs() {
return contexts.peek().bs() ;
}
private void checkState( Operation op ) {
contexts.peek().stateTransition( op ) ;
}
public final void _package( String name ) {
checkState( Operation.PACKAGE ) ;
if (!"".equals( name ))
Identifier.isValidFullIdentifier( name ) ;
_package = name ;
}
public final Type _import( final String name ) {
checkState( Operation.IMPORT ) ;
final Type type = Type._class( name ) ;
final Type itype = imports.lookup( type.className() ) ;
if (itype == null) {
imports.addImport( type ) ;
} else {
if (!type.equals( itype ))
throw new IllegalArgumentException( type.name()
+ " conflicts with " + itype.name() ) ;
}
return type ;
}
public final void _import( ImportList importList ) {
checkState( Operation.IMPORT ) ;
imports = importList.copy() ;
}
public final ImportList _import() {
checkState( Operation.IMPORT ) ;
return imports.copy() ;
}
public final void _class( int modifiers, String name,
Type superClass, List impls ) {
checkState( Operation.CLASS ) ;
String cname = name ;
if (!_package.equals(""))
cname = _package + "." + name ;
root = CodeGenerator.defineClass( modifiers,
cname, superClass, impls ) ;
new ClassContext( contexts, root ) ;
}
public final void _interface( int modifiers, String name,
List impls ) {
checkState( Operation.CLASS ) ;
String cname = name ;
if (!_package.equals(""))
cname = _package + "." + name ;
root = CodeGenerator.defineInterface( modifiers,
cname, impls ) ;
new ClassContext( contexts, root ) ;
}
public final FieldGenerator _data( int modifiers, Type type,
String name ) {
checkState( Operation.DATA ) ;
ClassContext cc = top( ClassContext.class ) ;
return cc._data( modifiers, type, name ) ;
}
public final void _initializer() {
checkState( Operation.INITIALIZER ) ;
ClassContext cc = top( ClassContext.class ) ;
cc._initializer() ;
}
public final void _method( int modifiers, Type type,
String name, List exceptions ) {
checkState( Operation.METHOD ) ;
ClassContext cc = top( ClassContext.class ) ;
cc._method( modifiers, type, name, exceptions ) ;
}
public final void _constructor( int modifiers, List exceptions ) {
checkState( Operation.METHOD ) ;
ClassContext cc = top( ClassContext.class ) ;
cc._constructor( modifiers, exceptions ) ;
}
public final Expression _arg( Type type, String name ) {
checkState( Operation.ARG ) ;
MethodContext mc = top( MethodContext.class ) ;
return mc._arg( type, name ) ;
}
public final void _body() {
checkState( Operation.BODY ) ;
MethodContext mc = top( MethodContext.class ) ;
mc._body() ;
}
public void _if( Expression expr ) {
checkState( Operation.IF ) ;
new IfStatementContext( contexts, expr ) ;
}
public void _else() {
checkState( Operation.ELSE ) ;
IfStatementContext isc = top( IfStatementContext.class ) ;
isc._else() ;
}
public void _try() {
checkState( Operation.TRY ) ;
new TryStatementContext( contexts ) ;
}
public Expression _catch( Type type, String name ) {
checkState( Operation.CATCH ) ;
TryStatementContext tsc = top( TryStatementContext.class ) ;
return tsc._catch( type, name ) ;
}
public void _finally() {
checkState( Operation.FINALLY ) ;
TryStatementContext tsc = top( TryStatementContext.class ) ;
tsc._finally() ;
}
public void _switch( Expression expr ) {
checkState( Operation.SWITCH ) ;
new SwitchStatementContext( contexts, expr ) ;
}
public void _case( int value ) {
checkState( Operation.CASE ) ;
SwitchStatementContext ssc = top( SwitchStatementContext.class ) ;
ssc._case( value ) ;
}
public void _default() {
checkState( Operation.DEFAULT ) ;
SwitchStatementContext ssc = top( SwitchStatementContext.class ) ;
ssc._default() ;
}
public void _while( Expression expr ) {
checkState( Operation.WHILE ) ;
new WhileStatementContext( contexts, expr ) ;
}
public void _end() {
checkState( Operation.END ) ;
contexts.peek()._end() ;
}
}
// This ThreadLocal maintains the environment for using the
// Wrapper methods in a thread.
private static ThreadLocal tl = new ThreadLocal() {
@Override
protected Environment initialValue() {
return new Environment() ;
}
} ;
private static Environment env() {
return tl.get() ;
}
//-------------------- Public API starts here -------------------------------
/** Obtain the ClassGeneratorImpl that is constructed by the Wrapper
* methods. This is only needed for using Wrapper with custom
* vistors.
*/
public static ClassGenerator _classGenerator() {
return env().classGenerator() ;
}
private static final String CODEGEN_PREFIX = "org.glassfish.dynamic.codegen" ;
private static final String DEBUG_PREFIX = CODEGEN_PREFIX +
".debug" ;
/** Set this to enable dumping the generated byte codes to a
* class file in the given directory.
*/
public static final String CLASS_GENERATION_DIRECTORY = CODEGEN_PREFIX +
".classGenerationDirectory" ;
/** Option used to enable generation of source files while
* generating bytecode. Set to name of directory that should
* contain the generated source file.
*/
public static final String SOURCE_GENERATION_DIRECTORY = CODEGEN_PREFIX +
".sourceGenerationDirectory" ;
/** Debugging option used to dump the contents of the AST after
* the setup visitor runs.
*/
public static final String DUMP_AFTER_SETUP_VISITOR = DEBUG_PREFIX +
".dumpAfterSetupVisitor" ;
/** Debugging option used to trace the byte code generation.
*/
public static final String TRACE_BYTE_CODE_GENERATION = DEBUG_PREFIX +
".traceByteCodeGeneration" ;
/** Causes contents of constant pool to be dumped.
*/
public static final String DUMP_CONSTANT_POOL = DEBUG_PREFIX +
".dumpConstantPool" ;
/** Debugging option used to enable the ASM verifier, which can be
* helpful for debugging errors in the code generation.
*/
public static final String USE_ASM_VERIFIER = DEBUG_PREFIX +
".useAsmVerifier" ;
/** Set the ClassLoader for this thread that will be used for validating
* references to pre-existing classes from generated code. Applications
* that use special ClassLoaders (such as the app server) should call this
* method before starting to generate a new Class. A good place to do this
* is just before the _package call.
*/
public static void _setClassLoader( ClassLoader cl ) {
CurrentClassLoader.set( cl ) ;
}
/** Generate byte codes for the current ClassGenerator.
* cl is used to resolve any references
* to other classes. options may be used
* to control some aspects of the code generation, such as
* debugging options. Supported options include
* DUMP_AFTER_SETUP_VISITOR, TRACE_BYTE_CODE_GENERATION,
* USE_ASM_VERIFIER.
*/
public static byte[] _byteCode( ClassLoader cl, Properties options ) {
return _byteCode( env().classGenerator(), cl, options ) ;
}
/** Generate byte codes for the ClassGenerator.
* cl is used to resolve any references
* to other classes. options may be used
* to control some aspects of the code generation, such as
* debugging options. Supported options include
* DUMP_AFTER_SETUP_VISITOR, TRACE_BYTE_CODE_GENERATION,
* USE_ASM_VERIFIER.
*/
public static byte[] _byteCode( ClassGenerator cgen, ClassLoader cl,
Properties options ) {
ClassGeneratorImpl cg = env().classGenerator() ;
ImportList imports = env().imports() ;
return CodeGenerator.generateBytecode( cg, cl, imports, options,
System.out ) ;
}
/** Convert an array of bytes into a Class using the given
* ClassLoader and ProtectionDomain. Use of this method requires
* the suppressAccessChecks ReflectionPermission.
*/
public static Class> _makeClass( byte[] data, String name,
ClassLoader cl, ProtectionDomain pd ) {
return CodeGeneratorUtil.makeClass( name, data, pd, cl ) ;
}
/** Generate a class for the current ClassGenerator.
* Basically equivalent to _byteCode followed by _makeClass.
* cl is used to resolve any references
* to other classes and to load the class given by
* the current ClassGenerator. options may be used
* to control some aspects of the code generation, such as
* debugging options.
*/
public static Class> _generate( ClassLoader cl, ProtectionDomain pd,
Properties props, PrintStream debugOutput ) {
ClassGenerator cg = env().classGenerator() ;
return _generate( cg, cl, pd, props, debugOutput ) ;
}
/** Generate a class for the ClassGenerator.
* Basically equivalent to _byteCode followed by _makeClass.
* cl is used to resolve any references
* to other classes and to load the class given by
* the current ClassGenerator. options may be used
* to control some aspects of the code generation, such as
* debugging options.
*/
public static Class> _generate( ClassGenerator cg, ClassLoader cl,
ProtectionDomain pd, Properties props, PrintStream debugOutput ) {
ImportList imports = env().imports() ;
byte[] data = CodeGenerator.generateBytecode( (ClassGeneratorImpl)cg,
cl, imports, props, debugOutput ) ;
return CodeGeneratorUtil.makeClass( cg.name(), data, pd, cl ) ;
}
/** Generate a class for the current ClassGenerator.
* Basically equivalent to _byteCode followed by _makeClass.
* cl is used to resolve any references
* to other classes and to load the class given by
* the current ClassGenerator. options may be used
* to control some aspects of the code generation, such as
* debugging options.
*/
public static Class> _generate( ClassLoader cl, ProtectionDomain pd,
Properties props ) {
ClassGenerator cg = env().classGenerator() ;
return _generate( cg, cl, pd, props ) ;
}
/** Generate a class for the current ClassGenerator.
* Basically equivalent to _byteCode followed by _makeClass.
* cl is used to resolve any references
* to other classes and to load the class given by
* the current ClassGenerator. options may be used
* to control some aspects of the code generation, such as
* debugging options.
*/
public static Class> _generate( ClassGenerator cg, ClassLoader cl,
ProtectionDomain pd, Properties props ) {
ImportList imports = env().imports() ;
byte[] data = CodeGenerator.generateBytecode( (ClassGeneratorImpl)cg,
cl, imports, props, System.out ) ;
return CodeGeneratorUtil.makeClass( cg.name(), data, pd, cl ) ;
}
private static ProtectionDomain getCurrentProtectionDomain( final Class cls ) {
if (System.getSecurityManager() == null) {
return cls.getProtectionDomain() ;
} else {
return AccessController.doPrivileged(
new PrivilegedAction() {
public ProtectionDomain run() {
return cls.getProtectionDomain() ;
}
}
) ;
}
}
/** Return a GenericClass instance so that we can easily create an instance
* of the generated class. This form should be used as an abbreviation,
* where the context ClassLoader and associated ProtectionDomain are all that
* is needed.
*/
public static GenericClass _generate( Class cls,
Properties props ) throws ClassNotFoundException {
ClassGenerator cg = env().classGenerator() ;
return _generate( cg, cls, props ) ;
}
/** Return a GenericClass instance so that we can easily create an instance
* of the generated class. This form should be used as an abbreviation,
* where the context ClassLoader and associated ProtectionDomain are all that
* is needed.
*/
public static GenericClass _generate( ClassGenerator cg,
Class cls, Properties props ) throws ClassNotFoundException {
ClassLoader cl = CurrentClassLoader.get() ;
ProtectionDomain pd = getCurrentProtectionDomain( cls ) ;
Class> implClass = _generate( cg, cl, pd, props ) ;
GenericClass gc = new GenericClass( cls, implClass ) ;
return gc ;
}
/** Generate the Java source code for the current Class defined by
* Wrapper calls. options may be used to control some aspects
* of the formatting of the source code, but no options are currently
* defined. The generate source code is written to the PrintStream.
*/
public static void _sourceCode( PrintStream ps,
Properties options ) throws IOException {
ClassGenerator cg = env().classGenerator() ;
_sourceCode( cg, ps, options ) ;
}
/** Generate the Java source code for the ClassGenerator.
* options may be used to control some aspects
* of the formatting of the source code, but no options are currently
* defined. The generate source code is written to the PrintStream.
*/
public static void _sourceCode( ClassGenerator cg, PrintStream ps,
Properties options ) throws IOException {
ImportList imports = env().imports() ;
CodeGenerator.generateSourceCode( ps,
(ClassGeneratorImpl)cg, imports, options ) ;
}
/** Generate source code into a specified output directory.
* options must set SOURCE_GENERATION_DIRECTORY to the name
* of the output directory.
*/
public static void _sourceCode( Properties options ) throws IOException {
ClassGenerator cg = env().classGenerator() ;
_sourceCode( cg, options ) ;
}
/** Generate source code into a specified output directory.
* options must set SOURCE_GENERATION_DIRECTORY to the name
* of the output directory.
*/
public static void _sourceCode( ClassGenerator cg,
Properties options ) throws IOException {
ImportList imports = env().imports() ;
String sourceGenDir = options.getProperty(
Wrapper.SOURCE_GENERATION_DIRECTORY ) ;
if (sourceGenDir == null) {
throw new IllegalArgumentException(
"options must specify SOURCE_GENERATION_DIRECTORY" ) ;
} else {
CodeGenerator.generateSourceCode( sourceGenDir,
(ClassGeneratorImpl)cg, imports,
options ) ;
}
}
/** Dump the contents of the AST for the current Class defined
* by Wrapper calls. The AST is dumped to the PrintStream.
*/
public static void _displayAST( PrintStream ps ) {
ClassGenerator cg = env().classGenerator() ;
_displayAST( cg, ps ) ;
}
/** Dump the contents of the AST for the current Class defined
* by Wrapper calls. The AST is dumped to the PrintStream.
*/
public static void _displayAST( ClassGenerator cg, PrintStream ps ) {
Util.display( (ClassGeneratorImpl)cg, ps ) ;
}
/** Discard the current Class generated by Wrapper calls, so that
* another Class may be generated.
*/
public static void _clear() {
env()._clear() ;
}
/** Create a signature that may be used for calling a method or
* constructor. rtype is the return type, and types gives all
* of the argument types. types is empty if there are no
* arguments.
*/
public static Signature _s( Type rtype, Type... types) {
return Signature.make( rtype, asList( types ) ) ;
}
/** Create a signature that may be used for calling a method or
* constructor. rtype is the return type, and types gives all
* of the argument types. types is empty if there are no
* arguments.
*/
public static Signature _s( Type rtype, List types) {
return Signature.make( rtype, types ) ;
}
// Types
/** Return the reference type for the given class name.
* name may be either the Class name, if the full name has
* been imported using an _import statement, or a
* fully qualified Class name.
*/
public static final Type _t( String name ) {
return env()._t( name ) ;
}
/** Return a representation of the void type. This is
* used whenever a method has a void return type.
*/
public static final Type _void() {
return Type._void() ;
}
/** Return a representation of the null type. This is
* the type of the null value. The null type is
* assignment compatible with any reference type.
* This is not normally needed in dynamically generated code.
*/
public static final Type _nullType() {
return Type._null() ;
}
/** Return a representation of the boolean type.
*/
public static final Type _boolean() {
return Type._boolean() ;
}
/** Return a representation of the byte type.
*/
public static final Type _byte() {
return Type._byte() ;
}
/** Return a representation of the short type.
*/
public static final Type _short() {
return Type._short() ;
}
/** Return a representation of the char type.
*/
public static final Type _char() {
return Type._char() ;
}
/** Return a representation of the int type.
*/
public static final Type _int() {
return Type._int() ;
}
/** Return a representation of the long type.
*/
public static final Type _long() {
return Type._long() ;
}
/** Return a representation of the float type.
*/
public static final Type _float() {
return Type._float() ;
}
/** Return a representation of the double type.
*/
public static final Type _double() {
return Type._double() ;
}
/** Return a representation of the java.lang.Object type.
*/
public static final Type _Object() {
return Type._Object() ;
}
/** Return a representation of the java.lang.String type.
*/
public static final Type _String() {
return Type._String() ;
}
/** Return a representation of the java.lang.Class type.
*/
public static final Type _Class() {
return Type._Class() ;
}
/** Return a representation of the array type with the
* given component type.
*/
public static final Type _array( Type type ) {
return Type._array( type ) ;
}
/** Split the class name into a pair of the package name and the unqualified class
* name. If name is the name of a class in the anonymous global package,
* the package name is "".
*/
public static final Pair splitClassName( String name ) {
int lastDot = name.lastIndexOf( '.' ) ;
String pname = (lastDot == -1) ? "" : name.substring( 0, lastDot ) ;
String cname = name.substring( lastDot + 1 ) ;
return new Pair( pname, cname ) ;
}
// Declarations
/** _package must be called first to set the package name for this
* class. After _package, all required _import calls must be made,
* followed by one _class call. name may be "", in which case
* the generated class is in the default package.
*/
public static final void _package( String name ) {
env()._package( name ) ;
}
/** Same as _package( "" ). Note that this method MUST be called
* before _class or _interface. This is a bit surprising,
* since Java allows omission of the package statement, but codegen
* requires an explicit package call.
*/
public static final void _package() {
env()._package( "" ) ;
}
/** Used to create short names for types. Name must be a fully
* qualified class name. The last name becomes the short
* name used in _t to look up the full type. The result Type can
* also be used directly.
*/
public static final Type _import( String name ) {
return env()._import( name ) ;
}
/** Return an ImportList that can be shared across multiple
* class generations.
*/
public static final ImportList _import() {
return env()._import() ;
}
/** Set the ImportList for the current class generation.
* Mainly useful for generating source code.
*/
public static final void _import( ImportList ilist ) {
env()._import( ilist ) ;
}
/** Define a class. This must be followed by calls to
* _data, _initializer, or _method in any order.
*/
public static final void _class( int modifiers, String name,
Type superClass, Type... impls ) {
env()._class( modifiers, name, superClass, asList(impls)) ;
}
/** Define a class. This must be followed by calls to
* _data, _initializer, or _method in any order.
*/
public static final void _class( int modifiers, String name,
Type superClass, List impls ) {
env()._class( modifiers, name, superClass, impls ) ;
}
/** Define an interface. This must be followed by calls to
* _method only. All _method calls must define abstract methods.
* Note that static data in interfaces is not currently supported.
*/
public static final void _interface( int modifiers, String name,
Type... impls ) {
env()._interface( modifiers, name, asList(impls) ) ;
}
/** Define an interface. This must be followed by calls to
* _method only. All _method calls must define abstract methods.
* Note that static data in interfaces is not currently supported.
*/
public static final void _interface( int modifiers, String name,
List impls ) {
env()._interface( modifiers, name, impls ) ;
}
/** Define a data member in a class. If static, it must be
* initialized in the class initializer, otherwise it must be
* initialized in a constructor.
*/
public static final Expression _data( int modifiers, Type type,
String name ) {
FieldGenerator fld = env()._data( modifiers, type, name ) ;
return fld.getExpression() ;
}
/* Begin or continue defining the static initializer for the class.
* Must be followed by any statement, or _end. May be re-opened
* later for additional statements.
*/
public static final void _initializer() {
env()._initializer() ;
}
/** Begin defining a method in the current class. Must be followed
* first be all _arg calls for the method, then by _body(), then
* by any statements, and finally by _end(). _body() may be followed
* immediately by _end(), in which case the method has an empty body.
* Abstract methods must have an empty body.
*/
public static final void _method( int modifiers, Type type,
String name, Type... exceptions ) {
env()._method( modifiers, type, name, asList(exceptions)) ;
}
/** Begin defining a method in the current class. Must be followed
* first by all _arg calls for the method, then by _body(), then
* by any statements, and finally by _end(). _body() may be followed
* immediately by _end(), in which case the method has an empty body.
* Abstract methods must have an empty body.
*/
public static final void _method( int modifiers, Type type,
String name, List exceptions ) {
env()._method( modifiers, type, name, exceptions ) ;
}
/** Begin defining a constructor in the current class.
* Must be followed
* first by all _arg calls for the constructor, then by _body(), then
* by optional statements, and finally by _end().
* Note that the first statement in any constructor must be
* a this() or super() call. Constructors may not have
* empty bodies.
*/
public static final void _constructor( int modifiers,
Type... exceptions ) {
env()._constructor( modifiers, asList(exceptions) ) ;
}
/** Begin defining a constructor in the current class.
* Must be followed
* first by all _arg calls for the constructor, then by _body(), then
* by any statements, and finally by _end().
* Note that the first statement in any constructor must be
* a _this() or _super() call. Constructors may not have
* empty bodies.
* Note that no default constructor is automatically generated
* using this API.
*/
public static final void _constructor( int modifiers,
List exceptions ) {
env()._constructor( modifiers, exceptions ) ;
}
/** Add an argument to the current method.
*/
public static final Expression _arg( Type type, String name ) {
return env()._arg( type, name ) ;
}
/** Indicates the start of the definition of the body of a method.
* Must be followed by 0 or more statements, and be terminated by _end().
*/
public static final void _body() {
env()._body() ;
}
/** Terminates the definition of the current statement, method,
* constructor, initializer, class, or package.
* Restores the context for the previous definition.
*/
public static final void _end() {
env()._end() ;
}
// Statements
/** Indicate that expr should be executed as a statement for its
* side effects.
*/
public static final void _expr( Expression expr ) {
env().bs().addExpression( expr ) ;
}
/** Indicates an assignment statement of the form var = expr.
* Var must be an assignable expression, such as a local variable,
* a non-final field reference, ior an array index expression.
*/
public static final void _assign( Expression var, Expression expr ) {
env().bs().addAssign( var, expr ) ;
}
/** Indicates the introduction of a new local variable initialized to
* the given expression.
*/
public static final Expression _define( Type type, String name,
Expression expr ) {
return env().bs().addDefinition( type, name, expr ) ;
}
/** Indicates a break statement, that should transfer control out of the
* nearest enclosing _switch or _while statement.
*/
public static final void _break() {
env().bs().addBreak() ;
}
/** Indicates the end of execution in a method. Can only occur inside
* a definition of a method with a void return type.
*/
public static final void _return() {
env().bs().addReturn() ;
}
/** Indicates the end of execution in a method with a return of the
* value of the expression. The type of the expression must be
* assignment compatible with the return type of the enclosing method.
*/
public static final void _return( Expression expr ) {
env().bs().addReturn( expr ) ;
}
/** Indicates a throw statement that throws the given expression.
* The type of expr must support Throwable.
*/
public static final void _throw( Expression expr ) {
env().bs().addThrow( expr ) ;
}
/** Indicate the start of an if statement with the given expression
* as the condition. All subsequent statements until the next
* matching _else are part of the true branch of this if statement.
*/
public static final void _if( Expression expr ) {
env()._if( expr ) ;
}
/** Indicate the start of the false branch of an if statement.
* All subsequent statements until the next matching _end are
* part of the false branch of the corresponding if statement.
*/
public static final void _else() {
env()._else() ;
}
/** Indicate the start of a try statement.
* All subsequent statements until the next matching _catch
* or _finally are part of this try statement.
*/
public static final void _try() {
env()._try() ;
}
/** Indicate the start of a catch clause in a try statement.
* All subsequent statements until the next matching _catch
* or _finally are part of this catch clause.
*/
public static final Expression _catch( Type type, String name ) {
return env()._catch( type, name ) ;
}
/** Indicate the start of a finally clause in a try statement.
* All subsequent statements until the next matching _end
* are part of this finally clause.
*/
public static final void _finally() {
env()._finally() ;
}
/** Indicate the start of a switch statement with the given
* expression at the switch expression. expr must have
* type int.
* Must be followed by a _case or _default call.
*/
public static final void _switch( Expression expr ) {
env()._switch( expr ) ;
}
/** Indicate the start of a particular case in a switch
* statement. All statements until the next corresponding
* _case or _default are part of this case.
*/
public static final void _case( int value ) {
env()._case( value ) ;
}
/** Indicate the start of the default case in a switch
* statement. All statements until the next corresponding
* _end are part of the default case.
*/
public static final void _default() {
env()._default() ;
}
/** Indicate the start of a while loop with the given
* expression as its condition. All statements until
* the next corresponding _end are part of the while loop.
*/
public static final void _while( Expression expr ) {
env()._while( expr ) ;
}
// Expressions
/** Construct the expression that refers to
* the variable named name. This is looked up
* following the Java name scope rules.
*/
public static final Expression _v(String name) {
return env()._v(name) ;
}
/** Return the null expression.
*/
public static final Expression _null() {
return env().ef()._null() ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( boolean c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( char c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( byte c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( short c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( int c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( long c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( float c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( double c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c.
*/
public static final Expression _const( String c ) {
return env().ef()._const(c) ;
}
/** Return a constant expression representing the
* value c. Here c is a type, and this corresponds
* to the Java ".class" reference.
*/
public static final Expression _const( Type c ) {
return env().ef()._const(c) ;
}
/** Generate a call to an instance method. The full signature
* must be specified.
*/
public static final Expression _call( Expression target, String ident,
Signature signature, Expression... args ) {
return env().ef().call( target, ident, signature, asList(args) ) ;
}
/** Generate a call to an instance method. The full signature
* must be specified.
*/
public static final Expression _call( Expression target, String ident,
Signature signature, List args ) {
return env().ef().call( target, ident, signature, args ) ;
}
/** Generate a call to an instance method, using the Java method
* overload resolution algorithm to determine the signature.
*/
public static final Expression _call( Expression target, String ident,
Expression... args ) {
return env().ef().call( target, ident, asList(args) ) ;
}
/** Generate a call to an instance method, using the Java method
* overload resolution algorithm to determine the signature.
*/
public static final Expression _call( Expression target, String ident,
List args ) {
return env().ef().call( target, ident, args ) ;
}
/** Generate a call to a static method. The full signature
* must be specified.
*/
public static final Expression _call( Type target, String ident,
Signature signature, Expression... args ) {
return env().ef().staticCall( target, ident, signature, asList(args) ) ;
}
/** Generate a call to a static method. The full signature
* must be specified.
*/
public static final Expression _call( Type target, String ident,
Signature signature, List args ) {
return env().ef().staticCall( target, ident, signature, args ) ;
}
/** Generate a call to a static method, using the Java method
* overload resolution algorithm to determine the signature.
*/
public static final Expression _call( Type target, String ident,
Expression... args ) {
return env().ef().staticCall( target, ident, asList(args) ) ;
}
/** Generate a call to a static method, using the Java method
* overload resolution algorithm to determine the signature.
*/
public static final Expression _call( Type target, String ident,
List args ) {
return env().ef().staticCall( target, ident, args ) ;
}
/** Generate a call to an instance method in the current super
* class. The full signature must be specified.
*/
public static final Expression _super( String ident,
Signature signature, Expression... exprs ) {
return env().ef().superCall( ident, signature, asList(exprs) ) ;
}
/** Generate a call to an instance method in the current super
* class. The full signature must be specified.
*/
public static final Expression _super( String ident,
Signature signature, List exprs ) {
return env().ef().superCall( ident, signature, exprs ) ;
}
/** Generate a call to an instance method in the current super
* class using the Java method overload resolution algorithm to
* determine the signature.
*/
public static final Expression _super( String ident,
Expression... exprs ) {
return env().ef().superCall( ident, asList(exprs) ) ;
}
/** Generate a call to an instance method in the current super
* class using the Java method overload resolution algorithm to
* determine the signature.
*/
public static final Expression _super( String ident,
List exprs ) {
return env().ef().superCall( ident, exprs ) ;
}
/** Invoke a superclass constructor as the first statement
* in a constructor for a class. The full signature must
* be specified.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _super( Signature signature,
Expression... exprs ) {
return env().ef().superObj( signature, asList(exprs) ) ;
}
/** Invoke a superclass constructor as the first statement
* in a constructor for a class. The full signature must
* be specified.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _super( Signature signature,
List exprs ) {
return env().ef().superObj( signature, exprs ) ;
}
/** Invoke a superclass constructor as the first statement
* in a constructor for a class using the Java method overload
* resolution algorithm to determine the signature.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _super( List exprs ) {
return env().ef().superObj( exprs ) ;
}
/** Invoke a superclass constructor as the first statement
* in a constructor for a class using the Java method overload
* resolution algorithm to determine the signature.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _super( Expression... exprs ) {
return env().ef().superObj( asList(exprs) ) ;
}
/** Invoke another constructor as the first statement
* in a constructor for a class. The full signature must
* be specified.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _this( Signature signature,
Expression... exprs ) {
return env().ef().thisObj( signature, asList(exprs) ) ;
}
/** Invoke another constructor as the first statement
* in a constructor for a class. The full signature must
* be specified.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _this( Signature signature,
List exprs ) {
return env().ef().thisObj( signature, exprs ) ;
}
/** Invoke another constructor as the first statement
* in a constructor for a class using the Java method overload
* resolution algorithm to determine the signature.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _this( Expression... exprs ) {
return env().ef().thisObj( asList(exprs) ) ;
}
/** Invoke another constructor as the first statement
* in a constructor for a class using the Java method overload
* resolution algorithm to determine the signature.
* This may only be used as the first expression
* in a constructor. Every constructor must begin with
* either a super(...) call or a this(...) call.
*/
public static final Expression _this( List exprs ) {
return env().ef().thisObj( exprs ) ;
}
/** Create an expression representing the application of the
* unary operator op to the given expression.
*/
private static final Expression _unary( ExpressionFactory.UnaryOperator op,
Expression expr ) {
return env().ef().unaryOp( op, expr ) ;
}
public static final Expression _not( Expression expr ) {
return _unary( ExpressionFactory.UnaryOperator.NOT, expr ) ;
}
private static final Expression _binary( Expression left,
ExpressionFactory.BinaryOperator op, Expression right ) {
return env().ef().binaryOperator( left, op, right ) ;
}
// Abbreviated forms for _binary
/** Create an expression representing the application of the
* + operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _add( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.PLUS,
right ) ;
}
/** Create an expression representing the application of the
* + operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _sub( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.MINUS,
right ) ;
}
/** Create an expression representing the application of the
* + operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _mul( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.TIMES,
right ) ;
}
/** Create an expression representing the application of the
* + operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _div( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.DIV,
right ) ;
}
/** Create an expression representing the application of the
* + operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _rem( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.REM,
right ) ;
}
/** Create an expression representing the application of the
* < operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _lt( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.LT,
right ) ;
}
/** Create an expression representing the application of the
* > operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _gt( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.GT,
right ) ;
}
/** Create an expression representing the application of the
* <= operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _le( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.LE,
right ) ;
}
/** Create an expression representing the application of the
* >= operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _ge( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.GE,
right ) ;
}
/** Create an expression representing the application of the
* == operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _eq( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.EQ,
right ) ;
}
/** Create an expression representing the application of the
* != operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _ne( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.NE,
right ) ;
}
/** Create an expression representing the application of the
* && operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _and( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.AND,
right ) ;
}
/** Create an expression representing the application of the
* || operator to the left and right expressions in the
* form (left op right).
*/
public static final Expression _or( Expression left,
Expression right ) {
return _binary( left, ExpressionFactory.BinaryOperator.OR,
right ) ;
}
/** Create an expression representing the type cast of expr
* to type.
*/
public static final Expression _cast( Type type, Expression expr ) {
return env().ef().cast( type, expr ) ;
}
/** Create an expression representing the instanceof test of
* expr and type (expr instanceof type).
*/
public static final Expression _instanceof( Expression expr, Type type ) {
return env().ef().instof( expr, type ) ;
}
/** Create an expression representing the construction of a
* new instance of the given type using the constructor with the
* given signature and the list of expressions as arguments.
*/
public static final Expression _new( Type type,
Signature signature, Expression... args ) {
return env().ef().newObj( type, signature, asList(args) ) ;
}
/** Create an expression representing the construction of a
* new instance of the given type using the constructor with the
* given signature and the list of expressions as arguments.
*/
public static final Expression _new( Type type,
Signature signature, List args ) {
return env().ef().newObj( type, signature, args ) ;
}
/** Create an expression representing the construction of a
* new instance of the given type using the constructor with the
* signature determined by the Java method overload resolution
* algorithm and the list of expressions as arguments.
*/
public static final Expression _new( Type type,
Expression... args ) {
return env().ef().newObj( type, asList(args) ) ;
}
/** Create an expression representing the construction of a
* new instance of the given type using the constructor with the
* signature determined by the Java method overload resolution
* algorithm and the list of expressions as arguments.
*/
public static final Expression _new( Type type,
List args ) {
return env().ef().newObj( type, args ) ;
}
/** Create an expression representing the construction of a
* new array with the given component type using the given
* expressions to initialize the array. We really only
* support single dimensional arrays here. The size of the
* resulting array is the number of expressions given here.
*/
public static final Expression _new_array_init( Type type,
Expression... args ) {
return env().ef().newArrInit( type, asList(args) ) ;
}
/** Create an expression representing the construction of a
* new array with the given component type using the given
* expressions to initialize the array. We really only
* support single dimensional arrays here. The size of the
* resulting array is the number of expressions given here.
* Equivalent to new A[] = { exprList }.
*/
public static final Expression _new_array_init( Type type,
List args ) {
return env().ef().newArrInit( type, args ) ;
}
/** Create an expression representing the construction of a
* new array of the given size with the given component type.
* Equivalent to new A[x].
*/
public static final Expression _new_array( Type type, Expression size ) {
return env().ef().newArr( type, size ) ;
}
/** Return the type of the current class.
*/
public static final Type _thisClass() {
return env()._thisClass() ;
}
/** Return an expression representing "this".
*/
public static final Expression _this() {
return env().ef()._this() ;
}
/** Return an expression used to access a field in an object
* given by expr. This expression may appear on the left side
* of an assignment statement.
*/
public static final Expression _field( Expression expr, String fieldName ) {
return env().ef().fieldAccess( expr, fieldName ) ;
}
/** Return an expression used to access a static data member in
* a class given by the type. This expression may appear on the
* left side of an assignment statement (but probably shouldn't).
*/
public static final Expression _field( Type type, String fieldName ) {
return env().ef().fieldAccess( type, fieldName ) ;
}
/** Return an expression used to access an element in an array
* given by expr. This expression may appear on the left side
* of an assignment statement.
*/
public static final Expression _index( Expression expr, Expression index ) {
return env().ef().arrayIndex( expr, index ) ;
}
/** Return an expression that gets the length of expr. expr must be
* an array type.
*/
public static final Expression _length( Expression expr ) {
return env().ef().arrayLength( expr ) ;
}
}