/* * * 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 java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.flex.abc.semantics.Label; import org.apache.flex.compiler.internal.tree.as.ConditionalNode; import org.apache.flex.compiler.internal.tree.as.IfNode; import org.apache.flex.compiler.internal.tree.as.LabeledStatementNode; import org.apache.flex.compiler.internal.tree.as.SwitchNode; import org.apache.flex.compiler.internal.tree.as.TerminalNode; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.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. */ 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; } }