From d8c470343e50b342024491219bd43678a24b4a03 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Fri, 26 Sep 2008 16:11:53 +0000 Subject: Compiler Connection! One world, one compiler! --- .../DotNetEngine/Compiler/YieldProlog/YP.cs | 2701 -------------------- 1 file changed, 2701 deletions(-) delete mode 100644 OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs') diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs deleted file mode 100644 index 694e733..0000000 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs +++ /dev/null @@ -1,2701 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Net.Sockets; -using System.Text; -using System.Text.RegularExpressions; - -namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog -{ - /// - /// YP has static methods for general functions in Yield Prolog such as - /// and . - /// - public class YP - { - private static Fail _fail = new Fail(); - private static Repeat _repeat = new Repeat(); - private static Dictionary> _predicatesStore = - new Dictionary>(); - private static TextWriter _outputStream = System.Console.Out; - private static TextReader _inputStream = System.Console.In; - private static IndexedAnswers _operatorTable = null; - private static Dictionary _prologFlags = new Dictionary(); - public const int MAX_ARITY = 255; - - /// - /// An IClause is used so that dynamic predicates can call match. - /// - public interface IClause - { - IEnumerable match(object[] args); - IEnumerable clause(object Head, object Body); - } - - /// - /// If value is a Variable, then return its getValue. Otherwise, just - /// return value. You should call YP.getValue on any object that - /// may be a Variable to get the value to pass to other functions in - /// your system that are not part of Yield Prolog, such as math functions - /// or file I/O. - /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html - /// - /// - /// - public static object getValue(object value) - { - if (value is Variable) - return ((Variable)value).getValue(); - else - return value; - } - - /// - /// If arg1 or arg2 is an object with a unify method (such as Variable or - /// Functor) then just call its unify with the other argument. The object's - /// unify method will bind the values or check for equals as needed. - /// Otherwise, both arguments are "normal" (atomic) values so if they - /// are equal then succeed (yield once), else fail (don't yield). - /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html - /// - /// - /// - /// - public static IEnumerable unify(object arg1, object arg2) - { - arg1 = getValue(arg1); - arg2 = getValue(arg2); - if (arg1 is IUnifiable) - return ((IUnifiable)arg1).unify(arg2); - else if (arg2 is IUnifiable) - return ((IUnifiable)arg2).unify(arg1); - else - { - // Arguments are "normal" types. - if (arg1.Equals(arg2)) - return new Succeed(); - else - return _fail; - } - } - - /// - /// This is used for the lookup key in _factStore. - /// - public struct NameArity - { - public readonly Atom _name; - public readonly int _arity; - - public NameArity(Atom name, int arity) - { - _name = name; - _arity = arity; - } - - public override bool Equals(object obj) - { - if (obj is NameArity) - { - NameArity nameArity = (NameArity)obj; - return nameArity._name.Equals(_name) && nameArity._arity.Equals(_arity); - } - else - { - return false; - } - } - - public override int GetHashCode() - { - return _name.GetHashCode() ^ _arity.GetHashCode(); - } - } - - /// - /// Convert term to an int. - /// If term is a single-element List, use its first element - /// (to handle the char types like "a"). - /// If can't convert, throw a PrologException for type_error evaluable (because this is only - /// called from arithmetic functions). - /// - /// - /// - public static int convertInt(object term) - { - term = YP.getValue(term); - if (term is Functor2 && ((Functor2)term)._name == Atom.DOT && - YP.getValue(((Functor2)term)._arg2) == Atom.NIL) - // Assume it is a char type like "a". - term = YP.getValue(((Functor2)term)._arg1); - if (term is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected a number but the argument is an unbound variable"); - - try - { - return (int)term; - } - catch (InvalidCastException) - { - throw new PrologException - (new Functor2 - ("type_error", Atom.a("evaluable"), - new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)), - "Term must be an integer"); - } - } - - /// - /// Convert term to a double. This may convert an int to a double, etc. - /// If term is a single-element List, use its first element - /// (to handle the char types like "a"). - /// If can't convert, throw a PrologException for type_error evaluable (because this is only - /// called from arithmetic functions). - /// - /// - /// - public static double convertDouble(object term) - { - term = YP.getValue(term); - if (term is Functor2 && ((Functor2)term)._name == Atom.DOT && - YP.getValue(((Functor2)term)._arg2) == Atom.NIL) - // Assume it is a char type like "a". - term = YP.getValue(((Functor2)term)._arg1); - if (term is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected a number but the argument is an unbound variable"); - - try - { - return Convert.ToDouble(term); - } - catch (InvalidCastException) - { - throw new PrologException - (new Functor2 - ("type_error", Atom.a("evaluable"), - new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)), - "Term must be an integer"); - } - } - - /// - /// If term is an integer, set intTerm. - /// If term is a single-element List, use its first element - /// (to handle the char types like "a"). Return true for success, false if can't convert. - /// We use a success return value because throwing an exception is inefficient. - /// - /// - /// - public static bool getInt(object term, out int intTerm) - { - term = YP.getValue(term); - if (term is Functor2 && ((Functor2)term)._name == Atom.DOT && - YP.getValue(((Functor2)term)._arg2) == Atom.NIL) - // Assume it is a char type like "a". - term = YP.getValue(((Functor2)term)._arg1); - - if (term is int) - { - intTerm = (int)term; - return true; - } - - intTerm = 0; - return false; - } - - public static bool equal(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x == (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) == YP.convertDouble(y); - } - - public static bool notEqual(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x != (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) != YP.convertDouble(y); - } - - public static bool greaterThan(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x > (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) > YP.convertDouble(y); - } - - public static bool lessThan(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x < (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) < YP.convertDouble(y); - } - - public static bool greaterThanOrEqual(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x >= (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) >= YP.convertDouble(y); - } - - public static bool lessThanOrEqual(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x <= (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) <= YP.convertDouble(y); - } - - public static object negate(object x) - { - int intX; - if (getInt(x, out intX)) - return -intX; - return -convertDouble(x); - } - - public static object abs(object x) - { - int intX; - if (getInt(x, out intX)) - return Math.Abs(intX); - return Math.Abs(convertDouble(x)); - } - - public static object sign(object x) - { - int intX; - if (getInt(x, out intX)) - return Math.Sign(intX); - return Math.Sign(convertDouble(x)); - } - - // Use toFloat instead of float because it is a reserved keyword. - public static object toFloat(object x) - { - return convertDouble(x); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object floor(object x) - { - return (int)Math.Floor(convertDouble(x)); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object truncate(object x) - { - return (int)Math.Truncate(convertDouble(x)); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object round(object x) - { - return (int)Math.Round(convertDouble(x)); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object ceiling(object x) - { - return (int)Math.Ceiling(convertDouble(x)); - } - - public static object sin(object x) - { - return Math.Sin(YP.convertDouble(x)); - } - - public static object cos(object x) - { - return Math.Cos(YP.convertDouble(x)); - } - - public static object atan(object x) - { - return Math.Atan(YP.convertDouble(x)); - } - - public static object exp(object x) - { - return Math.Exp(YP.convertDouble(x)); - } - - public static object log(object x) - { - return Math.Log(YP.convertDouble(x)); - } - - public static object sqrt(object x) - { - return Math.Sqrt(convertDouble(x)); - } - - public static object bitwiseComplement(object x) - { - return ~YP.convertInt(x); - } - - public static object add(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX + intY; - return convertDouble(x) + convertDouble(y); - } - - public static object subtract(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX - intY; - return convertDouble(x) - convertDouble(y); - } - - public static object multiply(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX * intY; - return convertDouble(x) * convertDouble(y); - } - - /// - /// Return floating point, even if both arguments are integer. - /// - /// - /// - /// - public static object divide(object x, object y) - { - return convertDouble(x) / convertDouble(y); - } - - public static object intDivide(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX / intY; - // Still allow passing a double, but treat as an int. - return (int)convertDouble(x) / (int)convertDouble(y); - } - - public static object mod(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX % intY; - // Still allow passing a double, but treat as an int. - return (int)convertDouble(x) % (int)convertDouble(y); - } - - public static object pow(object x, object y) - { - return Math.Pow(YP.convertDouble(x), YP.convertDouble(y)); - } - - public static object bitwiseShiftRight(object x, object y) - { - return YP.convertInt(x) >> YP.convertInt(y); - } - - public static object bitwiseShiftLeft(object x, object y) - { - return YP.convertInt(x) << YP.convertInt(y); - } - - public static object bitwiseAnd(object x, object y) - { - return YP.convertInt(x) & YP.convertInt(y); - } - - public static object bitwiseOr(object x, object y) - { - return YP.convertInt(x) | YP.convertInt(y); - } - - public static object min(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return Math.Min(intX, intY); - return Math.Min(convertDouble(x), convertDouble(y)); - } - - public static object max(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return Math.Max(intX, intY); - return Math.Max(convertDouble(x), convertDouble(y)); - } - - public static IEnumerable copy_term(object inTerm, object outTerm) - { - return YP.unify(outTerm, YP.makeCopy(inTerm, new Variable.CopyStore())); - } - - public static void addUniqueVariables(object term, List variableSet) - { - term = YP.getValue(term); - if (term is IUnifiable) - ((IUnifiable)term).addUniqueVariables(variableSet); - } - - public static object makeCopy(object term, Variable.CopyStore copyStore) - { - term = YP.getValue(term); - if (term is IUnifiable) - return ((IUnifiable)term).makeCopy(copyStore); - else - // term is a "normal" type. Assume it is ground. - return term; - } - - /// - /// Sort the array in place according to termLessThan. This does not remove duplicates - /// - /// - public static void sortArray(object[] array) - { - Array.Sort(array, YP.compareTerms); - } - - /// - /// Sort the array in place according to termLessThan. This does not remove duplicates - /// - /// - public static void sortArray(List array) - { - array.Sort(YP.compareTerms); - } - - /// - /// Sort List according to termLessThan, remove duplicates and unify with Sorted. - /// - /// - /// - /// - public static IEnumerable sort(object List, object Sorted) - { - object[] array = ListPair.toArray(List); - if (array == null) - return YP.fail(); - if (array.Length > 1) - sortArray(array); - return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array)); - } - - /// - /// Use YP.unify to unify each of the elements of the two arrays, and yield - /// once if they all unify. - /// - /// - /// - /// - public static IEnumerable unifyArrays(object[] array1, object[] array2) - { - if (array1.Length != array2.Length) - yield break; - - IEnumerator[] iterators = new IEnumerator[array1.Length]; - bool gotMatch = true; - int nIterators = 0; - // Try to bind all the arguments. - for (int i = 0; i < array1.Length; ++i) - { - IEnumerator iterator = YP.unify(array1[i], array2[i]).GetEnumerator(); - iterators[nIterators++] = iterator; - // MoveNext() is true if YP.unify succeeds. - if (!iterator.MoveNext()) - { - gotMatch = false; - break; - } - } - - try - { - if (gotMatch) - yield return false; - } - finally - { - // Manually finalize all the iterators. - for (int i = 0; i < nIterators; ++i) - iterators[i].Dispose(); - } - } - - /// - /// Return an iterator (which you can use in a for-in loop) which does - /// zero iterations. This returns a pre-existing iterator which is - /// more efficient than letting the compiler generate a new one. - /// - /// - public static IEnumerable fail() - { - return _fail; - } - - /// - /// Return an iterator (which you can use in a for-in loop) which does - /// one iteration. This returns a pre-existing iterator which is - /// more efficient than letting the compiler generate a new one. - /// - /// - public static IEnumerable succeed() - { - return new Succeed(); - } - - /// - /// Return an iterator (which you can use in a for-in loop) which repeats - /// indefinitely. This returns a pre-existing iterator which is - /// more efficient than letting the compiler generate a new one. - /// - /// - public static IEnumerable repeat() - { - return _repeat; - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168 - public static IEnumerable univ(object Term, object List) - { - Term = YP.getValue(Term); - List = YP.getValue(List); - - if (nonvar(Term)) - return YP.unify(new ListPair - (getFunctorName(Term), ListPair.make(getFunctorArgs(Term))), List); - - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l1 in new ListPair(Name, ArgList).unify(List)) - { - object[] args = ListPair.toArray(ArgList); - if (args == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), ArgList), - "Expected a list. Got: " + ArgList.getValue()); - if (args.Length == 0) - // Return the Name, even if it is not an Atom. - return YP.unify(Term, Name); - if (args.Length > MAX_ARITY) - throw new PrologException - (new Functor1("representation_error", Atom.a("max_arity")), - "Functor arity " + args.Length + " may not be greater than " + MAX_ARITY); - if (!atom(Name)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Name), - "Expected an atom. Got: " + Name.getValue()); - - return YP.unify(Term, Functor.make((Atom)YP.getValue(Name), args)); - } - - return YP.fail(); - } - - public static IEnumerable functor(object Term, object FunctorName, object Arity) - { - Term = YP.getValue(Term); - FunctorName = YP.getValue(FunctorName); - Arity = YP.getValue(Arity); - - if (Term is Variable) - { - if (FunctorName is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 FunctorName is an unbound variable"); - if (Arity is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 3 Arity is an unbound variable"); - if (!(Arity is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Arity), "Arity is not an integer"); - if (!YP.atomic(FunctorName)) - throw new PrologException - (new Functor2("type_error", Atom.a("atomic"), FunctorName), "FunctorName is not atomic"); - - if ((int)Arity < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Arity), - "Arity may not be less than zero"); - else if ((int)Arity == 0) - { - // Just unify Term with the atomic FunctorName. - foreach (bool l1 in YP.unify(Term, FunctorName)) - yield return false; - } - else - { - if ((int)Arity > MAX_ARITY) - throw new PrologException - (new Functor1("representation_error", Atom.a("max_arity")), - "Functor arity " + Arity + " may not be greater than " + MAX_ARITY); - if (!(FunctorName is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), FunctorName), "FunctorName is not an atom"); - // Construct a functor with unbound variables. - object[] args = new object[(int)Arity]; - for (int i = 0; i < args.Length; ++i) - args[i] = new Variable(); - #pragma warning disable 0219 - foreach (bool l1 in YP.unify(Term, Functor.make((Atom)FunctorName, args))) - yield return false; - #pragma warning restore 0219 - } - } - else - { - foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term))) - { - foreach (bool l2 in YP.unify(Arity, getFunctorArgs(Term).Length)) - yield return false; - } - } - } - - public static IEnumerable arg(object ArgNumber, object Term, object Value) - { - if (var(ArgNumber)) - throw new PrologException(Atom.a("instantiation_error"), "Arg 1 ArgNumber is an unbound variable"); - int argNumberInt; - if (!getInt(ArgNumber, out argNumberInt)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), ArgNumber), "Arg 1 ArgNumber must be integer"); - if (argNumberInt < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), argNumberInt), - "ArgNumber may not be less than zero"); - - if (YP.var(Term)) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 Term is an unbound variable"); - if (!YP.compound(Term)) - throw new PrologException - (new Functor2("type_error", Atom.a("compound"), Term), "Arg 2 Term must be compound"); - - object[] termArgs = YP.getFunctorArgs(Term); - // Silently fail if argNumberInt is out of range. - if (argNumberInt >= 1 && argNumberInt <= termArgs.Length) - { - // The first ArgNumber is at 1, not 0. - foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1])) - yield return false; - } - } - - public static bool termEqual(object Term1, object Term2) - { - Term1 = YP.getValue(Term1); - if (Term1 is IUnifiable) - return ((IUnifiable)Term1).termEqual(Term2); - return Term1.Equals(YP.getValue(Term2)); - } - - public static bool termNotEqual(object Term1, object Term2) - { - return !termEqual(Term1, Term2); - } - - public static bool termLessThan(object Term1, object Term2) - { - Term1 = YP.getValue(Term1); - Term2 = YP.getValue(Term2); - int term1TypeCode = getTypeCode(Term1); - int term2TypeCode = getTypeCode(Term2); - if (term1TypeCode != term2TypeCode) - return term1TypeCode < term2TypeCode; - - // The terms are the same type code. - if (term1TypeCode == -2) - { - // Variable. - // We always check for equality first because we want to be sure - // that less than returns false if the terms are equal, in - // case that the less than check really behaves like less than or equal. - if ((Variable)Term1 != (Variable)Term2) - // The hash code should be unique to a Variable object. - return Term1.GetHashCode() < Term2.GetHashCode(); - return false; - } - if (term1TypeCode == 0) - return ((Atom)Term1)._name.CompareTo(((Atom)Term2)._name) < 0; - if (term1TypeCode == 1) - return ((Functor1)Term1).lessThan((Functor1)Term2); - if (term1TypeCode == 2) - return ((Functor2)Term1).lessThan((Functor2)Term2); - if (term1TypeCode == 3) - return ((Functor3)Term1).lessThan((Functor3)Term2); - if (term1TypeCode == 4) - return ((Functor)Term1).lessThan((Functor)Term2); - - // Type code is -1 for general objects. First compare their type names. - // Note that this puts Double before Int32 as required by ISO Prolog. - string term1TypeName = Term1.GetType().ToString(); - string term2TypeName = Term2.GetType().ToString(); - if (term1TypeName != term2TypeName) - return term1TypeName.CompareTo(term2TypeName) < 0; - - // The terms are the same type name. - if (Term1 is int) - return (int)Term1 < (int)Term2; - else if (Term1 is double) - return (double)Term1 < (double)Term2; - else if (Term1 is DateTime) - return (DateTime)Term1 < (DateTime)Term2; - else if (Term1 is String) - return ((String)Term1).CompareTo((String)Term2) < 0; - // Debug: Should we try arrays, etc.? - - if (!Term1.Equals(Term2)) - // Could be equal or greater than. - return Term1.GetHashCode() < Term2.GetHashCode(); - return false; - } - - /// - /// Type code is -2 if term is a Variable, 0 if it is an Atom, - /// 1 if it is a Functor1, 2 if it is a Functor2, 3 if it is a Functor3, - /// 4 if it is Functor. - /// Otherwise, type code is -1. - /// This does not call YP.getValue(term). - /// - /// - /// - private static int getTypeCode(object term) - { - if (term is Variable) - return -2; - else if (term is Atom) - return 0; - else if (term is Functor1) - return 1; - else if (term is Functor2) - return 2; - else if (term is Functor3) - return 3; - else if (term is Functor) - return 4; - else - return -1; - } - - public static bool termLessThanOrEqual(object Term1, object Term2) - { - if (YP.termEqual(Term1, Term2)) - return true; - return YP.termLessThan(Term1, Term2); - } - - public static bool termGreaterThan(object Term1, object Term2) - { - return !YP.termLessThanOrEqual(Term1, Term2); - } - - public static bool termGreaterThanOrEqual(object Term1, object Term2) - { - // termLessThan should ensure that it returns false if terms are equal, - // so that this would return true. - return !YP.termLessThan(Term1, Term2); - } - - public static int compareTerms(object Term1, object Term2) - { - if (YP.termEqual(Term1, Term2)) - return 0; - else if (YP.termLessThan(Term1, Term2)) - return -1; - else - return 1; - } - - public static bool ground(object Term) - { - Term = YP.getValue(Term); - if (Term is IUnifiable) - return ((IUnifiable)Term).ground(); - return true; - } - - public static IEnumerable current_op - (object Priority, object Specifier, object Operator) - { - if (_operatorTable == null) - { - // Initialize. - _operatorTable = new IndexedAnswers(3); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") }); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") }); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a(":-") }); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a("?-") }); - _operatorTable.addAnswer(new object[] { 1100, Atom.a("xfy"), Atom.a(";") }); - _operatorTable.addAnswer(new object[] { 1050, Atom.a("xfy"), Atom.a("->") }); - _operatorTable.addAnswer(new object[] { 1000, Atom.a("xfy"), Atom.a(",") }); - _operatorTable.addAnswer(new object[] { 900, Atom.a("fy"), Atom.a("\\+") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("==") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=..") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("is") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">=") }); - _operatorTable.addAnswer(new object[] { 600, Atom.a("xfy"), Atom.a(":") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("+") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("-") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("*") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("/") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("//") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("rem") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("mod") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("<<") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a(">>") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("xfx"), Atom.a("**") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("xfy"), Atom.a("^") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("-") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("\\") }); - // Debug: This is hacked in to run the Prolog test suite until we implement op/3. - _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") }); - } - - return _operatorTable.match(new object[] { Priority, Specifier, Operator }); - } - - public static IEnumerable atom_length(object atom, object Length) - { - atom = YP.getValue(atom); - Length = YP.getValue(Length); - if (atom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected atom(Arg1) but it is an unbound variable"); - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom"); - if (!(Length is Variable)) - { - if (!(Length is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer"); - if ((int)Length < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length), - "Length must not be less than zero"); - } - return YP.unify(Length, ((Atom)atom)._name.Length); - } - - public static IEnumerable atom_concat(object Start, object End, object Whole) - { - // Debug: Should we try to preserve the _declaringClass? - Start = YP.getValue(Start); - End = YP.getValue(End); - Whole = YP.getValue(Whole); - if (Whole is Variable) - { - if (Start is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Start and arg 3 Whole are both var"); - if (End is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 End and arg 3 Whole are both var"); - if (!(Start is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not an atom"); - if (!(End is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not an atom"); - - foreach (bool l1 in YP.unify(Whole, Atom.a(((Atom)Start)._name + ((Atom)End)._name))) - yield return false; - } - else - { - if (!(Whole is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Whole), "Arg 3 Whole is not an atom"); - bool gotStartLength = false; - int startLength = 0; - if (!(Start is Variable)) - { - if (!(Start is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not var or atom"); - startLength = ((Atom)Start)._name.Length; - gotStartLength = true; - } - - bool gotEndLength = false; - int endLength = 0; - if (!(End is Variable)) - { - if (!(End is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not var or atom"); - endLength = ((Atom)End)._name.Length; - gotEndLength = true; - } - - // We are doing a search through all possible Start and End which concatenate to Whole. - string wholeString = ((Atom)Whole)._name; - for (int i = 0; i <= wholeString.Length; ++i) - { - // If we got either startLength or endLength, we know the lengths have to match so check - // the lengths instead of constructing an Atom to do it. - if (gotStartLength && startLength != i) - continue; - if (gotEndLength && endLength != wholeString.Length - i) - continue; - foreach (bool l1 in YP.unify(Start, Atom.a(wholeString.Substring(0, i)))) - { - foreach (bool l2 in YP.unify(End, Atom.a(wholeString.Substring(i, wholeString.Length - i)))) - yield return false; - } - } - } - } - - public static IEnumerable sub_atom - (object atom, object Before, object Length, object After, object Sub_atom) - { - // Debug: Should we try to preserve the _declaringClass? - atom = YP.getValue(atom); - Before = YP.getValue(Before); - Length = YP.getValue(Length); - After = YP.getValue(After); - Sub_atom = YP.getValue(Sub_atom); - if (atom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected atom(Arg1) but it is an unbound variable"); - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom"); - if (!(Sub_atom is Variable)) - { - if (!(Sub_atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Sub_atom), "Sub_atom is not var or atom"); - } - - bool beforeIsInt = false; - bool lengthIsInt = false; - bool afterIsInt = false; - if (!(Before is Variable)) - { - if (!(Before is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Before), "Before must be var or integer"); - beforeIsInt = true; - if ((int)Before < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Before), - "Before must not be less than zero"); - } - if (!(Length is Variable)) - { - if (!(Length is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer"); - lengthIsInt = true; - if ((int)Length < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length), - "Length must not be less than zero"); - } - if (!(After is Variable)) - { - if (!(After is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), After), "After must be var or integer"); - afterIsInt = true; - if ((int)After < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), After), - "After must not be less than zero"); - } - - Atom atomAtom = (Atom)atom; - int atomLength = atomAtom._name.Length; - if (beforeIsInt && lengthIsInt) - { - // Special case: the caller is just trying to extract a substring, so do it quickly. - int xAfter = atomLength - (int)Before - (int)Length; - if (xAfter >= 0) - { - foreach (bool l1 in YP.unify(After, xAfter)) - { - foreach (bool l2 in YP.unify - (Sub_atom, Atom.a(atomAtom._name.Substring((int)Before, (int)Length)))) - yield return false; - } - } - } - else if (afterIsInt && lengthIsInt) - { - // Special case: the caller is just trying to extract a substring, so do it quickly. - int xBefore = atomLength - (int)After - (int)Length; - if (xBefore >= 0) - { - foreach (bool l1 in YP.unify(Before, xBefore)) - { - foreach (bool l2 in YP.unify - (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, (int)Length)))) - yield return false; - } - } - } - else - { - // We are underconstrained and doing a search, so go through all possibilities. - for (int xBefore = 0; xBefore <= atomLength; ++xBefore) - { - foreach (bool l1 in YP.unify(Before, xBefore)) - { - for (int xLength = 0; xLength <= (atomLength - xBefore); ++xLength) - { - foreach (bool l2 in YP.unify(Length, xLength)) - { - foreach (bool l3 in YP.unify(After, atomLength - (xBefore + xLength))) - { - foreach (bool l4 in YP.unify - (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, xLength)))) - yield return false; - } - } - } - } - } - } - } - - public static IEnumerable atom_chars(object atom, object List) - { - atom = YP.getValue(atom); - List = YP.getValue(List); - - if (atom is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Atom and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - object listAtom = YP.getValue(codeArray[i]); - if (listAtom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 List has an element which is an unbound variable"); - if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1)) - throw new PrologException - (new Functor2("type_error", Atom.a("character"), listAtom), - "Arg 2 List has an element which is not a one character atom"); - charArray[i] = ((Atom)listAtom)._name[0]; - } - return YP.unify(atom, Atom.a(new String(charArray))); - } - else - { - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom"); - - string atomString = ((Atom)atom)._name; - object charList = Atom.NIL; - // Start from the back to make the list. - for (int i = atomString.Length - 1; i >= 0; --i) - charList = new ListPair(Atom.a(atomString.Substring(i, 1)), charList); - return YP.unify(List, charList); - } - } - - public static IEnumerable atom_codes(object atom, object List) - { - atom = YP.getValue(atom); - List = YP.getValue(List); - - if (atom is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Atom and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - int codeInt; - if (!getInt(codeArray[i], out codeInt) || codeInt < 0) - throw new PrologException - (new Functor1("representation_error", Atom.a("character_code")), - "Element of Arg 2 List is not a character code"); - charArray[i] = (char)codeInt; - } - return YP.unify(atom, Atom.a(new String(charArray))); - } - else - { - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom"); - - string atomString = ((Atom)atom)._name; - object codeList = Atom.NIL; - // Start from the back to make the list. - for (int i = atomString.Length - 1; i >= 0; --i) - codeList = new ListPair((int)atomString[i], codeList); - return YP.unify(List, codeList); - } - } - - public static IEnumerable number_chars(object Number, object List) - { - Number = YP.getValue(Number); - List = YP.getValue(List); - - if (Number is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Number and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - object listAtom = YP.getValue(codeArray[i]); - if (listAtom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 List has an element which is an unbound variable"); - if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1)) - throw new PrologException - (new Functor2("type_error", Atom.a("character"), listAtom), - "Arg 2 List has an element which is not a one character atom"); - charArray[i] = ((Atom)listAtom)._name[0]; - } - return YP.unify(Number, parseNumberString(charArray)); - } - else - { - string numberString = null; - // Try converting to an int first. - int intNumber; - if (YP.getInt(Number, out intNumber)) - numberString = intNumber.ToString(); - else - { - if (!YP.number(Number)) - throw new PrologException - (new Functor2("type_error", Atom.a("number"), Number), - "Arg 1 Number is not var or number"); - // We just checked, so convertDouble shouldn't throw an exception. - numberString = YP.doubleToString(YP.convertDouble(Number)); - } - - object charList = Atom.NIL; - // Start from the back to make the list. - for (int i = numberString.Length - 1; i >= 0; --i) - charList = new ListPair(Atom.a(numberString.Substring(i, 1)), charList); - return YP.unify(List, charList); - } - } - - public static IEnumerable number_codes(object Number, object List) - { - Number = YP.getValue(Number); - List = YP.getValue(List); - - if (Number is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Number and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - int codeInt; - if (!getInt(codeArray[i], out codeInt) || codeInt < 0) - throw new PrologException - (new Functor1("representation_error", Atom.a("character_code")), - "Element of Arg 2 List is not a character code"); - charArray[i] = (char)codeInt; - } - return YP.unify(Number, parseNumberString(charArray)); - } - else - { - string numberString = null; - // Try converting to an int first. - int intNumber; - if (YP.getInt(Number, out intNumber)) - numberString = intNumber.ToString(); - else - { - if (!YP.number(Number)) - throw new PrologException - (new Functor2("type_error", Atom.a("number"), Number), - "Arg 1 Number is not var or number"); - // We just checked, so convertDouble shouldn't throw an exception. - numberString = YP.doubleToString(YP.convertDouble(Number)); - } - - object codeList = Atom.NIL; - // Start from the back to make the list. - for (int i = numberString.Length - 1; i >= 0; --i) - codeList = new ListPair((int)numberString[i], codeList); - return YP.unify(List, codeList); - } - } - - /// - /// Used by number_chars and number_codes. Return the number in charArray or - /// throw an exception if can't parse. - /// - /// - /// - private static object parseNumberString(char[] charArray) - { - string numberString = new String(charArray); - if (charArray.Length == 3 && numberString.StartsWith("0'")) - // This is a char code. - return (int)charArray[2]; - if (numberString.StartsWith("0x")) - { - try - { - return Int32.Parse - (numberString.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier); - } - catch (FormatException) - { - throw new PrologException - (new Functor1("syntax_error", Atom.a("number_format: " + numberString)), - "Arg 2 List is not a list for a hexadecimal number"); - } - } - // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception? - try - { - // Try an int first. - return Convert.ToInt32(numberString); - } - catch (FormatException) { } - try - { - return Convert.ToDouble(numberString); - } - catch (FormatException) - { - throw new PrologException - (new Functor1("syntax_error", Atom.a("number_format: " + numberString)), - "Arg 2 List is not a list for a number"); - } - } - - public static IEnumerable char_code(object Char, object Code) - { - Char = YP.getValue(Char); - Code = YP.getValue(Code); - - int codeInt = 0; - if (!(Code is Variable)) - { - // Get codeInt now so we type check it whether or not Char is Variable. - if (!getInt(Code, out codeInt)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Code), - "Arg 2 Code is not var or a character code"); - if (codeInt < 0) - throw new PrologException - (new Functor1("representation_error", Atom.a("character_code")), - "Arg 2 Code is not a character code"); - } - - if (Char is Variable) - { - if (Code is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Char and arg 2 Code are both unbound variables"); - - return YP.unify(Char, Atom.a(new String(new char[] {(char)codeInt} ))); - } - else - { - if (!(Char is Atom) || ((Atom)Char)._name.Length != 1) - throw new PrologException - (new Functor2("type_error", Atom.a("character"), Char), - "Arg 1 Char is not var or one-character atom"); - - if (Code is Variable) - return YP.unify(Code, (int)((Atom)Char)._name[0]); - else - // Use codeInt to handle whether Code is supplied as, e.g., 97 or 0'a . - return YP.unify(codeInt, (int)((Atom)Char)._name[0]); - } - } - - /// - /// If term is an Atom or functor type, return its name. - /// Otherwise, return term. - /// - /// - /// - public static object getFunctorName(object term) - { - term = YP.getValue(term); - if (term is Functor1) - return ((Functor1)term)._name; - else if (term is Functor2) - return ((Functor2)term)._name; - else if (term is Functor3) - return ((Functor3)term)._name; - else if (term is Functor) - return ((Functor)term)._name; - else - return term; - } - - /// - /// If term is an Atom or functor type, return an array of its args. - /// Otherwise, return an empty array. - /// - /// - /// - public static object[] getFunctorArgs(object term) - { - term = YP.getValue(term); - if (term is Functor1) - { - Functor1 functor = (Functor1)term; - return new object[] { functor._arg1 }; - } - else if (term is Functor2) - { - Functor2 functor = (Functor2)term; - return new object[] { functor._arg1, functor._arg2 }; - } - else if (term is Functor3) - { - Functor3 functor = (Functor3)term; - return new object[] { functor._arg1, functor._arg2, functor._arg3 }; - } - else if (term is Functor) { - Functor functor = (Functor)term; - return functor._args; - } - else - return new object[0]; - } - - public static bool var(object Term) - { - return YP.getValue(Term) is Variable; - } - - public static bool nonvar(object Term) - { - return !YP.var(Term); - } - - public static bool atom(object Term) - { - return YP.getValue(Term) is Atom; - } - - public static bool integer(object Term) - { - // Debug: Should exhaustively check for all integer types. - return getValue(Term) is int; - } - - // Use isFloat instead of float because it is a reserved keyword. - public static bool isFloat(object Term) - { - // Debug: Should exhaustively check for all float types. - return getValue(Term) is double; - } - - public static bool number(object Term) - { - return YP.integer(Term) || YP.isFloat(Term); - } - - public static bool atomic(object Term) - { - return YP.atom(Term) || YP.number(Term); - } - - public static bool compound(object Term) - { - Term = getValue(Term); - return Term is Functor1 || Term is Functor2 || Term is Functor3 || Term is Functor; - } - - /// - /// If input is a TextReader, use it. If input is an Atom or String, create a StreamReader with the - /// input as the filename. If input is a Prolog list, then read character codes from it. - /// - /// - public static void see(object input) - { - input = YP.getValue(input); - if (input is Variable) - throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable"); - - if (input == null) - { - _inputStream = null; - return; - } - if (input is TextReader) - { - _inputStream = (TextReader)input; - return; - } - else if (input is Atom) - { - _inputStream = new StreamReader(((Atom)input)._name); - return; - } - else if (input is String) - { - _inputStream = new StreamReader((String)input); - return; - } - else if (input is Functor2 && ((Functor2)input)._name == Atom.DOT) - { - _inputStream = new CodeListReader(input); - return; - } - else - throw new PrologException - (new Functor2("domain_error", Atom.a("stream_or_alias"), input), - "Input stream specifier not recognized"); - } - - public static void seen() - { - if (_inputStream == null) - return; - if (_inputStream == Console.In) - return; - _inputStream.Close(); - _inputStream = Console.In; - } - - public static IEnumerable current_input(object Stream) - { - return YP.unify(Stream, _inputStream); - } - - /// - /// If output is a TextWriter, use it. If output is an Atom or a String, create a StreamWriter - /// with the input as the filename. - /// - /// - public static void tell(object output) - { - output = YP.getValue(output); - if (output is Variable) - throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable"); - - if (output == null) - { - _outputStream = null; - return; - } - if (output is TextWriter) - { - _outputStream = (TextWriter)output; - return; - } - else if (output is Atom) - { - _outputStream = new StreamWriter(((Atom)output)._name); - return; - } - else if (output is String) - { - _outputStream = new StreamWriter((String)output); - return; - } - else - throw new PrologException - (new Functor2("domain_error", Atom.a("stream_or_alias"), output), - "Can't open stream for " + output); - } - - public static void told() - { - if (_outputStream == null) - return; - if (_outputStream == Console.Out) - return; - _outputStream.Close(); - _outputStream = Console.Out; - } - - public static IEnumerable current_output(object Stream) - { - return YP.unify(Stream, _outputStream); - } - - public static void write(object x) - { - if (_outputStream == null) - return; - x = YP.getValue(x); - if (x is double) - _outputStream.Write(doubleToString((double)x)); - else - _outputStream.Write(x.ToString()); - } - - /// - /// Format x as a string, making sure that it won't parse as an int later. I.e., for 1.0, don't just - /// use "1" which will parse as an int. - /// - /// - /// - private static string doubleToString(double x) - { - string xString = x.ToString(); - // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception? - try - { - Convert.ToInt32(xString); - // The string will parse as an int, not a double, so re-format so that it does. - // Use float if possible, else exponential if it would be too big. - return x.ToString(x >= 100000.0 ? "E1" : "f1"); - } - catch (FormatException) - { - // Assume it will parse as a double. - } - return xString; - } - - public static void put_code(object x) - { - if (_outputStream == null) - return; - if (var(x)) - throw new PrologException(Atom.a("instantiation_error"), "Arg 1 is an unbound variable"); - int xInt; - if (!getInt(x, out xInt)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), x), "Arg 1 must be integer"); - _outputStream.Write((char)xInt); - } - - public static void nl() - { - if (_outputStream == null) - return; - _outputStream.WriteLine(); - } - - public static IEnumerable get_code(object code) - { - if (_inputStream == null) - return YP.unify(code, -1); - else - return YP.unify(code, _inputStream.Read()); - } - - public static void asserta(object Term, Type declaringClass) - { - assertDynamic(Term, declaringClass, true); - } - - public static void assertz(object Term, Type declaringClass) - { - assertDynamic(Term, declaringClass, false); - } - - public static void assertDynamic(object Term, Type declaringClass, bool prepend) - { - Term = getValue(Term); - if (Term is Variable) - throw new PrologException("instantiation_error", "Term to assert is an unbound variable"); - - Variable.CopyStore copyStore = new Variable.CopyStore(); - object TermCopy = makeCopy(Term, copyStore); - object Head, Body; - if (TermCopy is Functor2 && ((Functor2)TermCopy)._name == Atom.RULE) - { - Head = YP.getValue(((Functor2)TermCopy)._arg1); - Body = YP.getValue(((Functor2)TermCopy)._arg2); - if (Head is Variable) - throw new PrologException("instantiation_error", "Head to assert is an unbound variable"); - if (Body is Variable) - throw new PrologException("instantiation_error", "Body to assert is an unbound variable"); - } - else - { - Head = TermCopy; - Body = Atom.a("true"); - } - - Atom name = getFunctorName(Head) as Atom; - if (name == null) - // name is a non-Atom, such as a number. - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Head), "Term to assert is not callable"); - object[] args = getFunctorArgs(Head); - if (isSystemPredicate(name, args.Length)) - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), - new Functor2(Atom.SLASH, name, args.Length)), - "Assert cannot modify static predicate " + name + "/" + args.Length); - - if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true")) - { - // This is a fact with no unbound variables - // assertFact and prependFact use IndexedAnswers, so don't we don't need to compile. - if (prepend) - prependFact(name, args); - else - assertFact(name, args); - - return; - } - - IClause clause = YPCompiler.compileAnonymousClause(Head, Body, declaringClass); - // We expect clause to be a ClauseHeadAndBody (from Compiler.compileAnonymousFunction) - // so we can set the Head and Body. - if (clause is ClauseHeadAndBody) - ((ClauseHeadAndBody)clause).setHeadAndBody(Head, Body); - - // Add the clause to the entry in _predicatesStore. - NameArity nameArity = new NameArity(name, args.Length); - List clauses; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - // Create an entry for the nameArity. - _predicatesStore[nameArity] = (clauses = new List()); - - if (prepend) - clauses.Insert(0, clause); - else - clauses.Add(clause); - } - - private static bool isSystemPredicate(Atom name, int arity) - { - if (arity == 2 && (name == Atom.a(",") || name == Atom.a(";") || name == Atom.DOT)) - return true; - // Use the same mapping to static predicates in YP as the compiler. - foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable())) - return true; - // Debug: Do we need to check if name._module is null? - return false; - } - - /// - /// Assert values at the end of the set of facts for the predicate with the - /// name and with arity values.Length. - /// - /// must be an Atom - /// the array of arguments to the fact predicate. - /// It is an error if an value has an unbound variable. - public static void assertFact(Atom name, object[] values) - { - NameArity nameArity = new NameArity(name, values.Length); - List clauses; - IndexedAnswers indexedAnswers; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - { - // Create an IndexedAnswers as the only clause of the predicate. - _predicatesStore[nameArity] = (clauses = new List()); - clauses.Add(indexedAnswers = new IndexedAnswers(values.Length)); - } - else - { - indexedAnswers = null; - if (clauses.Count >= 1) - indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers; - if (indexedAnswers == null) - // The latest clause is not an IndexedAnswers, so add one. - clauses.Add(indexedAnswers = new IndexedAnswers(values.Length)); - } - - indexedAnswers.addAnswer(values); - } - - /// - /// Assert values, prepending to the front of the set of facts for the predicate with the - /// name and with arity values.Length. - /// - /// must be an Atom - /// the array of arguments to the fact predicate. - /// It is an error if an value has an unbound variable. - public static void prependFact(Atom name, object[] values) - { - NameArity nameArity = new NameArity(name, values.Length); - List clauses; - IndexedAnswers indexedAnswers; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - { - // Create an IndexedAnswers as the only clause of the predicate. - _predicatesStore[nameArity] = (clauses = new List()); - clauses.Add(indexedAnswers = new IndexedAnswers(values.Length)); - } - else - { - indexedAnswers = null; - if (clauses.Count >= 1) - indexedAnswers = clauses[0] as IndexedAnswers; - if (indexedAnswers == null) - // The first clause is not an IndexedAnswers, so prepend one. - clauses.Insert(0, indexedAnswers = new IndexedAnswers(values.Length)); - } - - indexedAnswers.prependAnswer(values); - } - - /// - /// Match all clauses of the dynamic predicate with the name and with arity - /// arguments.Length. - /// If the predicate is not defined, return the result of YP.unknownPredicate. - /// - /// must be an Atom - /// an array of arity number of arguments - /// an iterator which you can use in foreach - public static IEnumerable matchDynamic(Atom name, object[] arguments) - { - List clauses; - if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses)) - return unknownPredicate(name, arguments.Length, - "Undefined dynamic predicate: " + name + "/" + arguments.Length); - - if (clauses.Count == 1) - // Usually there is only one clause, so return it without needing to wrap it in an iterator. - return clauses[0].match(arguments); - else - return matchAllClauses(clauses, arguments); - } - - /// - /// Call match(arguments) for each IClause in clauses. We make this a separate - /// function so that matchDynamic itself does not need to be an iterator object. - /// - /// - /// - /// - private static IEnumerable matchAllClauses(List clauses, object[] arguments) - { - // Debug: If the caller asserts another clause into this same predicate during yield, the iterator - // over clauses will be corrupted. Should we take the time to copy clauses? - foreach (IClause clause in clauses) - { - foreach (bool lastCall in clause.match(arguments)) - { - yield return false; - if (lastCall) - // This happens after a cut in a clause. - yield break; - } - } - } - - /// - /// If _prologFlags["unknown"] is fail then return fail(), else if - /// _prologFlags["unknown"] is warning then write the message to YP.write and - /// return fail(), else throw a PrologException for existence_error. . - /// - /// - /// - /// - /// - public static IEnumerable unknownPredicate(Atom name, int arity, string message) - { - establishPrologFlags(); - - if (_prologFlags["unknown"] == Atom.a("fail")) - return fail(); - else if (_prologFlags["unknown"] == Atom.a("warning")) - { - write(message); - nl(); - return fail(); - } - else - throw new PrologException - (new Functor2 - (Atom.a("existence_error"), Atom.a("procedure"), - new Functor2(Atom.SLASH, name, arity)), message); - } - - /// - /// This is deprecated and just calls matchDynamic. This matches all clauses, - /// not just the ones defined with assertFact. - /// - /// - /// - /// - public static IEnumerable matchFact(Atom name, object[] arguments) - { - return matchDynamic(name, arguments); - } - - public static IEnumerable clause(object Head, object Body) - { - Head = getValue(Head); - Body = getValue(Body); - if (Head is Variable) - throw new PrologException("instantiation_error", "Head is an unbound variable"); - - Atom name = getFunctorName(Head) as Atom; - if (name == null) - // name is a non-Atom, such as a number. - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable"); - object[] args = getFunctorArgs(Head); - if (isSystemPredicate(name, args.Length)) - throw new PrologException - (new Functor3("permission_error", Atom.a("access"), Atom.a("private_procedure"), - new Functor2(Atom.SLASH, name, args.Length)), - "clause cannot access private predicate " + name + "/" + args.Length); - if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable"); - - List clauses; - if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses)) - yield break; - // The caller can assert another clause into this same predicate during yield, so we have to - // make a copy of the clauses. - foreach (IClause predicateClause in clauses.ToArray()) - { - foreach (bool l1 in predicateClause.clause(Head, Body)) - yield return false; - } - } - - public static IEnumerable retract(object Term) - { - Term = getValue(Term); - if (Term is Variable) - throw new PrologException("instantiation_error", "Term to retract is an unbound variable"); - - object Head, Body; - if (Term is Functor2 && ((Functor2)Term)._name == Atom.RULE) - { - Head = YP.getValue(((Functor2)Term)._arg1); - Body = YP.getValue(((Functor2)Term)._arg2); - } - else - { - Head = Term; - Body = Atom.a("true"); - } - if (Head is Variable) - throw new PrologException("instantiation_error", "Head is an unbound variable"); - - Atom name = getFunctorName(Head) as Atom; - if (name == null) - // name is a non-Atom, such as a number. - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable"); - object[] args = getFunctorArgs(Head); - if (isSystemPredicate(name, args.Length)) - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), - new Functor2(Atom.SLASH, name, args.Length)), - "clause cannot access private predicate " + name + "/" + args.Length); - if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable"); - - List clauses; - if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses)) - yield break; - // The caller can assert another clause into this same predicate during yield, so we have to - // make a copy of the clauses. - foreach (IClause predicateClause in clauses.ToArray()) - { - if (predicateClause is IndexedAnswers) - { - // IndexedAnswers handles its own retract. Even if it removes all of its - // answers, it is OK to leave it empty as one of the elements in clauses. - foreach (bool l1 in ((IndexedAnswers)predicateClause).retract(Head, Body)) - yield return false; - } - else - { - foreach (bool l1 in predicateClause.clause(Head, Body)) - { - clauses.Remove(predicateClause); - yield return false; - } - } - } - } - - /// - /// This is deprecated for backward compatibility. You should use retractall. - /// - /// must be an Atom - /// an array of arity number of arguments - public static void retractFact(Atom name, object[] arguments) - { - retractall(Functor.make(name, arguments)); - } - - /// - /// Retract all dynamic clauses which unify with Head. If this matches all clauses in a predicate, - /// the predicate is still defined. To completely remove the predicate, see abolish. - /// - /// - public static void retractall(object Head) - { - object name = YP.getFunctorName(Head); - object[] arguments = getFunctorArgs(Head); - if (!(name is Atom)) - return; - NameArity nameArity = new NameArity((Atom)name, arguments.Length); - List clauses; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - // Can't find, so ignore. - return; - - foreach (object arg in arguments) - { - if (!YP.var(arg)) - throw new InvalidOperationException - ("Until matching retractall is supported, all arguments must be unbound to retract all clauses"); - } - // Clear all clauses. - _predicatesStore[nameArity] = new List(); - } - - /// - /// If NameSlashArity is var, match with all the dynamic predicates using the - /// Name/Artity form. - /// If NameSlashArity is not var, check if the Name/Arity exists as a static or - /// dynamic predicate. - /// - /// - /// if not null, used to resolve references to the default - /// module Atom.a("") - /// - public static IEnumerable current_predicate(object NameSlashArity, Type declaringClass) - { - NameSlashArity = YP.getValue(NameSlashArity); - // First check if Name and Arity are nonvar so we can do a direct lookup. - if (YP.ground(NameSlashArity)) - { - Functor2 NameArityFunctor = NameSlashArity as Functor2; - if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH)) - throw new PrologException - (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity), - "Must be a name/arity predicate indicator"); - object name = YP.getValue(NameArityFunctor._arg1); - object arity = YP.getValue(NameArityFunctor._arg2); - if (name is Variable || arity is Variable) - throw new PrologException - ("instantiation_error", "Predicate indicator name or arity is an unbound variable"); - if (!(name is Atom && arity is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity), - "Must be a name/arity predicate indicator"); - if ((int)arity < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity), - "Arity may not be less than zero"); - - if (YPCompiler.isCurrentPredicate((Atom)name, (int)arity, declaringClass)) - // The predicate is defined. - yield return false; - } - else - { - foreach (NameArity key in _predicatesStore.Keys) - { - foreach (bool l1 in YP.unify - (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity)) - yield return false; - } - } - } - - /// - /// Return true if the dynamic predicate store has an entry for the predicate - /// with name and arity. - /// - /// - /// - /// - public static bool isDynamicCurrentPredicate(Atom name, int arity) - { - return _predicatesStore.ContainsKey(new NameArity(name, arity)); - } - - public static void abolish(object NameSlashArity) - { - NameSlashArity = YP.getValue(NameSlashArity); - if (NameSlashArity is Variable) - throw new PrologException - ("instantiation_error", "Predicate indicator is an unbound variable"); - Functor2 NameArityFunctor = NameSlashArity as Functor2; - if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH)) - throw new PrologException - (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity), - "Must be a name/arity predicate indicator"); - object name = YP.getValue(NameArityFunctor._arg1); - object arity = YP.getValue(NameArityFunctor._arg2); - if (name is Variable || arity is Variable) - throw new PrologException - ("instantiation_error", "Predicate indicator name or arity is an unbound variable"); - if (!(name is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), name), - "Predicate indicator name must be an atom"); - if (!(arity is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), arity), - "Predicate indicator arity must be an integer"); - if ((int)arity < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity), - "Arity may not be less than zero"); - if ((int)arity > MAX_ARITY) - throw new PrologException - (new Functor1("representation_error", Atom.a("max_arity")), - "Arity may not be greater than " + MAX_ARITY); - - if (isSystemPredicate((Atom)name, (int)arity)) - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), - new Functor2(Atom.SLASH, name, arity)), - "Abolish cannot modify static predicate " + name + "/" + arity); - _predicatesStore.Remove(new NameArity((Atom)name, (int)arity)); - } - - /// - /// If Goal is a simple predicate, call YP.getFunctorName(Goal) using arguments from - /// YP.getFunctorArgs(Goal). If not found, this throws a PrologException for existence_error. - /// Otherwise, compile the goal as a single clause predicate and invoke it. - /// - /// - /// if not null, used to resolve references to the default - /// module Atom.a("") - /// - public static IEnumerable getIterator(object Goal, Type declaringClass) - { - Atom name; - object[] args; - while (true) - { - Goal = YP.getValue(Goal); - if (Goal is Variable) - throw new PrologException("instantiation_error", "Goal to call is an unbound variable"); - name = YP.getFunctorName(Goal) as Atom; - if (name == null) - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Goal), "Goal to call is not callable"); - args = YP.getFunctorArgs(Goal); - if (name == Atom.HAT && args.Length == 2) - // Assume this is called from a bagof operation. Skip the leading qualifiers. - Goal = YP.getValue(((Functor2)Goal)._arg2); - else - break; - } - - IEnumerable simpleIterator = YPCompiler.getSimpleIterator(name, args, declaringClass); - if (simpleIterator != null) - // We don't need to compile since the goal is a simple predicate which we call directly. - return simpleIterator; - - // Compile the goal as a clause. - List variableSetList = new List(); - addUniqueVariables(Goal, variableSetList); - Variable[] variableSet = variableSetList.ToArray(); - - // Use Atom.F since it is ignored. - return YPCompiler.compileAnonymousClause - (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet); - } - - public static void throwException(object Term) - { - throw new PrologException(Term); - } - /// - /// This must be called by any function that uses YP._prologFlags to make sure - /// the initial defaults are loaded. - /// - private static void establishPrologFlags() - { - if (_prologFlags.Count > 0) - // Already established. - return; - - // List these in the order they appear in the ISO standard. - _prologFlags["bounded"] = Atom.a("true"); - _prologFlags["max_integer"] = Int32.MaxValue; - _prologFlags["min_integer"] = Int32.MinValue; - _prologFlags["integer_rounding_function"] = Atom.a("toward_zero"); - _prologFlags["char_conversion"] = Atom.a("off"); - _prologFlags["debug"] = Atom.a("off"); - _prologFlags["max_arity"] = MAX_ARITY; - _prologFlags["unknown"] = Atom.a("error"); - _prologFlags["double_quotes"] = Atom.a("codes"); - } - - public static IEnumerable current_prolog_flag(object Key, object Value) - { - establishPrologFlags(); - - Key = YP.getValue(Key); - Value = YP.getValue(Value); - - if (Key is Variable) - { - // Bind all key values. - foreach (string key in _prologFlags.Keys) - { - foreach (bool l1 in YP.unify(Key, Atom.a(key))) - { - foreach (bool l2 in YP.unify(Value, _prologFlags[key])) - yield return false; - } - } - } - else - { - if (!(Key is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom"); - if (!_prologFlags.ContainsKey(((Atom)Key)._name)) - throw new PrologException - (new Functor2("domain_error", Atom.a("prolog_flag"), Key), - "Arg 1 Key is not a recognized flag"); - - foreach (bool l1 in YP.unify(Value, _prologFlags[((Atom)Key)._name])) - yield return false; - } - } - - public static void set_prolog_flag(object Key, object Value) - { - establishPrologFlags(); - - Key = YP.getValue(Key); - Value = YP.getValue(Value); - - if (Key is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Key is an unbound variable"); - if (Value is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Key is an unbound variable"); - if (!(Key is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom"); - - string keyName = ((Atom)Key)._name; - if (!_prologFlags.ContainsKey(keyName)) - throw new PrologException - (new Functor2("domain_error", Atom.a("prolog_flag"), Key), - "Arg 1 Key " + Key + " is not a recognized flag"); - - bool valueIsOK = false; - if (keyName == "char_conversion") - valueIsOK = (Value == _prologFlags[keyName]); - else if (keyName == "debug") - valueIsOK = (Value == _prologFlags[keyName]); - else if (keyName == "unknown") - valueIsOK = (Value == Atom.a("fail") || Value == Atom.a("warning") || - Value == Atom.a("error")); - else if (keyName == "double_quotes") - valueIsOK = (Value == Atom.a("codes") || Value == Atom.a("chars") || - Value == Atom.a("atom")); - else - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("flag"), Key), - "May not modify Prolog flag " + Key); - - if (!valueIsOK) - throw new PrologException - (new Functor2("domain_error", Atom.a("flag_value"), new Functor2("+", Key, Value)), - "May not set arg 1 Key " + Key + " to arg 2 Value " + Value); - - _prologFlags[keyName] = Value; - } - /// - /// script_event calls hosting script with events as a callback method. - /// - /// - /// - /// - public static IEnumerable script_event(object script_event, object script_params) - { - // string function = ((Atom)YP.getValue(script_event))._name; - object[] array = ListPair.toArray(script_params); - if (array == null) - yield return false; // return; // YP.fail(); - if (array.Length > 1) - { - //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue - //(localID, itemID, function, array); - // sortArray(array); - } - //return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array)); - yield return false; - } - - /* Non-prolog-ish functions for inline coding */ - public static string regexString(string inData, string inPattern, string presep,string postsep) - { - //string str=cycMessage; - //string strMatch = @"\. \#\$(.*)\)"; - string results = ""; - for (Match m = Regex.Match(inData,inPattern); m.Success; m=m.NextMatch()) - { - //Console.WriteLine( m ); - results += presep+ m + postsep; - } - return results; - } - - public static string cycComm(object msgobj) - { - string cycInputString = msgobj.ToString(); - string cycOutputString=""; - TcpClient socketForServer; - - try - { - socketForServer = new TcpClient("localHost", 3601); - } - catch - { - Console.WriteLine("Failed to connect to server at {0}:999", "localhost"); - return ""; - } - - NetworkStream networkStream = socketForServer.GetStream(); - - System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream); - - System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream); - - try - { - // read the data from the host and display it - - { - - streamWriter.WriteLine(cycInputString); - streamWriter.Flush(); - - cycOutputString = streamReader.ReadLine(); - Console.WriteLine("Cycoutput:" + cycOutputString); - //streamWriter.WriteLine("Client Message"); - //Console.WriteLine("Client Message"); - streamWriter.Flush(); - } - - } - catch - { - Console.WriteLine("Exception reading from Server"); - return ""; - } - // tidy up - networkStream.Close(); - return cycOutputString; - - } - //public static void throwException(object Term) - //{ - // throw new PrologException(Term); - //} - /// - /// An enumerator that does zero loops. - /// - private class Fail : IEnumerator, IEnumerable - { - public bool MoveNext() - { - return false; - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return true; } - } - - object IEnumerator.Current - { - get { return true; } - } - - public void Dispose() - { - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - - /// - /// An enumerator that does one iteration. - /// - private class Succeed : IEnumerator, IEnumerable - { - private bool _didIteration = false; - - public bool MoveNext() - { - if (!_didIteration) - { - _didIteration = true; - return true; - } - else - return false; - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return false; } - } - - object IEnumerator.Current - { - get { return false; } - } - - public void Dispose() - { - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - - /// - /// An enumerator that repeats forever. - /// - private class Repeat : IEnumerator, IEnumerable - { - public bool MoveNext() - { - return true; - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return false; } - } - - object IEnumerator.Current - { - get { return false; } - } - - public void Dispose() - { - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - - /// - /// An enumerator that wraps another enumerator in order to catch a PrologException. - /// - public class Catch : IEnumerator, IEnumerable - { - private IEnumerator _enumerator; - private PrologException _exception = null; - - /// - /// Call YP.getIterator(Goal, declaringClass) and save the returned iterator. - /// If getIterator throws an exception, save it the same as MoveNext(). - /// - /// - /// - public Catch(object Goal, Type declaringClass) - { - try - { - _enumerator = getIterator(Goal, declaringClass).GetEnumerator(); - } - catch (PrologException exception) - { - // MoveNext() will check this. - _exception = exception; - } - } - - /// - /// Call _enumerator.MoveNext(). If it throws a PrologException, set _exception - /// and return false. After this returns false, call unifyExceptionOrThrow. - /// - /// - public bool MoveNext() - { - if (_exception != null) - return false; - - try - { - return _enumerator.MoveNext(); - } - catch (PrologException exception) - { - _exception = exception; - return false; - } - } - - /// - /// Call this after MoveNext() returns false to check for an exception. If - /// MoveNext did not get a PrologException, don't yield. - /// Otherwise, unify the exception with Catcher and yield so the caller can - /// do the handler code. However, if can't unify with Catcher then throw the exception. - /// - /// - /// - public IEnumerable unifyExceptionOrThrow(object Catcher) - { - if (_exception != null) - { - bool didUnify = false; - foreach (bool l1 in YP.unify(_exception._term, Catcher)) - { - didUnify = true; - yield return false; - } - if (!didUnify) - throw _exception; - } - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return _enumerator.Current; } - } - - object IEnumerator.Current - { - get { return _enumerator.Current; } - } - - public void Dispose() - { - if (_enumerator != null) - _enumerator.Dispose(); - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - #pragma warning restore 0168 - /// - /// A ClauseHeadAndBody is used in Compiler.compileAnonymousFunction as a base class - /// in order to implement YP.IClause. After creating the object, you must call setHeadAndBody. - /// - public class ClauseHeadAndBody - { - private object _Head; - private object _Body; - - public void setHeadAndBody(object Head, object Body) - { - _Head = Head; - _Body = Body; - } - - public IEnumerable clause(object Head, object Body) - { - if (_Head == null || _Body == null) - yield break; - - #pragma warning disable 0168 - foreach (bool l1 in YP.unify(Head, _Head)) - { - foreach (bool l2 in YP.unify(Body, _Body)) - yield return false; - } - #pragma warning restore 0168 - } - } - - /// - /// CodeListReader extends TextReader and overrides Read to read the next code from - /// the CodeList which is a Prolog list of integer character codes. - /// - public class CodeListReader : TextReader - { - private object _CodeList; - - public CodeListReader(object CodeList) - { - _CodeList = YP.getValue(CodeList); - } - - /// - /// If the head of _CodeList is an integer, return it and advance the list. Otherwise, - /// return -1 for end of file. - /// - /// - public override int Read() - { - Functor2 CodeListPair = _CodeList as Functor2; - int code; - if (!(CodeListPair != null && CodeListPair._name == Atom.DOT && - getInt(CodeListPair._arg1, out code))) - { - _CodeList = Atom.NIL; - return -1; - } - - // Advance. - _CodeList = YP.getValue(CodeListPair._arg2); - return code; - } - } - } -} -- cgit v1.1