private AltLoopStatus TryOneAlternative(int ip, VarStack varStack, ListPatternElem e, int k, int marker, ListTerm RangeList, int i, BaseTerm t, ref bool negSearchSucceeded, BaseTerm searchTerm) { bool unified = searchTerm.Unify(t, varStack); if (e.IsNegSearch) // none of the terms in the inner loop may match. ~(a | b | c) = ~a & ~b & ~c { if (unified) // ... no point in investigating the other alternatives if one does { negSearchSucceeded = false; return(AltLoopStatus.Break); // don't try the other alternatives } return(AltLoopStatus.TryNextDown); // non of the downranges matches may lead to a success } else { if (unified && // we found a match. Unify, and TryBindingAltListVarToMatch(e.AltListBindVar, t, varStack) && // bind the AltListBindVar to the match TryBindingRangeRelatedVars(e, i, RangeList, varStack)) // bind the range to the range variables { if (ip == pattern.Length - 1) // this was the last pattern element { if (k == target.Count - 1) // both pattern and target exhausted { return(AltLoopStatus.MatchFound); } } else if (UnifyTailEx(ip + 1, k + 1, varStack)) // now deal with the rest { return(AltLoopStatus.MatchFound); } } // if we arrive here, it was not possible to ... // (1) ... unify the range's SearchTerm with the target element, or // (2) ... unify the range variable with the range last, or // (3) ... successfully process the rest of the pattern and target // Now unbind and try matching with the next target element BaseTerm.UnbindToMarker(varStack, marker); return(AltLoopStatus.TryNextDown); // try the next downrange match } }
// calculated the upper and lower bounds imposed by the remainder of the pattern bool DoLowerAndUpperboundChecks(int ip, int it, out int minLen, out int maxLen) { ListPatternElem e = (ListPatternElem)pattern[ip]; int minRangeLen = e.MinRangeLen; // min and max range length ... int maxRangeLen = e.MaxRangeLen; // ... as specified in ListPatternElem int termLen = (e.HasSearchTerm ? 1 : 0); // take the search term into account if present // calculated the minimum required and maximum possible range length, // given the rest of the pattern and the remaining part of the target int minRequiredForRestOfRanges = 0; int maxPossibleForRestOfRanges = 0; // calculated the minimum and maximum remaining pattern length (and // hence the number of target terms that should still be available) for (int i = ip + 1; i < pattern.Length; i++) { minRequiredForRestOfRanges += (e = (ListPatternElem)pattern[i]).MinRangeTermLen; maxPossibleForRestOfRanges = ListPatternElem.SaveAdd(maxPossibleForRestOfRanges, e.MaxRangeTermLen); } // calculate the number of target terms that are actually available int remainingTargetLength = target.Count - it; // 'it' is the index of the first of the remaining target terms // calculate the lower bound for the number of target terms to be consumed by this range int minRequiredRangeLen = Math.Max(0, remainingTargetLength - termLen - maxPossibleForRestOfRanges); // calculate the upper bound for the number of target terms to be consumed by this range int maxPossibleRangeLen = remainingTargetLength - termLen - minRequiredForRestOfRanges; // the bounds just calculated must be adjusted with the values specified in the range descriptor itself. // the lower bound should always at least be equal to minRequiredRangeLen, so take the highest value minLen = Math.Max(minRangeLen, minRequiredRangeLen); // the upper bound should always at most be equal to maxPossibleRangeLen, so take the lowest value maxLen = Math.Min(maxRangeLen, maxPossibleRangeLen); return(minLen <= maxLen); // fail if we ended up with a zero-length range }
BaseTerm CopyEx(int newVerNo, bool mustBeNamed) { if (IsUnified) { return(ChainEnd().CopyEx(newVerNo, mustBeNamed)); } // A neater solution would be to use overrides for each term subtype. if (this is Variable) { Variable v = (Variable)this; if (newVerNo == v.verNo) { return(v.newVar); } v.verNo = newVerNo; return(v.newVar = (mustBeNamed && this is NamedVariable) ? new NamedVariable(((NamedVariable)v).Name) : new Variable()); } else if (this is CatchOpenTerm) { CatchOpenTerm c = (CatchOpenTerm)this; return(new CatchOpenTerm(c.Id, c.ExceptionClass, c.MsgVar.CopyEx(newVerNo, mustBeNamed), c.SeqNo, c.SaveStackSize)); } else { if (arity == 0) { return(this); } BaseTerm t = null; BaseTerm[] a = new BaseTerm[arity]; for (int i = 0; i < arity; i++) { if (args[i] != null) // may be null for a GapTerm { a[i] = args[i].CopyEx(newVerNo, mustBeNamed); // recursively refresh arguments } } if (this is ListPatternTerm) { t = new ListPatternTerm(a); } else if (this is AltListTerm) { AltListTerm alt = (AltListTerm)this; t = new AltListTerm(alt.LeftBracket, alt.RightBracket, a[0], a[1]); } else if (this is ListTerm) { if (((ListTerm)this).CharCodeString == null) { t = new ListTerm(a[0], a[1]); } else // it's an ISO-style string { t = new ListTerm(((ListTerm)this).CharCodeString); } } else if (this is OperatorTerm) { t = new OperatorTerm(((OperatorTerm)this).od, a); } else if (this is DcgTerm) { t = new DcgTerm(functor, a); } else if (this is WrapperTerm) { t = new WrapperTerm((WrapperTerm)this, a); } else if (this is IntRangeTerm) { t = new IntRangeTerm((IntRangeTerm)this); } else if (this is ListPatternElem) { t = new ListPatternElem(a, ((ListPatternElem)this).downRepFactor, ((ListPatternElem)this).IsNegSearch); } else if (this is CompoundTerm) { t = new CompoundTerm(functor, a); } else { IO.Error("CopyEx(): type '{0}' not handled explicitly", this.GetType()); } return(t); } }
// each call processes one element of pattern[] bool UnifyTailEx(int ip, int it, VarStack varStack) { ListPatternElem e = (ListPatternElem)pattern[ip]; Variable rangeSpecVar = (Variable)e.RangeBindVar; NodeIterator subtreeIterator; int k; int marker; ListTerm RangeList = null; BaseTerm tail = null; int minLen; // minimum required range length (number of range elements) int maxLen; // maximum possible ... if (!DoLowerAndUpperboundChecks(ip, it, out minLen, out maxLen)) { return(false); } // scan the minimal number of range elements. Add them to the range list, // i.e. the last variable (if present) preceding the '{ , }' for (int i = 0; i < minLen; i++) { if ((k = it + i) >= target.Count) { return(false); } AppendToRangeList(ref RangeList, rangeSpecVar, target[k], ref tail); } marker = varStack.Count; // register the point to which we must possibly undo unifications if (e.HasSearchTerm) { // scan the elements up to the maximum range length, and the element immediately thereafter for (int i = minLen; i <= maxLen; i++) { BaseTerm t = null; k = it + i; if (k == target.Count) { return(false); } bool negSearchSucceeded = true; // iff none of the alternative term matches the target term for (int j = 4; j < e.Args.Length; j++) // scan all AltSearchTerm alternatives (separated by '|') { BaseTerm searchTerm = e.AltSearchTerms[j]; DownRepFactor downRepFactor = null; // e.downRepFactor [j]; t = target[k]; AltLoopStatus status = AltLoopStatus.TryNextAlt; if (downRepFactor == null) { status = TryOneAlternative(ip, varStack, e, k, marker, RangeList, i, t, ref negSearchSucceeded, searchTerm); if (status == AltLoopStatus.MatchFound) { return(true); } } else // traverse the downRepFactor tree, which in principle may yield more than one match { subtreeIterator = new NodeIterator(t, searchTerm, downRepFactor.minLenTerm, downRepFactor.maxLenTerm, false, downRepFactor.bindVar, varStack); foreach (BaseTerm match in subtreeIterator) // try -- if necessary -- each tree match with the current search term { status = TryOneAlternative(ip, varStack, e, k, marker, RangeList, i, match, ref negSearchSucceeded, searchTerm); if (status == AltLoopStatus.MatchFound) { return(true); } if (status == AltLoopStatus.Break) { break; } } } if (status == AltLoopStatus.Break) { break; } } // at this point sufficient alternatives have been tried if (e.IsNegSearch && negSearchSucceeded) // none of the terms matched => ok if binding succeeds { if (!TryBindingAltListVarToMatch(e.AltListBindVar, t, varStack) || // bind the AltListBindVar to the match !TryBindingRangeRelatedVars(e, i, RangeList, varStack)) // bind the range to the range variables { return(false); // binding failed } if (ip == pattern.Length - 1) // this was the last pattern element { if (k == target.Count - 1) // both pattern and target exhausted { return(true); } } else if (UnifyTailEx(ip + 1, k + 1, varStack)) // now deal with the rest { return(true); } } else if (i < maxLen) // append the rejected term to the range list and go try the next term { AppendToRangeList(ref RangeList, rangeSpecVar, t, ref tail); } } } else // a range without a subsequent search term (so followed by another range or end of pattern) { for (int i = minLen; i <= maxLen; i++) { k = it + i; if (k == target.Count) // ok, target[k] does not exist, end of target hit { return(TryBindingRangeRelatedVars(e, i, RangeList, varStack)); // i is actual range length } // k is ok if (i < maxLen) { AppendToRangeList(ref RangeList, rangeSpecVar, target[k], ref tail); } // now deal with the rest if (TryBindingRangeRelatedVars(e, i, RangeList, varStack) && UnifyTailEx(ip + 1, k, varStack)) { return(true); } } } // If we arrive here, no matching term was found in or immediately after the permitted range. // Therefore, undo any unifications made locally in this method and return with failure. if (marker != 0) { BaseTerm.UnbindToMarker(varStack, marker); } return(false); }
// try to bind the range specification variable (if present) to the range last. // if the minimun or the maximum range length was a variable, then bind it to the actual length just found bool TryBindingRangeRelatedVars (ListPatternElem g, int rangeLength, ListTerm RangeList, VarStack varStack) { if (g.MinLenTerm.IsVar) g.MinLenTerm.Unify (new DecimalTerm (rangeLength), varStack); if (g.MaxLenTerm.IsVar) g.MaxLenTerm.Unify (new DecimalTerm (rangeLength), varStack); if (g.RangeBindVar != null) { if (RangeList == null) RangeList = ListTerm.EMPTYLIST; if (!g.RangeBindVar.Unify (RangeList, varStack)) return false; // alas, the same range var was apparently used & bound earlier in the pattern } return true; }
private AltLoopStatus TryOneAlternative (int ip, VarStack varStack, ListPatternElem e, int k, int marker, ListTerm RangeList, int i, BaseTerm t, ref bool negSearchSucceeded, BaseTerm searchTerm) { bool unified = searchTerm.Unify (t, varStack); if (e.IsNegSearch) // none of the terms in the inner loop may match. ~(a | b | c) = ~a & ~b & ~c { if (unified) // ... no point in investigating the other alternatives if one does { negSearchSucceeded = false; return AltLoopStatus.Break; // don't try the other alternatives } return AltLoopStatus.TryNextDown; // non of the downranges matches may lead to a success } else { if (unified && // we found a match. Unify, and TryBindingAltListVarToMatch (e.AltListBindVar, t, varStack) && // bind the AltListBindVar to the match TryBindingRangeRelatedVars (e, i, RangeList, varStack)) // bind the range to the range variables { if (ip == pattern.Length - 1) // this was the last pattern element { if (k == target.Count - 1) // both pattern and target exhausted return AltLoopStatus.MatchFound; } else if (UnifyTailEx (ip + 1, k + 1, varStack)) // now deal with the rest return AltLoopStatus.MatchFound; } // if we arrive here, it was not possible to ... // (1) ... unify the range's SearchTerm with the target element, or // (2) ... unify the range variable with the range last, or // (3) ... successfully process the rest of the pattern and target // Now unbind and try matching with the next target element BaseTerm.UnbindToMarker (varStack, marker); return AltLoopStatus.TryNextDown; // try the next downrange match } }