private string ComputeRecursiveExitLabel(LabelGroupData data, string label) { var labelData = data[label]; var recursiveExit = labelData.DirectExitLabel; if (recursiveExit == null) { return(null); } while (recursiveExit != null) { LabelGroupLabelData targetLabelData; if (!data.TryGetValue(recursiveExit, out targetLabelData)) { // The label is part of another label group. return(null); } if (targetLabelData.DirectExitLabel == null) { if ( (targetLabelData.ExitTargetLabels.Count == 0) /* && * FIXME: Is this right? * (targetLabelData.UntargettedExitCount <= 1) */ ) { return(recursiveExit); } else { return(null); } } else { // Cycle detected if (recursiveExit == targetLabelData.DirectExitLabel) { return(null); } recursiveExit = targetLabelData.DirectExitLabel; } // Cycle detected if (recursiveExit == label) { return(null); } } return(null); }
public void VisitNode(JSLabelGroupStatement lgs) { CheckForFallthrough(lgs); var data = new LabelGroupData(); LabelGroupStack.Push(data); foreach (var key in lgs.Labels.Keys) { data.Add(key.Value, new LabelGroupLabelData()); } VisitChildren(lgs); // Scan all the labels to determine their direct exit label, if any foreach (var kvp in data) { var targetLabels = kvp.Value.ExitTargetLabels.Distinct().ToArray(); if ( (targetLabels.Length == 1) && (kvp.Value.UntargettedExitCount == 0) ) { kvp.Value.DirectExitLabel = targetLabels[0]; } else { kvp.Value.DirectExitLabel = null; } } // Scan all the labels again to determine their recursive exit label foreach (var kvp in data) { var rel = kvp.Value.RecursiveExitLabel = ComputeRecursiveExitLabel(data, kvp.Key); if (rel != null) { data[rel].TimesUsedAsRecursiveExitTarget += 1; } } // If we have one label that is the recursive exit target for all other labels, we can turn it into the exit label var recursiveExitTargets = data.Where( (kvp) => kvp.Value.TimesUsedAsRecursiveExitTarget > 0 ).ToArray(); if (recursiveExitTargets.Length == 1) { var onlyRecursiveExitTarget = recursiveExitTargets[0].Key; var exitLabel = lgs.ExitLabel; var newExitLabel = lgs.Labels[onlyRecursiveExitTarget]; var newExitLabelData = data[newExitLabel.Label]; if ( (newExitLabelData.ExitTargetLabels.Count == 0) && (newExitLabelData.UntargettedExitCount == 0) && (newExitLabel != lgs.Labels.LastOrDefault().Value) ) { if (TraceLevel >= 1) { Console.WriteLine("// Cannot mark label '{0}' as exit label because it falls through and is not the last label", onlyRecursiveExitTarget); } } else if (exitLabel != null) { if (exitLabel != newExitLabel) { if (TraceLevel >= 1) { Console.WriteLine("// Cannot mark label '{0}' as exit label because this labelgroup already has one", onlyRecursiveExitTarget); } } } else { if (TraceLevel >= 1) { Console.WriteLine("// Marking label '{0}' as exit label", onlyRecursiveExitTarget); } lgs.ExitLabel = newExitLabel; MadeChanges = true; } } if ((lgs.ExitLabel != null) && (lgs.Labels.Count > 1)) { ExtractExitLabel(lgs); } LabelGroupStack.Pop(); }