PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs

https://bitbucket.org/VirtualReality/taiga
C# | 2701 lines | 2416 code | 87 blank | 198 comment | 134 complexity | da07ed504aba40384e157eacf6c0cd67 MD5 | raw file
  1. /*
  2. * Copyright (C) 2007-2008, Jeff Thompson
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of the copyright holder nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. using System;
  31. using System.Collections;
  32. using System.Collections.Generic;
  33. using System.IO;
  34. using System.Reflection;
  35. using System.Net.Sockets;
  36. using System.Text;
  37. using System.Text.RegularExpressions;
  38. using log4net;
  39. namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
  40. {
  41. /// <summary>
  42. /// YP has static methods for general functions in Yield Prolog such as <see cref="getValue"/>
  43. /// and <see cref="unify"/>.
  44. /// </summary>
  45. public class YP
  46. {
  47. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  48. private static Fail _fail = new Fail();
  49. private static Repeat _repeat = new Repeat();
  50. private static Dictionary<NameArity, List<IClause>> _predicatesStore =
  51. new Dictionary<NameArity, List<IClause>>();
  52. private static TextWriter _outputStream = System.Console.Out;
  53. private static TextReader _inputStream = System.Console.In;
  54. private static IndexedAnswers _operatorTable = null;
  55. private static Dictionary<string, object> _prologFlags = new Dictionary<string, object>();
  56. public const int MAX_ARITY = 255;
  57. /// <summary>
  58. /// An IClause is used so that dynamic predicates can call match.
  59. /// </summary>
  60. public interface IClause
  61. {
  62. IEnumerable<bool> match(object[] args);
  63. IEnumerable<bool> clause(object Head, object Body);
  64. }
  65. /// <summary>
  66. /// If value is a Variable, then return its getValue. Otherwise, just
  67. /// return value. You should call YP.getValue on any object that
  68. /// may be a Variable to get the value to pass to other functions in
  69. /// your system that are not part of Yield Prolog, such as math functions
  70. /// or file I/O.
  71. /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
  72. /// </summary>
  73. /// <param name="value"></param>
  74. /// <returns></returns>
  75. public static object getValue(object value)
  76. {
  77. if (value is Variable)
  78. return ((Variable)value).getValue();
  79. else
  80. return value;
  81. }
  82. /// <summary>
  83. /// If arg1 or arg2 is an object with a unify method (such as Variable or
  84. /// Functor) then just call its unify with the other argument. The object's
  85. /// unify method will bind the values or check for equals as needed.
  86. /// Otherwise, both arguments are "normal" (atomic) values so if they
  87. /// are equal then succeed (yield once), else fail (don't yield).
  88. /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
  89. /// </summary>
  90. /// <param name="arg1"></param>
  91. /// <param name="arg2"></param>
  92. /// <returns></returns>
  93. public static IEnumerable<bool> unify(object arg1, object arg2)
  94. {
  95. arg1 = getValue(arg1);
  96. arg2 = getValue(arg2);
  97. if (arg1 is IUnifiable)
  98. return ((IUnifiable)arg1).unify(arg2);
  99. else if (arg2 is IUnifiable)
  100. return ((IUnifiable)arg2).unify(arg1);
  101. else
  102. {
  103. // Arguments are "normal" types.
  104. if (arg1.Equals(arg2))
  105. return new Succeed();
  106. else
  107. return _fail;
  108. }
  109. }
  110. /// <summary>
  111. /// This is used for the lookup key in _factStore.
  112. /// </summary>
  113. public struct NameArity
  114. {
  115. public readonly Atom _name;
  116. public readonly int _arity;
  117. public NameArity(Atom name, int arity)
  118. {
  119. _name = name;
  120. _arity = arity;
  121. }
  122. public override bool Equals(object obj)
  123. {
  124. if (obj is NameArity)
  125. {
  126. NameArity nameArity = (NameArity)obj;
  127. return nameArity._name.Equals(_name) && nameArity._arity.Equals(_arity);
  128. }
  129. else
  130. {
  131. return false;
  132. }
  133. }
  134. public override int GetHashCode()
  135. {
  136. return _name.GetHashCode() ^ _arity.GetHashCode();
  137. }
  138. }
  139. /// <summary>
  140. /// Convert term to an int.
  141. /// If term is a single-element List, use its first element
  142. /// (to handle the char types like "a").
  143. /// If can't convert, throw a PrologException for type_error evaluable (because this is only
  144. /// called from arithmetic functions).
  145. /// </summary>
  146. /// <param name="term"></param>
  147. /// <returns></returns>
  148. public static int convertInt(object term)
  149. {
  150. term = YP.getValue(term);
  151. if (term is Functor2 && ((Functor2)term)._name == Atom.DOT &&
  152. YP.getValue(((Functor2)term)._arg2) == Atom.NIL)
  153. // Assume it is a char type like "a".
  154. term = YP.getValue(((Functor2)term)._arg1);
  155. if (term is Variable)
  156. throw new PrologException(Atom.a("instantiation_error"),
  157. "Expected a number but the argument is an unbound variable");
  158. try
  159. {
  160. return (int)term;
  161. }
  162. catch (InvalidCastException)
  163. {
  164. throw new PrologException
  165. (new Functor2
  166. ("type_error", Atom.a("evaluable"),
  167. new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)),
  168. "Term must be an integer");
  169. }
  170. }
  171. /// <summary>
  172. /// Convert term to a double. This may convert an int to a double, etc.
  173. /// If term is a single-element List, use its first element
  174. /// (to handle the char types like "a").
  175. /// If can't convert, throw a PrologException for type_error evaluable (because this is only
  176. /// called from arithmetic functions).
  177. /// </summary>
  178. /// <param name="term"></param>
  179. /// <returns></returns>
  180. public static double convertDouble(object term)
  181. {
  182. term = YP.getValue(term);
  183. if (term is Functor2 && ((Functor2)term)._name == Atom.DOT &&
  184. YP.getValue(((Functor2)term)._arg2) == Atom.NIL)
  185. // Assume it is a char type like "a".
  186. term = YP.getValue(((Functor2)term)._arg1);
  187. if (term is Variable)
  188. throw new PrologException(Atom.a("instantiation_error"),
  189. "Expected a number but the argument is an unbound variable");
  190. try
  191. {
  192. return Convert.ToDouble(term);
  193. }
  194. catch (InvalidCastException)
  195. {
  196. throw new PrologException
  197. (new Functor2
  198. ("type_error", Atom.a("evaluable"),
  199. new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)),
  200. "Term must be an integer");
  201. }
  202. }
  203. /// <summary>
  204. /// If term is an integer, set intTerm.
  205. /// If term is a single-element List, use its first element
  206. /// (to handle the char types like "a"). Return true for success, false if can't convert.
  207. /// We use a success return value because throwing an exception is inefficient.
  208. /// </summary>
  209. /// <param name="term"></param>
  210. /// <returns></returns>
  211. public static bool getInt(object term, out int intTerm)
  212. {
  213. term = YP.getValue(term);
  214. if (term is Functor2 && ((Functor2)term)._name == Atom.DOT &&
  215. YP.getValue(((Functor2)term)._arg2) == Atom.NIL)
  216. // Assume it is a char type like "a".
  217. term = YP.getValue(((Functor2)term)._arg1);
  218. if (term is int)
  219. {
  220. intTerm = (int)term;
  221. return true;
  222. }
  223. intTerm = 0;
  224. return false;
  225. }
  226. public static bool equal(object x, object y)
  227. {
  228. x = YP.getValue(x);
  229. if (x is DateTime)
  230. return (DateTime)x == (DateTime)YP.getValue(y);
  231. // Assume convertDouble converts an int to a double perfectly.
  232. return YP.convertDouble(x) == YP.convertDouble(y);
  233. }
  234. public static bool notEqual(object x, object y)
  235. {
  236. x = YP.getValue(x);
  237. if (x is DateTime)
  238. return (DateTime)x != (DateTime)YP.getValue(y);
  239. // Assume convertDouble converts an int to a double perfectly.
  240. return YP.convertDouble(x) != YP.convertDouble(y);
  241. }
  242. public static bool greaterThan(object x, object y)
  243. {
  244. x = YP.getValue(x);
  245. if (x is DateTime)
  246. return (DateTime)x > (DateTime)YP.getValue(y);
  247. // Assume convertDouble converts an int to a double perfectly.
  248. return YP.convertDouble(x) > YP.convertDouble(y);
  249. }
  250. public static bool lessThan(object x, object y)
  251. {
  252. x = YP.getValue(x);
  253. if (x is DateTime)
  254. return (DateTime)x < (DateTime)YP.getValue(y);
  255. // Assume convertDouble converts an int to a double perfectly.
  256. return YP.convertDouble(x) < YP.convertDouble(y);
  257. }
  258. public static bool greaterThanOrEqual(object x, object y)
  259. {
  260. x = YP.getValue(x);
  261. if (x is DateTime)
  262. return (DateTime)x >= (DateTime)YP.getValue(y);
  263. // Assume convertDouble converts an int to a double perfectly.
  264. return YP.convertDouble(x) >= YP.convertDouble(y);
  265. }
  266. public static bool lessThanOrEqual(object x, object y)
  267. {
  268. x = YP.getValue(x);
  269. if (x is DateTime)
  270. return (DateTime)x <= (DateTime)YP.getValue(y);
  271. // Assume convertDouble converts an int to a double perfectly.
  272. return YP.convertDouble(x) <= YP.convertDouble(y);
  273. }
  274. public static object negate(object x)
  275. {
  276. int intX;
  277. if (getInt(x, out intX))
  278. return -intX;
  279. return -convertDouble(x);
  280. }
  281. public static object abs(object x)
  282. {
  283. int intX;
  284. if (getInt(x, out intX))
  285. return Math.Abs(intX);
  286. return Math.Abs(convertDouble(x));
  287. }
  288. public static object sign(object x)
  289. {
  290. int intX;
  291. if (getInt(x, out intX))
  292. return Math.Sign(intX);
  293. return Math.Sign(convertDouble(x));
  294. }
  295. // Use toFloat instead of float because it is a reserved keyword.
  296. public static object toFloat(object x)
  297. {
  298. return convertDouble(x);
  299. }
  300. /// <summary>
  301. /// The ISO standard returns an int.
  302. /// </summary>
  303. /// <param name="x"></param>
  304. /// <returns></returns>
  305. public static object floor(object x)
  306. {
  307. return (int)Math.Floor(convertDouble(x));
  308. }
  309. /// <summary>
  310. /// The ISO standard returns an int.
  311. /// </summary>
  312. /// <param name="x"></param>
  313. /// <returns></returns>
  314. public static object truncate(object x)
  315. {
  316. return (int)Math.Truncate(convertDouble(x));
  317. }
  318. /// <summary>
  319. /// The ISO standard returns an int.
  320. /// </summary>
  321. /// <param name="x"></param>
  322. /// <returns></returns>
  323. public static object round(object x)
  324. {
  325. return (int)Math.Round(convertDouble(x));
  326. }
  327. /// <summary>
  328. /// The ISO standard returns an int.
  329. /// </summary>
  330. /// <param name="x"></param>
  331. /// <returns></returns>
  332. public static object ceiling(object x)
  333. {
  334. return (int)Math.Ceiling(convertDouble(x));
  335. }
  336. public static object sin(object x)
  337. {
  338. return Math.Sin(YP.convertDouble(x));
  339. }
  340. public static object cos(object x)
  341. {
  342. return Math.Cos(YP.convertDouble(x));
  343. }
  344. public static object atan(object x)
  345. {
  346. return Math.Atan(YP.convertDouble(x));
  347. }
  348. public static object exp(object x)
  349. {
  350. return Math.Exp(YP.convertDouble(x));
  351. }
  352. public static object log(object x)
  353. {
  354. return Math.Log(YP.convertDouble(x));
  355. }
  356. public static object sqrt(object x)
  357. {
  358. return Math.Sqrt(convertDouble(x));
  359. }
  360. public static object bitwiseComplement(object x)
  361. {
  362. return ~YP.convertInt(x);
  363. }
  364. public static object add(object x, object y)
  365. {
  366. int intX, intY;
  367. if (getInt(x, out intX) && getInt(y, out intY))
  368. return intX + intY;
  369. return convertDouble(x) + convertDouble(y);
  370. }
  371. public static object subtract(object x, object y)
  372. {
  373. int intX, intY;
  374. if (getInt(x, out intX) && getInt(y, out intY))
  375. return intX - intY;
  376. return convertDouble(x) - convertDouble(y);
  377. }
  378. public static object multiply(object x, object y)
  379. {
  380. int intX, intY;
  381. if (getInt(x, out intX) && getInt(y, out intY))
  382. return intX * intY;
  383. return convertDouble(x) * convertDouble(y);
  384. }
  385. /// <summary>
  386. /// Return floating point, even if both arguments are integer.
  387. /// </summary>
  388. /// <param name="x"></param>
  389. /// <param name="y"></param>
  390. /// <returns></returns>
  391. public static object divide(object x, object y)
  392. {
  393. return convertDouble(x) / convertDouble(y);
  394. }
  395. public static object intDivide(object x, object y)
  396. {
  397. int intX, intY;
  398. if (getInt(x, out intX) && getInt(y, out intY))
  399. return intX / intY;
  400. // Still allow passing a double, but treat as an int.
  401. return (int)convertDouble(x) / (int)convertDouble(y);
  402. }
  403. public static object mod(object x, object y)
  404. {
  405. int intX, intY;
  406. if (getInt(x, out intX) && getInt(y, out intY))
  407. return intX % intY;
  408. // Still allow passing a double, but treat as an int.
  409. return (int)convertDouble(x) % (int)convertDouble(y);
  410. }
  411. public static object pow(object x, object y)
  412. {
  413. return Math.Pow(YP.convertDouble(x), YP.convertDouble(y));
  414. }
  415. public static object bitwiseShiftRight(object x, object y)
  416. {
  417. return YP.convertInt(x) >> YP.convertInt(y);
  418. }
  419. public static object bitwiseShiftLeft(object x, object y)
  420. {
  421. return YP.convertInt(x) << YP.convertInt(y);
  422. }
  423. public static object bitwiseAnd(object x, object y)
  424. {
  425. return YP.convertInt(x) & YP.convertInt(y);
  426. }
  427. public static object bitwiseOr(object x, object y)
  428. {
  429. return YP.convertInt(x) | YP.convertInt(y);
  430. }
  431. public static object min(object x, object y)
  432. {
  433. int intX, intY;
  434. if (getInt(x, out intX) && getInt(y, out intY))
  435. return Math.Min(intX, intY);
  436. return Math.Min(convertDouble(x), convertDouble(y));
  437. }
  438. public static object max(object x, object y)
  439. {
  440. int intX, intY;
  441. if (getInt(x, out intX) && getInt(y, out intY))
  442. return Math.Max(intX, intY);
  443. return Math.Max(convertDouble(x), convertDouble(y));
  444. }
  445. public static IEnumerable<bool> copy_term(object inTerm, object outTerm)
  446. {
  447. return YP.unify(outTerm, YP.makeCopy(inTerm, new Variable.CopyStore()));
  448. }
  449. public static void addUniqueVariables(object term, List<Variable> variableSet)
  450. {
  451. term = YP.getValue(term);
  452. if (term is IUnifiable)
  453. ((IUnifiable)term).addUniqueVariables(variableSet);
  454. }
  455. public static object makeCopy(object term, Variable.CopyStore copyStore)
  456. {
  457. term = YP.getValue(term);
  458. if (term is IUnifiable)
  459. return ((IUnifiable)term).makeCopy(copyStore);
  460. else
  461. // term is a "normal" type. Assume it is ground.
  462. return term;
  463. }
  464. /// <summary>
  465. /// Sort the array in place according to termLessThan. This does not remove duplicates
  466. /// </summary>
  467. /// <param name="array"></param>
  468. public static void sortArray(object[] array)
  469. {
  470. Array.Sort(array, YP.compareTerms);
  471. }
  472. /// <summary>
  473. /// Sort the array in place according to termLessThan. This does not remove duplicates
  474. /// </summary>
  475. /// <param name="array"></param>
  476. public static void sortArray(List<object> array)
  477. {
  478. array.Sort(YP.compareTerms);
  479. }
  480. /// <summary>
  481. /// Sort List according to termLessThan, remove duplicates and unify with Sorted.
  482. /// </summary>
  483. /// <param name="List"></param>
  484. /// <param name="Sorted"></param>
  485. /// <returns></returns>
  486. public static IEnumerable<bool> sort(object List, object Sorted)
  487. {
  488. object[] array = ListPair.toArray(List);
  489. if (array == null)
  490. return YP.fail();
  491. if (array.Length > 1)
  492. sortArray(array);
  493. return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array));
  494. }
  495. /// <summary>
  496. /// Use YP.unify to unify each of the elements of the two arrays, and yield
  497. /// once if they all unify.
  498. /// </summary>
  499. /// <param name="array1"></param>
  500. /// <param name="array2"></param>
  501. /// <returns></returns>
  502. public static IEnumerable<bool> unifyArrays(object[] array1, object[] array2)
  503. {
  504. if (array1.Length != array2.Length)
  505. yield break;
  506. IEnumerator<bool>[] iterators = new IEnumerator<bool>[array1.Length];
  507. bool gotMatch = true;
  508. int nIterators = 0;
  509. // Try to bind all the arguments.
  510. for (int i = 0; i < array1.Length; ++i)
  511. {
  512. IEnumerator<bool> iterator = YP.unify(array1[i], array2[i]).GetEnumerator();
  513. iterators[nIterators++] = iterator;
  514. // MoveNext() is true if YP.unify succeeds.
  515. if (!iterator.MoveNext())
  516. {
  517. gotMatch = false;
  518. break;
  519. }
  520. }
  521. try
  522. {
  523. if (gotMatch)
  524. yield return false;
  525. }
  526. finally
  527. {
  528. // Manually finalize all the iterators.
  529. for (int i = 0; i < nIterators; ++i)
  530. iterators[i].Dispose();
  531. }
  532. }
  533. /// <summary>
  534. /// Return an iterator (which you can use in a for-in loop) which does
  535. /// zero iterations. This returns a pre-existing iterator which is
  536. /// more efficient than letting the compiler generate a new one.
  537. /// </summary>
  538. /// <returns></returns>
  539. public static IEnumerable<bool> fail()
  540. {
  541. return _fail;
  542. }
  543. /// <summary>
  544. /// Return an iterator (which you can use in a for-in loop) which does
  545. /// one iteration. This returns a pre-existing iterator which is
  546. /// more efficient than letting the compiler generate a new one.
  547. /// </summary>
  548. /// <returns></returns>
  549. public static IEnumerable<bool> succeed()
  550. {
  551. return new Succeed();
  552. }
  553. /// <summary>
  554. /// Return an iterator (which you can use in a for-in loop) which repeats
  555. /// indefinitely. This returns a pre-existing iterator which is
  556. /// more efficient than letting the compiler generate a new one.
  557. /// </summary>
  558. /// <returns></returns>
  559. public static IEnumerable<bool> repeat()
  560. {
  561. return _repeat;
  562. }
  563. // disable warning on l1, don't see how we can
  564. // code this differently
  565. #pragma warning disable 0168, 0219
  566. public static IEnumerable<bool> univ(object Term, object List)
  567. {
  568. Term = YP.getValue(Term);
  569. List = YP.getValue(List);
  570. if (nonvar(Term))
  571. return YP.unify(new ListPair
  572. (getFunctorName(Term), ListPair.make(getFunctorArgs(Term))), List);
  573. Variable Name = new Variable();
  574. Variable ArgList = new Variable();
  575. foreach (bool l1 in new ListPair(Name, ArgList).unify(List))
  576. {
  577. object[] args = ListPair.toArray(ArgList);
  578. if (args == null)
  579. throw new PrologException
  580. (new Functor2("type_error", Atom.a("list"), ArgList),
  581. "Expected a list. Got: " + ArgList.getValue());
  582. if (args.Length == 0)
  583. // Return the Name, even if it is not an Atom.
  584. return YP.unify(Term, Name);
  585. if (args.Length > MAX_ARITY)
  586. throw new PrologException
  587. (new Functor1("representation_error", Atom.a("max_arity")),
  588. "Functor arity " + args.Length + " may not be greater than " + MAX_ARITY);
  589. if (!atom(Name))
  590. throw new PrologException
  591. (new Functor2("type_error", Atom.a("atom"), Name),
  592. "Expected an atom. Got: " + Name.getValue());
  593. return YP.unify(Term, Functor.make((Atom)YP.getValue(Name), args));
  594. }
  595. return YP.fail();
  596. }
  597. public static IEnumerable<bool> functor(object Term, object FunctorName, object Arity)
  598. {
  599. Term = YP.getValue(Term);
  600. FunctorName = YP.getValue(FunctorName);
  601. Arity = YP.getValue(Arity);
  602. if (Term is Variable)
  603. {
  604. if (FunctorName is Variable)
  605. throw new PrologException(Atom.a("instantiation_error"),
  606. "Arg 2 FunctorName is an unbound variable");
  607. if (Arity is Variable)
  608. throw new PrologException(Atom.a("instantiation_error"),
  609. "Arg 3 Arity is an unbound variable");
  610. if (!(Arity is int))
  611. throw new PrologException
  612. (new Functor2("type_error", Atom.a("integer"), Arity), "Arity is not an integer");
  613. if (!YP.atomic(FunctorName))
  614. throw new PrologException
  615. (new Functor2("type_error", Atom.a("atomic"), FunctorName), "FunctorName is not atomic");
  616. if ((int)Arity < 0)
  617. throw new PrologException
  618. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Arity),
  619. "Arity may not be less than zero");
  620. else if ((int)Arity == 0)
  621. {
  622. // Just unify Term with the atomic FunctorName.
  623. foreach (bool l1 in YP.unify(Term, FunctorName))
  624. yield return false;
  625. }
  626. else
  627. {
  628. if ((int)Arity > MAX_ARITY)
  629. throw new PrologException
  630. (new Functor1("representation_error", Atom.a("max_arity")),
  631. "Functor arity " + Arity + " may not be greater than " + MAX_ARITY);
  632. if (!(FunctorName is Atom))
  633. throw new PrologException
  634. (new Functor2("type_error", Atom.a("atom"), FunctorName), "FunctorName is not an atom");
  635. // Construct a functor with unbound variables.
  636. object[] args = new object[(int)Arity];
  637. for (int i = 0; i < args.Length; ++i)
  638. args[i] = new Variable();
  639. foreach (bool l1 in YP.unify(Term, Functor.make((Atom)FunctorName, args)))
  640. yield return false;
  641. }
  642. }
  643. else
  644. {
  645. foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term)))
  646. {
  647. foreach (bool l2 in YP.unify(Arity, getFunctorArgs(Term).Length))
  648. yield return false;
  649. }
  650. }
  651. }
  652. public static IEnumerable<bool> arg(object ArgNumber, object Term, object Value)
  653. {
  654. if (var(ArgNumber))
  655. throw new PrologException(Atom.a("instantiation_error"), "Arg 1 ArgNumber is an unbound variable");
  656. int argNumberInt;
  657. if (!getInt(ArgNumber, out argNumberInt))
  658. throw new PrologException
  659. (new Functor2("type_error", Atom.a("integer"), ArgNumber), "Arg 1 ArgNumber must be integer");
  660. if (argNumberInt < 0)
  661. throw new PrologException
  662. (new Functor2("domain_error", Atom.a("not_less_than_zero"), argNumberInt),
  663. "ArgNumber may not be less than zero");
  664. if (YP.var(Term))
  665. throw new PrologException(Atom.a("instantiation_error"),
  666. "Arg 2 Term is an unbound variable");
  667. if (!YP.compound(Term))
  668. throw new PrologException
  669. (new Functor2("type_error", Atom.a("compound"), Term), "Arg 2 Term must be compound");
  670. object[] termArgs = YP.getFunctorArgs(Term);
  671. // Silently fail if argNumberInt is out of range.
  672. if (argNumberInt >= 1 && argNumberInt <= termArgs.Length)
  673. {
  674. // The first ArgNumber is at 1, not 0.
  675. foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1]))
  676. yield return false;
  677. }
  678. }
  679. public static bool termEqual(object Term1, object Term2)
  680. {
  681. Term1 = YP.getValue(Term1);
  682. if (Term1 is IUnifiable)
  683. return ((IUnifiable)Term1).termEqual(Term2);
  684. return Term1.Equals(YP.getValue(Term2));
  685. }
  686. public static bool termNotEqual(object Term1, object Term2)
  687. {
  688. return !termEqual(Term1, Term2);
  689. }
  690. public static bool termLessThan(object Term1, object Term2)
  691. {
  692. Term1 = YP.getValue(Term1);
  693. Term2 = YP.getValue(Term2);
  694. int term1TypeCode = getTypeCode(Term1);
  695. int term2TypeCode = getTypeCode(Term2);
  696. if (term1TypeCode != term2TypeCode)
  697. return term1TypeCode < term2TypeCode;
  698. // The terms are the same type code.
  699. if (term1TypeCode == -2)
  700. {
  701. // Variable.
  702. // We always check for equality first because we want to be sure
  703. // that less than returns false if the terms are equal, in
  704. // case that the less than check really behaves like less than or equal.
  705. if ((Variable)Term1 != (Variable)Term2)
  706. // The hash code should be unique to a Variable object.
  707. return Term1.GetHashCode() < Term2.GetHashCode();
  708. return false;
  709. }
  710. if (term1TypeCode == 0)
  711. return ((Atom)Term1)._name.CompareTo(((Atom)Term2)._name) < 0;
  712. if (term1TypeCode == 1)
  713. return ((Functor1)Term1).lessThan((Functor1)Term2);
  714. if (term1TypeCode == 2)
  715. return ((Functor2)Term1).lessThan((Functor2)Term2);
  716. if (term1TypeCode == 3)
  717. return ((Functor3)Term1).lessThan((Functor3)Term2);
  718. if (term1TypeCode == 4)
  719. return ((Functor)Term1).lessThan((Functor)Term2);
  720. // Type code is -1 for general objects. First compare their type names.
  721. // Note that this puts Double before Int32 as required by ISO Prolog.
  722. string term1TypeName = Term1.GetType().ToString();
  723. string term2TypeName = Term2.GetType().ToString();
  724. if (term1TypeName != term2TypeName)
  725. return term1TypeName.CompareTo(term2TypeName) < 0;
  726. // The terms are the same type name.
  727. if (Term1 is int)
  728. return (int)Term1 < (int)Term2;
  729. else if (Term1 is double)
  730. return (double)Term1 < (double)Term2;
  731. else if (Term1 is DateTime)
  732. return (DateTime)Term1 < (DateTime)Term2;
  733. else if (Term1 is String)
  734. return ((String)Term1).CompareTo((String)Term2) < 0;
  735. // Debug: Should we try arrays, etc.?
  736. if (!Term1.Equals(Term2))
  737. // Could be equal or greater than.
  738. return Term1.GetHashCode() < Term2.GetHashCode();
  739. return false;
  740. }
  741. /// <summary>
  742. /// Type code is -2 if term is a Variable, 0 if it is an Atom,
  743. /// 1 if it is a Functor1, 2 if it is a Functor2, 3 if it is a Functor3,
  744. /// 4 if it is Functor.
  745. /// Otherwise, type code is -1.
  746. /// This does not call YP.getValue(term).
  747. /// </summary>
  748. /// <param name="term"></param>
  749. /// <returns></returns>
  750. private static int getTypeCode(object term)
  751. {
  752. if (term is Variable)
  753. return -2;
  754. else if (term is Atom)
  755. return 0;
  756. else if (term is Functor1)
  757. return 1;
  758. else if (term is Functor2)
  759. return 2;
  760. else if (term is Functor3)
  761. return 3;
  762. else if (term is Functor)
  763. return 4;
  764. else
  765. return -1;
  766. }
  767. public static bool termLessThanOrEqual(object Term1, object Term2)
  768. {
  769. if (YP.termEqual(Term1, Term2))
  770. return true;
  771. return YP.termLessThan(Term1, Term2);
  772. }
  773. public static bool termGreaterThan(object Term1, object Term2)
  774. {
  775. return !YP.termLessThanOrEqual(Term1, Term2);
  776. }
  777. public static bool termGreaterThanOrEqual(object Term1, object Term2)
  778. {
  779. // termLessThan should ensure that it returns false if terms are equal,
  780. // so that this would return true.
  781. return !YP.termLessThan(Term1, Term2);
  782. }
  783. public static int compareTerms(object Term1, object Term2)
  784. {
  785. if (YP.termEqual(Term1, Term2))
  786. return 0;
  787. else if (YP.termLessThan(Term1, Term2))
  788. return -1;
  789. else
  790. return 1;
  791. }
  792. public static bool ground(object Term)
  793. {
  794. Term = YP.getValue(Term);
  795. if (Term is IUnifiable)
  796. return ((IUnifiable)Term).ground();
  797. return true;
  798. }
  799. public static IEnumerable<bool> current_op
  800. (object Priority, object Specifier, object Operator)
  801. {
  802. if (_operatorTable == null)
  803. {
  804. // Initialize.
  805. _operatorTable = new IndexedAnswers(3);
  806. _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") });
  807. _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") });
  808. _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a(":-") });
  809. _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a("?-") });
  810. _operatorTable.addAnswer(new object[] { 1100, Atom.a("xfy"), Atom.a(";") });
  811. _operatorTable.addAnswer(new object[] { 1050, Atom.a("xfy"), Atom.a("->") });
  812. _operatorTable.addAnswer(new object[] { 1000, Atom.a("xfy"), Atom.a(",") });
  813. _operatorTable.addAnswer(new object[] { 900, Atom.a("fy"), Atom.a("\\+") });
  814. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=") });
  815. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") });
  816. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("==") });
  817. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") });
  818. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@<") });
  819. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") });
  820. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>") });
  821. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") });
  822. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=..") });
  823. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("is") });
  824. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") });
  825. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") });
  826. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("<") });
  827. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=<") });
  828. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">") });
  829. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">=") });
  830. _operatorTable.addAnswer(new object[] { 600, Atom.a("xfy"), Atom.a(":") });
  831. _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("+") });
  832. _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("-") });
  833. _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") });
  834. _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") });
  835. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("*") });
  836. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("/") });
  837. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("//") });
  838. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("rem") });
  839. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("mod") });
  840. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("<<") });
  841. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a(">>") });
  842. _operatorTable.addAnswer(new object[] { 200, Atom.a("xfx"), Atom.a("**") });
  843. _operatorTable.addAnswer(new object[] { 200, Atom.a("xfy"), Atom.a("^") });
  844. _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("-") });
  845. _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("\\") });
  846. // Debug: This is hacked in to run the Prolog test suite until we implement op/3.
  847. _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") });
  848. }
  849. return _operatorTable.match(new object[] { Priority, Specifier, Operator });
  850. }
  851. public static IEnumerable<bool> atom_length(object atom, object Length)
  852. {
  853. atom = YP.getValue(atom);
  854. Length = YP.getValue(Length);
  855. if (atom is Variable)
  856. throw new PrologException(Atom.a("instantiation_error"),
  857. "Expected atom(Arg1) but it is an unbound variable");
  858. if (!(atom is Atom))
  859. throw new PrologException
  860. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom");
  861. if (!(Length is Variable))
  862. {
  863. if (!(Length is int))
  864. throw new PrologException
  865. (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer");
  866. if ((int)Length < 0)
  867. throw new PrologException
  868. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length),
  869. "Length must not be less than zero");
  870. }
  871. return YP.unify(Length, ((Atom)atom)._name.Length);
  872. }
  873. public static IEnumerable<bool> atom_concat(object Start, object End, object Whole)
  874. {
  875. // Debug: Should we try to preserve the _declaringClass?
  876. Start = YP.getValue(Start);
  877. End = YP.getValue(End);
  878. Whole = YP.getValue(Whole);
  879. if (Whole is Variable)
  880. {
  881. if (Start is Variable)
  882. throw new PrologException(Atom.a("instantiation_error"),
  883. "Arg 1 Start and arg 3 Whole are both var");
  884. if (End is Variable)
  885. throw new PrologException(Atom.a("instantiation_error"),
  886. "Arg 2 End and arg 3 Whole are both var");
  887. if (!(Start is Atom))
  888. throw new PrologException
  889. (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not an atom");
  890. if (!(End is Atom))
  891. throw new PrologException
  892. (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not an atom");
  893. foreach (bool l1 in YP.unify(Whole, Atom.a(((Atom)Start)._name + ((Atom)End)._name)))
  894. yield return false;
  895. }
  896. else
  897. {
  898. if (!(Whole is Atom))
  899. throw new PrologException
  900. (new Functor2("type_error", Atom.a("atom"), Whole), "Arg 3 Whole is not an atom");
  901. bool gotStartLength = false;
  902. int startLength = 0;
  903. if (!(Start is Variable))
  904. {
  905. if (!(Start is Atom))
  906. throw new PrologException
  907. (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not var or atom");
  908. startLength = ((Atom)Start)._name.Length;
  909. gotStartLength = true;
  910. }
  911. bool gotEndLength = false;
  912. int endLength = 0;
  913. if (!(End is Variable))
  914. {
  915. if (!(End is Atom))
  916. throw new PrologException
  917. (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not var or atom");
  918. endLength = ((Atom)End)._name.Length;
  919. gotEndLength = true;
  920. }
  921. // We are doing a search through all possible Start and End which concatenate to Whole.
  922. string wholeString = ((Atom)Whole)._name;
  923. for (int i = 0; i <= wholeString.Length; ++i)
  924. {
  925. // If we got either startLength or endLength, we know the lengths have to match so check
  926. // the lengths instead of constructing an Atom to do it.
  927. if (gotStartLength && startLength != i)
  928. continue;
  929. if (gotEndLength && endLength != wholeString.Length - i)
  930. continue;
  931. foreach (bool l1 in YP.unify(Start, Atom.a(wholeString.Substring(0, i))))
  932. {
  933. foreach (bool l2 in YP.unify(End, Atom.a(wholeString.Substring(i, wholeString.Length - i))))
  934. yield return false;
  935. }
  936. }
  937. }
  938. }
  939. public static IEnumerable<bool> sub_atom
  940. (object atom, object Before, object Length, object After, object Sub_atom)
  941. {
  942. // Debug: Should we try to preserve the _declaringClass?
  943. atom = YP.getValue(atom);
  944. Before = YP.getValue(Before);
  945. Length = YP.getValue(Length);
  946. After = YP.getValue(After);
  947. Sub_atom = YP.getValue(Sub_atom);
  948. if (atom is Variable)
  949. throw new PrologException(Atom.a("instantiation_error"),
  950. "Expected atom(Arg1) but it is an unbound variable");
  951. if (!(atom is Atom))
  952. throw new PrologException
  953. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom");
  954. if (!(Sub_atom is Variable))
  955. {
  956. if (!(Sub_atom is Atom))
  957. throw new PrologException
  958. (new Functor2("type_error", Atom.a("atom"), Sub_atom), "Sub_atom is not var or atom");
  959. }
  960. bool beforeIsInt = false;
  961. bool lengthIsInt = false;
  962. bool afterIsInt = false;
  963. if (!(Before is Variable))
  964. {
  965. if (!(Before is int))
  966. throw new PrologException
  967. (new Functor2("type_error", Atom.a("integer"), Before), "Before must be var or integer");
  968. beforeIsInt = true;
  969. if ((int)Before < 0)
  970. throw new PrologException
  971. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Before),
  972. "Before must not be less than zero");
  973. }
  974. if (!(Length is Variable))
  975. {
  976. if (!(Length is int))
  977. throw new PrologException
  978. (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer");
  979. lengthIsInt = true;
  980. if ((int)Length < 0)
  981. throw new PrologException
  982. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length),
  983. "Length must not be less than zero");
  984. }
  985. if (!(After is Variable))
  986. {
  987. if (!(After is int))
  988. throw new PrologException
  989. (new Functor2("type_error", Atom.a("integer"), After), "After must be var or integer");
  990. afterIsInt = true;
  991. if ((int)After < 0)
  992. throw new PrologException
  993. (new Functor2("domain_error", Atom.a("not_less_than_zero"), After),
  994. "After must not be less than zero");
  995. }
  996. Atom atomAtom = (Atom)atom;
  997. int atomLength = atomAtom._name.Length;
  998. if (beforeIsInt && lengthIsInt)
  999. {
  1000. // Special case: the caller is just trying to extract a substring, so do it quickly.
  1001. int xAfter = atomLength - (int)Before - (int)Length;
  1002. if (xAfter >= 0)
  1003. {
  1004. foreach (bool l1 in YP.unify(After, xAfter))
  1005. {
  1006. foreach (bool l2 in YP.unify
  1007. (Sub_atom, Atom.a(atomAtom._name.Substring((int)Before, (int)Length))))
  1008. yield return false;
  1009. }
  1010. }
  1011. }
  1012. else if (afterIsInt && lengthIsInt)
  1013. {
  1014. // Special case: the caller is just trying to extract a substring, so do it quickly.
  1015. int xBefore = atomLength - (int)After - (int)Length;
  1016. if (xBefore >= 0)
  1017. {
  1018. foreach (bool l1 in YP.unify(Before, xBefore))
  1019. {
  1020. foreach (bool l2 in YP.unify
  1021. (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, (int)Length))))
  1022. yield return false;
  1023. }
  1024. }
  1025. }
  1026. else
  1027. {
  1028. // We are underconstrained and doing a search, so go through all possibilities.
  1029. for (int xBefore = 0; xBefore <= atomLength; ++xBefore)
  1030. {
  1031. foreach (bool l1 in YP.unify(Before, xBefore))
  1032. {
  1033. for (int xLength = 0; xLength <= (atomLength - xBefore); ++xLength)
  1034. {
  1035. foreach (bool l2 in YP.unify(Length, xLength))
  1036. {
  1037. foreach (bool l3 in YP.unify(After, atomLength - (xBefore + xLength)))
  1038. {
  1039. foreach (bool l4 in YP.unify
  1040. (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, xLength))))
  1041. yield return false;
  1042. }
  1043. }
  1044. }
  1045. }
  1046. }
  1047. }
  1048. }
  1049. public static IEnumerable<bool> atom_chars(object atom, object List)
  1050. {
  1051. atom = YP.getValue(atom);
  1052. List = YP.getValue(List);
  1053. if (atom is Variable)
  1054. {
  1055. if (List is Variable)
  1056. throw new PrologException(Atom.a("instantiation_error"),
  1057. "Arg 1 Atom and arg 2 List are both unbound variables");
  1058. object[] codeArray = ListPair.toArray(List);
  1059. if (codeArray == null)
  1060. throw new PrologException
  1061. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1062. char[] charArray = new char[codeArray.Length];
  1063. for (int i = 0; i < codeArray.Length; ++i)
  1064. {
  1065. object listAtom = YP.getValue(codeArray[i]);
  1066. if (listAtom is Variable)
  1067. throw new PrologException(Atom.a("instantiation_error"),
  1068. "Arg 2 List has an element which is an unbound variable");
  1069. if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1))
  1070. throw new PrologException
  1071. (new Functor2("type_error", Atom.a("character"), listAtom),
  1072. "Arg 2 List has an element which is not a one character atom");
  1073. charArray[i] = ((Atom)listAtom)._name[0];
  1074. }
  1075. return YP.unify(atom, Atom.a(new String(charArray)));
  1076. }
  1077. else
  1078. {
  1079. if (!(atom is Atom))
  1080. throw new PrologException
  1081. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom");
  1082. string atomString = ((Atom)atom)._name;
  1083. object charList = Atom.NIL;
  1084. // Start from the back to make the list.
  1085. for (int i = atomString.Length - 1; i >= 0; --i)
  1086. charList = new ListPair(Atom.a(atomString.Substring(i, 1)), charList);
  1087. return YP.unify(List, charList);
  1088. }
  1089. }
  1090. public static IEnumerable<bool> atom_codes(object atom, object List)
  1091. {
  1092. atom = YP.getValue(atom);
  1093. List = YP.getValue(List);
  1094. if (atom is Variable)
  1095. {
  1096. if (List is Variable)
  1097. throw new PrologException(Atom.a("instantiation_error"),
  1098. "Arg 1 Atom and arg 2 List are both unbound variables");
  1099. object[] codeArray = ListPair.toArray(List);
  1100. if (codeArray == null)
  1101. throw new PrologException
  1102. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1103. char[] charArray = new char[codeArray.Length];
  1104. for (int i = 0; i < codeArray.Length; ++i)
  1105. {
  1106. int codeInt;
  1107. if (!getInt(codeArray[i], out codeInt) || codeInt < 0)
  1108. throw new PrologException
  1109. (new Functor1("representation_error", Atom.a("character_code")),
  1110. "Element of Arg 2 List is not a character code");
  1111. charArray[i] = (char)codeInt;
  1112. }
  1113. return YP.unify(atom, Atom.a(new String(charArray)));
  1114. }
  1115. else
  1116. {
  1117. if (!(atom is Atom))
  1118. throw new PrologException
  1119. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom");
  1120. string atomString = ((Atom)atom)._name;
  1121. object codeList = Atom.NIL;
  1122. // Start from the back to make the list.
  1123. for (int i = atomString.Length - 1; i >= 0; --i)
  1124. codeList = new ListPair((int)atomString[i], codeList);
  1125. return YP.unify(List, codeList);
  1126. }
  1127. }
  1128. public static IEnumerable<bool> number_chars(object Number, object List)
  1129. {
  1130. Number = YP.getValue(Number);
  1131. List = YP.getValue(List);
  1132. if (Number is Variable)
  1133. {
  1134. if (List is Variable)
  1135. throw new PrologException(Atom.a("instantiation_error"),
  1136. "Arg 1 Number and arg 2 List are both unbound variables");
  1137. object[] codeArray = ListPair.toArray(List);
  1138. if (codeArray == null)
  1139. throw new PrologException
  1140. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1141. char[] charArray = new char[codeArray.Length];
  1142. for (int i = 0; i < codeArray.Length; ++i)
  1143. {
  1144. object listAtom = YP.getValue(codeArray[i]);
  1145. if (listAtom is Variable)
  1146. throw new PrologException(Atom.a("instantiation_error"),
  1147. "Arg 2 List has an element which is an unbound variable");
  1148. if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1))
  1149. throw new PrologException
  1150. (new Functor2("type_error", Atom.a("character"), listAtom),
  1151. "Arg 2 List has an element which is not a one character atom");
  1152. charArray[i] = ((Atom)listAtom)._name[0];
  1153. }
  1154. return YP.unify(Number, parseNumberString(charArray));
  1155. }
  1156. else
  1157. {
  1158. string numberString = null;
  1159. // Try converting to an int first.
  1160. int intNumber;
  1161. if (YP.getInt(Number, out intNumber))
  1162. numberString = intNumber.ToString();
  1163. else
  1164. {
  1165. if (!YP.number(Number))
  1166. throw new PrologException
  1167. (new Functor2("type_error", Atom.a("number"), Number),
  1168. "Arg 1 Number is not var or number");
  1169. // We just checked, so convertDouble shouldn't throw an exception.
  1170. numberString = YP.doubleToString(YP.convertDouble(Number));
  1171. }
  1172. object charList = Atom.NIL;
  1173. // Start from the back to make the list.
  1174. for (int i = numberString.Length - 1; i >= 0; --i)
  1175. charList = new ListPair(Atom.a(numberString.Substring(i, 1)), charList);
  1176. return YP.unify(List, charList);
  1177. }
  1178. }
  1179. public static IEnumerable<bool> number_codes(object Number, object List)
  1180. {
  1181. Number = YP.getValue(Number);
  1182. List = YP.getValue(List);
  1183. if (Number is Variable)
  1184. {
  1185. if (List is Variable)
  1186. throw new PrologException(Atom.a("instantiation_error"),
  1187. "Arg 1 Number and arg 2 List are both unbound variables");
  1188. object[] codeArray = ListPair.toArray(List);
  1189. if (codeArray == null)
  1190. throw new PrologException
  1191. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1192. char[] charArray = new char[codeArray.Length];
  1193. for (int i = 0; i < codeArray.Length; ++i)
  1194. {
  1195. int codeInt;
  1196. if (!getInt(codeArray[i], out codeInt) || codeInt < 0)
  1197. throw new PrologException
  1198. (new Functor1("representation_error", Atom.a("character_code")),
  1199. "Element of Arg 2 List is not a character code");
  1200. charArray[i] = (char)codeInt;
  1201. }
  1202. return YP.unify(Number, parseNumberString(charArray));
  1203. }
  1204. else
  1205. {
  1206. string numberString = null;
  1207. // Try converting to an int first.
  1208. int intNumber;
  1209. if (YP.getInt(Number, out intNumber))
  1210. numberString = intNumber.ToString();
  1211. else
  1212. {
  1213. if (!YP.number(Number))
  1214. throw new PrologException
  1215. (new Functor2("type_error", Atom.a("number"), Number),
  1216. "Arg 1 Number is not var or number");
  1217. // We just checked, so convertDouble shouldn't throw an exception.
  1218. numberString = YP.doubleToString(YP.convertDouble(Number));
  1219. }
  1220. object codeList = Atom.NIL;
  1221. // Start from the back to make the list.
  1222. for (int i = numberString.Length - 1; i >= 0; --i)
  1223. codeList = new ListPair((int)numberString[i], codeList);
  1224. return YP.unify(List, codeList);
  1225. }
  1226. }
  1227. /// <summary>
  1228. /// Used by number_chars and number_codes. Return the number in charArray or
  1229. /// throw an exception if can't parse.
  1230. /// </summary>
  1231. /// <param name="numberString"></param>
  1232. /// <returns></returns>
  1233. private static object parseNumberString(char[] charArray)
  1234. {
  1235. string numberString = new String(charArray);
  1236. if (charArray.Length == 3 && numberString.StartsWith("0'"))
  1237. // This is a char code.
  1238. return (int)charArray[2];
  1239. if (numberString.StartsWith("0x"))
  1240. {
  1241. try
  1242. {
  1243. return Int32.Parse
  1244. (numberString.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier);
  1245. }
  1246. catch (FormatException)
  1247. {
  1248. throw new PrologException
  1249. (new Functor1("syntax_error", Atom.a("number_format: " + numberString)),
  1250. "Arg 2 List is not a list for a hexadecimal number");
  1251. }
  1252. }
  1253. // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
  1254. try
  1255. {
  1256. // Try an int first.
  1257. return Convert.ToInt32(numberString);
  1258. }
  1259. catch (FormatException) { }
  1260. try
  1261. {
  1262. return Convert.ToDouble(numberString);
  1263. }
  1264. catch (FormatException)
  1265. {
  1266. throw new PrologException
  1267. (new Functor1("syntax_error", Atom.a("number_format: " + numberString)),
  1268. "Arg 2 List is not a list for a number");
  1269. }
  1270. }
  1271. public static IEnumerable<bool> char_code(object Char, object Code)
  1272. {
  1273. Char = YP.getValue(Char);
  1274. Code = YP.getValue(Code);
  1275. int codeInt = 0;
  1276. if (!(Code is Variable))
  1277. {
  1278. // Get codeInt now so we type check it whether or not Char is Variable.
  1279. if (!getInt(Code, out codeInt))
  1280. throw new PrologException
  1281. (new Functor2("type_error", Atom.a("integer"), Code),
  1282. "Arg 2 Code is not var or a character code");
  1283. if (codeInt < 0)
  1284. throw new PrologException
  1285. (new Functor1("representation_error", Atom.a("character_code")),
  1286. "Arg 2 Code is not a character code");
  1287. }
  1288. if (Char is Variable)
  1289. {
  1290. if (Code is Variable)
  1291. throw new PrologException(Atom.a("instantiation_error"),
  1292. "Arg 1 Char and arg 2 Code are both unbound variables");
  1293. return YP.unify(Char, Atom.a(new String(new char[] {(char)codeInt})));
  1294. }
  1295. else
  1296. {
  1297. if (!(Char is Atom) || ((Atom)Char)._name.Length != 1)
  1298. throw new PrologException
  1299. (new Functor2("type_error", Atom.a("character"), Char),
  1300. "Arg 1 Char is not var or one-character atom");
  1301. if (Code is Variable)
  1302. return YP.unify(Code, (int)((Atom)Char)._name[0]);
  1303. else
  1304. // Use codeInt to handle whether Code is supplied as, e.g., 97 or 0'a .
  1305. return YP.unify(codeInt, (int)((Atom)Char)._name[0]);
  1306. }
  1307. }
  1308. /// <summary>
  1309. /// If term is an Atom or functor type, return its name.
  1310. /// Otherwise, return term.
  1311. /// </summary>
  1312. /// <param name="term"></param>
  1313. /// <returns></returns>
  1314. public static object getFunctorName(object term)
  1315. {
  1316. term = YP.getValue(term);
  1317. if (term is Functor1)
  1318. return ((Functor1)term)._name;
  1319. else if (term is Functor2)
  1320. return ((Functor2)term)._name;
  1321. else if (term is Functor3)
  1322. return ((Functor3)term)._name;
  1323. else if (term is Functor)
  1324. return ((Functor)term)._name;
  1325. else
  1326. return term;
  1327. }
  1328. /// <summary>
  1329. /// If term is an Atom or functor type, return an array of its args.
  1330. /// Otherwise, return an empty array.
  1331. /// </summary>
  1332. /// <param name="term"></param>
  1333. /// <returns></returns>
  1334. public static object[] getFunctorArgs(object term)
  1335. {
  1336. term = YP.getValue(term);
  1337. if (term is Functor1)
  1338. {
  1339. Functor1 functor = (Functor1)term;
  1340. return new object[] { functor._arg1 };
  1341. }
  1342. else if (term is Functor2)
  1343. {
  1344. Functor2 functor = (Functor2)term;
  1345. return new object[] { functor._arg1, functor._arg2 };
  1346. }
  1347. else if (term is Functor3)
  1348. {
  1349. Functor3 functor = (Functor3)term;
  1350. return new object[] { functor._arg1, functor._arg2, functor._arg3 };
  1351. }
  1352. else if (term is Functor) {
  1353. Functor functor = (Functor)term;
  1354. return functor._args;
  1355. }
  1356. else
  1357. return new object[0];
  1358. }
  1359. public static bool var(object Term)
  1360. {
  1361. return YP.getValue(Term) is Variable;
  1362. }
  1363. public static bool nonvar(object Term)
  1364. {
  1365. return !YP.var(Term);
  1366. }
  1367. public static bool atom(object Term)
  1368. {
  1369. return YP.getValue(Term) is Atom;
  1370. }
  1371. public static bool integer(object Term)
  1372. {
  1373. // Debug: Should exhaustively check for all integer types.
  1374. return getValue(Term) is int;
  1375. }
  1376. // Use isFloat instead of float because it is a reserved keyword.
  1377. public static bool isFloat(object Term)
  1378. {
  1379. // Debug: Should exhaustively check for all float types.
  1380. return getValue(Term) is double;
  1381. }
  1382. public static bool number(object Term)
  1383. {
  1384. return YP.integer(Term) || YP.isFloat(Term);
  1385. }
  1386. public static bool atomic(object Term)
  1387. {
  1388. return YP.atom(Term) || YP.number(Term);
  1389. }
  1390. public static bool compound(object Term)
  1391. {
  1392. Term = getValue(Term);
  1393. return Term is Functor1 || Term is Functor2 || Term is Functor3 || Term is Functor;
  1394. }
  1395. /// <summary>
  1396. /// If input is a TextReader, use it. If input is an Atom or String, create a StreamReader with the
  1397. /// input as the filename. If input is a Prolog list, then read character codes from it.
  1398. /// </summary>
  1399. /// <param name="input"></param>
  1400. public static void see(object input)
  1401. {
  1402. input = YP.getValue(input);
  1403. if (input is Variable)
  1404. throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable");
  1405. if (input == null)
  1406. {
  1407. _inputStream = null;
  1408. return;
  1409. }
  1410. if (input is TextReader)
  1411. {
  1412. _inputStream = (TextReader)input;
  1413. return;
  1414. }
  1415. else if (input is Atom)
  1416. {
  1417. _inputStream = new StreamReader(((Atom)input)._name);
  1418. return;
  1419. }
  1420. else if (input is String)
  1421. {
  1422. _inputStream = new StreamReader((String)input);
  1423. return;
  1424. }
  1425. else if (input is Functor2 && ((Functor2)input)._name == Atom.DOT)
  1426. {
  1427. _inputStream = new CodeListReader(input);
  1428. return;
  1429. }
  1430. else
  1431. throw new PrologException
  1432. (new Functor2("domain_error", Atom.a("stream_or_alias"), input),
  1433. "Input stream specifier not recognized");
  1434. }
  1435. public static void seen()
  1436. {
  1437. if (_inputStream == null)
  1438. return;
  1439. if (_inputStream == Console.In)
  1440. return;
  1441. _inputStream.Close();
  1442. _inputStream = Console.In;
  1443. }
  1444. public static IEnumerable<bool> current_input(object Stream)
  1445. {
  1446. return YP.unify(Stream, _inputStream);
  1447. }
  1448. /// <summary>
  1449. /// If output is a TextWriter, use it. If output is an Atom or a String, create a StreamWriter
  1450. /// with the input as the filename.
  1451. /// </summary>
  1452. /// <param name="output"></param>
  1453. public static void tell(object output)
  1454. {
  1455. output = YP.getValue(output);
  1456. if (output is Variable)
  1457. throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable");
  1458. if (output == null)
  1459. {
  1460. _outputStream = null;
  1461. return;
  1462. }
  1463. if (output is TextWriter)
  1464. {
  1465. _outputStream = (TextWriter)output;
  1466. return;
  1467. }
  1468. else if (output is Atom)
  1469. {
  1470. _outputStream = new StreamWriter(((Atom)output)._name);
  1471. return;
  1472. }
  1473. else if (output is String)
  1474. {
  1475. _outputStream = new StreamWriter((String)output);
  1476. return;
  1477. }
  1478. else
  1479. throw new PrologException
  1480. (new Functor2("domain_error", Atom.a("stream_or_alias"), output),
  1481. "Can't open stream for " + output);
  1482. }
  1483. public static void told()
  1484. {
  1485. if (_outputStream == null)
  1486. return;
  1487. if (_outputStream == Console.Out)
  1488. return;
  1489. _outputStream.Close();
  1490. _outputStream = Console.Out;
  1491. }
  1492. public static IEnumerable<bool> current_output(object Stream)
  1493. {
  1494. return YP.unify(Stream, _outputStream);
  1495. }
  1496. public static void write(object x)
  1497. {
  1498. if (_outputStream == null)
  1499. return;
  1500. x = YP.getValue(x);
  1501. if (x is double)
  1502. _outputStream.Write(doubleToString((double)x));
  1503. else
  1504. _outputStream.Write(x.ToString());
  1505. }
  1506. /// <summary>
  1507. /// Format x as a string, making sure that it won't parse as an int later. I.e., for 1.0, don't just
  1508. /// use "1" which will parse as an int.
  1509. /// </summary>
  1510. /// <param name="x"></param>
  1511. /// <returns></returns>
  1512. private static string doubleToString(double x)
  1513. {
  1514. string xString = x.ToString();
  1515. // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
  1516. try
  1517. {
  1518. Convert.ToInt32(xString);
  1519. // The string will parse as an int, not a double, so re-format so that it does.
  1520. // Use float if possible, else exponential if it would be too big.
  1521. return x.ToString(x >= 100000.0 ? "E1" : "f1");
  1522. }
  1523. catch (FormatException)
  1524. {
  1525. // Assume it will parse as a double.
  1526. }
  1527. return xString;
  1528. }
  1529. public static void put_code(object x)
  1530. {
  1531. if (_outputStream == null)
  1532. return;
  1533. if (var(x))
  1534. throw new PrologException(Atom.a("instantiation_error"), "Arg 1 is an unbound variable");
  1535. int xInt;
  1536. if (!getInt(x, out xInt))
  1537. throw new PrologException
  1538. (new Functor2("type_error", Atom.a("integer"), x), "Arg 1 must be integer");
  1539. _outputStream.Write((char)xInt);
  1540. }
  1541. public static void nl()
  1542. {
  1543. if (_outputStream == null)
  1544. return;
  1545. _outputStream.WriteLine();
  1546. }
  1547. public static IEnumerable<bool> get_code(object code)
  1548. {
  1549. if (_inputStream == null)
  1550. return YP.unify(code, -1);
  1551. else
  1552. return YP.unify(code, _inputStream.Read());
  1553. }
  1554. public static void asserta(object Term, Type declaringClass)
  1555. {
  1556. assertDynamic(Term, declaringClass, true);
  1557. }
  1558. public static void assertz(object Term, Type declaringClass)
  1559. {
  1560. assertDynamic(Term, declaringClass, false);
  1561. }
  1562. public static void assertDynamic(object Term, Type declaringClass, bool prepend)
  1563. {
  1564. Term = getValue(Term);
  1565. if (Term is Variable)
  1566. throw new PrologException("instantiation_error", "Term to assert is an unbound variable");
  1567. Variable.CopyStore copyStore = new Variable.CopyStore();
  1568. object TermCopy = makeCopy(Term, copyStore);
  1569. object Head, Body;
  1570. if (TermCopy is Functor2 && ((Functor2)TermCopy)._name == Atom.RULE)
  1571. {
  1572. Head = YP.getValue(((Functor2)TermCopy)._arg1);
  1573. Body = YP.getValue(((Functor2)TermCopy)._arg2);
  1574. if (Head is Variable)
  1575. throw new PrologException("instantiation_error", "Head to assert is an unbound variable");
  1576. if (Body is Variable)
  1577. throw new PrologException("instantiation_error", "Body to assert is an unbound variable");
  1578. }
  1579. else
  1580. {
  1581. Head = TermCopy;
  1582. Body = Atom.a("true");
  1583. }
  1584. Atom name = getFunctorName(Head) as Atom;
  1585. if (name == null)
  1586. // name is a non-Atom, such as a number.
  1587. throw new PrologException
  1588. (new Functor2("type_error", Atom.a("callable"), Head), "Term to assert is not callable");
  1589. object[] args = getFunctorArgs(Head);
  1590. if (isSystemPredicate(name, args.Length))
  1591. throw new PrologException
  1592. (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
  1593. new Functor2(Atom.SLASH, name, args.Length)),
  1594. "Assert cannot modify static predicate " + name + "/" + args.Length);
  1595. if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true"))
  1596. {
  1597. // This is a fact with no unbound variables
  1598. // assertFact and prependFact use IndexedAnswers, so don't we don't need to compile.
  1599. if (prepend)
  1600. prependFact(name, args);
  1601. else
  1602. assertFact(name, args);
  1603. return;
  1604. }
  1605. IClause clause = YPCompiler.compileAnonymousClause(Head, Body, declaringClass);
  1606. // We expect clause to be a ClauseHeadAndBody (from Compiler.compileAnonymousFunction)
  1607. // so we can set the Head and Body.
  1608. if (clause is ClauseHeadAndBody)
  1609. ((ClauseHeadAndBody)clause).setHeadAndBody(Head, Body);
  1610. // Add the clause to the entry in _predicatesStore.
  1611. NameArity nameArity = new NameArity(name, args.Length);
  1612. List<IClause> clauses;
  1613. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1614. // Create an entry for the nameArity.
  1615. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1616. if (prepend)
  1617. clauses.Insert(0, clause);
  1618. else
  1619. clauses.Add(clause);
  1620. }
  1621. private static bool isSystemPredicate(Atom name, int arity)
  1622. {
  1623. if (arity == 2 && (name == Atom.a(",") || name == Atom.a(";") || name == Atom.DOT))
  1624. return true;
  1625. // Use the same mapping to static predicates in YP as the compiler.
  1626. foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable()))
  1627. return true;
  1628. // Debug: Do we need to check if name._module is null?
  1629. return false;
  1630. }
  1631. /// <summary>
  1632. /// Assert values at the end of the set of facts for the predicate with the
  1633. /// name and with arity values.Length.
  1634. /// </summary>
  1635. /// <param name="name">must be an Atom</param>
  1636. /// <param name="values">the array of arguments to the fact predicate.
  1637. /// It is an error if an value has an unbound variable.</param>
  1638. public static void assertFact(Atom name, object[] values)
  1639. {
  1640. NameArity nameArity = new NameArity(name, values.Length);
  1641. List<IClause> clauses;
  1642. IndexedAnswers indexedAnswers;
  1643. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1644. {
  1645. // Create an IndexedAnswers as the only clause of the predicate.
  1646. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1647. clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
  1648. }
  1649. else
  1650. {
  1651. indexedAnswers = null;
  1652. if (clauses.Count >= 1)
  1653. indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers;
  1654. if (indexedAnswers == null)
  1655. // The latest clause is not an IndexedAnswers, so add one.
  1656. clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
  1657. }
  1658. indexedAnswers.addAnswer(values);
  1659. }
  1660. /// <summary>
  1661. /// Assert values, prepending to the front of the set of facts for the predicate with the
  1662. /// name and with arity values.Length.
  1663. /// </summary>
  1664. /// <param name="name">must be an Atom</param>
  1665. /// <param name="values">the array of arguments to the fact predicate.
  1666. /// It is an error if an value has an unbound variable.</param>
  1667. public static void prependFact(Atom name, object[] values)
  1668. {
  1669. NameArity nameArity = new NameArity(name, values.Length);
  1670. List<IClause> clauses;
  1671. IndexedAnswers indexedAnswers;
  1672. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1673. {
  1674. // Create an IndexedAnswers as the only clause of the predicate.
  1675. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1676. clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
  1677. }
  1678. else
  1679. {
  1680. indexedAnswers = null;
  1681. if (clauses.Count >= 1)
  1682. indexedAnswers = clauses[0] as IndexedAnswers;
  1683. if (indexedAnswers == null)
  1684. // The first clause is not an IndexedAnswers, so prepend one.
  1685. clauses.Insert(0, indexedAnswers = new IndexedAnswers(values.Length));
  1686. }
  1687. indexedAnswers.prependAnswer(values);
  1688. }
  1689. /// <summary>
  1690. /// Match all clauses of the dynamic predicate with the name and with arity
  1691. /// arguments.Length.
  1692. /// If the predicate is not defined, return the result of YP.unknownPredicate.
  1693. /// </summary>
  1694. /// <param name="name">must be an Atom</param>
  1695. /// <param name="arguments">an array of arity number of arguments</param>
  1696. /// <returns>an iterator which you can use in foreach</returns>
  1697. public static IEnumerable<bool> matchDynamic(Atom name, object[] arguments)
  1698. {
  1699. List<IClause> clauses;
  1700. if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses))
  1701. return unknownPredicate(name, arguments.Length,
  1702. "Undefined dynamic predicate: " + name + "/" + arguments.Length);
  1703. if (clauses.Count == 1)
  1704. // Usually there is only one clause, so return it without needing to wrap it in an iterator.
  1705. return clauses[0].match(arguments);
  1706. else
  1707. return matchAllClauses(clauses, arguments);
  1708. }
  1709. /// <summary>
  1710. /// Call match(arguments) for each IClause in clauses. We make this a separate
  1711. /// function so that matchDynamic itself does not need to be an iterator object.
  1712. /// </summary>
  1713. /// <param name="clauses"></param>
  1714. /// <param name="arguments"></param>
  1715. /// <returns></returns>
  1716. private static IEnumerable<bool> matchAllClauses(List<IClause> clauses, object[] arguments)
  1717. {
  1718. // Debug: If the caller asserts another clause into this same predicate during yield, the iterator
  1719. // over clauses will be corrupted. Should we take the time to copy clauses?
  1720. foreach (IClause clause in clauses)
  1721. {
  1722. foreach (bool lastCall in clause.match(arguments))
  1723. {
  1724. yield return false;
  1725. if (lastCall)
  1726. // This happens after a cut in a clause.
  1727. yield break;
  1728. }
  1729. }
  1730. }
  1731. /// <summary>
  1732. /// If _prologFlags["unknown"] is fail then return fail(), else if
  1733. /// _prologFlags["unknown"] is warning then write the message to YP.write and
  1734. /// return fail(), else throw a PrologException for existence_error. .
  1735. /// </summary>
  1736. /// <param name="name"></param>
  1737. /// <param name="arity"></param>
  1738. /// <param name="message"></param>
  1739. /// <returns></returns>
  1740. public static IEnumerable<bool> unknownPredicate(Atom name, int arity, string message)
  1741. {
  1742. establishPrologFlags();
  1743. if (_prologFlags["unknown"] == Atom.a("fail"))
  1744. return fail();
  1745. else if (_prologFlags["unknown"] == Atom.a("warning"))
  1746. {
  1747. write(message);
  1748. nl();
  1749. return fail();
  1750. }
  1751. else
  1752. throw new PrologException
  1753. (new Functor2
  1754. (Atom.a("existence_error"), Atom.a("procedure"),
  1755. new Functor2(Atom.SLASH, name, arity)), message);
  1756. }
  1757. /// <summary>
  1758. /// This is deprecated and just calls matchDynamic. This matches all clauses,
  1759. /// not just the ones defined with assertFact.
  1760. /// </summary>
  1761. /// <param name="name"></param>
  1762. /// <param name="arguments"></param>
  1763. /// <returns></returns>
  1764. public static IEnumerable<bool> matchFact(Atom name, object[] arguments)
  1765. {
  1766. return matchDynamic(name, arguments);
  1767. }
  1768. public static IEnumerable<bool> clause(object Head, object Body)
  1769. {
  1770. Head = getValue(Head);
  1771. Body = getValue(Body);
  1772. if (Head is Variable)
  1773. throw new PrologException("instantiation_error", "Head is an unbound variable");
  1774. Atom name = getFunctorName(Head) as Atom;
  1775. if (name == null)
  1776. // name is a non-Atom, such as a number.
  1777. throw new PrologException
  1778. (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable");
  1779. object[] args = getFunctorArgs(Head);
  1780. if (isSystemPredicate(name, args.Length))
  1781. throw new PrologException
  1782. (new Functor3("permission_error", Atom.a("access"), Atom.a("private_procedure"),
  1783. new Functor2(Atom.SLASH, name, args.Length)),
  1784. "clause cannot access private predicate " + name + "/" + args.Length);
  1785. if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom))
  1786. throw new PrologException
  1787. (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable");
  1788. List<IClause> clauses;
  1789. if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses))
  1790. yield break;
  1791. // The caller can assert another clause into this same predicate during yield, so we have to
  1792. // make a copy of the clauses.
  1793. foreach (IClause predicateClause in clauses.ToArray())
  1794. {
  1795. foreach (bool l1 in predicateClause.clause(Head, Body))
  1796. yield return false;
  1797. }
  1798. }
  1799. public static IEnumerable<bool> retract(object Term)
  1800. {
  1801. Term = getValue(Term);
  1802. if (Term is Variable)
  1803. throw new PrologException("instantiation_error", "Term to retract is an unbound variable");
  1804. object Head, Body;
  1805. if (Term is Functor2 && ((Functor2)Term)._name == Atom.RULE)
  1806. {
  1807. Head = YP.getValue(((Functor2)Term)._arg1);
  1808. Body = YP.getValue(((Functor2)Term)._arg2);
  1809. }
  1810. else
  1811. {
  1812. Head = Term;
  1813. Body = Atom.a("true");
  1814. }
  1815. if (Head is Variable)
  1816. throw new PrologException("instantiation_error", "Head is an unbound variable");
  1817. Atom name = getFunctorName(Head) as Atom;
  1818. if (name == null)
  1819. // name is a non-Atom, such as a number.
  1820. throw new PrologException
  1821. (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable");
  1822. object[] args = getFunctorArgs(Head);
  1823. if (isSystemPredicate(name, args.Length))
  1824. throw new PrologException
  1825. (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
  1826. new Functor2(Atom.SLASH, name, args.Length)),
  1827. "clause cannot access private predicate " + name + "/" + args.Length);
  1828. if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom))
  1829. throw new PrologException
  1830. (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable");
  1831. List<IClause> clauses;
  1832. if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses))
  1833. yield break;
  1834. // The caller can assert another clause into this same predicate during yield, so we have to
  1835. // make a copy of the clauses.
  1836. foreach (IClause predicateClause in clauses.ToArray())
  1837. {
  1838. if (predicateClause is IndexedAnswers)
  1839. {
  1840. // IndexedAnswers handles its own retract. Even if it removes all of its
  1841. // answers, it is OK to leave it empty as one of the elements in clauses.
  1842. foreach (bool l1 in ((IndexedAnswers)predicateClause).retract(Head, Body))
  1843. yield return false;
  1844. }
  1845. else
  1846. {
  1847. foreach (bool l1 in predicateClause.clause(Head, Body))
  1848. {
  1849. clauses.Remove(predicateClause);
  1850. yield return false;
  1851. }
  1852. }
  1853. }
  1854. }
  1855. /// <summary>
  1856. /// This is deprecated for backward compatibility. You should use retractall.
  1857. /// </summary>
  1858. /// <param name="name">must be an Atom</param>
  1859. /// <param name="arguments">an array of arity number of arguments</param>
  1860. public static void retractFact(Atom name, object[] arguments)
  1861. {
  1862. retractall(Functor.make(name, arguments));
  1863. }
  1864. /// <summary>
  1865. /// Retract all dynamic clauses which unify with Head. If this matches all clauses in a predicate,
  1866. /// the predicate is still defined. To completely remove the predicate, see abolish.
  1867. /// </summary>
  1868. /// <param name="Head"></param>
  1869. public static void retractall(object Head)
  1870. {
  1871. object name = YP.getFunctorName(Head);
  1872. object[] arguments = getFunctorArgs(Head);
  1873. if (!(name is Atom))
  1874. return;
  1875. NameArity nameArity = new NameArity((Atom)name, arguments.Length);
  1876. List<IClause> clauses;
  1877. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1878. // Can't find, so ignore.
  1879. return;
  1880. foreach (object arg in arguments)
  1881. {
  1882. if (!YP.var(arg))
  1883. throw new InvalidOperationException
  1884. ("Until matching retractall is supported, all arguments must be unbound to retract all clauses");
  1885. }
  1886. // Clear all clauses.
  1887. _predicatesStore[nameArity] = new List<IClause>();
  1888. }
  1889. /// <summary>
  1890. /// If NameSlashArity is var, match with all the dynamic predicates using the
  1891. /// Name/Artity form.
  1892. /// If NameSlashArity is not var, check if the Name/Arity exists as a static or
  1893. /// dynamic predicate.
  1894. /// </summary>
  1895. /// <param name="NameSlashArity"></param>
  1896. /// <param name="declaringClass">if not null, used to resolve references to the default
  1897. /// module Atom.a("")</param>
  1898. /// <returns></returns>
  1899. public static IEnumerable<bool> current_predicate(object NameSlashArity, Type declaringClass)
  1900. {
  1901. NameSlashArity = YP.getValue(NameSlashArity);
  1902. // First check if Name and Arity are nonvar so we can do a direct lookup.
  1903. if (YP.ground(NameSlashArity))
  1904. {
  1905. Functor2 NameArityFunctor = NameSlashArity as Functor2;
  1906. if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH))
  1907. throw new PrologException
  1908. (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
  1909. "Must be a name/arity predicate indicator");
  1910. object name = YP.getValue(NameArityFunctor._arg1);
  1911. object arity = YP.getValue(NameArityFunctor._arg2);
  1912. if (name is Variable || arity is Variable)
  1913. throw new PrologException
  1914. ("instantiation_error", "Predicate indicator name or arity is an unbound variable");
  1915. if (!(name is Atom && arity is int))
  1916. throw new PrologException
  1917. (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
  1918. "Must be a name/arity predicate indicator");
  1919. if ((int)arity < 0)
  1920. throw new PrologException
  1921. (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
  1922. "Arity may not be less than zero");
  1923. if (YPCompiler.isCurrentPredicate((Atom)name, (int)arity, declaringClass))
  1924. // The predicate is defined.
  1925. yield return false;
  1926. }
  1927. else
  1928. {
  1929. foreach (NameArity key in _predicatesStore.Keys)
  1930. {
  1931. foreach (bool l1 in YP.unify
  1932. (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity))
  1933. yield return false;
  1934. }
  1935. }
  1936. }
  1937. /// <summary>
  1938. /// Return true if the dynamic predicate store has an entry for the predicate
  1939. /// with name and arity.
  1940. /// </summary>
  1941. /// <param name="name"></param>
  1942. /// <param name="arity"></param>
  1943. /// <returns></returns>
  1944. public static bool isDynamicCurrentPredicate(Atom name, int arity)
  1945. {
  1946. return _predicatesStore.ContainsKey(new NameArity(name, arity));
  1947. }
  1948. public static void abolish(object NameSlashArity)
  1949. {
  1950. NameSlashArity = YP.getValue(NameSlashArity);
  1951. if (NameSlashArity is Variable)
  1952. throw new PrologException
  1953. ("instantiation_error", "Predicate indicator is an unbound variable");
  1954. Functor2 NameArityFunctor = NameSlashArity as Functor2;
  1955. if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH))
  1956. throw new PrologException
  1957. (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
  1958. "Must be a name/arity predicate indicator");
  1959. object name = YP.getValue(NameArityFunctor._arg1);
  1960. object arity = YP.getValue(NameArityFunctor._arg2);
  1961. if (name is Variable || arity is Variable)
  1962. throw new PrologException
  1963. ("instantiation_error", "Predicate indicator name or arity is an unbound variable");
  1964. if (!(name is Atom))
  1965. throw new PrologException
  1966. (new Functor2("type_error", Atom.a("atom"), name),
  1967. "Predicate indicator name must be an atom");
  1968. if (!(arity is int))
  1969. throw new PrologException
  1970. (new Functor2("type_error", Atom.a("integer"), arity),
  1971. "Predicate indicator arity must be an integer");
  1972. if ((int)arity < 0)
  1973. throw new PrologException
  1974. (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
  1975. "Arity may not be less than zero");
  1976. if ((int)arity > MAX_ARITY)
  1977. throw new PrologException
  1978. (new Functor1("representation_error", Atom.a("max_arity")),
  1979. "Arity may not be greater than " + MAX_ARITY);
  1980. if (isSystemPredicate((Atom)name, (int)arity))
  1981. throw new PrologException
  1982. (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
  1983. new Functor2(Atom.SLASH, name, arity)),
  1984. "Abolish cannot modify static predicate " + name + "/" + arity);
  1985. _predicatesStore.Remove(new NameArity((Atom)name, (int)arity));
  1986. }
  1987. /// <summary>
  1988. /// If Goal is a simple predicate, call YP.getFunctorName(Goal) using arguments from
  1989. /// YP.getFunctorArgs(Goal). If not found, this throws a PrologException for existence_error.
  1990. /// Otherwise, compile the goal as a single clause predicate and invoke it.
  1991. /// </summary>
  1992. /// <param name="Goal"></param>
  1993. /// <param name="declaringClass">if not null, used to resolve references to the default
  1994. /// module Atom.a("")</param>
  1995. /// <returns></returns>
  1996. public static IEnumerable<bool> getIterator(object Goal, Type declaringClass)
  1997. {
  1998. Atom name;
  1999. object[] args;
  2000. while (true)
  2001. {
  2002. Goal = YP.getValue(Goal);
  2003. if (Goal is Variable)
  2004. throw new PrologException("instantiation_error", "Goal to call is an unbound variable");
  2005. name = YP.getFunctorName(Goal) as Atom;
  2006. if (name == null)
  2007. throw new PrologException
  2008. (new Functor2("type_error", Atom.a("callable"), Goal), "Goal to call is not callable");
  2009. args = YP.getFunctorArgs(Goal);
  2010. if (name == Atom.HAT && args.Length == 2)
  2011. // Assume this is called from a bagof operation. Skip the leading qualifiers.
  2012. Goal = YP.getValue(((Functor2)Goal)._arg2);
  2013. else
  2014. break;
  2015. }
  2016. IEnumerable<bool> simpleIterator = YPCompiler.getSimpleIterator(name, args, declaringClass);
  2017. if (simpleIterator != null)
  2018. // We don't need to compile since the goal is a simple predicate which we call directly.
  2019. return simpleIterator;
  2020. // Compile the goal as a clause.
  2021. List<Variable> variableSetList = new List<Variable>();
  2022. addUniqueVariables(Goal, variableSetList);
  2023. Variable[] variableSet = variableSetList.ToArray();
  2024. // Use Atom.F since it is ignored.
  2025. return YPCompiler.compileAnonymousClause
  2026. (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet);
  2027. }
  2028. public static void throwException(object Term)
  2029. {
  2030. throw new PrologException(Term);
  2031. }
  2032. /// <summary>
  2033. /// This must be called by any function that uses YP._prologFlags to make sure
  2034. /// the initial defaults are loaded.
  2035. /// </summary>
  2036. private static void establishPrologFlags()
  2037. {
  2038. if (_prologFlags.Count > 0)
  2039. // Already established.
  2040. return;
  2041. // List these in the order they appear in the ISO standard.
  2042. _prologFlags["bounded"] = Atom.a("true");
  2043. _prologFlags["max_integer"] = Int32.MaxValue;
  2044. _prologFlags["min_integer"] = Int32.MinValue;
  2045. _prologFlags["integer_rounding_function"] = Atom.a("toward_zero");
  2046. _prologFlags["char_conversion"] = Atom.a("off");
  2047. _prologFlags["debug"] = Atom.a("off");
  2048. _prologFlags["max_arity"] = MAX_ARITY;
  2049. _prologFlags["unknown"] = Atom.a("error");
  2050. _prologFlags["double_quotes"] = Atom.a("codes");
  2051. }
  2052. public static IEnumerable<bool> current_prolog_flag(object Key, object Value)
  2053. {
  2054. establishPrologFlags();
  2055. Key = YP.getValue(Key);
  2056. Value = YP.getValue(Value);
  2057. if (Key is Variable)
  2058. {
  2059. // Bind all key values.
  2060. foreach (string key in _prologFlags.Keys)
  2061. {
  2062. foreach (bool l1 in YP.unify(Key, Atom.a(key)))
  2063. {
  2064. foreach (bool l2 in YP.unify(Value, _prologFlags[key]))
  2065. yield return false;
  2066. }
  2067. }
  2068. }
  2069. else
  2070. {
  2071. if (!(Key is Atom))
  2072. throw new PrologException
  2073. (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom");
  2074. if (!_prologFlags.ContainsKey(((Atom)Key)._name))
  2075. throw new PrologException
  2076. (new Functor2("domain_error", Atom.a("prolog_flag"), Key),
  2077. "Arg 1 Key is not a recognized flag");
  2078. foreach (bool l1 in YP.unify(Value, _prologFlags[((Atom)Key)._name]))
  2079. yield return false;
  2080. }
  2081. }
  2082. public static void set_prolog_flag(object Key, object Value)
  2083. {
  2084. establishPrologFlags();
  2085. Key = YP.getValue(Key);
  2086. Value = YP.getValue(Value);
  2087. if (Key is Variable)
  2088. throw new PrologException(Atom.a("instantiation_error"),
  2089. "Arg 1 Key is an unbound variable");
  2090. if (Value is Variable)
  2091. throw new PrologException(Atom.a("instantiation_error"),
  2092. "Arg 1 Key is an unbound variable");
  2093. if (!(Key is Atom))
  2094. throw new PrologException
  2095. (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom");
  2096. string keyName = ((Atom)Key)._name;
  2097. if (!_prologFlags.ContainsKey(keyName))
  2098. throw new PrologException
  2099. (new Functor2("domain_error", Atom.a("prolog_flag"), Key),
  2100. "Arg 1 Key " + Key + " is not a recognized flag");
  2101. bool valueIsOK = false;
  2102. if (keyName == "char_conversion")
  2103. valueIsOK = (Value == _prologFlags[keyName]);
  2104. else if (keyName == "debug")
  2105. valueIsOK = (Value == _prologFlags[keyName]);
  2106. else if (keyName == "unknown")
  2107. valueIsOK = (Value == Atom.a("fail") || Value == Atom.a("warning") ||
  2108. Value == Atom.a("error"));
  2109. else if (keyName == "double_quotes")
  2110. valueIsOK = (Value == Atom.a("codes") || Value == Atom.a("chars") ||
  2111. Value == Atom.a("atom"));
  2112. else
  2113. throw new PrologException
  2114. (new Functor3("permission_error", Atom.a("modify"), Atom.a("flag"), Key),
  2115. "May not modify Prolog flag " + Key);
  2116. if (!valueIsOK)
  2117. throw new PrologException
  2118. (new Functor2("domain_error", Atom.a("flag_value"), new Functor2("+", Key, Value)),
  2119. "May not set arg 1 Key " + Key + " to arg 2 Value " + Value);
  2120. _prologFlags[keyName] = Value;
  2121. }
  2122. /// <summary>
  2123. /// script_event calls hosting script with events as a callback method.
  2124. /// </summary>
  2125. /// <param name="script_event"></param>
  2126. /// <param name="script_params"></param>
  2127. /// <returns></returns>
  2128. public static IEnumerable<bool> script_event(object script_event, object script_params)
  2129. {
  2130. // string function = ((Atom)YP.getValue(script_event))._name;
  2131. object[] array = ListPair.toArray(script_params);
  2132. if (array == null)
  2133. yield return false; // return; // YP.fail();
  2134. if (array.Length > 1)
  2135. {
  2136. //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue
  2137. //(localID, itemID, function, array);
  2138. // sortArray(array);
  2139. }
  2140. //return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array));
  2141. yield return false;
  2142. }
  2143. /* Non-prolog-ish functions for inline coding */
  2144. public static string regexString(string inData, string inPattern, string presep,string postsep)
  2145. {
  2146. //string str=cycMessage;
  2147. //string strMatch = @"\. \#\$(.*)\)";
  2148. string results = "";
  2149. for (Match m = Regex.Match(inData,inPattern); m.Success; m=m.NextMatch())
  2150. {
  2151. //m_log.Debug(m);
  2152. results += presep+ m + postsep;
  2153. }
  2154. return results;
  2155. }
  2156. public static string cycComm(object msgobj)
  2157. {
  2158. string cycInputString = msgobj.ToString();
  2159. string cycOutputString="";
  2160. TcpClient socketForServer;
  2161. try
  2162. {
  2163. socketForServer = new TcpClient("localHost", 3601);
  2164. }
  2165. catch
  2166. {
  2167. m_log.Error("Failed to connect to server at localhost:999");
  2168. return "";
  2169. }
  2170. NetworkStream networkStream = socketForServer.GetStream();
  2171. System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
  2172. System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
  2173. try
  2174. {
  2175. // read the data from the host and display it
  2176. {
  2177. streamWriter.WriteLine(cycInputString);
  2178. streamWriter.Flush();
  2179. cycOutputString = streamReader.ReadLine();
  2180. m_log.Debug("Cycoutput:" + cycOutputString);
  2181. //streamWriter.WriteLine("Client Message");
  2182. //m_log.Debug("Client Message");
  2183. streamWriter.Flush();
  2184. }
  2185. }
  2186. catch
  2187. {
  2188. m_log.Error("Exception reading from Server");
  2189. return "";
  2190. }
  2191. // tidy up
  2192. networkStream.Close();
  2193. return cycOutputString;
  2194. }
  2195. //public static void throwException(object Term)
  2196. //{
  2197. // throw new PrologException(Term);
  2198. //}
  2199. /// <summary>
  2200. /// An enumerator that does zero loops.
  2201. /// </summary>
  2202. private class Fail : IEnumerator<bool>, IEnumerable<bool>
  2203. {
  2204. public bool MoveNext()
  2205. {
  2206. return false;
  2207. }
  2208. public IEnumerator<bool> GetEnumerator()
  2209. {
  2210. return (IEnumerator<bool>)this;
  2211. }
  2212. IEnumerator IEnumerable.GetEnumerator()
  2213. {
  2214. return GetEnumerator();
  2215. }
  2216. public bool Current
  2217. {
  2218. get { return true; }
  2219. }
  2220. object IEnumerator.Current
  2221. {
  2222. get { return true; }
  2223. }
  2224. public void Dispose()
  2225. {
  2226. }
  2227. public void Reset()
  2228. {
  2229. throw new NotImplementedException();
  2230. }
  2231. }
  2232. /// <summary>
  2233. /// An enumerator that does one iteration.
  2234. /// </summary>
  2235. private class Succeed : IEnumerator<bool>, IEnumerable<bool>
  2236. {
  2237. private bool _didIteration = false;
  2238. public bool MoveNext()
  2239. {
  2240. if (!_didIteration)
  2241. {
  2242. _didIteration = true;
  2243. return true;
  2244. }
  2245. else
  2246. return false;
  2247. }
  2248. public IEnumerator<bool> GetEnumerator()
  2249. {
  2250. return (IEnumerator<bool>)this;
  2251. }
  2252. IEnumerator IEnumerable.GetEnumerator()
  2253. {
  2254. return GetEnumerator();
  2255. }
  2256. public bool Current
  2257. {
  2258. get { return false; }
  2259. }
  2260. object IEnumerator.Current
  2261. {
  2262. get { return false; }
  2263. }
  2264. public void Dispose()
  2265. {
  2266. }
  2267. public void Reset()
  2268. {
  2269. throw new NotImplementedException();
  2270. }
  2271. }
  2272. /// <summary>
  2273. /// An enumerator that repeats forever.
  2274. /// </summary>
  2275. private class Repeat : IEnumerator<bool>, IEnumerable<bool>
  2276. {
  2277. public bool MoveNext()
  2278. {
  2279. return true;
  2280. }
  2281. public IEnumerator<bool> GetEnumerator()
  2282. {
  2283. return (IEnumerator<bool>)this;
  2284. }
  2285. IEnumerator IEnumerable.GetEnumerator()
  2286. {
  2287. return GetEnumerator();
  2288. }
  2289. public bool Current
  2290. {
  2291. get { return false; }
  2292. }
  2293. object IEnumerator.Current
  2294. {
  2295. get { return false; }
  2296. }
  2297. public void Dispose()
  2298. {
  2299. }
  2300. public void Reset()
  2301. {
  2302. throw new NotImplementedException();
  2303. }
  2304. }
  2305. /// <summary>
  2306. /// An enumerator that wraps another enumerator in order to catch a PrologException.
  2307. /// </summary>
  2308. public class Catch : IEnumerator<bool>, IEnumerable<bool>
  2309. {
  2310. private IEnumerator<bool> _enumerator;
  2311. private PrologException _exception = null;
  2312. /// <summary>
  2313. /// Call YP.getIterator(Goal, declaringClass) and save the returned iterator.
  2314. /// If getIterator throws an exception, save it the same as MoveNext().
  2315. /// </summary>
  2316. /// <param name="Goal"></param>
  2317. /// <param name="declaringClass"></param>
  2318. public Catch(object Goal, Type declaringClass)
  2319. {
  2320. try
  2321. {
  2322. _enumerator = getIterator(Goal, declaringClass).GetEnumerator();
  2323. }
  2324. catch (PrologException exception)
  2325. {
  2326. // MoveNext() will check this.
  2327. _exception = exception;
  2328. }
  2329. }
  2330. /// <summary>
  2331. /// Call _enumerator.MoveNext(). If it throws a PrologException, set _exception
  2332. /// and return false. After this returns false, call unifyExceptionOrThrow.
  2333. /// </summary>
  2334. /// <returns></returns>
  2335. public bool MoveNext()
  2336. {
  2337. if (_exception != null)
  2338. return false;
  2339. try
  2340. {
  2341. return _enumerator.MoveNext();
  2342. }
  2343. catch (PrologException exception)
  2344. {
  2345. _exception = exception;
  2346. return false;
  2347. }
  2348. }
  2349. /// <summary>
  2350. /// Call this after MoveNext() returns false to check for an exception. If
  2351. /// MoveNext did not get a PrologException, don't yield.
  2352. /// Otherwise, unify the exception with Catcher and yield so the caller can
  2353. /// do the handler code. However, if can't unify with Catcher then throw the exception.
  2354. /// </summary>
  2355. /// <param name="Catcher"></param>
  2356. /// <returns></returns>
  2357. public IEnumerable<bool> unifyExceptionOrThrow(object Catcher)
  2358. {
  2359. if (_exception != null)
  2360. {
  2361. bool didUnify = false;
  2362. foreach (bool l1 in YP.unify(_exception._term, Catcher))
  2363. {
  2364. didUnify = true;
  2365. yield return false;
  2366. }
  2367. if (!didUnify)
  2368. throw _exception;
  2369. }
  2370. }
  2371. public IEnumerator<bool> GetEnumerator()
  2372. {
  2373. return (IEnumerator<bool>)this;
  2374. }
  2375. IEnumerator IEnumerable.GetEnumerator()
  2376. {
  2377. return GetEnumerator();
  2378. }
  2379. public bool Current
  2380. {
  2381. get { return _enumerator.Current; }
  2382. }
  2383. object IEnumerator.Current
  2384. {
  2385. get { return _enumerator.Current; }
  2386. }
  2387. public void Dispose()
  2388. {
  2389. if (_enumerator != null)
  2390. _enumerator.Dispose();
  2391. }
  2392. public void Reset()
  2393. {
  2394. throw new NotImplementedException();
  2395. }
  2396. }
  2397. #pragma warning restore 0168, 0219
  2398. /// <summary>
  2399. /// A ClauseHeadAndBody is used in Compiler.compileAnonymousFunction as a base class
  2400. /// in order to implement YP.IClause. After creating the object, you must call setHeadAndBody.
  2401. /// </summary>
  2402. public class ClauseHeadAndBody
  2403. {
  2404. private object _Head;
  2405. private object _Body;
  2406. public void setHeadAndBody(object Head, object Body)
  2407. {
  2408. _Head = Head;
  2409. _Body = Body;
  2410. }
  2411. public IEnumerable<bool> clause(object Head, object Body)
  2412. {
  2413. if (_Head == null || _Body == null)
  2414. yield break;
  2415. #pragma warning disable 0168, 0219
  2416. foreach (bool l1 in YP.unify(Head, _Head))
  2417. {
  2418. foreach (bool l2 in YP.unify(Body, _Body))
  2419. yield return false;
  2420. }
  2421. #pragma warning restore 0168, 0219
  2422. }
  2423. }
  2424. /// <summary>
  2425. /// CodeListReader extends TextReader and overrides Read to read the next code from
  2426. /// the CodeList which is a Prolog list of integer character codes.
  2427. /// </summary>
  2428. public class CodeListReader : TextReader
  2429. {
  2430. private object _CodeList;
  2431. public CodeListReader(object CodeList)
  2432. {
  2433. _CodeList = YP.getValue(CodeList);
  2434. }
  2435. /// <summary>
  2436. /// If the head of _CodeList is an integer, return it and advance the list. Otherwise,
  2437. /// return -1 for end of file.
  2438. /// </summary>
  2439. /// <returns></returns>
  2440. public override int Read()
  2441. {
  2442. Functor2 CodeListPair = _CodeList as Functor2;
  2443. int code;
  2444. if (!(CodeListPair != null && CodeListPair._name == Atom.DOT &&
  2445. getInt(CodeListPair._arg1, out code)))
  2446. {
  2447. _CodeList = Atom.NIL;
  2448. return -1;
  2449. }
  2450. // Advance.
  2451. _CodeList = YP.getValue(CodeListPair._arg2);
  2452. return code;
  2453. }
  2454. }
  2455. }
  2456. }