PageRenderTime 64ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/YieldProlog/Modules/YP.cs

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