From 620f7926f3f2ad05fdb72050a87e49d0fa2357dd Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Wed, 16 Jul 2008 01:00:40 +0000 Subject: Mantis#1753. Thank you kindly, Kinoc for a patch that: Brings Yield Prolog up to date with sourceforge version 0.9.10 Patched applies to both DotNet and XEngine. --- .../Compiler/YieldProlog/IndexedAnswers.cs | 107 +++++++++++++++++++-- 1 file changed, 100 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs') diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs index e1efda8..bba7d03 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs @@ -39,6 +39,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog /// public class IndexedAnswers : YP.IClause { + private int _arity; // addAnswer adds the answer here and indexes it later. private List _allAnswers = new List(); // The key has the arity of answers with non-null values for each indexed arg. The value @@ -49,17 +50,43 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog private Dictionary _gotAnswersForSignature = new Dictionary(); private const int MAX_INDEX_ARGS = 31; - public IndexedAnswers() + public IndexedAnswers(int arity) { + _arity = arity; } - + /// + /// Append the answer to the list and update the indexes, if any. /// Elements of answer must be ground, since arguments with unbound variables make this /// into a dynamic rule which we don't index. /// /// public void addAnswer(object[] answer) { + addOrPrependAnswer(answer, false); + } + + /// + /// Prepend the answer to the list and clear the indexes so that they must be re-computed + /// on the next call to match. (Only addAnswer will maintain the indexes while adding answers.) + /// Elements of answer must be ground, since arguments with unbound variables make this + /// into a dynamic rule which we don't index. + /// + /// + public void prependAnswer(object[] answer) + { + addOrPrependAnswer(answer, true); + } + + /// + /// Do the work of addAnswer or prependAnswer. + /// + /// + private void addOrPrependAnswer(object[] answer, bool prepend) + { + if (answer.Length != _arity) + return; + // Store a copy of the answer array. object[] answerCopy = new object[answer.Length]; Variable.CopyStore copyStore = new Variable.CopyStore(); @@ -69,12 +96,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog throw new InvalidOperationException ("Elements of answer must be ground, but found " + copyStore.getNUniqueVariables() + " unbound variables"); - _allAnswers.Add(answerCopy); - // If match has already indexed answers for a signature, we need to add - // this to the existing indexed answers. - foreach (int signature in _gotAnswersForSignature.Keys) - indexAnswerForSignature(answerCopy, signature); + if (prepend) + { + _allAnswers.Insert(0, answerCopy); + clearIndexes(); + } + else + { + _allAnswers.Add(answerCopy); + // If match has already indexed answers for a signature, we need to add + // this to the existing indexed answers. + foreach (int signature in _gotAnswersForSignature.Keys) + indexAnswerForSignature(answerCopy, signature); + } } private void indexAnswerForSignature(object[] answer, int signature) @@ -119,6 +154,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog public IEnumerable match(object[] arguments) { + if (arguments.Length != _arity) + yield break; + // Set up indexArgs, up to arg position MAX_INDEX_ARGS. The signature has a 1 bit for // each non-null index arg. HashedList indexArgs = new HashedList(arguments.Length); @@ -166,6 +204,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog // Find matches in answers. IEnumerator[] iterators = new IEnumerator[arguments.Length]; + // Debug: If the caller asserts another answer into this same predicate during yield, the iterator + // over clauses will be corrupted. Should we take the time to copy answers? foreach (object[] answer in answers) { bool gotMatch = true; @@ -201,6 +241,59 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog } } + public IEnumerable clause(object Head, object Body) + { + Head = YP.getValue(Head); + if (Head is Variable) + throw new PrologException("instantiation_error", "Head is an unbound variable"); + object[] arguments = YP.getFunctorArgs(Head); + + // We always match Head from _allAnswers, and the Body is Atom.a("true"). + foreach (bool l1 in YP.unify(Body, Atom.a("true"))) + { + // The caller can assert another answer into this same predicate during yield, so we have to + // make a copy of the answers. + foreach (object[] answer in _allAnswers.ToArray()) + { + foreach (bool l2 in YP.unifyArrays(arguments, answer)) + yield return false; + } + } + } + + public IEnumerable retract(object Head, object Body) + { + Head = YP.getValue(Head); + if (Head is Variable) + throw new PrologException("instantiation_error", "Head is an unbound variable"); + object[] arguments = YP.getFunctorArgs(Head); + + // We always match Head from _allAnswers, and the Body is Atom.a("true"). + foreach (bool l1 in YP.unify(Body, Atom.a("true"))) + { + // The caller can assert another answer into this same predicate during yield, so we have to + // make a copy of the answers. + foreach (object[] answer in _allAnswers.ToArray()) + { + foreach (bool l2 in YP.unifyArrays(arguments, answer)) + { + _allAnswers.Remove(answer); + clearIndexes(); + yield return false; + } + } + } + } + + /// + /// After retracting or prepending an answer in _allAnswers, the indexes are invalid, so clear them. + /// + private void clearIndexes() + { + _indexedAnswers.Clear(); + _gotAnswersForSignature.Clear(); + } + /// /// A HashedList extends an ArrayList with methods to get a hash and to check equality /// based on the elements of the list. -- cgit v1.1