blob: a01549f84aecc25accc79f875c4147ad4e75aa2d [file] [log] [blame]
/*
*
* 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.royale.compiler.internal.as.codegen;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.royale.abc.semantics.Label;
import org.apache.royale.compiler.internal.tree.as.ConditionalNode;
import org.apache.royale.compiler.internal.tree.as.IfNode;
import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode;
import org.apache.royale.compiler.internal.tree.as.SwitchNode;
import org.apache.royale.compiler.internal.tree.as.TerminalNode;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
/**
* {@link ControlFlowContext} sub-class for a syntactic region of a function the
* determines the visibility of labels referenced by goto statements. goto
* statements can not reference labels in a a in a loop, with statement, try,
* catch, or finally unless the construct containing the label is an ancestor of
* the goto statement.
*/
class LabelScopeControlFlowContext extends ControlFlowContext
{
/**
* @param controlFlowTreeNode Syntax tree node for which this context is being created.
*/
public LabelScopeControlFlowContext(IASNode controlFlowTreeNode)
{
super(controlFlowTreeNode);
aetLabelMap = new HashMap<String, Label>();
}
private Multimap<String, LabeledStatementNode> labelNameToLabeledStatments;
private final Map<String, Label> aetLabelMap;
private Multimap<String, LabeledStatementNode> getLabelMap()
{
if (labelNameToLabeledStatments != null)
return labelNameToLabeledStatments;
labelNameToLabeledStatments = LinkedListMultimap.<String, LabeledStatementNode>create();
populateLabelMap(labelNameToLabeledStatments, controlFlowTreeNode);
return labelNameToLabeledStatments;
}
/**
* Scans the tree looking for labels that can be referenced from goto
* statements in the syntactic region for which this context was created.
*
* @param labelMap Map to populate with found labels
* @param node Node to search from.
*/
@SuppressWarnings("incomplete-switch")
private static void populateLabelMap(Multimap<String, LabeledStatementNode> labelMap, IASNode node)
{
ASTNodeID nodeID = node.getNodeID();
switch (nodeID)
{
case IfStatementID:
{
IfNode ifNode = (IfNode) node;
int nIfNodeChildren = ifNode.getChildCount();
for (int i = 0; i < nIfNodeChildren; ++i)
{
IASNode ifNodeChild = ifNode.getChild(i);
if (ifNodeChild instanceof ConditionalNode)
{
ConditionalNode conditionalNode = (ConditionalNode) ifNodeChild;
IASNode conditionalBlockNode = conditionalNode.getContentsNode();
assert conditionalBlockNode != null;
populateLabelMap(labelMap, conditionalBlockNode);
}
else if (ifNodeChild instanceof TerminalNode)
{
TerminalNode terminalNode = (TerminalNode) ifNodeChild;
IASNode terminalBlockNode = terminalNode.getContentsNode();
assert terminalBlockNode != null;
populateLabelMap(labelMap, terminalBlockNode);
}
}
}
break;
case LabledStatementID:
{
LabeledStatementNode labelNode = (LabeledStatementNode) node;
String labelName = labelNode.getLabel();
if (labelName != null)
labelMap.put(labelName, labelNode);
populateLabelMap(labelMap, labelNode.getLabeledStatement());
}
break;
case FileID:
case BlockID:
case MXMLEventSpecifierID:
{
int childCount = node.getChildCount();
for (int i = 0; i < childCount; ++i)
{
IASNode child = node.getChild(i);
assert child != null;
populateLabelMap(labelMap, child);
}
}
break;
case SwitchID:
{
SwitchNode switchNode = (SwitchNode)node;
populateLabelMap(labelMap, switchNode.getStatementContentsNode());
}
break;
case ConditionalID:
{
ConditionalNode conditionalNode = (ConditionalNode)node;
populateLabelMap(labelMap, conditionalNode.getStatementContentsNode());
}
break;
}
}
/**
* Finds all the {@link LabeledStatementNode}'s in this context with the
* specified label name.
*
* @param label Name of the {@link LabeledStatementNode}'s to search for.
* @return All the {@link LabeledStatementNode}'s in this context with the
* specified label name.
*/
Collection<LabeledStatementNode> getLabelNodes(String label)
{
Multimap<String, LabeledStatementNode> labelMap = getLabelMap();
return labelMap.get(label);
}
@Override
Label getGotoLabel(String label)
{
assert !getLabelNodes(label).isEmpty() : "Don't try to get AET labels for labels not in this context!";
Label result = aetLabelMap.get(label);
if (result != null)
return result;
result = new Label(label);
aetLabelMap.put(label, result);
return result;
}
@Override
boolean hasGotoLabel(String label, boolean allowDuplicates)
{
Multimap<String, LabeledStatementNode> labelMap = getLabelMap();
if (allowDuplicates)
return labelMap.containsKey(label);
else
return labelMap.get(label).size() == 1;
}
}