All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.dev.compiler.java.ForStatement Maven / Gradle / Ivy

There is a newer version: 24.03
Show newest version
/*
 * 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;
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy