Пример #1
0
 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));
 }
Пример #2
0
			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);
			}
Пример #3
0
			// 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);
				}
			}
Пример #4
0
			/// <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);
			}
Пример #5
0
				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;
				}
Пример #6
0
			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);
			}
Пример #7
0
			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);
			}
Пример #8
0
			/// <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
					}
				}
			}
Пример #9
0
		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;
		}
Пример #10
0
		public virtual void ReplaceChildrenOf(Alts pred, bool includeError) 
		{
			VisitAndReplace(pred.Arms);
			if (includeError && pred.ErrorBranch != null && pred.ErrorBranch != DefaultErrorBranch.Value)
				VisitAndReplace(ref pred.ErrorBranch);
		}
Пример #11
0
		public override void Visit(Alts pred)    { VisitOther(pred); ReplaceChildrenOf(pred, true); }
Пример #12
0
		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);
		}
Пример #13
0
		public virtual void Visit(Alts alts)        { VisitOther(alts); }