com.tangosol.dev.compiler.java.ForStatement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.dev.compiler.java;
import com.tangosol.dev.assembler.CodeAttribute;
import com.tangosol.dev.assembler.Begin;
import com.tangosol.dev.assembler.End;
import com.tangosol.dev.assembler.Label;
import com.tangosol.dev.assembler.Goto;
import com.tangosol.dev.assembler.Ifne;
import com.tangosol.dev.compiler.CompilerException;
import com.tangosol.dev.compiler.Context;
import com.tangosol.dev.component.DataType;
import com.tangosol.util.ErrorList;
import com.tangosol.util.NullImplementation;
import java.util.Set;
import java.util.Map;
import java.util.Iterator;
import java.util.HashSet;
/**
* This class implements the for loop construct.
*
* ForStatement:
* for ( ForInit-opt ; Expression-opt ; ForUpdate-opt ) Statement
* ForInit:
* StatementExpressionList
* LocalVariableDeclaration
* ForUpdate:
* StatementExpressionList
* StatementExpressionList:
* StatementExpression
* StatementExpressionList , StatementExpression
*
* @version 1.00, 09/21/98
* @author Cameron Purdy
*/
public class ForStatement extends Block
{
// ----- construction ---------------------------------------------------
/**
* Construct a for statement.
*
* @param stmt the statement within which this element exists
* @param token the "for" token
*/
public ForStatement(Statement stmt, Token token)
{
super(stmt, token);
}
// ----- code generation ------------------------------------------------
/**
* Perform semantic checks, parse tree re-organization, name binding,
* and optimizations.
*
* @param ctx the compiler context
* @param setUVars the set of potentially unassigned variables
* @param setFVars the set of potentially assigned final variables
* @param mapThrown the set of potentially thrown checked exceptions
* @param errlist the error list
*
* @exception CompilerException thrown if an error occurs that should
* stop the compilation process
*/
protected Element precompile(Context ctx, DualSet setUVars, DualSet setFVars, Map mapThrown, ErrorList errlist)
throws CompilerException
{
Statement stmtInit = getInit();
Expression exprTest = getTest();
Statement stmtUpdate = getUpdate();
Statement stmtBody = getBody();
// for statements have their own variable scope
DualSet setUBlockVars = new DualSet(setUVars);
DualSet setFBlockVars = new DualSet(setFVars);
// JLS 16.2.10 for Statements
// - V is definitely assigned before the initialization part of the
// for statement iff V is definitely assigned before the for
// statement.
// JLS 16.2.10.1 Initialization Part
// - If the initialization part of the for statement is a local
// variable declaration statement, the rules of 16.2.3 apply.
// - Otherwise, if the initialization part is empty, then V is
// definitely assigned after the initialization part iff V is
// definitely assigned before the initialization part.
// - Otherwise, three rules apply:
// - V is definitely assigned after the initialization part
// iff V is definitely assigned after the last expression
// statement in the initialization part.
// - V is definitely assigned before the first expression
// statement in the initialization part iff V is definitely
// assigned before the initialization part.
// - V is definitely assigned before an expression statement E
// other than the first in the initialization part iff V is
// definitely assigned after the expression statement
// immediately preceding E.
while (stmtInit != null)
{
stmtInit.precompile(ctx, setUBlockVars, setFBlockVars, mapThrown, errlist);
stmtInit = stmtInit.getNextStatement();
}
// determine what final variables were assigned by just the init
// portion of the for statement
Set setFInitAssigned = NullImplementation.getSet();
if (!setFBlockVars.getAdded().isEmpty())
{
setFInitAssigned = new HashSet(setFBlockVars.getAdded());
}
// JLS 16.2.10 for Statements
// - V is definitely assigned before the condition part of the for
// statement iff V is definitely assigned after the initialization
// part of the for statement.
if (exprTest != null)
{
exprTest = (Expression) exprTest.precompile(ctx, setUBlockVars, setFBlockVars, mapThrown, errlist);
exprTest.checkBoolean(errlist);
setTest(exprTest);
}
// JLS 16.2.10 for Statements
// - V is definitely assigned before the contained statement iff
// either of the following is true:
// - A condition expression is present and V is definitely
// assigned after the condition expression when true.
// - No condition expression is present and V is definitely
// assigned after the initialization part of the for
// statement.
DualSet setUTrueVars = new DualSet(setUBlockVars.getTrueSet());
DualSet setFTrueVars = new DualSet(setFBlockVars.getTrueSet());
stmtBody.precompile(ctx, setUTrueVars, setFTrueVars, mapThrown, errlist);
// JLS 16.2.10 for Statements
// - V is definitely assigned before the incrementation part of the
// for statement iff V is definitely assigned after the contained
// statement and V is definitely assigned before every continue
// statement that may exit the body of the for statement.
// JLS 16.2.10.2 Incrementation Part
// - If the incrementation part of the for statement is empty, then
// V is definitely assigned after the incrementation part iff V is
// definitely assigned before the incrementation part.
// - Otherwise, three rules apply:
// - V is definitely assigned after the incrementation part iff
// V is definitely assigned after the last expression
// statement in the incrementation part.
// - V is definitely assigned before the first expression
// statement in the incrementation part iff V is definitely
// assigned before the incrementation part.
// - V is definitely assigned before an expression statement E
// other than the first in the incrementation part iff V is
// definitely assigned after the expression statement
// immediately preceding E.
while (stmtUpdate != null)
{
stmtUpdate.precompile(ctx, setUTrueVars, setFTrueVars, mapThrown, errlist);
stmtUpdate = stmtUpdate.getNextStatement();
}
// JLS 16.2.10 for Statements
// - V is definitely assigned after a for statement iff both of the
// following are true:
// - Either a condition expression is not present or V is
// definitely assigned after the condition expression when
// false.
// - V is definitely assigned before every break statement that
// may exit the for statement.
setUTrueVars.addAll(getBreakUVars());
setUTrueVars.resolve();
setUBlockVars.merge();
Set setAssigned = setUBlockVars.getRemoved();
if (!setAssigned.isEmpty())
{
// it is not possible for a statement block to cause variables
// from its outer block to become unassigned (i.e. nothing is
// added to setUVars) but it is possible that some have been
// assigned (i.e. need to be removed)
setUVars.removeAll(setAssigned);
}
// likewise for the final variables ("definite unassignment")
setFTrueVars.addAll(getBreakFVars());
setFTrueVars.resolve();
setFBlockVars.merge();
// no new final variables have been declared for the outer block,
// but it is possible that final variables that were previously
// declared for the outer block have since been potentially assigned
setAssigned = setFBlockVars.getAdded();
if (!setAssigned.isEmpty())
{
// some of the assigned final variables may not be from the
// outer variable scope
setAssigned.retainAll(getBlock().getVariables());
if (!setAssigned.isEmpty())
{
setFVars.addAll(setAssigned);
}
// it is an error for a final variable declared outside of the
// for statement to be assigned within the for statement, except
// by the init portion which is only executed once
setAssigned.removeAll(setFInitAssigned);
if (!setAssigned.isEmpty())
{
for (Iterator iter = setAssigned.iterator(); iter.hasNext(); )
{
Variable var = (Variable) iter.next();
logError(ERROR, FINAL_IN_LOOP, new String[] {var.getName()}, errlist);
}
}
}
return this;
}
/**
* Perform final optimizations and code generation.
*
* @param ctx the compiler context
* @param code the assembler code attribute to compile to
* @param fReached true if this language element is reached (JLS 14.19)
* @param errlist the error list to log errors to
*
* @return true if the element can complete normally (JLS 14.1)
*
* @exception CompilerException thrown if an error occurs that should
* stop the compilation process
*/
protected boolean compileImpl(Context ctx, CodeAttribute code, boolean fReached, ErrorList errlist)
throws CompilerException
{
// compilation for "for (; ; ) ":
//
// start:
// begin
// [init-opt]
// goto test
// again:
// [stmt]
// lcp: // loop continuation point
// [update-opt]
// test:
// [test]
// ifne again
// end
// end:
//
// compilation for "for (; ; ) ":
// (also for which evaluates to true)
//
// start:
// begin
// [init-opt]
// again: // loop continuation point
// [stmt]
// lcp: // loop continuation point
// [update-opt]
// test:
// goto again
// end
// end:
Statement stmtInit = getInit();
Expression exprTest = getTest();
Statement stmtUpdate = getUpdate();
Statement stmtBody = getBody();
// determine endless (e.g. "for(;true;)" or "for(;;)")
boolean fEndless = false;
if (exprTest == null)
{
fEndless = true;
}
else if (exprTest instanceof BooleanExpression || !ctx.isDebug() && exprTest.isConstant())
{
if (((Boolean) exprTest.getValue()).booleanValue())
{
// "for(;true;)" or equivalent
fEndless = true;
}
else
{
// JLS 14.19: The contained statement is reachable iff
// the for statement is reachable and the condition
// expression is not a constant expression whose value is
// false.
if (fReached)
{
stmtBody.notReached(errlist);
}
// since "for (;false;)" or equivalent is optimized out
// entirely, the for statement can complete if reached
return fReached;
}
}
code.add(new Begin());
// figure out where the loop continuation label goes (see above)
Label lblAgain = new Label();
Label lblContinue = getContinuationLabel();
Label lblTest = new Label();
// compile for-init statement list (if it exists)
while (stmtInit != null)
{
stmtInit.compile(ctx, code, fReached, errlist);
stmtInit = stmtInit.getNextStatement();
}
// execute the test (if it exists) before the inner statement
if (!fEndless)
{
code.add(new Goto(lblTest));
}
// repeat the for body
code.add(lblAgain);
// compile statement
stmtBody.compile(ctx, code, fReached, errlist);
// loop continuation point
code.add(lblContinue);
// compile update statement list (if it exists)
while (stmtUpdate != null)
{
stmtUpdate.compile(ctx, code, fReached, errlist);
stmtUpdate = stmtUpdate.getNextStatement();
}
// location of for-exit test
code.add(lblTest);
if (fEndless)
{
// no exit condition
code.add(new Goto(lblAgain));
}
else
{
// test for-exit condition
exprTest.compile(ctx, code, fReached, errlist);
code.add(new Ifne(lblAgain));
}
code.add(new End());
// JLS 14.19: A for statement can complete normally iff at least
// one of the following is true:
// - The for statement is reachable, there is a condition
// expression, and the condition expression is not a constant
// expression with value true.
// - There is a reachable break statement that exits the for
// statement.
// (Note: Completion via a break statement is implemented by the
// Statement.compile() method, which wraps this method.)
return fReached && !fEndless;
}
// ----- accessors ------------------------------------------------------
/**
* Get the init statement.
*
* @return the init statement
*/
public Statement getInit()
{
return init;
}
/**
* Set the init statement.
*
* @param init the init statement
*/
protected void setInit(Statement init)
{
this.init = init;
}
/**
* Get the test expression.
*
* @return the test expression
*/
public Expression getTest()
{
return test;
}
/**
* Set the test expression.
*
* @param test the test expression
*/
protected void setTest(Expression test)
{
this.test = test;
}
/**
* Get the update statement.
*
* @return the update statement
*/
public Statement getUpdate()
{
return update;
}
/**
* Set the update statement.
*
* @param update the update statement
*/
protected void setUpdate(Statement update)
{
this.update = update;
}
/**
* Get the body of the for statement.
*
* @return the body of the for statement
*/
public Statement getBody()
{
return getInnerStatement();
}
// ----- Element methods ------------------------------------------------
/**
* Print the element information.
*
* @param sIndent
*/
public void print(String sIndent)
{
out(sIndent + toString());
out(sIndent + " Init:");
if (init == null)
{
out(sIndent + " ");
}
else
{
init.print(sIndent + " ");
}
out(sIndent + " Test:");
if (test == null)
{
out(sIndent + " ");
}
else
{
test.print(sIndent + " ");
}
out(sIndent + " Update:");
if (update == null)
{
out(sIndent + " ");
}
else
{
update.print(sIndent + " ");
}
out(sIndent + " Statement:");
getInnerStatement().print(sIndent + " ");
}
// ----- data members ---------------------------------------------------
/**
* The class name.
*/
private static final String CLASS = "ForStatement";
/**
* The conditional expression.
*/
private Expression test;
/**
* A linked list of ForInit statements.
*/
private Statement init;
/**
* A linked list of ForUpdate statements.
*/
private Statement update;
}