PageRenderTime 29ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/KyanhaLLC/opensim
C# | 2701 lines | 2417 code | 86 blank | 198 comment | 134 complexity | 61356a824155d23230738390536ee451 MD5 | raw file
Possible License(s): Unlicense, MIT, BSD-3-Clause
  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. int z = 0;
  522. try
  523. {
  524. if (gotMatch)
  525. yield return false;
  526. }
  527. finally
  528. {
  529. // Manually finalize all the iterators.
  530. for (z = 0; z < nIterators; ++z)
  531. iterators[z].Dispose();
  532. }
  533. }
  534. /// <summary>
  535. /// Return an iterator (which you can use in a for-in loop) which does
  536. /// zero iterations. This returns a pre-existing iterator which is
  537. /// more efficient than letting the compiler generate a new one.
  538. /// </summary>
  539. /// <returns></returns>
  540. public static IEnumerable<bool> fail()
  541. {
  542. return _fail;
  543. }
  544. /// <summary>
  545. /// Return an iterator (which you can use in a for-in loop) which does
  546. /// one iteration. This returns a pre-existing iterator which is
  547. /// more efficient than letting the compiler generate a new one.
  548. /// </summary>
  549. /// <returns></returns>
  550. public static IEnumerable<bool> succeed()
  551. {
  552. return new Succeed();
  553. }
  554. /// <summary>
  555. /// Return an iterator (which you can use in a for-in loop) which repeats
  556. /// indefinitely. This returns a pre-existing iterator which is
  557. /// more efficient than letting the compiler generate a new one.
  558. /// </summary>
  559. /// <returns></returns>
  560. public static IEnumerable<bool> repeat()
  561. {
  562. return _repeat;
  563. }
  564. // disable warning on l1, don't see how we can
  565. // code this differently
  566. #pragma warning disable 0168, 0219
  567. public static IEnumerable<bool> univ(object Term, object List)
  568. {
  569. Term = YP.getValue(Term);
  570. List = YP.getValue(List);
  571. if (nonvar(Term))
  572. return YP.unify(new ListPair
  573. (getFunctorName(Term), ListPair.make(getFunctorArgs(Term))), List);
  574. Variable Name = new Variable();
  575. Variable ArgList = new Variable();
  576. foreach (bool l1 in new ListPair(Name, ArgList).unify(List))
  577. {
  578. object[] args = ListPair.toArray(ArgList);
  579. if (args == null)
  580. throw new PrologException
  581. (new Functor2("type_error", Atom.a("list"), ArgList),
  582. "Expected a list. Got: " + ArgList.getValue());
  583. if (args.Length == 0)
  584. // Return the Name, even if it is not an Atom.
  585. return YP.unify(Term, Name);
  586. if (args.Length > MAX_ARITY)
  587. throw new PrologException
  588. (new Functor1("representation_error", Atom.a("max_arity")),
  589. "Functor arity " + args.Length + " may not be greater than " + MAX_ARITY);
  590. if (!atom(Name))
  591. throw new PrologException
  592. (new Functor2("type_error", Atom.a("atom"), Name),
  593. "Expected an atom. Got: " + Name.getValue());
  594. return YP.unify(Term, Functor.make((Atom)YP.getValue(Name), args));
  595. }
  596. return YP.fail();
  597. }
  598. public static IEnumerable<bool> functor(object Term, object FunctorName, object Arity)
  599. {
  600. Term = YP.getValue(Term);
  601. FunctorName = YP.getValue(FunctorName);
  602. Arity = YP.getValue(Arity);
  603. if (Term is Variable)
  604. {
  605. if (FunctorName is Variable)
  606. throw new PrologException(Atom.a("instantiation_error"),
  607. "Arg 2 FunctorName is an unbound variable");
  608. if (Arity is Variable)
  609. throw new PrologException(Atom.a("instantiation_error"),
  610. "Arg 3 Arity is an unbound variable");
  611. if (!(Arity is int))
  612. throw new PrologException
  613. (new Functor2("type_error", Atom.a("integer"), Arity), "Arity is not an integer");
  614. if (!YP.atomic(FunctorName))
  615. throw new PrologException
  616. (new Functor2("type_error", Atom.a("atomic"), FunctorName), "FunctorName is not atomic");
  617. if ((int)Arity < 0)
  618. throw new PrologException
  619. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Arity),
  620. "Arity may not be less than zero");
  621. else if ((int)Arity == 0)
  622. {
  623. // Just unify Term with the atomic FunctorName.
  624. foreach (bool l1 in YP.unify(Term, FunctorName))
  625. yield return false;
  626. }
  627. else
  628. {
  629. if ((int)Arity > MAX_ARITY)
  630. throw new PrologException
  631. (new Functor1("representation_error", Atom.a("max_arity")),
  632. "Functor arity " + Arity + " may not be greater than " + MAX_ARITY);
  633. if (!(FunctorName is Atom))
  634. throw new PrologException
  635. (new Functor2("type_error", Atom.a("atom"), FunctorName), "FunctorName is not an atom");
  636. // Construct a functor with unbound variables.
  637. object[] args = new object[(int)Arity];
  638. for (int i = 0; i < args.Length; ++i)
  639. args[i] = new Variable();
  640. foreach (bool l1 in YP.unify(Term, Functor.make((Atom)FunctorName, args)))
  641. yield return false;
  642. }
  643. }
  644. else
  645. {
  646. foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term)))
  647. {
  648. foreach (bool l2 in YP.unify(Arity, getFunctorArgs(Term).Length))
  649. yield return false;
  650. }
  651. }
  652. }
  653. public static IEnumerable<bool> arg(object ArgNumber, object Term, object Value)
  654. {
  655. if (var(ArgNumber))
  656. throw new PrologException(Atom.a("instantiation_error"), "Arg 1 ArgNumber is an unbound variable");
  657. int argNumberInt;
  658. if (!getInt(ArgNumber, out argNumberInt))
  659. throw new PrologException
  660. (new Functor2("type_error", Atom.a("integer"), ArgNumber), "Arg 1 ArgNumber must be integer");
  661. if (argNumberInt < 0)
  662. throw new PrologException
  663. (new Functor2("domain_error", Atom.a("not_less_than_zero"), argNumberInt),
  664. "ArgNumber may not be less than zero");
  665. if (YP.var(Term))
  666. throw new PrologException(Atom.a("instantiation_error"),
  667. "Arg 2 Term is an unbound variable");
  668. if (!YP.compound(Term))
  669. throw new PrologException
  670. (new Functor2("type_error", Atom.a("compound"), Term), "Arg 2 Term must be compound");
  671. object[] termArgs = YP.getFunctorArgs(Term);
  672. // Silently fail if argNumberInt is out of range.
  673. if (argNumberInt >= 1 && argNumberInt <= termArgs.Length)
  674. {
  675. // The first ArgNumber is at 1, not 0.
  676. foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1]))
  677. yield return false;
  678. }
  679. }
  680. public static bool termEqual(object Term1, object Term2)
  681. {
  682. Term1 = YP.getValue(Term1);
  683. if (Term1 is IUnifiable)
  684. return ((IUnifiable)Term1).termEqual(Term2);
  685. return Term1.Equals(YP.getValue(Term2));
  686. }
  687. public static bool termNotEqual(object Term1, object Term2)
  688. {
  689. return !termEqual(Term1, Term2);
  690. }
  691. public static bool termLessThan(object Term1, object Term2)
  692. {
  693. Term1 = YP.getValue(Term1);
  694. Term2 = YP.getValue(Term2);
  695. int term1TypeCode = getTypeCode(Term1);
  696. int term2TypeCode = getTypeCode(Term2);
  697. if (term1TypeCode != term2TypeCode)
  698. return term1TypeCode < term2TypeCode;
  699. // The terms are the same type code.
  700. if (term1TypeCode == -2)
  701. {
  702. // Variable.
  703. // We always check for equality first because we want to be sure
  704. // that less than returns false if the terms are equal, in
  705. // case that the less than check really behaves like less than or equal.
  706. if ((Variable)Term1 != (Variable)Term2)
  707. // The hash code should be unique to a Variable object.
  708. return Term1.GetHashCode() < Term2.GetHashCode();
  709. return false;
  710. }
  711. if (term1TypeCode == 0)
  712. return ((Atom)Term1)._name.CompareTo(((Atom)Term2)._name) < 0;
  713. if (term1TypeCode == 1)
  714. return ((Functor1)Term1).lessThan((Functor1)Term2);
  715. if (term1TypeCode == 2)
  716. return ((Functor2)Term1).lessThan((Functor2)Term2);
  717. if (term1TypeCode == 3)
  718. return ((Functor3)Term1).lessThan((Functor3)Term2);
  719. if (term1TypeCode == 4)
  720. return ((Functor)Term1).lessThan((Functor)Term2);
  721. // Type code is -1 for general objects. First compare their type names.
  722. // Note that this puts Double before Int32 as required by ISO Prolog.
  723. string term1TypeName = Term1.GetType().ToString();
  724. string term2TypeName = Term2.GetType().ToString();
  725. if (term1TypeName != term2TypeName)
  726. return term1TypeName.CompareTo(term2TypeName) < 0;
  727. // The terms are the same type name.
  728. if (Term1 is int)
  729. return (int)Term1 < (int)Term2;
  730. else if (Term1 is double)
  731. return (double)Term1 < (double)Term2;
  732. else if (Term1 is DateTime)
  733. return (DateTime)Term1 < (DateTime)Term2;
  734. else if (Term1 is String)
  735. return ((String)Term1).CompareTo((String)Term2) < 0;
  736. // Debug: Should we try arrays, etc.?
  737. if (!Term1.Equals(Term2))
  738. // Could be equal or greater than.
  739. return Term1.GetHashCode() < Term2.GetHashCode();
  740. return false;
  741. }
  742. /// <summary>
  743. /// Type code is -2 if term is a Variable, 0 if it is an Atom,
  744. /// 1 if it is a Functor1, 2 if it is a Functor2, 3 if it is a Functor3,
  745. /// 4 if it is Functor.
  746. /// Otherwise, type code is -1.
  747. /// This does not call YP.getValue(term).
  748. /// </summary>
  749. /// <param name="term"></param>
  750. /// <returns></returns>
  751. private static int getTypeCode(object term)
  752. {
  753. if (term is Variable)
  754. return -2;
  755. else if (term is Atom)
  756. return 0;
  757. else if (term is Functor1)
  758. return 1;
  759. else if (term is Functor2)
  760. return 2;
  761. else if (term is Functor3)
  762. return 3;
  763. else if (term is Functor)
  764. return 4;
  765. else
  766. return -1;
  767. }
  768. public static bool termLessThanOrEqual(object Term1, object Term2)
  769. {
  770. if (YP.termEqual(Term1, Term2))
  771. return true;
  772. return YP.termLessThan(Term1, Term2);
  773. }
  774. public static bool termGreaterThan(object Term1, object Term2)
  775. {
  776. return !YP.termLessThanOrEqual(Term1, Term2);
  777. }
  778. public static bool termGreaterThanOrEqual(object Term1, object Term2)
  779. {
  780. // termLessThan should ensure that it returns false if terms are equal,
  781. // so that this would return true.
  782. return !YP.termLessThan(Term1, Term2);
  783. }
  784. public static int compareTerms(object Term1, object Term2)
  785. {
  786. if (YP.termEqual(Term1, Term2))
  787. return 0;
  788. else if (YP.termLessThan(Term1, Term2))
  789. return -1;
  790. else
  791. return 1;
  792. }
  793. public static bool ground(object Term)
  794. {
  795. Term = YP.getValue(Term);
  796. if (Term is IUnifiable)
  797. return ((IUnifiable)Term).ground();
  798. return true;
  799. }
  800. public static IEnumerable<bool> current_op
  801. (object Priority, object Specifier, object Operator)
  802. {
  803. if (_operatorTable == null)
  804. {
  805. // Initialize.
  806. _operatorTable = new IndexedAnswers(3);
  807. _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") });
  808. _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") });
  809. _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a(":-") });
  810. _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a("?-") });
  811. _operatorTable.addAnswer(new object[] { 1100, Atom.a("xfy"), Atom.a(";") });
  812. _operatorTable.addAnswer(new object[] { 1050, Atom.a("xfy"), Atom.a("->") });
  813. _operatorTable.addAnswer(new object[] { 1000, Atom.a("xfy"), Atom.a(",") });
  814. _operatorTable.addAnswer(new object[] { 900, Atom.a("fy"), 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("=..") });
  824. _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("is") });
  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[] { 700, Atom.a("xfx"), Atom.a(">=") });
  831. _operatorTable.addAnswer(new object[] { 600, Atom.a("xfy"), 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[] { 500, 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("//") });
  839. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("rem") });
  840. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("mod") });
  841. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("<<") });
  842. _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a(">>") });
  843. _operatorTable.addAnswer(new object[] { 200, Atom.a("xfx"), Atom.a("**") });
  844. _operatorTable.addAnswer(new object[] { 200, Atom.a("xfy"), Atom.a("^") });
  845. _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("-") });
  846. _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("\\") });
  847. // Debug: This is hacked in to run the Prolog test suite until we implement op/3.
  848. _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") });
  849. }
  850. return _operatorTable.match(new object[] { Priority, Specifier, Operator });
  851. }
  852. public static IEnumerable<bool> atom_length(object atom, object Length)
  853. {
  854. atom = YP.getValue(atom);
  855. Length = YP.getValue(Length);
  856. if (atom is Variable)
  857. throw new PrologException(Atom.a("instantiation_error"),
  858. "Expected atom(Arg1) but it is an unbound variable");
  859. if (!(atom is Atom))
  860. throw new PrologException
  861. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom");
  862. if (!(Length is Variable))
  863. {
  864. if (!(Length is int))
  865. throw new PrologException
  866. (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer");
  867. if ((int)Length < 0)
  868. throw new PrologException
  869. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length),
  870. "Length must not be less than zero");
  871. }
  872. return YP.unify(Length, ((Atom)atom)._name.Length);
  873. }
  874. public static IEnumerable<bool> atom_concat(object Start, object End, object Whole)
  875. {
  876. // Debug: Should we try to preserve the _declaringClass?
  877. Start = YP.getValue(Start);
  878. End = YP.getValue(End);
  879. Whole = YP.getValue(Whole);
  880. if (Whole is Variable)
  881. {
  882. if (Start is Variable)
  883. throw new PrologException(Atom.a("instantiation_error"),
  884. "Arg 1 Start and arg 3 Whole are both var");
  885. if (End is Variable)
  886. throw new PrologException(Atom.a("instantiation_error"),
  887. "Arg 2 End and arg 3 Whole are both var");
  888. if (!(Start is Atom))
  889. throw new PrologException
  890. (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not an atom");
  891. if (!(End is Atom))
  892. throw new PrologException
  893. (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not an atom");
  894. foreach (bool l1 in YP.unify(Whole, Atom.a(((Atom)Start)._name + ((Atom)End)._name)))
  895. yield return false;
  896. }
  897. else
  898. {
  899. if (!(Whole is Atom))
  900. throw new PrologException
  901. (new Functor2("type_error", Atom.a("atom"), Whole), "Arg 3 Whole is not an atom");
  902. bool gotStartLength = false;
  903. int startLength = 0;
  904. if (!(Start is Variable))
  905. {
  906. if (!(Start is Atom))
  907. throw new PrologException
  908. (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not var or atom");
  909. startLength = ((Atom)Start)._name.Length;
  910. gotStartLength = true;
  911. }
  912. bool gotEndLength = false;
  913. int endLength = 0;
  914. if (!(End is Variable))
  915. {
  916. if (!(End is Atom))
  917. throw new PrologException
  918. (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not var or atom");
  919. endLength = ((Atom)End)._name.Length;
  920. gotEndLength = true;
  921. }
  922. // We are doing a search through all possible Start and End which concatenate to Whole.
  923. string wholeString = ((Atom)Whole)._name;
  924. for (int i = 0; i <= wholeString.Length; ++i)
  925. {
  926. // If we got either startLength or endLength, we know the lengths have to match so check
  927. // the lengths instead of constructing an Atom to do it.
  928. if (gotStartLength && startLength != i)
  929. continue;
  930. if (gotEndLength && endLength != wholeString.Length - i)
  931. continue;
  932. foreach (bool l1 in YP.unify(Start, Atom.a(wholeString.Substring(0, i))))
  933. {
  934. foreach (bool l2 in YP.unify(End, Atom.a(wholeString.Substring(i, wholeString.Length - i))))
  935. yield return false;
  936. }
  937. }
  938. }
  939. }
  940. public static IEnumerable<bool> sub_atom
  941. (object atom, object Before, object Length, object After, object Sub_atom)
  942. {
  943. // Debug: Should we try to preserve the _declaringClass?
  944. atom = YP.getValue(atom);
  945. Before = YP.getValue(Before);
  946. Length = YP.getValue(Length);
  947. After = YP.getValue(After);
  948. Sub_atom = YP.getValue(Sub_atom);
  949. if (atom is Variable)
  950. throw new PrologException(Atom.a("instantiation_error"),
  951. "Expected atom(Arg1) but it is an unbound variable");
  952. if (!(atom is Atom))
  953. throw new PrologException
  954. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom");
  955. if (!(Sub_atom is Variable))
  956. {
  957. if (!(Sub_atom is Atom))
  958. throw new PrologException
  959. (new Functor2("type_error", Atom.a("atom"), Sub_atom), "Sub_atom is not var or atom");
  960. }
  961. bool beforeIsInt = false;
  962. bool lengthIsInt = false;
  963. bool afterIsInt = false;
  964. if (!(Before is Variable))
  965. {
  966. if (!(Before is int))
  967. throw new PrologException
  968. (new Functor2("type_error", Atom.a("integer"), Before), "Before must be var or integer");
  969. beforeIsInt = true;
  970. if ((int)Before < 0)
  971. throw new PrologException
  972. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Before),
  973. "Before must not be less than zero");
  974. }
  975. if (!(Length is Variable))
  976. {
  977. if (!(Length is int))
  978. throw new PrologException
  979. (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer");
  980. lengthIsInt = true;
  981. if ((int)Length < 0)
  982. throw new PrologException
  983. (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length),
  984. "Length must not be less than zero");
  985. }
  986. if (!(After is Variable))
  987. {
  988. if (!(After is int))
  989. throw new PrologException
  990. (new Functor2("type_error", Atom.a("integer"), After), "After must be var or integer");
  991. afterIsInt = true;
  992. if ((int)After < 0)
  993. throw new PrologException
  994. (new Functor2("domain_error", Atom.a("not_less_than_zero"), After),
  995. "After must not be less than zero");
  996. }
  997. Atom atomAtom = (Atom)atom;
  998. int atomLength = atomAtom._name.Length;
  999. if (beforeIsInt && lengthIsInt)
  1000. {
  1001. // Special case: the caller is just trying to extract a substring, so do it quickly.
  1002. int xAfter = atomLength - (int)Before - (int)Length;
  1003. if (xAfter >= 0)
  1004. {
  1005. foreach (bool l1 in YP.unify(After, xAfter))
  1006. {
  1007. foreach (bool l2 in YP.unify
  1008. (Sub_atom, Atom.a(atomAtom._name.Substring((int)Before, (int)Length))))
  1009. yield return false;
  1010. }
  1011. }
  1012. }
  1013. else if (afterIsInt && lengthIsInt)
  1014. {
  1015. // Special case: the caller is just trying to extract a substring, so do it quickly.
  1016. int xBefore = atomLength - (int)After - (int)Length;
  1017. if (xBefore >= 0)
  1018. {
  1019. foreach (bool l1 in YP.unify(Before, xBefore))
  1020. {
  1021. foreach (bool l2 in YP.unify
  1022. (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, (int)Length))))
  1023. yield return false;
  1024. }
  1025. }
  1026. }
  1027. else
  1028. {
  1029. // We are underconstrained and doing a search, so go through all possibilities.
  1030. for (int xBefore = 0; xBefore <= atomLength; ++xBefore)
  1031. {
  1032. foreach (bool l1 in YP.unify(Before, xBefore))
  1033. {
  1034. for (int xLength = 0; xLength <= (atomLength - xBefore); ++xLength)
  1035. {
  1036. foreach (bool l2 in YP.unify(Length, xLength))
  1037. {
  1038. foreach (bool l3 in YP.unify(After, atomLength - (xBefore + xLength)))
  1039. {
  1040. foreach (bool l4 in YP.unify
  1041. (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, xLength))))
  1042. yield return false;
  1043. }
  1044. }
  1045. }
  1046. }
  1047. }
  1048. }
  1049. }
  1050. public static IEnumerable<bool> atom_chars(object atom, object List)
  1051. {
  1052. atom = YP.getValue(atom);
  1053. List = YP.getValue(List);
  1054. if (atom is Variable)
  1055. {
  1056. if (List is Variable)
  1057. throw new PrologException(Atom.a("instantiation_error"),
  1058. "Arg 1 Atom and arg 2 List are both unbound variables");
  1059. object[] codeArray = ListPair.toArray(List);
  1060. if (codeArray == null)
  1061. throw new PrologException
  1062. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1063. char[] charArray = new char[codeArray.Length];
  1064. for (int i = 0; i < codeArray.Length; ++i)
  1065. {
  1066. object listAtom = YP.getValue(codeArray[i]);
  1067. if (listAtom is Variable)
  1068. throw new PrologException(Atom.a("instantiation_error"),
  1069. "Arg 2 List has an element which is an unbound variable");
  1070. if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1))
  1071. throw new PrologException
  1072. (new Functor2("type_error", Atom.a("character"), listAtom),
  1073. "Arg 2 List has an element which is not a one character atom");
  1074. charArray[i] = ((Atom)listAtom)._name[0];
  1075. }
  1076. return YP.unify(atom, Atom.a(new String(charArray)));
  1077. }
  1078. else
  1079. {
  1080. if (!(atom is Atom))
  1081. throw new PrologException
  1082. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom");
  1083. string atomString = ((Atom)atom)._name;
  1084. object charList = Atom.NIL;
  1085. // Start from the back to make the list.
  1086. for (int i = atomString.Length - 1; i >= 0; --i)
  1087. charList = new ListPair(Atom.a(atomString.Substring(i, 1)), charList);
  1088. return YP.unify(List, charList);
  1089. }
  1090. }
  1091. public static IEnumerable<bool> atom_codes(object atom, object List)
  1092. {
  1093. atom = YP.getValue(atom);
  1094. List = YP.getValue(List);
  1095. if (atom is Variable)
  1096. {
  1097. if (List is Variable)
  1098. throw new PrologException(Atom.a("instantiation_error"),
  1099. "Arg 1 Atom and arg 2 List are both unbound variables");
  1100. object[] codeArray = ListPair.toArray(List);
  1101. if (codeArray == null)
  1102. throw new PrologException
  1103. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1104. char[] charArray = new char[codeArray.Length];
  1105. for (int i = 0; i < codeArray.Length; ++i)
  1106. {
  1107. int codeInt;
  1108. if (!getInt(codeArray[i], out codeInt) || codeInt < 0)
  1109. throw new PrologException
  1110. (new Functor1("representation_error", Atom.a("character_code")),
  1111. "Element of Arg 2 List is not a character code");
  1112. charArray[i] = (char)codeInt;
  1113. }
  1114. return YP.unify(atom, Atom.a(new String(charArray)));
  1115. }
  1116. else
  1117. {
  1118. if (!(atom is Atom))
  1119. throw new PrologException
  1120. (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom");
  1121. string atomString = ((Atom)atom)._name;
  1122. object codeList = Atom.NIL;
  1123. // Start from the back to make the list.
  1124. for (int i = atomString.Length - 1; i >= 0; --i)
  1125. codeList = new ListPair((int)atomString[i], codeList);
  1126. return YP.unify(List, codeList);
  1127. }
  1128. }
  1129. public static IEnumerable<bool> number_chars(object Number, object List)
  1130. {
  1131. Number = YP.getValue(Number);
  1132. List = YP.getValue(List);
  1133. if (Number is Variable)
  1134. {
  1135. if (List is Variable)
  1136. throw new PrologException(Atom.a("instantiation_error"),
  1137. "Arg 1 Number and arg 2 List are both unbound variables");
  1138. object[] codeArray = ListPair.toArray(List);
  1139. if (codeArray == null)
  1140. throw new PrologException
  1141. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1142. char[] charArray = new char[codeArray.Length];
  1143. for (int i = 0; i < codeArray.Length; ++i)
  1144. {
  1145. object listAtom = YP.getValue(codeArray[i]);
  1146. if (listAtom is Variable)
  1147. throw new PrologException(Atom.a("instantiation_error"),
  1148. "Arg 2 List has an element which is an unbound variable");
  1149. if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1))
  1150. throw new PrologException
  1151. (new Functor2("type_error", Atom.a("character"), listAtom),
  1152. "Arg 2 List has an element which is not a one character atom");
  1153. charArray[i] = ((Atom)listAtom)._name[0];
  1154. }
  1155. return YP.unify(Number, parseNumberString(charArray));
  1156. }
  1157. else
  1158. {
  1159. string numberString = null;
  1160. // Try converting to an int first.
  1161. int intNumber;
  1162. if (YP.getInt(Number, out intNumber))
  1163. numberString = intNumber.ToString();
  1164. else
  1165. {
  1166. if (!YP.number(Number))
  1167. throw new PrologException
  1168. (new Functor2("type_error", Atom.a("number"), Number),
  1169. "Arg 1 Number is not var or number");
  1170. // We just checked, so convertDouble shouldn't throw an exception.
  1171. numberString = YP.doubleToString(YP.convertDouble(Number));
  1172. }
  1173. object charList = Atom.NIL;
  1174. // Start from the back to make the list.
  1175. for (int i = numberString.Length - 1; i >= 0; --i)
  1176. charList = new ListPair(Atom.a(numberString.Substring(i, 1)), charList);
  1177. return YP.unify(List, charList);
  1178. }
  1179. }
  1180. public static IEnumerable<bool> number_codes(object Number, object List)
  1181. {
  1182. Number = YP.getValue(Number);
  1183. List = YP.getValue(List);
  1184. if (Number is Variable)
  1185. {
  1186. if (List is Variable)
  1187. throw new PrologException(Atom.a("instantiation_error"),
  1188. "Arg 1 Number and arg 2 List are both unbound variables");
  1189. object[] codeArray = ListPair.toArray(List);
  1190. if (codeArray == null)
  1191. throw new PrologException
  1192. (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
  1193. char[] charArray = new char[codeArray.Length];
  1194. for (int i = 0; i < codeArray.Length; ++i)
  1195. {
  1196. int codeInt;
  1197. if (!getInt(codeArray[i], out codeInt) || codeInt < 0)
  1198. throw new PrologException
  1199. (new Functor1("representation_error", Atom.a("character_code")),
  1200. "Element of Arg 2 List is not a character code");
  1201. charArray[i] = (char)codeInt;
  1202. }
  1203. return YP.unify(Number, parseNumberString(charArray));
  1204. }
  1205. else
  1206. {
  1207. string numberString = null;
  1208. // Try converting to an int first.
  1209. int intNumber;
  1210. if (YP.getInt(Number, out intNumber))
  1211. numberString = intNumber.ToString();
  1212. else
  1213. {
  1214. if (!YP.number(Number))
  1215. throw new PrologException
  1216. (new Functor2("type_error", Atom.a("number"), Number),
  1217. "Arg 1 Number is not var or number");
  1218. // We just checked, so convertDouble shouldn't throw an exception.
  1219. numberString = YP.doubleToString(YP.convertDouble(Number));
  1220. }
  1221. object codeList = Atom.NIL;
  1222. // Start from the back to make the list.
  1223. for (int i = numberString.Length - 1; i >= 0; --i)
  1224. codeList = new ListPair((int)numberString[i], codeList);
  1225. return YP.unify(List, codeList);
  1226. }
  1227. }
  1228. /// <summary>
  1229. /// Used by number_chars and number_codes. Return the number in charArray or
  1230. /// throw an exception if can't parse.
  1231. /// </summary>
  1232. /// <param name="numberString"></param>
  1233. /// <returns></returns>
  1234. private static object parseNumberString(char[] charArray)
  1235. {
  1236. string numberString = new String(charArray);
  1237. if (charArray.Length == 3 && numberString.StartsWith("0'"))
  1238. // This is a char code.
  1239. return (int)charArray[2];
  1240. if (numberString.StartsWith("0x"))
  1241. {
  1242. try
  1243. {
  1244. return Int32.Parse
  1245. (numberString.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier);
  1246. }
  1247. catch (FormatException)
  1248. {
  1249. throw new PrologException
  1250. (new Functor1("syntax_error", Atom.a("number_format: " + numberString)),
  1251. "Arg 2 List is not a list for a hexadecimal number");
  1252. }
  1253. }
  1254. // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
  1255. try
  1256. {
  1257. // Try an int first.
  1258. return Convert.ToInt32(numberString);
  1259. }
  1260. catch (FormatException) { }
  1261. try
  1262. {
  1263. return Convert.ToDouble(numberString);
  1264. }
  1265. catch (FormatException)
  1266. {
  1267. throw new PrologException
  1268. (new Functor1("syntax_error", Atom.a("number_format: " + numberString)),
  1269. "Arg 2 List is not a list for a number");
  1270. }
  1271. }
  1272. public static IEnumerable<bool> char_code(object Char, object Code)
  1273. {
  1274. Char = YP.getValue(Char);
  1275. Code = YP.getValue(Code);
  1276. int codeInt = 0;
  1277. if (!(Code is Variable))
  1278. {
  1279. // Get codeInt now so we type check it whether or not Char is Variable.
  1280. if (!getInt(Code, out codeInt))
  1281. throw new PrologException
  1282. (new Functor2("type_error", Atom.a("integer"), Code),
  1283. "Arg 2 Code is not var or a character code");
  1284. if (codeInt < 0)
  1285. throw new PrologException
  1286. (new Functor1("representation_error", Atom.a("character_code")),
  1287. "Arg 2 Code is not a character code");
  1288. }
  1289. if (Char is Variable)
  1290. {
  1291. if (Code is Variable)
  1292. throw new PrologException(Atom.a("instantiation_error"),
  1293. "Arg 1 Char and arg 2 Code are both unbound variables");
  1294. return YP.unify(Char, Atom.a(new String(new char[] {(char)codeInt})));
  1295. }
  1296. else
  1297. {
  1298. if (!(Char is Atom) || ((Atom)Char)._name.Length != 1)
  1299. throw new PrologException
  1300. (new Functor2("type_error", Atom.a("character"), Char),
  1301. "Arg 1 Char is not var or one-character atom");
  1302. if (Code is Variable)
  1303. return YP.unify(Code, (int)((Atom)Char)._name[0]);
  1304. else
  1305. // Use codeInt to handle whether Code is supplied as, e.g., 97 or 0'a .
  1306. return YP.unify(codeInt, (int)((Atom)Char)._name[0]);
  1307. }
  1308. }
  1309. /// <summary>
  1310. /// If term is an Atom or functor type, return its name.
  1311. /// Otherwise, return term.
  1312. /// </summary>
  1313. /// <param name="term"></param>
  1314. /// <returns></returns>
  1315. public static object getFunctorName(object term)
  1316. {
  1317. term = YP.getValue(term);
  1318. if (term is Functor1)
  1319. return ((Functor1)term)._name;
  1320. else if (term is Functor2)
  1321. return ((Functor2)term)._name;
  1322. else if (term is Functor3)
  1323. return ((Functor3)term)._name;
  1324. else if (term is Functor)
  1325. return ((Functor)term)._name;
  1326. else
  1327. return term;
  1328. }
  1329. /// <summary>
  1330. /// If term is an Atom or functor type, return an array of its args.
  1331. /// Otherwise, return an empty array.
  1332. /// </summary>
  1333. /// <param name="term"></param>
  1334. /// <returns></returns>
  1335. public static object[] getFunctorArgs(object term)
  1336. {
  1337. term = YP.getValue(term);
  1338. if (term is Functor1)
  1339. {
  1340. Functor1 functor = (Functor1)term;
  1341. return new object[] { functor._arg1 };
  1342. }
  1343. else if (term is Functor2)
  1344. {
  1345. Functor2 functor = (Functor2)term;
  1346. return new object[] { functor._arg1, functor._arg2 };
  1347. }
  1348. else if (term is Functor3)
  1349. {
  1350. Functor3 functor = (Functor3)term;
  1351. return new object[] { functor._arg1, functor._arg2, functor._arg3 };
  1352. }
  1353. else if (term is Functor) {
  1354. Functor functor = (Functor)term;
  1355. return functor._args;
  1356. }
  1357. else
  1358. return new object[0];
  1359. }
  1360. public static bool var(object Term)
  1361. {
  1362. return YP.getValue(Term) is Variable;
  1363. }
  1364. public static bool nonvar(object Term)
  1365. {
  1366. return !YP.var(Term);
  1367. }
  1368. public static bool atom(object Term)
  1369. {
  1370. return YP.getValue(Term) is Atom;
  1371. }
  1372. public static bool integer(object Term)
  1373. {
  1374. // Debug: Should exhaustively check for all integer types.
  1375. return getValue(Term) is int;
  1376. }
  1377. // Use isFloat instead of float because it is a reserved keyword.
  1378. public static bool isFloat(object Term)
  1379. {
  1380. // Debug: Should exhaustively check for all float types.
  1381. return getValue(Term) is double;
  1382. }
  1383. public static bool number(object Term)
  1384. {
  1385. return YP.integer(Term) || YP.isFloat(Term);
  1386. }
  1387. public static bool atomic(object Term)
  1388. {
  1389. return YP.atom(Term) || YP.number(Term);
  1390. }
  1391. public static bool compound(object Term)
  1392. {
  1393. Term = getValue(Term);
  1394. return Term is Functor1 || Term is Functor2 || Term is Functor3 || Term is Functor;
  1395. }
  1396. /// <summary>
  1397. /// If input is a TextReader, use it. If input is an Atom or String, create a StreamReader with the
  1398. /// input as the filename. If input is a Prolog list, then read character codes from it.
  1399. /// </summary>
  1400. /// <param name="input"></param>
  1401. public static void see(object input)
  1402. {
  1403. input = YP.getValue(input);
  1404. if (input is Variable)
  1405. throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable");
  1406. if (input == null)
  1407. {
  1408. _inputStream = null;
  1409. return;
  1410. }
  1411. if (input is TextReader)
  1412. {
  1413. _inputStream = (TextReader)input;
  1414. return;
  1415. }
  1416. else if (input is Atom)
  1417. {
  1418. _inputStream = new StreamReader(((Atom)input)._name);
  1419. return;
  1420. }
  1421. else if (input is String)
  1422. {
  1423. _inputStream = new StreamReader((String)input);
  1424. return;
  1425. }
  1426. else if (input is Functor2 && ((Functor2)input)._name == Atom.DOT)
  1427. {
  1428. _inputStream = new CodeListReader(input);
  1429. return;
  1430. }
  1431. else
  1432. throw new PrologException
  1433. (new Functor2("domain_error", Atom.a("stream_or_alias"), input),
  1434. "Input stream specifier not recognized");
  1435. }
  1436. public static void seen()
  1437. {
  1438. if (_inputStream == null)
  1439. return;
  1440. if (_inputStream == Console.In)
  1441. return;
  1442. _inputStream.Close();
  1443. _inputStream = Console.In;
  1444. }
  1445. public static IEnumerable<bool> current_input(object Stream)
  1446. {
  1447. return YP.unify(Stream, _inputStream);
  1448. }
  1449. /// <summary>
  1450. /// If output is a TextWriter, use it. If output is an Atom or a String, create a StreamWriter
  1451. /// with the input as the filename.
  1452. /// </summary>
  1453. /// <param name="output"></param>
  1454. public static void tell(object output)
  1455. {
  1456. output = YP.getValue(output);
  1457. if (output is Variable)
  1458. throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable");
  1459. if (output == null)
  1460. {
  1461. _outputStream = null;
  1462. return;
  1463. }
  1464. if (output is TextWriter)
  1465. {
  1466. _outputStream = (TextWriter)output;
  1467. return;
  1468. }
  1469. else if (output is Atom)
  1470. {
  1471. _outputStream = new StreamWriter(((Atom)output)._name);
  1472. return;
  1473. }
  1474. else if (output is String)
  1475. {
  1476. _outputStream = new StreamWriter((String)output);
  1477. return;
  1478. }
  1479. else
  1480. throw new PrologException
  1481. (new Functor2("domain_error", Atom.a("stream_or_alias"), output),
  1482. "Can't open stream for " + output);
  1483. }
  1484. public static void told()
  1485. {
  1486. if (_outputStream == null)
  1487. return;
  1488. if (_outputStream == Console.Out)
  1489. return;
  1490. _outputStream.Close();
  1491. _outputStream = Console.Out;
  1492. }
  1493. public static IEnumerable<bool> current_output(object Stream)
  1494. {
  1495. return YP.unify(Stream, _outputStream);
  1496. }
  1497. public static void write(object x)
  1498. {
  1499. if (_outputStream == null)
  1500. return;
  1501. x = YP.getValue(x);
  1502. if (x is double)
  1503. _outputStream.Write(doubleToString((double)x));
  1504. else
  1505. _outputStream.Write(x.ToString());
  1506. }
  1507. /// <summary>
  1508. /// Format x as a string, making sure that it won't parse as an int later. I.e., for 1.0, don't just
  1509. /// use "1" which will parse as an int.
  1510. /// </summary>
  1511. /// <param name="x"></param>
  1512. /// <returns></returns>
  1513. private static string doubleToString(double x)
  1514. {
  1515. string xString = x.ToString();
  1516. // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
  1517. try
  1518. {
  1519. Convert.ToInt32(xString);
  1520. // The string will parse as an int, not a double, so re-format so that it does.
  1521. // Use float if possible, else exponential if it would be too big.
  1522. return x.ToString(x >= 100000.0 ? "E1" : "f1");
  1523. }
  1524. catch (FormatException)
  1525. {
  1526. // Assume it will parse as a double.
  1527. }
  1528. return xString;
  1529. }
  1530. public static void put_code(object x)
  1531. {
  1532. if (_outputStream == null)
  1533. return;
  1534. if (var(x))
  1535. throw new PrologException(Atom.a("instantiation_error"), "Arg 1 is an unbound variable");
  1536. int xInt;
  1537. if (!getInt(x, out xInt))
  1538. throw new PrologException
  1539. (new Functor2("type_error", Atom.a("integer"), x), "Arg 1 must be integer");
  1540. _outputStream.Write((char)xInt);
  1541. }
  1542. public static void nl()
  1543. {
  1544. if (_outputStream == null)
  1545. return;
  1546. _outputStream.WriteLine();
  1547. }
  1548. public static IEnumerable<bool> get_code(object code)
  1549. {
  1550. if (_inputStream == null)
  1551. return YP.unify(code, -1);
  1552. else
  1553. return YP.unify(code, _inputStream.Read());
  1554. }
  1555. public static void asserta(object Term, Type declaringClass)
  1556. {
  1557. assertDynamic(Term, declaringClass, true);
  1558. }
  1559. public static void assertz(object Term, Type declaringClass)
  1560. {
  1561. assertDynamic(Term, declaringClass, false);
  1562. }
  1563. public static void assertDynamic(object Term, Type declaringClass, bool prepend)
  1564. {
  1565. Term = getValue(Term);
  1566. if (Term is Variable)
  1567. throw new PrologException("instantiation_error", "Term to assert is an unbound variable");
  1568. Variable.CopyStore copyStore = new Variable.CopyStore();
  1569. object TermCopy = makeCopy(Term, copyStore);
  1570. object Head, Body;
  1571. if (TermCopy is Functor2 && ((Functor2)TermCopy)._name == Atom.RULE)
  1572. {
  1573. Head = YP.getValue(((Functor2)TermCopy)._arg1);
  1574. Body = YP.getValue(((Functor2)TermCopy)._arg2);
  1575. if (Head is Variable)
  1576. throw new PrologException("instantiation_error", "Head to assert is an unbound variable");
  1577. if (Body is Variable)
  1578. throw new PrologException("instantiation_error", "Body to assert is an unbound variable");
  1579. }
  1580. else
  1581. {
  1582. Head = TermCopy;
  1583. Body = Atom.a("true");
  1584. }
  1585. Atom name = getFunctorName(Head) as Atom;
  1586. if (name == null)
  1587. // name is a non-Atom, such as a number.
  1588. throw new PrologException
  1589. (new Functor2("type_error", Atom.a("callable"), Head), "Term to assert is not callable");
  1590. object[] args = getFunctorArgs(Head);
  1591. if (isSystemPredicate(name, args.Length))
  1592. throw new PrologException
  1593. (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
  1594. new Functor2(Atom.SLASH, name, args.Length)),
  1595. "Assert cannot modify static predicate " + name + "/" + args.Length);
  1596. if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true"))
  1597. {
  1598. // This is a fact with no unbound variables
  1599. // assertFact and prependFact use IndexedAnswers, so don't we don't need to compile.
  1600. if (prepend)
  1601. prependFact(name, args);
  1602. else
  1603. assertFact(name, args);
  1604. return;
  1605. }
  1606. IClause clause = YPCompiler.compileAnonymousClause(Head, Body, declaringClass);
  1607. // We expect clause to be a ClauseHeadAndBody (from Compiler.compileAnonymousFunction)
  1608. // so we can set the Head and Body.
  1609. if (clause is ClauseHeadAndBody)
  1610. ((ClauseHeadAndBody)clause).setHeadAndBody(Head, Body);
  1611. // Add the clause to the entry in _predicatesStore.
  1612. NameArity nameArity = new NameArity(name, args.Length);
  1613. List<IClause> clauses;
  1614. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1615. // Create an entry for the nameArity.
  1616. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1617. if (prepend)
  1618. clauses.Insert(0, clause);
  1619. else
  1620. clauses.Add(clause);
  1621. }
  1622. private static bool isSystemPredicate(Atom name, int arity)
  1623. {
  1624. if (arity == 2 && (name == Atom.a(",") || name == Atom.a(";") || name == Atom.DOT))
  1625. return true;
  1626. // Use the same mapping to static predicates in YP as the compiler.
  1627. foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable()))
  1628. return true;
  1629. // Debug: Do we need to check if name._module is null?
  1630. return false;
  1631. }
  1632. /// <summary>
  1633. /// Assert values at the end of the set of facts for the predicate with the
  1634. /// name and with arity values.Length.
  1635. /// </summary>
  1636. /// <param name="name">must be an Atom</param>
  1637. /// <param name="values">the array of arguments to the fact predicate.
  1638. /// It is an error if an value has an unbound variable.</param>
  1639. public static void assertFact(Atom name, object[] values)
  1640. {
  1641. NameArity nameArity = new NameArity(name, values.Length);
  1642. List<IClause> clauses;
  1643. IndexedAnswers indexedAnswers;
  1644. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1645. {
  1646. // Create an IndexedAnswers as the only clause of the predicate.
  1647. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1648. clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
  1649. }
  1650. else
  1651. {
  1652. indexedAnswers = null;
  1653. if (clauses.Count >= 1)
  1654. indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers;
  1655. if (indexedAnswers == null)
  1656. // The latest clause is not an IndexedAnswers, so add one.
  1657. clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
  1658. }
  1659. indexedAnswers.addAnswer(values);
  1660. }
  1661. /// <summary>
  1662. /// Assert values, prepending to the front of the set of facts for the predicate with the
  1663. /// name and with arity values.Length.
  1664. /// </summary>
  1665. /// <param name="name">must be an Atom</param>
  1666. /// <param name="values">the array of arguments to the fact predicate.
  1667. /// It is an error if an value has an unbound variable.</param>
  1668. public static void prependFact(Atom name, object[] values)
  1669. {
  1670. NameArity nameArity = new NameArity(name, values.Length);
  1671. List<IClause> clauses;
  1672. IndexedAnswers indexedAnswers;
  1673. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1674. {
  1675. // Create an IndexedAnswers as the only clause of the predicate.
  1676. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1677. clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
  1678. }
  1679. else
  1680. {
  1681. indexedAnswers = null;
  1682. if (clauses.Count >= 1)
  1683. indexedAnswers = clauses[0] as IndexedAnswers;
  1684. if (indexedAnswers == null)
  1685. // The first clause is not an IndexedAnswers, so prepend one.
  1686. clauses.Insert(0, indexedAnswers = new IndexedAnswers(values.Length));
  1687. }
  1688. indexedAnswers.prependAnswer(values);
  1689. }
  1690. /// <summary>
  1691. /// Match all clauses of the dynamic predicate with the name and with arity
  1692. /// arguments.Length.
  1693. /// If the predicate is not defined, return the result of YP.unknownPredicate.
  1694. /// </summary>
  1695. /// <param name="name">must be an Atom</param>
  1696. /// <param name="arguments">an array of arity number of arguments</param>
  1697. /// <returns>an iterator which you can use in foreach</returns>
  1698. public static IEnumerable<bool> matchDynamic(Atom name, object[] arguments)
  1699. {
  1700. List<IClause> clauses;
  1701. if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses))
  1702. return unknownPredicate(name, arguments.Length,
  1703. "Undefined dynamic predicate: " + name + "/" + arguments.Length);
  1704. if (clauses.Count == 1)
  1705. // Usually there is only one clause, so return it without needing to wrap it in an iterator.
  1706. return clauses[0].match(arguments);
  1707. else
  1708. return matchAllClauses(clauses, arguments);
  1709. }
  1710. /// <summary>
  1711. /// Call match(arguments) for each IClause in clauses. We make this a separate
  1712. /// function so that matchDynamic itself does not need to be an iterator object.
  1713. /// </summary>
  1714. /// <param name="clauses"></param>
  1715. /// <param name="arguments"></param>
  1716. /// <returns></returns>
  1717. private static IEnumerable<bool> matchAllClauses(List<IClause> clauses, object[] arguments)
  1718. {
  1719. // Debug: If the caller asserts another clause into this same predicate during yield, the iterator
  1720. // over clauses will be corrupted. Should we take the time to copy clauses?
  1721. foreach (IClause clause in clauses)
  1722. {
  1723. foreach (bool lastCall in clause.match(arguments))
  1724. {
  1725. yield return false;
  1726. if (lastCall)
  1727. // This happens after a cut in a clause.
  1728. yield break;
  1729. }
  1730. }
  1731. }
  1732. /// <summary>
  1733. /// If _prologFlags["unknown"] is fail then return fail(), else if
  1734. /// _prologFlags["unknown"] is warning then write the message to YP.write and
  1735. /// return fail(), else throw a PrologException for existence_error. .
  1736. /// </summary>
  1737. /// <param name="name"></param>
  1738. /// <param name="arity"></param>
  1739. /// <param name="message"></param>
  1740. /// <returns></returns>
  1741. public static IEnumerable<bool> unknownPredicate(Atom name, int arity, string message)
  1742. {
  1743. establishPrologFlags();
  1744. if (_prologFlags["unknown"] == Atom.a("fail"))
  1745. return fail();
  1746. else if (_prologFlags["unknown"] == Atom.a("warning"))
  1747. {
  1748. write(message);
  1749. nl();
  1750. return fail();
  1751. }
  1752. else
  1753. throw new PrologException
  1754. (new Functor2
  1755. (Atom.a("existence_error"), Atom.a("procedure"),
  1756. new Functor2(Atom.SLASH, name, arity)), message);
  1757. }
  1758. /// <summary>
  1759. /// This is deprecated and just calls matchDynamic. This matches all clauses,
  1760. /// not just the ones defined with assertFact.
  1761. /// </summary>
  1762. /// <param name="name"></param>
  1763. /// <param name="arguments"></param>
  1764. /// <returns></returns>
  1765. public static IEnumerable<bool> matchFact(Atom name, object[] arguments)
  1766. {
  1767. return matchDynamic(name, arguments);
  1768. }
  1769. public static IEnumerable<bool> clause(object Head, object Body)
  1770. {
  1771. Head = getValue(Head);
  1772. Body = getValue(Body);
  1773. if (Head is Variable)
  1774. throw new PrologException("instantiation_error", "Head is an unbound variable");
  1775. Atom name = getFunctorName(Head) as Atom;
  1776. if (name == null)
  1777. // name is a non-Atom, such as a number.
  1778. throw new PrologException
  1779. (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable");
  1780. object[] args = getFunctorArgs(Head);
  1781. if (isSystemPredicate(name, args.Length))
  1782. throw new PrologException
  1783. (new Functor3("permission_error", Atom.a("access"), Atom.a("private_procedure"),
  1784. new Functor2(Atom.SLASH, name, args.Length)),
  1785. "clause cannot access private predicate " + name + "/" + args.Length);
  1786. if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom))
  1787. throw new PrologException
  1788. (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable");
  1789. List<IClause> clauses;
  1790. if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses))
  1791. yield break;
  1792. // The caller can assert another clause into this same predicate during yield, so we have to
  1793. // make a copy of the clauses.
  1794. foreach (IClause predicateClause in clauses.ToArray())
  1795. {
  1796. foreach (bool l1 in predicateClause.clause(Head, Body))
  1797. yield return false;
  1798. }
  1799. }
  1800. public static IEnumerable<bool> retract(object Term)
  1801. {
  1802. Term = getValue(Term);
  1803. if (Term is Variable)
  1804. throw new PrologException("instantiation_error", "Term to retract is an unbound variable");
  1805. object Head, Body;
  1806. if (Term is Functor2 && ((Functor2)Term)._name == Atom.RULE)
  1807. {
  1808. Head = YP.getValue(((Functor2)Term)._arg1);
  1809. Body = YP.getValue(((Functor2)Term)._arg2);
  1810. }
  1811. else
  1812. {
  1813. Head = Term;
  1814. Body = Atom.a("true");
  1815. }
  1816. if (Head is Variable)
  1817. throw new PrologException("instantiation_error", "Head is an unbound variable");
  1818. Atom name = getFunctorName(Head) as Atom;
  1819. if (name == null)
  1820. // name is a non-Atom, such as a number.
  1821. throw new PrologException
  1822. (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable");
  1823. object[] args = getFunctorArgs(Head);
  1824. if (isSystemPredicate(name, args.Length))
  1825. throw new PrologException
  1826. (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
  1827. new Functor2(Atom.SLASH, name, args.Length)),
  1828. "clause cannot access private predicate " + name + "/" + args.Length);
  1829. if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom))
  1830. throw new PrologException
  1831. (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable");
  1832. List<IClause> clauses;
  1833. if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses))
  1834. yield break;
  1835. // The caller can assert another clause into this same predicate during yield, so we have to
  1836. // make a copy of the clauses.
  1837. foreach (IClause predicateClause in clauses.ToArray())
  1838. {
  1839. if (predicateClause is IndexedAnswers)
  1840. {
  1841. // IndexedAnswers handles its own retract. Even if it removes all of its
  1842. // answers, it is OK to leave it empty as one of the elements in clauses.
  1843. foreach (bool l1 in ((IndexedAnswers)predicateClause).retract(Head, Body))
  1844. yield return false;
  1845. }
  1846. else
  1847. {
  1848. foreach (bool l1 in predicateClause.clause(Head, Body))
  1849. {
  1850. clauses.Remove(predicateClause);
  1851. yield return false;
  1852. }
  1853. }
  1854. }
  1855. }
  1856. /// <summary>
  1857. /// This is deprecated for backward compatibility. You should use retractall.
  1858. /// </summary>
  1859. /// <param name="name">must be an Atom</param>
  1860. /// <param name="arguments">an array of arity number of arguments</param>
  1861. public static void retractFact(Atom name, object[] arguments)
  1862. {
  1863. retractall(Functor.make(name, arguments));
  1864. }
  1865. /// <summary>
  1866. /// Retract all dynamic clauses which unify with Head. If this matches all clauses in a predicate,
  1867. /// the predicate is still defined. To completely remove the predicate, see abolish.
  1868. /// </summary>
  1869. /// <param name="Head"></param>
  1870. public static void retractall(object Head)
  1871. {
  1872. object name = YP.getFunctorName(Head);
  1873. object[] arguments = getFunctorArgs(Head);
  1874. if (!(name is Atom))
  1875. return;
  1876. NameArity nameArity = new NameArity((Atom)name, arguments.Length);
  1877. List<IClause> clauses;
  1878. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1879. // Can't find, so ignore.
  1880. return;
  1881. foreach (object arg in arguments)
  1882. {
  1883. if (!YP.var(arg))
  1884. throw new InvalidOperationException
  1885. ("Until matching retractall is supported, all arguments must be unbound to retract all clauses");
  1886. }
  1887. // Clear all clauses.
  1888. _predicatesStore[nameArity] = new List<IClause>();
  1889. }
  1890. /// <summary>
  1891. /// If NameSlashArity is var, match with all the dynamic predicates using the
  1892. /// Name/Artity form.
  1893. /// If NameSlashArity is not var, check if the Name/Arity exists as a static or
  1894. /// dynamic predicate.
  1895. /// </summary>
  1896. /// <param name="NameSlashArity"></param>
  1897. /// <param name="declaringClass">if not null, used to resolve references to the default
  1898. /// module Atom.a("")</param>
  1899. /// <returns></returns>
  1900. public static IEnumerable<bool> current_predicate(object NameSlashArity, Type declaringClass)
  1901. {
  1902. NameSlashArity = YP.getValue(NameSlashArity);
  1903. // First check if Name and Arity are nonvar so we can do a direct lookup.
  1904. if (YP.ground(NameSlashArity))
  1905. {
  1906. Functor2 NameArityFunctor = NameSlashArity as Functor2;
  1907. if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH))
  1908. throw new PrologException
  1909. (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
  1910. "Must be a name/arity predicate indicator");
  1911. object name = YP.getValue(NameArityFunctor._arg1);
  1912. object arity = YP.getValue(NameArityFunctor._arg2);
  1913. if (name is Variable || arity is Variable)
  1914. throw new PrologException
  1915. ("instantiation_error", "Predicate indicator name or arity is an unbound variable");
  1916. if (!(name is Atom && arity is int))
  1917. throw new PrologException
  1918. (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
  1919. "Must be a name/arity predicate indicator");
  1920. if ((int)arity < 0)
  1921. throw new PrologException
  1922. (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
  1923. "Arity may not be less than zero");
  1924. if (YPCompiler.isCurrentPredicate((Atom)name, (int)arity, declaringClass))
  1925. // The predicate is defined.
  1926. yield return false;
  1927. }
  1928. else
  1929. {
  1930. foreach (NameArity key in _predicatesStore.Keys)
  1931. {
  1932. foreach (bool l1 in YP.unify
  1933. (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity))
  1934. yield return false;
  1935. }
  1936. }
  1937. }
  1938. /// <summary>
  1939. /// Return true if the dynamic predicate store has an entry for the predicate
  1940. /// with name and arity.
  1941. /// </summary>
  1942. /// <param name="name"></param>
  1943. /// <param name="arity"></param>
  1944. /// <returns></returns>
  1945. public static bool isDynamicCurrentPredicate(Atom name, int arity)
  1946. {
  1947. return _predicatesStore.ContainsKey(new NameArity(name, arity));
  1948. }
  1949. public static void abolish(object NameSlashArity)
  1950. {
  1951. NameSlashArity = YP.getValue(NameSlashArity);
  1952. if (NameSlashArity is Variable)
  1953. throw new PrologException
  1954. ("instantiation_error", "Predicate indicator is an unbound variable");
  1955. Functor2 NameArityFunctor = NameSlashArity as Functor2;
  1956. if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH))
  1957. throw new PrologException
  1958. (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
  1959. "Must be a name/arity predicate indicator");
  1960. object name = YP.getValue(NameArityFunctor._arg1);
  1961. object arity = YP.getValue(NameArityFunctor._arg2);
  1962. if (name is Variable || arity is Variable)
  1963. throw new PrologException
  1964. ("instantiation_error", "Predicate indicator name or arity is an unbound variable");
  1965. if (!(name is Atom))
  1966. throw new PrologException
  1967. (new Functor2("type_error", Atom.a("atom"), name),
  1968. "Predicate indicator name must be an atom");
  1969. if (!(arity is int))
  1970. throw new PrologException
  1971. (new Functor2("type_error", Atom.a("integer"), arity),
  1972. "Predicate indicator arity must be an integer");
  1973. if ((int)arity < 0)
  1974. throw new PrologException
  1975. (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
  1976. "Arity may not be less than zero");
  1977. if ((int)arity > MAX_ARITY)
  1978. throw new PrologException
  1979. (new Functor1("representation_error", Atom.a("max_arity")),
  1980. "Arity may not be greater than " + MAX_ARITY);
  1981. if (isSystemPredicate((Atom)name, (int)arity))
  1982. throw new PrologException
  1983. (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
  1984. new Functor2(Atom.SLASH, name, arity)),
  1985. "Abolish cannot modify static predicate " + name + "/" + arity);
  1986. _predicatesStore.Remove(new NameArity((Atom)name, (int)arity));
  1987. }
  1988. /// <summary>
  1989. /// If Goal is a simple predicate, call YP.getFunctorName(Goal) using arguments from
  1990. /// YP.getFunctorArgs(Goal). If not found, this throws a PrologException for existence_error.
  1991. /// Otherwise, compile the goal as a single clause predicate and invoke it.
  1992. /// </summary>
  1993. /// <param name="Goal"></param>
  1994. /// <param name="declaringClass">if not null, used to resolve references to the default
  1995. /// module Atom.a("")</param>
  1996. /// <returns></returns>
  1997. public static IEnumerable<bool> getIterator(object Goal, Type declaringClass)
  1998. {
  1999. Atom name;
  2000. object[] args;
  2001. while (true)
  2002. {
  2003. Goal = YP.getValue(Goal);
  2004. if (Goal is Variable)
  2005. throw new PrologException("instantiation_error", "Goal to call is an unbound variable");
  2006. name = YP.getFunctorName(Goal) as Atom;
  2007. if (name == null)
  2008. throw new PrologException
  2009. (new Functor2("type_error", Atom.a("callable"), Goal), "Goal to call is not callable");
  2010. args = YP.getFunctorArgs(Goal);
  2011. if (name == Atom.HAT && args.Length == 2)
  2012. // Assume this is called from a bagof operation. Skip the leading qualifiers.
  2013. Goal = YP.getValue(((Functor2)Goal)._arg2);
  2014. else
  2015. break;
  2016. }
  2017. IEnumerable<bool> simpleIterator = YPCompiler.getSimpleIterator(name, args, declaringClass);
  2018. if (simpleIterator != null)
  2019. // We don't need to compile since the goal is a simple predicate which we call directly.
  2020. return simpleIterator;
  2021. // Compile the goal as a clause.
  2022. List<Variable> variableSetList = new List<Variable>();
  2023. addUniqueVariables(Goal, variableSetList);
  2024. Variable[] variableSet = variableSetList.ToArray();
  2025. // Use Atom.F since it is ignored.
  2026. return YPCompiler.compileAnonymousClause
  2027. (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet);
  2028. }
  2029. public static void throwException(object Term)
  2030. {
  2031. throw new PrologException(Term);
  2032. }
  2033. /// <summary>
  2034. /// This must be called by any function that uses YP._prologFlags to make sure
  2035. /// the initial defaults are loaded.
  2036. /// </summary>
  2037. private static void establishPrologFlags()
  2038. {
  2039. if (_prologFlags.Count > 0)
  2040. // Already established.
  2041. return;
  2042. // List these in the order they appear in the ISO standard.
  2043. _prologFlags["bounded"] = Atom.a("true");
  2044. _prologFlags["max_integer"] = Int32.MaxValue;
  2045. _prologFlags["min_integer"] = Int32.MinValue;
  2046. _prologFlags["integer_rounding_function"] = Atom.a("toward_zero");
  2047. _prologFlags["char_conversion"] = Atom.a("off");
  2048. _prologFlags["debug"] = Atom.a("off");
  2049. _prologFlags["max_arity"] = MAX_ARITY;
  2050. _prologFlags["unknown"] = Atom.a("error");
  2051. _prologFlags["double_quotes"] = Atom.a("codes");
  2052. }
  2053. public static IEnumerable<bool> current_prolog_flag(object Key, object Value)
  2054. {
  2055. establishPrologFlags();
  2056. Key = YP.getValue(Key);
  2057. Value = YP.getValue(Value);
  2058. if (Key is Variable)
  2059. {
  2060. // Bind all key values.
  2061. foreach (string key in _prologFlags.Keys)
  2062. {
  2063. foreach (bool l1 in YP.unify(Key, Atom.a(key)))
  2064. {
  2065. foreach (bool l2 in YP.unify(Value, _prologFlags[key]))
  2066. yield return false;
  2067. }
  2068. }
  2069. }
  2070. else
  2071. {
  2072. if (!(Key is Atom))
  2073. throw new PrologException
  2074. (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom");
  2075. if (!_prologFlags.ContainsKey(((Atom)Key)._name))
  2076. throw new PrologException
  2077. (new Functor2("domain_error", Atom.a("prolog_flag"), Key),
  2078. "Arg 1 Key is not a recognized flag");
  2079. foreach (bool l1 in YP.unify(Value, _prologFlags[((Atom)Key)._name]))
  2080. yield return false;
  2081. }
  2082. }
  2083. public static void set_prolog_flag(object Key, object Value)
  2084. {
  2085. establishPrologFlags();
  2086. Key = YP.getValue(Key);
  2087. Value = YP.getValue(Value);
  2088. if (Key is Variable)
  2089. throw new PrologException(Atom.a("instantiation_error"),
  2090. "Arg 1 Key is an unbound variable");
  2091. if (Value is Variable)
  2092. throw new PrologException(Atom.a("instantiation_error"),
  2093. "Arg 1 Key is an unbound variable");
  2094. if (!(Key is Atom))
  2095. throw new PrologException
  2096. (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom");
  2097. string keyName = ((Atom)Key)._name;
  2098. if (!_prologFlags.ContainsKey(keyName))
  2099. throw new PrologException
  2100. (new Functor2("domain_error", Atom.a("prolog_flag"), Key),
  2101. "Arg 1 Key " + Key + " is not a recognized flag");
  2102. bool valueIsOK = false;
  2103. if (keyName == "char_conversion")
  2104. valueIsOK = (Value == _prologFlags[keyName]);
  2105. else if (keyName == "debug")
  2106. valueIsOK = (Value == _prologFlags[keyName]);
  2107. else if (keyName == "unknown")
  2108. valueIsOK = (Value == Atom.a("fail") || Value == Atom.a("warning") ||
  2109. Value == Atom.a("error"));
  2110. else if (keyName == "double_quotes")
  2111. valueIsOK = (Value == Atom.a("codes") || Value == Atom.a("chars") ||
  2112. Value == Atom.a("atom"));
  2113. else
  2114. throw new PrologException
  2115. (new Functor3("permission_error", Atom.a("modify"), Atom.a("flag"), Key),
  2116. "May not modify Prolog flag " + Key);
  2117. if (!valueIsOK)
  2118. throw new PrologException
  2119. (new Functor2("domain_error", Atom.a("flag_value"), new Functor2("+", Key, Value)),
  2120. "May not set arg 1 Key " + Key + " to arg 2 Value " + Value);
  2121. _prologFlags[keyName] = Value;
  2122. }
  2123. /// <summary>
  2124. /// script_event calls hosting script with events as a callback method.
  2125. /// </summary>
  2126. /// <param name="script_event"></param>
  2127. /// <param name="script_params"></param>
  2128. /// <returns></returns>
  2129. public static IEnumerable<bool> script_event(object script_event, object script_params)
  2130. {
  2131. // string function = ((Atom)YP.getValue(script_event))._name;
  2132. object[] array = ListPair.toArray(script_params);
  2133. if (array == null)
  2134. yield return false; // return; // YP.fail();
  2135. if (array.Length > 1)
  2136. {
  2137. //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue
  2138. //(localID, itemID, function, array);
  2139. // sortArray(array);
  2140. }
  2141. //return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array));
  2142. yield return false;
  2143. }
  2144. /* Non-prolog-ish functions for inline coding */
  2145. public static string regexString(string inData, string inPattern, string presep,string postsep)
  2146. {
  2147. //string str=cycMessage;
  2148. //string strMatch = @"\. \#\$(.*)\)";
  2149. string results = "";
  2150. for (Match m = Regex.Match(inData,inPattern); m.Success; m=m.NextMatch())
  2151. {
  2152. //m_log.Debug(m);
  2153. results += presep+ m + postsep;
  2154. }
  2155. return results;
  2156. }
  2157. public static string cycComm(object msgobj)
  2158. {
  2159. string cycInputString = msgobj.ToString();
  2160. string cycOutputString="";
  2161. TcpClient socketForServer;
  2162. try
  2163. {
  2164. socketForServer = new TcpClient("localHost", 3601);
  2165. }
  2166. catch
  2167. {
  2168. m_log.Error("Failed to connect to server at localhost:999");
  2169. return "";
  2170. }
  2171. NetworkStream networkStream = socketForServer.GetStream();
  2172. System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
  2173. System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
  2174. try
  2175. {
  2176. // read the data from the host and display it
  2177. {
  2178. streamWriter.WriteLine(cycInputString);
  2179. streamWriter.Flush();
  2180. cycOutputString = streamReader.ReadLine();
  2181. m_log.Debug("Cycoutput:" + cycOutputString);
  2182. //streamWriter.WriteLine("Client Message");
  2183. //m_log.Debug("Client Message");
  2184. streamWriter.Flush();
  2185. }
  2186. }
  2187. catch
  2188. {
  2189. m_log.Error("Exception reading from Server");
  2190. return "";
  2191. }
  2192. // tidy up
  2193. networkStream.Close();
  2194. return cycOutputString;
  2195. }
  2196. //public static void throwException(object Term)
  2197. //{
  2198. // throw new PrologException(Term);
  2199. //}
  2200. /// <summary>
  2201. /// An enumerator that does zero loops.
  2202. /// </summary>
  2203. private class Fail : IEnumerator<bool>, IEnumerable<bool>
  2204. {
  2205. public bool MoveNext()
  2206. {
  2207. return false;
  2208. }
  2209. public IEnumerator<bool> GetEnumerator()
  2210. {
  2211. return (IEnumerator<bool>)this;
  2212. }
  2213. IEnumerator IEnumerable.GetEnumerator()
  2214. {
  2215. return GetEnumerator();
  2216. }
  2217. public bool Current
  2218. {
  2219. get { return true; }
  2220. }
  2221. object IEnumerator.Current
  2222. {
  2223. get { return true; }
  2224. }
  2225. public void Dispose()
  2226. {
  2227. }
  2228. public void Reset()
  2229. {
  2230. throw new NotImplementedException();
  2231. }
  2232. }
  2233. /// <summary>
  2234. /// An enumerator that does one iteration.
  2235. /// </summary>
  2236. private class Succeed : IEnumerator<bool>, IEnumerable<bool>
  2237. {
  2238. private bool _didIteration = false;
  2239. public bool MoveNext()
  2240. {
  2241. if (!_didIteration)
  2242. {
  2243. _didIteration = true;
  2244. return true;
  2245. }
  2246. else
  2247. return false;
  2248. }
  2249. public IEnumerator<bool> GetEnumerator()
  2250. {
  2251. return (IEnumerator<bool>)this;
  2252. }
  2253. IEnumerator IEnumerable.GetEnumerator()
  2254. {
  2255. return GetEnumerator();
  2256. }
  2257. public bool Current
  2258. {
  2259. get { return false; }
  2260. }
  2261. object IEnumerator.Current
  2262. {
  2263. get { return false; }
  2264. }
  2265. public void Dispose()
  2266. {
  2267. }
  2268. public void Reset()
  2269. {
  2270. throw new NotImplementedException();
  2271. }
  2272. }
  2273. /// <summary>
  2274. /// An enumerator that repeats forever.
  2275. /// </summary>
  2276. private class Repeat : IEnumerator<bool>, IEnumerable<bool>
  2277. {
  2278. public bool MoveNext()
  2279. {
  2280. return true;
  2281. }
  2282. public IEnumerator<bool> GetEnumerator()
  2283. {
  2284. return (IEnumerator<bool>)this;
  2285. }
  2286. IEnumerator IEnumerable.GetEnumerator()
  2287. {
  2288. return GetEnumerator();
  2289. }
  2290. public bool Current
  2291. {
  2292. get { return false; }
  2293. }
  2294. object IEnumerator.Current
  2295. {
  2296. get { return false; }
  2297. }
  2298. public void Dispose()
  2299. {
  2300. }
  2301. public void Reset()
  2302. {
  2303. throw new NotImplementedException();
  2304. }
  2305. }
  2306. /// <summary>
  2307. /// An enumerator that wraps another enumerator in order to catch a PrologException.
  2308. /// </summary>
  2309. public class Catch : IEnumerator<bool>, IEnumerable<bool>
  2310. {
  2311. private IEnumerator<bool> _enumerator;
  2312. private PrologException _exception = null;
  2313. /// <summary>
  2314. /// Call YP.getIterator(Goal, declaringClass) and save the returned iterator.
  2315. /// If getIterator throws an exception, save it the same as MoveNext().
  2316. /// </summary>
  2317. /// <param name="Goal"></param>
  2318. /// <param name="declaringClass"></param>
  2319. public Catch(object Goal, Type declaringClass)
  2320. {
  2321. try
  2322. {
  2323. _enumerator = getIterator(Goal, declaringClass).GetEnumerator();
  2324. }
  2325. catch (PrologException exception)
  2326. {
  2327. // MoveNext() will check this.
  2328. _exception = exception;
  2329. }
  2330. }
  2331. /// <summary>
  2332. /// Call _enumerator.MoveNext(). If it throws a PrologException, set _exception
  2333. /// and return false. After this returns false, call unifyExceptionOrThrow.
  2334. /// </summary>
  2335. /// <returns></returns>
  2336. public bool MoveNext()
  2337. {
  2338. if (_exception != null)
  2339. return false;
  2340. try
  2341. {
  2342. return _enumerator.MoveNext();
  2343. }
  2344. catch (PrologException exception)
  2345. {
  2346. _exception = exception;
  2347. return false;
  2348. }
  2349. }
  2350. /// <summary>
  2351. /// Call this after MoveNext() returns false to check for an exception. If
  2352. /// MoveNext did not get a PrologException, don't yield.
  2353. /// Otherwise, unify the exception with Catcher and yield so the caller can
  2354. /// do the handler code. However, if can't unify with Catcher then throw the exception.
  2355. /// </summary>
  2356. /// <param name="Catcher"></param>
  2357. /// <returns></returns>
  2358. public IEnumerable<bool> unifyExceptionOrThrow(object Catcher)
  2359. {
  2360. if (_exception != null)
  2361. {
  2362. bool didUnify = false;
  2363. foreach (bool l1 in YP.unify(_exception._term, Catcher))
  2364. {
  2365. didUnify = true;
  2366. yield return false;
  2367. }
  2368. if (!didUnify)
  2369. throw _exception;
  2370. }
  2371. }
  2372. public IEnumerator<bool> GetEnumerator()
  2373. {
  2374. return (IEnumerator<bool>)this;
  2375. }
  2376. IEnumerator IEnumerable.GetEnumerator()
  2377. {
  2378. return GetEnumerator();
  2379. }
  2380. public bool Current
  2381. {
  2382. get { return _enumerator.Current; }
  2383. }
  2384. object IEnumerator.Current
  2385. {
  2386. get { return _enumerator.Current; }
  2387. }
  2388. public void Dispose()
  2389. {
  2390. if (_enumerator != null)
  2391. _enumerator.Dispose();
  2392. }
  2393. public void Reset()
  2394. {
  2395. throw new NotImplementedException();
  2396. }
  2397. }
  2398. #pragma warning restore 0168, 0219
  2399. /// <summary>
  2400. /// A ClauseHeadAndBody is used in Compiler.compileAnonymousFunction as a base class
  2401. /// in order to implement YP.IClause. After creating the object, you must call setHeadAndBody.
  2402. /// </summary>
  2403. public class ClauseHeadAndBody
  2404. {
  2405. private object _Head;
  2406. private object _Body;
  2407. public void setHeadAndBody(object Head, object Body)
  2408. {
  2409. _Head = Head;
  2410. _Body = Body;
  2411. }
  2412. public IEnumerable<bool> clause(object Head, object Body)
  2413. {
  2414. if (_Head == null || _Body == null)
  2415. yield break;
  2416. #pragma warning disable 0168, 0219
  2417. foreach (bool l1 in YP.unify(Head, _Head))
  2418. {
  2419. foreach (bool l2 in YP.unify(Body, _Body))
  2420. yield return false;
  2421. }
  2422. #pragma warning restore 0168, 0219
  2423. }
  2424. }
  2425. /// <summary>
  2426. /// CodeListReader extends TextReader and overrides Read to read the next code from
  2427. /// the CodeList which is a Prolog list of integer character codes.
  2428. /// </summary>
  2429. public class CodeListReader : TextReader
  2430. {
  2431. private object _CodeList;
  2432. public CodeListReader(object CodeList)
  2433. {
  2434. _CodeList = YP.getValue(CodeList);
  2435. }
  2436. /// <summary>
  2437. /// If the head of _CodeList is an integer, return it and advance the list. Otherwise,
  2438. /// return -1 for end of file.
  2439. /// </summary>
  2440. /// <returns></returns>
  2441. public override int Read()
  2442. {
  2443. Functor2 CodeListPair = _CodeList as Functor2;
  2444. int code;
  2445. if (!(CodeListPair != null && CodeListPair._name == Atom.DOT &&
  2446. getInt(CodeListPair._arg1, out code)))
  2447. {
  2448. _CodeList = Atom.NIL;
  2449. return -1;
  2450. }
  2451. // Advance.
  2452. _CodeList = YP.getValue(CodeListPair._arg2);
  2453. return code;
  2454. }
  2455. }
  2456. }
  2457. }