Beispiel #1
0
        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);
        }
Beispiel #2
0
        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();
        }