/*
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.apache.flex.compiler.internal.as.codegen;

import org.apache.flex.abc.instructionlist.InstructionList;
import org.apache.flex.abc.semantics.Label;
import org.apache.flex.compiler.tree.as.IASNode;

/**
 * There is an active ControlFlowContext for each syntactic region that can
 * introduce new labels or requires clean up code in the presence of non-linear
 * code.:
 * <dl>
 * <dt>Loops</dt>
 * <dd>Loops can contain break or continue statements. Loops also scope label
 * definitions.</dd>
 * <dt>try/catch/finally</dt>
 * <dd>Jumps ( using break, continue, or goto ) out of a try block require the
 * finally block to be executed.
 * <p>
 * Jumps out of an exception handler block require code to adjust the scope
 * chain.</dd>
 * <dt>with</dt>
 * <dd>Jumps ( using break, continue, or goto ) out of a with block require code
 * to adjust the scope chain.</dd>
 * </dl>
 * <p>
 * Helper methods on the {@link ControlFlowContextManager} push and pop sub-classes of this class
 * on and off an activation stack in {@link ControlFlowContextManager}.
 */
public abstract class ControlFlowContext
{
    protected ControlFlowContext(IASNode controlFlowTreeNode)
    {
        this.controlFlowTreeNode = controlFlowTreeNode;
    }
    
    final IASNode controlFlowTreeNode;
    
    /**
     * Virtual method called by the criteria objects returned from
     * {@link ControlFlowContextManager#breakWithLabelCriteria(String)}.
     * Sub-classes of this class that contain a target which can be referenced by
     * a break statement with a label should return true.
     * @param label Name of the label referenced by a break statement.
     * @return true if the context contains a label with the specified name that can
     * be referenced by a break statement with a label, false otherwise.
     */
    boolean hasBreakLabel(String label)
    {
        return false;
    }
    
    /**
     * Virtual method called by the criteria object returned from
     * {@link ControlFlowContextManager#breakWithOutLabelCriteria}. Sub-classes
     * of this class that contain a target which can be referenced by a break
     * statement without a label should return true.
     * 
     * @return true if this context contains the target of a break statement,
     * false otherwise.
     */
    boolean hasDefaultBreakLabel()
    {
        return false;
    }
    
    
    /**
     * @return The {@link Label} that break statements that target this control
     * flow context should jump to.
     */
    Label getBreakLabel()
    {
        return null;
    }
    
    /**
     * Virtual method called by the criteria objects returned from
     * {@link ControlFlowContextManager#continueWithLabelCriteria(String)}
     * Sub-classes of this class that contain a target which can be referenced by
     * a continue statement with a label should return true.
     * @param label Name of the label referenced by a continue statement.
     * @return true if the context contains a label with the specified name that can
     * be referenced by a continue statement with a label, false otherwise.
     */
    boolean hasContinueLabel(String label)
    {
        return false;
    }
    

    
    /**
     * Virtual method called by the criteria object returned from
     * {@link ControlFlowContextManager#continueWithOutLabelCriteria}.
     * Sub-classes of this class that contain a target which can be referenced
     * by a continue statement without a label should return true.
     * 
     * @return true if this context contains the target of a continue statement,
     * false otherwise.
     */
    boolean hasDefaultContinueLabel()
    {
        return false;
    }
    
    /**
     * @return The {@link Label} that continue statements that target this control
     * flow context should jump to.
     */
    Label getContinueLabel()
    {
        return null;
    }
    
    /**
     * Virtual method called by the criteria objects returned from
     * {@link ControlFlowContextManager#gotoLabelCriteria(String, boolean)}.
     * Sub-classes of this class that contain a target which can be referenced
     * by a goto statement should return true.
     * <p>
     * If there is more than one label in this context with the specified label,
     * then this should should return false, unless the allowDuplicates option
     * is true.
     * 
     * @param label Name of the labeled referenced by a goto statement.
     * @param allowDuplicates If false, this method will return false if there
     * is more than one label with the specified name in this context. If true,
     * this method will return true if there is at least one label in this
     * context with the specified name.
     * @return <ul>
     * <li>true if there is exactly one label in this context with the specified
     * name</li> <li>true if allowDuplicates is true <b>and</b> there is at
     * least one label in this context with the specified name.</li> <li>false
     * otherwise</li>
     * </ul>
     */
    boolean hasGotoLabel(String label, boolean allowDuplicates)
    {
        return false;
    }
    
    /**
     * @return The {@link Label} that goto statements that target this control
     * flow context should jump to.
     */
    Label getGotoLabel(String label)
    {
        return null;
    }
    
    /**
     * Create a new instruction list that starts with code to exit this control
     * flow context and ends the specified instructions.
     * <p>
     * Sub-classes should override this method if a jump out of this control
     * flow context requires code other than the jump to run. Eg: When jumping
     * out of a try or exception block, the finally block must be run first.
     * 
     * @param exitBranch Code to execute after leaving this control flow
     * context.
     * @return A new instruction list that contains code the exit this control
     * flow context and all the instructions from the specified instruciton
     * list.
     */
    InstructionList addExitPath(InstructionList exitBranch)
    {
        return exitBranch;
    }
    
    /**
     * Add instructions to the specified instruction list that will re-establish
     * this control flow context ( currently this code only ever push a value on
     * the scope stack ).
     * 
     * @param exceptionHandler {@link InstructionList} to add to.
     */
    void addExceptionHandlerEntry(InstructionList exceptionHandler)
    {
        
    }
}
