public bool Equals(SmogonOob?other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(this, other)) { return(true); } return(DexNumber == other.DexNumber && Evolutions.SetEquals(other.Evolutions) && Alts.SetEquals(other.Alts) && GenFamily.SetEquals(other.GenFamily)); }
public override void Visit(Alts alts) { _currentAlts = alts; KthSet[] firstSets = LLPG.ComputeFirstSets(alts); if (LLPG.Verbosity > 0) { var sb = new StringBuilder(); for (int i = 0; i < firstSets.Length; i++) { if (firstSets[i].Alt == -1 || LLPG.Verbosity > 2) { if (sb.Length != 0) sb.Append('\n'); sb.AppendFormat("First set for {0}: {1}", firstSets[i].Alt == -1 ? "exit" : "alt #" + (firstSets[i].Alt + 1), firstSets[i]); } } if (sb.Length != 0) LLPG.Output(Verbose, alts, sb.ToString()); } try { EzStopwatch TEMP = new EzStopwatch(true); alts.PredictionTree = ComputePredictionTree(firstSets); if (TEMP.Millisec > 500) LLPG.Output(Warning, alts, "Slug? This took a long time to analyze: " + TEMP.Millisec + "ms"); } catch (System.Threading.ThreadAbortException) { LLPG.Output(Error, alts, "ThreadAbortException in rule '" + _currentRule.Name + "'"); // user diagnostic throw; } if ((LLPG.Verbosity & 2) != 0) LLPG.Output(Verbose, alts, "(unsimplified) " + alts.PredictionTree.ToString()); SimplifyPredictionTree(alts.PredictionTree); AddElseCases(alts, alts.PredictionTree); _currentAlts = null; if ((LLPG.Verbosity & 1) != 0) LLPG.Output(Verbose, alts, "(simplified) " + alts.PredictionTree.ToString()); VisitChildrenOf(alts, true); }
// GENERATED CODE EXAMPLE: The methods in this region generate // the for(;;) loop in this example and everything inside it, except // the calls to Match() which are generated by Visit(TerminalPred). // The generated code uses "goto" and "match" blocks in some cases // to avoid code duplication. This occurs when the matching code // requires multiple statements AND appears more than once in the // prediction tree. Otherwise, matching is done "inline" during // prediction. We generate a for(;;) loop for (...)*, and in certain // cases, we generates a do...while(false) loop for (...)?. // // rule Foo @{ (('a'|'A') 'A')* 'a'..'z' 'a'..'z' }; // public void Foo() // { // int la0, la1; // for (;;) { // la0 = LA(0); // if (la0 == 'a') { // la1 = LA(1); // if (la1 == 'A') // goto match1; // else // break; // } else if (la0 == 'A') // goto match1; // else // break; // match1: // { // Match('A', 'a'); // Match('A'); // } // } // MatchRange('a', 'z'); // MatchRange('a', 'z'); // } private void GenerateCodeForAlts(Alts alts, Dictionary<int, int> timesUsed, PredictionTree tree) { bool needError = LLPG.NeedsErrorBranch(tree, alts); if (!needError && alts.ErrorBranch != null) LLPG.Output(Warning, alts, "The error branch will not be used because the other alternatives are exhaustive (cover all cases)"); bool userDefinedError = needError && alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value; // Generate matching code for each arm. the "string" in each pair // becomes non-null if the matching code for that branch needs to be // split out (separated) from the prediction tree because it appears // multiple times in the tree. The string is the goto-label name. Pair<LNode, string>[] matchingCode = new Pair<LNode, string>[alts.Arms.Count + (userDefinedError ? 1 : 0)]; MSet<int> unreachable = new MSet<int>(); int separateCount = 0; for (int i = 0; i < alts.Arms.Count; i++) { if (!timesUsed.ContainsKey(i)) { unreachable.Add(i); continue; } var codeForThisArm = new WList<LNode>(); VisitWithNewTarget(alts.Arms[i], codeForThisArm); matchingCode[i].A = F.Braces(codeForThisArm.ToVList()); if (timesUsed[i] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { separateCount++; matchingCode[i].B = alts.Arms[i].ChooseGotoLabel() ?? "match" + (i + 1).ToString(); } } // Add matching code for the error branch, if present. Note: the // default error branch, which is produced by IPGCodeGenHelper. // ErrorBranch() is handled differently: default error code can // differ at each error point in the prediction tree. Therefore // we generate it later, on-demand. if (userDefinedError) { int i = alts.Arms.Count; var errorHandler = new WList<LNode>(); VisitWithNewTarget(alts.ErrorBranch, errorHandler); matchingCode[i].A = F.Braces(errorHandler.ToVList()); if (timesUsed[ErrorAlt] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { matchingCode[i].B = "error"; separateCount++; } } // Print unreachability warnings if (unreachable.Count == 1) LLPG.Output(Warning, alts, string.Format("Branch {{{0}}} is unreachable.", alts.AltName(unreachable.First()))); else if (unreachable.Count > 1) LLPG.Output(Warning, alts, string.Format("Branches {{{0}}} are unreachable.", unreachable.Select(i => alts.AltName(i)).Join(", "))); if (!timesUsed.ContainsKey(ExitAlt) && alts.Mode != LoopMode.None) LLPG.Output(Warning, alts, "Infinite loop. The exit branch is unreachable."); Symbol loopType = null; // Choose a loop type for (...)* or (...)?: if (alts.Mode == LoopMode.Star) loopType = S.For; else if (alts.Mode == LoopMode.Opt) { if (alts.HasErrorBranch(LLPG) || alts.NonExitDefaultArmRequested()) loopType = S.DoWhile; } // If the code for an arm is nontrivial and appears multiple times // in the prediction table, it will have to be split out into a // labeled block and reached via "goto". I'd rather just do a goto // from inside one "if" statement to inside another, but in C# // (unlike in CIL, and unlike in C) that is prohibited :( DeduplicateLabels(matchingCode); var extraMatching = GenerateExtraMatchingCode(matchingCode, separateCount, ref loopType); if (separateCount != 0) loopType = loopType ?? S.DoWhile; Symbol breakMode = loopType; // used to request a "goto" label in addition to the loop LNode code = GeneratePredictionTreeCode(tree, matchingCode, ref breakMode); // Add break/continue between prediction tree and extra matching code, // if necessary. if (extraMatching.Count != 0 && CodeGenHelperBase.EndMayBeReachable(code)) { loopType = loopType ?? S.DoWhile; extraMatching.Insert(0, GetContinueStmt(loopType)); } if (!extraMatching.IsEmpty) code = LNode.MergeLists(code, F.Braces(extraMatching), S.Braces); if (loopType == S.For) { // (...)* => for (;;) {} code = F.Call(S.For, F.List(), F.Missing, F.List(), code); } else if (loopType == S.DoWhile) { // (...)? becomes "do {...} while(false);" IF the exit branch is NOT the default. // If the exit branch is the default, then no loop and no "break" is needed. code = F.Call(S.DoWhile, code, F.@false); } if (breakMode != loopType && breakMode != null) { // Add "stop:" label (plus extra ";" for C# compatibility, in // case the label ends the block in which it is located.) var stopLabel = F.Call(S.Label, F.Id(breakMode)) .PlusTrailingTrivia(F.Trivia(S.TriviaRawText, ";")); code = LNode.MergeLists(code, stopLabel, S.Braces); } int oldCount = _target.Count; _target.SpliceAdd(code, S.Braces); // Add comment before code if (LLPG.AddComments) { var pos = alts.Basis.Range.Start; var comment = F.Trivia(S.TriviaSLComment, string.Format(" Line {0}: {1}", pos.Line, alts.ToString())); if (_target.Count > oldCount) _target[oldCount] = _target[oldCount].PlusAttr(comment); } }
/// <summary> /// Visit(Alts) is the most important method in this class. It generates /// all prediction code, which is the majority of the code in a parser. /// </summary> public override void Visit(Alts alts) { PredictionTree tree = alts.PredictionTree; var timesUsed = new Dictionary<int, int>(); tree.CountTimesUsed(timesUsed); GenerateCodeForAlts(alts, timesUsed, tree); }
public override void Visit(Alts alts) { bool stop = true; _reachedInnerAlts = true; if (alts.Mode == LoopMode.None) { stop = false; int startIndex = _index; int length = -1; foreach (var p in alts.ArmsAndCustomErrorBranch) { _index = startIndex; p.Call(this); int newLen = _index - startIndex; if (length == -1) length = newLen; else if (length != newLen) stop = true; } } // stop prematching after a variable-length Alts (including any loop) // ...or after a default error branch (we don't know what it consumes) if (stop || alts.HasDefaultErrorBranch(LLPG)) _index = int.MaxValue; }
void ScanTree(PredictionTree tree, Alts alts, DList<Prematched> path) { int oldCount = path.Count; while (path.Count <= tree.Lookahead) path.Add(new Prematched { Terminals = Anything }); Prematched pm = path.Last; if (tree.IsAssertionLevel) { foreach (PredictionBranch b in tree.Children) { var old = pm.AndPreds.Clone(); var verified = Enumerable.Aggregate(b.AndPreds, (set1, set2) => (set1.Union(set2))); // usually empty if more than one pm.AndPreds.UnionWith(verified); if (b.Sub.Tree != null) { ScanTree(b.Sub.Tree, alts, path); } else { Debug.Assert(b.Sub.Alt != ErrorAlt); if (b.Sub.Alt == ExitAlt) _apply.ApplyPrematchData(alts.Next, path); else _apply.ApplyPrematchData(alts.Arms[b.Sub.Alt], path); } pm.AndPreds = old; } } else // !IsAssertionLevel (terminal-matching level) { bool needErrorBranch = LLPG.NeedsErrorBranch(tree, alts); for (int i = 0; i < tree.Children.Count; i++) { PredictionBranch b = tree.Children[i]; IPGTerminalSet set = b.Set; if (!needErrorBranch && i + 1 == tree.Children.Count) // Add all the default cases set = set.Union(tree.TotalCoverage.Inverted()); pm.Terminals = set; if (b.Sub.Tree != null) { ScanTree(b.Sub.Tree, alts, path); } else { if (b.Sub.Alt == ExitAlt) _apply.ApplyPrematchData(alts.Next, path); else if (b.Sub.Alt != ErrorAlt) _apply.ApplyPrematchData(alts.Arms[b.Sub.Alt], path); } } path.PopLast(); } path.Resize(oldCount); }
public override void Visit(Alts alts) { // Traverse each prediction tree find branches taken and save prematch info ScanTree(alts.PredictionTree, alts, new DList<Prematched>()); VisitChildrenOf(alts, true); }
/// <summary>Extends each level of the prediction tree so that it has /// total coverage. For example, a typicaly prediction tree might have /// branches for 'a'..'z' and '0..'9'; this method will add coverage for /// all other possible inputs. It does this either by adding an error /// branch, or by extending the set handled by the default branch of /// each level.</summary> private void AddElseCases(Alts alts, PredictionTree tree) { foreach (var branch in tree.Children) if (branch.Sub.Tree != null) AddElseCases(alts, branch.Sub.Tree); if (tree.IsAssertionLevel) { tree.Children.Last.AndPreds.Clear(); tree.Children.Last.AndPreds.Add(Set<AndPred>.Empty); } else if (!tree.TotalCoverage.ContainsEverything) { var rest = tree.TotalCoverage.Inverted(); if (alts.HasErrorBranch(LLPG)) tree.Children.Add(new PredictionBranch(rest, new PredictionTreeOrAlt { Alt = ErrorAlt }, tree.TotalCoverage)); else { // No error branch, so use default arm #if false // First try: this tends to produce less intuitive code. Neither // version is objectively better; sometimes this version gives // faster code and sometimes the other version gives faster code. int defaultArm = alts.DefaultArmInt(); foreach (PredictionBranch branch in tree.Children) if (branch.Sub.Tree == null && branch.Sub.Alt == defaultArm) { branch.Set = branch.Set.Union(rest); goto done; } if (alts.DefaultArm != null) tree.Children.Add(new PredictionBranch(rest, defaultArm, tree.TotalCoverage)); else tree.Children.Last.Set = tree.Children.Last.Set.Union(rest); done:; #else PredictionBranch last = tree.Children.Last; if (alts.DefaultArm != null && (last.Sub.Tree != null || last.Sub.Alt != alts.DefaultArm.Value)) tree.Children.Add(new PredictionBranch(rest, alts.DefaultArm.Value, tree.TotalCoverage)); else last.Set = last.Set.Union(rest); #endif } } }
private Pred TranslateLoopExpr(LNode expr, Context ctx) { Symbol type = expr.Name; bool? greedy = null; bool g; expr = expr.Args[0]; if ((g = expr.Calls(_Greedy, 1)) || expr.Calls(_Nongreedy, 1)) { greedy = g; expr = expr.Args[0]; } BranchMode branchMode; Pred subpred = BranchToPred(expr, out branchMode, ctx); if (branchMode == BranchMode.ErrorContinue || branchMode == BranchMode.ErrorExit) _sink.Error(expr, "'error' only applies when there are multiple arms (a|b, a/b)"); Pred clone = type == _Plus ? subpred.Clone() : null; Alts alts = new Alts(expr, type == _Opt ? LoopMode.Opt : LoopMode.Star, clone ?? subpred, greedy); if (branchMode == BranchMode.Default) alts.DefaultArm = 0; if (clone != null) return new Seq(subpred, alts, expr); else return alts; }
public virtual void ReplaceChildrenOf(Alts pred, bool includeError) { VisitAndReplace(pred.Arms); if (includeError && pred.ErrorBranch != null && pred.ErrorBranch != DefaultErrorBranch.Value) VisitAndReplace(ref pred.ErrorBranch); }
public override void Visit(Alts pred) { VisitOther(pred); ReplaceChildrenOf(pred, true); }
public void VisitChildrenOf(Alts pred, bool includeError) { foreach (var p in pred.Arms) p.Call(this); if (includeError && pred.ErrorBranch != null && pred.ErrorBranch != DefaultErrorBranch.Value) pred.ErrorBranch.Call(this); }
public virtual void Visit(Alts alts) { VisitOther(alts); }