YP.cs 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677
  1. /*
  2. * Copyright (C) 2007-2008, Jeff Thompson
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of the copyright holder nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. using System;
  31. using System.Collections;
  32. using System.Collections.Generic;
  33. using System.IO;
  34. using System.Reflection;
  35. namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
  36. {
  37. /// <summary>
  38. /// YP has static methods for general functions in Yield Prolog such as <see cref="getValue"/>
  39. /// and <see cref="unify"/>.
  40. /// </summary>
  41. public class YP
  42. {
  43. private static Fail _fail = new Fail();
  44. private static Repeat _repeat = new Repeat();
  45. private static Dictionary<NameArity, List<IClause>> _predicatesStore =
  46. new Dictionary<NameArity, List<IClause>>();
  47. private static TextWriter _outputStream = System.Console.Out;
  48. private static TextReader _inputStream = System.Console.In;
  49. private static List<object[]> _operatorTable = null;
  50. /// <summary>
  51. /// An IClause is used so that dynamic predicates can call match.
  52. /// </summary>
  53. public interface IClause
  54. {
  55. IEnumerable<bool> match(object[] args);
  56. }
  57. public static object getValue(object value)
  58. {
  59. if (value is Variable)
  60. return ((Variable)value).getValue();
  61. else
  62. return value;
  63. }
  64. public static IEnumerable<bool> unify(object arg1, object arg2)
  65. {
  66. arg1 = getValue(arg1);
  67. arg2 = getValue(arg2);
  68. if (arg1 is IUnifiable)
  69. return ((IUnifiable)arg1).unify(arg2);
  70. else if (arg2 is IUnifiable)
  71. return ((IUnifiable)arg2).unify(arg1);
  72. else
  73. {
  74. // Arguments are "normal" types.
  75. if (arg1.Equals(arg2))
  76. return new Succeed();
  77. else
  78. return _fail;
  79. }
  80. }
  81. /// <summary>
  82. /// This is used for the lookup key in _factStore.
  83. /// </summary>
  84. public struct NameArity
  85. {
  86. public readonly Atom _name;
  87. public readonly int _arity;
  88. public NameArity(Atom name, int arity)
  89. {
  90. _name = name;
  91. _arity = arity;
  92. }
  93. public override bool Equals(object obj)
  94. {
  95. if (obj is NameArity)
  96. {
  97. NameArity nameArity = (NameArity)obj;
  98. return nameArity._name.Equals(_name) && nameArity._arity.Equals(_arity);
  99. }
  100. else
  101. {
  102. return false;
  103. }
  104. }
  105. public override int GetHashCode()
  106. {
  107. return _name.GetHashCode() ^ _arity.GetHashCode();
  108. }
  109. }
  110. /// <summary>
  111. /// Convert term to an int.
  112. /// If term is a single-element List, use its first element
  113. /// (to handle the char types like "a"). If can't convert, throw an exception.
  114. /// </summary>
  115. /// <param name="term"></param>
  116. /// <returns></returns>
  117. public static int convertInt(object term)
  118. {
  119. term = YP.getValue(term);
  120. if (term is Functor2 && ((Functor2)term)._name == Atom.DOT &&
  121. YP.getValue(((Functor2)term)._arg2) == Atom.NIL)
  122. // Assume it is a char type like "a".
  123. term = YP.getValue(((Functor2)term)._arg1);
  124. return (int)term;
  125. }
  126. /// <summary>
  127. /// Convert term to a double. This may convert an int to a double, etc.
  128. /// If term is a single-element List, use its first element
  129. /// (to handle the char types like "a"). If can't convert, throw an exception.
  130. /// </summary>
  131. /// <param name="term"></param>
  132. /// <returns></returns>
  133. public static double convertDouble(object term)
  134. {
  135. term = YP.getValue(term);
  136. if (term is Functor2 && ((Functor2)term)._name == Atom.DOT &&
  137. YP.getValue(((Functor2)term)._arg2) == Atom.NIL)
  138. // Assume it is a char type like "a".
  139. term = YP.getValue(((Functor2)term)._arg1);
  140. if (term is Variable)
  141. throw new PrologException(Atom.a("instantiation_error"),
  142. "Expected a number but the argument is an unbound variable");
  143. return Convert.ToDouble(term);
  144. }
  145. /// <summary>
  146. /// If term is an integer, set intTerm.
  147. /// If term is a single-element List, use its first element
  148. /// (to handle the char types like "a"). Return true for success, false if can't convert.
  149. /// We use a success return value because throwing an exception is inefficient.
  150. /// </summary>
  151. /// <param name="term"></param>
  152. /// <returns></returns>
  153. public static bool getInt(object term, out int intTerm)
  154. {
  155. term = YP.getValue(term);
  156. if (term is Functor2 && ((Functor2)term)._name == Atom.DOT &&
  157. YP.getValue(((Functor2)term)._arg2) == Atom.NIL)
  158. // Assume it is a char type like "a".
  159. term = YP.getValue(((Functor2)term)._arg1);
  160. if (term is int)
  161. {
  162. intTerm = (int)term;
  163. return true;
  164. }
  165. intTerm = 0;
  166. return false;
  167. }
  168. public static bool equal(object x, object y)
  169. {
  170. x = YP.getValue(x);
  171. if (x is DateTime)
  172. return (DateTime)x == (DateTime)YP.getValue(y);
  173. // Assume convertDouble converts an int to a double perfectly.
  174. return YP.convertDouble(x) == YP.convertDouble(y);
  175. }
  176. public static bool notEqual(object x, object y)
  177. {
  178. x = YP.getValue(x);
  179. if (x is DateTime)
  180. return (DateTime)x != (DateTime)YP.getValue(y);
  181. // Assume convertDouble converts an int to a double perfectly.
  182. return YP.convertDouble(x) != YP.convertDouble(y);
  183. }
  184. public static bool greaterThan(object x, object y)
  185. {
  186. x = YP.getValue(x);
  187. if (x is DateTime)
  188. return (DateTime)x > (DateTime)YP.getValue(y);
  189. // Assume convertDouble converts an int to a double perfectly.
  190. return YP.convertDouble(x) > YP.convertDouble(y);
  191. }
  192. public static bool lessThan(object x, object y)
  193. {
  194. x = YP.getValue(x);
  195. if (x is DateTime)
  196. return (DateTime)x < (DateTime)YP.getValue(y);
  197. // Assume convertDouble converts an int to a double perfectly.
  198. return YP.convertDouble(x) < YP.convertDouble(y);
  199. }
  200. public static bool greaterThanOrEqual(object x, object y)
  201. {
  202. x = YP.getValue(x);
  203. if (x is DateTime)
  204. return (DateTime)x >= (DateTime)YP.getValue(y);
  205. // Assume convertDouble converts an int to a double perfectly.
  206. return YP.convertDouble(x) >= YP.convertDouble(y);
  207. }
  208. public static bool lessThanOrEqual(object x, object y)
  209. {
  210. x = YP.getValue(x);
  211. if (x is DateTime)
  212. return (DateTime)x <= (DateTime)YP.getValue(y);
  213. // Assume convertDouble converts an int to a double perfectly.
  214. return YP.convertDouble(x) <= YP.convertDouble(y);
  215. }
  216. public static object negate(object x)
  217. {
  218. int intX;
  219. if (getInt(x, out intX))
  220. return -intX;
  221. return -convertDouble(x);
  222. }
  223. public static object abs(object x)
  224. {
  225. int intX;
  226. if (getInt(x, out intX))
  227. return Math.Abs(intX);
  228. return Math.Abs(convertDouble(x));
  229. }
  230. public static object sign(object x)
  231. {
  232. int intX;
  233. if (getInt(x, out intX))
  234. return Math.Sign(intX);
  235. return Math.Sign(convertDouble(x));
  236. }
  237. /// <summary>
  238. /// The ISO standard returns an int.
  239. /// </summary>
  240. /// <param name="x"></param>
  241. /// <returns></returns>
  242. public static object floor(object x)
  243. {
  244. return (int)Math.Floor(convertDouble(x));
  245. }
  246. /// <summary>
  247. /// The ISO standard returns an int.
  248. /// </summary>
  249. /// <param name="x"></param>
  250. /// <returns></returns>
  251. public static object truncate(object x)
  252. {
  253. return (int)Math.Truncate(convertDouble(x));
  254. }
  255. /// <summary>
  256. /// The ISO standard returns an int.
  257. /// </summary>
  258. /// <param name="x"></param>
  259. /// <returns></returns>
  260. public static object round(object x)
  261. {
  262. return (int)Math.Round(convertDouble(x));
  263. }
  264. /// <summary>
  265. /// The ISO standard returns an int.
  266. /// </summary>
  267. /// <param name="x"></param>
  268. /// <returns></returns>
  269. public static object ceiling(object x)
  270. {
  271. return (int)Math.Ceiling(convertDouble(x));
  272. }
  273. public static object sin(object x)
  274. {
  275. return Math.Sin(YP.convertDouble(x));
  276. }
  277. public static object cos(object x)
  278. {
  279. return Math.Cos(YP.convertDouble(x));
  280. }
  281. public static object atan(object x)
  282. {
  283. return Math.Atan(YP.convertDouble(x));
  284. }
  285. public static object exp(object x)
  286. {
  287. return Math.Exp(YP.convertDouble(x));
  288. }
  289. public static object log(object x)
  290. {
  291. return Math.Log(YP.convertDouble(x));
  292. }
  293. public static object sqrt(object x)
  294. {
  295. return Math.Sqrt(convertDouble(x));
  296. }
  297. public static object bitwiseComplement(object x)
  298. {
  299. return ~YP.convertInt(x);
  300. }
  301. public static object add(object x, object y)
  302. {
  303. int intX, intY;
  304. if (getInt(x, out intX) && getInt(y, out intY))
  305. return intX + intY;
  306. return convertDouble(x) + convertDouble(y);
  307. }
  308. public static object subtract(object x, object y)
  309. {
  310. int intX, intY;
  311. if (getInt(x, out intX) && getInt(y, out intY))
  312. return intX - intY;
  313. return convertDouble(x) - convertDouble(y);
  314. }
  315. public static object multiply(object x, object y)
  316. {
  317. int intX, intY;
  318. if (getInt(x, out intX) && getInt(y, out intY))
  319. return intX * intY;
  320. return convertDouble(x) * convertDouble(y);
  321. }
  322. /// <summary>
  323. /// Return floating point, even if both arguments are integer.
  324. /// </summary>
  325. /// <param name="x"></param>
  326. /// <param name="y"></param>
  327. /// <returns></returns>
  328. public static object divide(object x, object y)
  329. {
  330. return convertDouble(x) / convertDouble(y);
  331. }
  332. public static object intDivide(object x, object y)
  333. {
  334. int intX, intY;
  335. if (getInt(x, out intX) && getInt(y, out intY))
  336. return intX / intY;
  337. // Still allow passing a double, but treat as an int.
  338. return (int)convertDouble(x) / (int)convertDouble(y);
  339. }
  340. public static object mod(object x, object y)
  341. {
  342. int intX, intY;
  343. if (getInt(x, out intX) && getInt(y, out intY))
  344. return intX % intY;
  345. // Still allow passing a double, but treat as an int.
  346. return (int)convertDouble(x) % (int)convertDouble(y);
  347. }
  348. public static object pow(object x, object y)
  349. {
  350. return Math.Pow(YP.convertDouble(x), YP.convertDouble(y));
  351. }
  352. public static object bitwiseShiftRight(object x, object y)
  353. {
  354. return YP.convertInt(x) >> YP.convertInt(y);
  355. }
  356. public static object bitwiseShiftLeft(object x, object y)
  357. {
  358. return YP.convertInt(x) << YP.convertInt(y);
  359. }
  360. public static object bitwiseAnd(object x, object y)
  361. {
  362. return YP.convertInt(x) & YP.convertInt(y);
  363. }
  364. public static object bitwiseOr(object x, object y)
  365. {
  366. return YP.convertInt(x) | YP.convertInt(y);
  367. }
  368. public static object min(object x, object y)
  369. {
  370. int intX, intY;
  371. if (getInt(x, out intX) && getInt(y, out intY))
  372. return Math.Min(intX, intY);
  373. return Math.Min(convertDouble(x), convertDouble(y));
  374. }
  375. public static object max(object x, object y)
  376. {
  377. int intX, intY;
  378. if (getInt(x, out intX) && getInt(y, out intY))
  379. return Math.Max(intX, intY);
  380. return Math.Max(convertDouble(x), convertDouble(y));
  381. }
  382. public static IEnumerable<bool> copy_term(object inTerm, object outTerm)
  383. {
  384. return YP.unify(outTerm, YP.makeCopy(inTerm, new Variable.CopyStore()));
  385. }
  386. public static void addUniqueVariables(object term, List<Variable> variableSet)
  387. {
  388. term = YP.getValue(term);
  389. if (term is IUnifiable)
  390. ((IUnifiable)term).addUniqueVariables(variableSet);
  391. }
  392. public static object makeCopy(object term, Variable.CopyStore copyStore)
  393. {
  394. term = YP.getValue(term);
  395. if (term is IUnifiable)
  396. return ((IUnifiable)term).makeCopy(copyStore);
  397. else
  398. // term is a "normal" type. Assume it is ground.
  399. return term;
  400. }
  401. /// <summary>
  402. /// Sort the array in place according to termLessThan. This does not remove duplicates
  403. /// </summary>
  404. /// <param name="array"></param>
  405. public static void sortArray(object[] array)
  406. {
  407. Array.Sort(array, YP.compareTerms);
  408. }
  409. /// <summary>
  410. /// Sort the array in place according to termLessThan. This does not remove duplicates
  411. /// </summary>
  412. /// <param name="array"></param>
  413. public static void sortArray(List<object> array)
  414. {
  415. array.Sort(YP.compareTerms);
  416. }
  417. /// <summary>
  418. /// Sort List according to termLessThan, remove duplicates and unify with Sorted.
  419. /// </summary>
  420. /// <param name="List"></param>
  421. /// <param name="Sorted"></param>
  422. /// <returns></returns>
  423. public static IEnumerable<bool> sort(object List, object Sorted)
  424. {
  425. object[] array = ListPair.toArray(List);
  426. if (array == null)
  427. return YP.fail();
  428. if (array.Length > 1)
  429. sortArray(array);
  430. return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array));
  431. }
  432. /// <summary>
  433. /// Use YP.unify to unify each of the elements of the two arrays, and yield
  434. /// once if they all unify.
  435. /// </summary>
  436. /// <param name="array1"></param>
  437. /// <param name="array2"></param>
  438. /// <returns></returns>
  439. public static IEnumerable<bool> unifyArrays(object[] array1, object[] array2)
  440. {
  441. if (array1.Length != array2.Length)
  442. yield break;
  443. IEnumerator<bool>[] iterators = new IEnumerator<bool>[array1.Length];
  444. bool gotMatch = true;
  445. int nIterators = 0;
  446. // Try to bind all the arguments.
  447. for (int i = 0; i < array1.Length; ++i)
  448. {
  449. IEnumerator<bool> iterator = YP.unify(array1[i], array2[i]).GetEnumerator();
  450. iterators[nIterators++] = iterator;
  451. // MoveNext() is true if YP.unify succeeds.
  452. if (!iterator.MoveNext())
  453. {
  454. gotMatch = false;
  455. break;
  456. }
  457. }
  458. try
  459. {
  460. if (gotMatch)
  461. yield return false;
  462. }
  463. finally
  464. {
  465. // Manually finalize all the iterators.
  466. for (int i = 0; i < nIterators; ++i)
  467. iterators[i].Dispose();
  468. }
  469. }
  470. /// <summary>
  471. /// Return an iterator (which you can use in a for-in loop) which does
  472. /// zero iterations. This returns a pre-existing iterator which is
  473. /// more efficient than letting the compiler generate a new one.
  474. /// </summary>
  475. /// <returns></returns>
  476. public static IEnumerable<bool> fail()
  477. {
  478. return _fail;
  479. }
  480. /// <summary>
  481. /// Return an iterator (which you can use in a for-in loop) which does
  482. /// one iteration. This returns a pre-existing iterator which is
  483. /// more efficient than letting the compiler generate a new one.
  484. /// </summary>
  485. /// <returns></returns>
  486. public static IEnumerable<bool> succeed()
  487. {
  488. return new Succeed();
  489. }
  490. /// <summary>
  491. /// Return an iterator (which you can use in a for-in loop) which repeats
  492. /// indefinitely. This returns a pre-existing iterator which is
  493. /// more efficient than letting the compiler generate a new one.
  494. /// </summary>
  495. /// <returns></returns>
  496. public static IEnumerable<bool> repeat()
  497. {
  498. return _repeat;
  499. }
  500. public static IEnumerable<bool> univ(object Term, object List)
  501. {
  502. Term = YP.getValue(Term);
  503. List = YP.getValue(List);
  504. if (nonvar(Term))
  505. return YP.unify(new ListPair
  506. (getFunctorName(Term), ListPair.make(getFunctorArgs(Term))), List);
  507. Variable Name = new Variable();
  508. Variable ArgList = new Variable();
  509. // disable warning: don't see how we can code this differently short
  510. // of rewriting the whole thing
  511. #pragma warning disable 0168
  512. foreach (bool l1 in new ListPair(Name, ArgList).unify(List))
  513. {
  514. object[] args = ListPair.toArray(ArgList);
  515. if (args == null)
  516. throw new Exception("Expected a list. Got: " + ArgList.getValue());
  517. if (args.Length == 0)
  518. // Return the Name, even if it is not an Atom.
  519. return YP.unify(Term, Name);
  520. if (!atom(Name))
  521. throw new Exception("Expected an atom. Got: " + Name.getValue());
  522. return YP.unify(Term, Functor.make((Atom)YP.getValue(Name), args));
  523. }
  524. #pragma warning restore 0168
  525. return YP.fail();
  526. }
  527. public static IEnumerable<bool> functor(object Term, object FunctorName, object Arity)
  528. {
  529. Term = YP.getValue(Term);
  530. FunctorName = YP.getValue(FunctorName);
  531. Arity = YP.getValue(Arity);
  532. if (!(Term is Variable))
  533. {
  534. // disable warning: don't see how we can code this differently short
  535. // of rewriting the whole thing
  536. #pragma warning disable 0168
  537. foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term)))
  538. {
  539. foreach (bool l2 in YP.unify(Arity, getFunctorArgs(Term).Length))
  540. yield return false;
  541. }
  542. #pragma warning restore 0168
  543. }
  544. else
  545. throw new NotImplementedException("Debug: must finish functor/3");
  546. }
  547. public static IEnumerable<bool> arg(object ArgNumber, object Term, object Value)
  548. {
  549. if (YP.var(ArgNumber))
  550. throw new NotImplementedException("Debug: must finish arg/3");
  551. else
  552. {
  553. int argNumberInt = convertInt(ArgNumber);
  554. if (argNumberInt < 0)
  555. throw new Exception("ArgNumber must be non-negative");
  556. object[] termArgs = YP.getFunctorArgs(Term);
  557. // Silently fail if argNumberInt is out of range.
  558. if (argNumberInt >= 1 && argNumberInt <= termArgs.Length)
  559. {
  560. // The first ArgNumber is at 1, not 0.
  561. // disable warning: don't see how we can code this differently short
  562. // of rewriting the whole thing
  563. #pragma warning disable 0168
  564. foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1]))
  565. yield return false;
  566. #pragma warning restore 0168
  567. }
  568. }
  569. }
  570. public static bool termEqual(object Term1, object Term2)
  571. {
  572. Term1 = YP.getValue(Term1);
  573. if (Term1 is IUnifiable)
  574. return ((IUnifiable)Term1).termEqual(Term2);
  575. return Term1.Equals(YP.getValue(Term2));
  576. }
  577. public static bool termNotEqual(object Term1, object Term2)
  578. {
  579. return !termEqual(Term1, Term2);
  580. }
  581. public static bool termLessThan(object Term1, object Term2)
  582. {
  583. Term1 = YP.getValue(Term1);
  584. Term2 = YP.getValue(Term2);
  585. int term1TypeCode = getTypeCode(Term1);
  586. int term2TypeCode = getTypeCode(Term2);
  587. if (term1TypeCode != term2TypeCode)
  588. return term1TypeCode < term2TypeCode;
  589. // The terms are the same type code.
  590. if (term1TypeCode == -2)
  591. {
  592. // Variable.
  593. // We always check for equality first because we want to be sure
  594. // that less than returns false if the terms are equal, in
  595. // case that the less than check really behaves like less than or equal.
  596. if ((Variable)Term1 != (Variable)Term2)
  597. // The hash code should be unique to a Variable object.
  598. return Term1.GetHashCode() < Term2.GetHashCode();
  599. return false;
  600. }
  601. if (term1TypeCode == 0)
  602. return ((Atom)Term1)._name.CompareTo(((Atom)Term2)._name) < 0;
  603. if (term1TypeCode == 1)
  604. return ((Functor1)Term1).lessThan((Functor1)Term2);
  605. if (term1TypeCode == 2)
  606. return ((Functor2)Term1).lessThan((Functor2)Term2);
  607. if (term1TypeCode == 3)
  608. return ((Functor3)Term1).lessThan((Functor3)Term2);
  609. if (term1TypeCode == 4)
  610. return ((Functor)Term1).lessThan((Functor)Term2);
  611. // Type code is -1 for general objects. First compare their type names.
  612. // Note that this puts Double before Int32 as required by ISO Prolog.
  613. string term1TypeName = Term1.GetType().ToString();
  614. string term2TypeName = Term2.GetType().ToString();
  615. if (term1TypeName != term2TypeName)
  616. return term1TypeName.CompareTo(term2TypeName) < 0;
  617. // The terms are the same type name.
  618. if (Term1 is int)
  619. return (int)Term1 < (int)Term2;
  620. else if (Term1 is double)
  621. return (double)Term1 < (double)Term2;
  622. else if (Term1 is DateTime)
  623. return (DateTime)Term1 < (DateTime)Term2;
  624. else if (Term1 is String)
  625. return ((String)Term1).CompareTo((String)Term2) < 0;
  626. // Debug: Should we try arrays, etc.?
  627. if (!Term1.Equals(Term2))
  628. // Could be equal or greater than.
  629. return Term1.GetHashCode() < Term2.GetHashCode();
  630. return false;
  631. }
  632. /// <summary>
  633. /// Type code is -2 if term is a Variable, 0 if it is an Atom,
  634. /// 1 if it is a Functor1, 2 if it is a Functor2, 3 if it is a Functor3,
  635. /// 4 if it is Functor.
  636. /// Otherwise, type code is -1.
  637. /// This does not call YP.getValue(term).
  638. /// </summary>
  639. /// <param name="term"></param>
  640. /// <returns></returns>
  641. private static int getTypeCode(object term)
  642. {
  643. if (term is Variable)
  644. return -2;
  645. else if (term is Atom)
  646. return 0;
  647. else if (term is Functor1)
  648. return 1;
  649. else if (term is Functor2)
  650. return 2;
  651. else if (term is Functor3)
  652. return 3;
  653. else if (term is Functor)
  654. return 4;
  655. else
  656. return -1;
  657. }
  658. public static bool termLessThanOrEqual(object Term1, object Term2)
  659. {
  660. if (YP.termEqual(Term1, Term2))
  661. return true;
  662. return YP.termLessThan(Term1, Term2);
  663. }
  664. public static bool termGreaterThan(object Term1, object Term2)
  665. {
  666. return !YP.termLessThanOrEqual(Term1, Term2);
  667. }
  668. public static bool termGreaterThanOrEqual(object Term1, object Term2)
  669. {
  670. // termLessThan should ensure that it returns false if terms are equal,
  671. // so that this would return true.
  672. return !YP.termLessThan(Term1, Term2);
  673. }
  674. public static int compareTerms(object Term1, object Term2)
  675. {
  676. if (YP.termEqual(Term1, Term2))
  677. return 0;
  678. else if (YP.termLessThan(Term1, Term2))
  679. return -1;
  680. else
  681. return 1;
  682. }
  683. public static bool ground(object Term)
  684. {
  685. Term = YP.getValue(Term);
  686. if (Term is IUnifiable)
  687. return ((IUnifiable)Term).ground();
  688. return true;
  689. }
  690. public static IEnumerable<bool> current_op
  691. (object Priority, object Specifier, object Operator)
  692. {
  693. if (_operatorTable == null)
  694. {
  695. // Initialize.
  696. _operatorTable = new List<object[]>();
  697. _operatorTable.Add(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") });
  698. _operatorTable.Add(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") });
  699. _operatorTable.Add(new object[] { 1200, Atom.a("fx"), Atom.a(":-") });
  700. _operatorTable.Add(new object[] { 1200, Atom.a("fx"), Atom.a("?-") });
  701. _operatorTable.Add(new object[] { 1100, Atom.a("xfy"), Atom.a(";") });
  702. _operatorTable.Add(new object[] { 1050, Atom.a("xfy"), Atom.a("->") });
  703. _operatorTable.Add(new object[] { 1000, Atom.a("xfy"), Atom.a(",") });
  704. _operatorTable.Add(new object[] { 900, Atom.a("fy"), Atom.a("\\+") });
  705. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=") });
  706. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") });
  707. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("==") });
  708. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") });
  709. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@<") });
  710. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") });
  711. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@>") });
  712. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") });
  713. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=..") });
  714. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("is") });
  715. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") });
  716. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") });
  717. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("<") });
  718. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=<") });
  719. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a(">") });
  720. _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a(">=") });
  721. _operatorTable.Add(new object[] { 600, Atom.a("xfy"), Atom.a(":") });
  722. _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("+") });
  723. _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("-") });
  724. _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") });
  725. _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") });
  726. _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("*") });
  727. _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("/") });
  728. _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("//") });
  729. _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("rem") });
  730. _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("mod") });
  731. _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("<<") });
  732. _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a(">>") });
  733. _operatorTable.Add(new object[] { 200, Atom.a("xfx"), Atom.a("**") });
  734. _operatorTable.Add(new object[] { 200, Atom.a("xfy"), Atom.a("^") });
  735. _operatorTable.Add(new object[] { 200, Atom.a("fy"), Atom.a("-") });
  736. _operatorTable.Add(new object[] { 200, Atom.a("fy"), Atom.a("\\") });
  737. // Debug: This is hacked in to run the Prolog test suite until we implement op/3.
  738. _operatorTable.Add(new object[] { 20, Atom.a("xfx"), Atom.a("<--") });
  739. }
  740. object[] args = new object[] { Priority, Specifier, Operator };
  741. foreach (object[] answer in _operatorTable)
  742. {
  743. // disable warning: don't see how we can code this differently short
  744. // of rewriting the whole thing
  745. #pragma warning disable 0168
  746. foreach (bool l1 in YP.unifyArrays(args, answer))
  747. yield return false;
  748. #pragma warning restore 0168
  749. }
  750. }
  751. public static IEnumerable<bool> atom_length(object atom, object Length)
  752. {
  753. return YP.unify(Length, ((Atom)YP.getValue(atom))._name.Length);
  754. }
  755. public static IEnumerable<bool> atom_concat(object Start, object End, object Whole)
  756. {
  757. // Debug: Should implement for var(Start) which is a kind of search.
  758. // Debug: Should we try to preserve the _declaringClass?
  759. return YP.unify(Whole, Atom.a(((Atom)YP.getValue(Start))._name +
  760. ((Atom)YP.getValue(End))._name));
  761. }
  762. public static IEnumerable<bool> sub_atom
  763. (object atom, object Before, object Length, object After, object Sub_atom)
  764. {
  765. // Debug: Should implement for var(atom) which is a kind of search.
  766. // Debug: Should we try to preserve the _declaringClass?
  767. Atom atomAtom = (Atom)YP.getValue(atom);
  768. int beforeInt = YP.convertInt(Before);
  769. int lengthInt = YP.convertInt(Length);
  770. if (beforeInt < 0)
  771. throw new Exception("Before must be non-negative");
  772. if (lengthInt < 0)
  773. throw new Exception("Length must be non-negative");
  774. int afterInt = atomAtom._name.Length - (beforeInt + lengthInt);
  775. if (afterInt >= 0)
  776. {
  777. // disable warning: don't see how we can code this differently short
  778. // of rewriting the whole thing
  779. #pragma warning disable 0168
  780. foreach (bool l1 in YP.unify(After, afterInt))
  781. {
  782. foreach (bool l2 in YP.unify
  783. (Sub_atom, Atom.a(atomAtom._name.Substring(beforeInt, lengthInt))))
  784. yield return false;
  785. }
  786. #pragma warning restore 0168
  787. }
  788. }
  789. public static IEnumerable<bool> atom_codes(object atom, object List)
  790. {
  791. atom = YP.getValue(atom);
  792. List = YP.getValue(List);
  793. if (nonvar(atom))
  794. {
  795. string name = ((Atom)atom)._name;
  796. object codeList = Atom.NIL;
  797. // Start from the back to make the list.
  798. for (int i = name.Length - 1; i >= 0; --i)
  799. codeList = new ListPair((int)name[i], codeList);
  800. return YP.unify(List, codeList);
  801. }
  802. {
  803. object[] codeArray = ListPair.toArray(List);
  804. char[] charArray = new char[codeArray.Length];
  805. for (int i = 0; i < codeArray.Length; ++i)
  806. charArray[i] = (char)YP.convertInt(codeArray[i]);
  807. return YP.unify(atom, Atom.a(new String(charArray)));
  808. }
  809. }
  810. public static IEnumerable<bool> number_codes(object number, object List)
  811. {
  812. number = YP.getValue(number);
  813. List = YP.getValue(List);
  814. if (nonvar(number))
  815. {
  816. string numberString = null;
  817. // Try converting to an int first.
  818. int intNumber;
  819. if (YP.getInt(number, out intNumber))
  820. numberString = intNumber.ToString();
  821. else
  822. numberString = YP.doubleToString(YP.convertDouble(number));
  823. object codeList = Atom.NIL;
  824. // Start from the back to make the list.
  825. for (int i = numberString.Length - 1; i >= 0; --i)
  826. codeList = new ListPair((int)numberString[i], codeList);
  827. return YP.unify(List, codeList);
  828. }
  829. {
  830. object[] codeArray = ListPair.toArray(List);
  831. char[] charArray = new char[codeArray.Length];
  832. for (int i = 0; i < codeArray.Length; ++i)
  833. charArray[i] = (char)YP.convertInt(codeArray[i]);
  834. String numberString = new String(charArray);
  835. // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
  836. try
  837. {
  838. // Try an int first.
  839. return YP.unify(number, Convert.ToInt32(numberString));
  840. }
  841. catch (FormatException) { }
  842. return YP.unify(number, Convert.ToDouble(numberString));
  843. }
  844. }
  845. /// <summary>
  846. /// If term is an Atom or functor type, return its name.
  847. /// Otherwise, return term.
  848. /// </summary>
  849. /// <param name="term"></param>
  850. /// <returns></returns>
  851. public static object getFunctorName(object term)
  852. {
  853. term = YP.getValue(term);
  854. if (term is Functor1)
  855. return ((Functor1)term)._name;
  856. else if (term is Functor2)
  857. return ((Functor2)term)._name;
  858. else if (term is Functor3)
  859. return ((Functor3)term)._name;
  860. else if (term is Functor)
  861. return ((Functor)term)._name;
  862. else
  863. return term;
  864. }
  865. /// <summary>
  866. /// If term is an Atom or functor type, return an array of its args.
  867. /// Otherwise, return an empty array.
  868. /// </summary>
  869. /// <param name="term"></param>
  870. /// <returns></returns>
  871. public static object[] getFunctorArgs(object term)
  872. {
  873. term = YP.getValue(term);
  874. if (term is Functor1)
  875. {
  876. Functor1 functor = (Functor1)term;
  877. return new object[] { functor._arg1 };
  878. }
  879. else if (term is Functor2)
  880. {
  881. Functor2 functor = (Functor2)term;
  882. return new object[] { functor._arg1, functor._arg2 };
  883. }
  884. else if (term is Functor3)
  885. {
  886. Functor3 functor = (Functor3)term;
  887. return new object[] { functor._arg1, functor._arg2, functor._arg3 };
  888. }
  889. else if (term is Functor) {
  890. Functor functor = (Functor)term;
  891. return functor._args;
  892. }
  893. else
  894. return new object[0];
  895. }
  896. public static bool var(object Term)
  897. {
  898. return YP.getValue(Term) is Variable;
  899. }
  900. public static bool nonvar(object Term)
  901. {
  902. return !YP.var(Term);
  903. }
  904. public static bool atom(object Term)
  905. {
  906. return YP.getValue(Term) is Atom;
  907. }
  908. public static bool integer(object Term)
  909. {
  910. // Debug: Should exhaustively check for all integer types.
  911. return getValue(Term) is int;
  912. }
  913. // Use isFloat instead of float because it is a reserved keyword.
  914. public static bool isFloat(object Term)
  915. {
  916. // Debug: Should exhaustively check for all float types.
  917. return getValue(Term) is double;
  918. }
  919. public static bool number(object Term)
  920. {
  921. return YP.integer(Term) || YP.isFloat(Term);
  922. }
  923. public static bool atomic(object Term)
  924. {
  925. return YP.atom(Term) || YP.number(Term);
  926. }
  927. public static bool compound(object Term)
  928. {
  929. Term = getValue(Term);
  930. return Term is Functor1 || Term is Functor2 || Term is Functor3 || Term is Functor;
  931. }
  932. public static void see(object input)
  933. {
  934. input = YP.getValue(input);
  935. if (input is TextReader)
  936. {
  937. _inputStream = (TextReader)input;
  938. return;
  939. }
  940. else if (input is Atom)
  941. {
  942. _inputStream = new StreamReader(((Atom)input)._name);
  943. return;
  944. }
  945. else if (input is String)
  946. {
  947. _inputStream = new StreamReader((String)input);
  948. return;
  949. }
  950. else
  951. throw new InvalidOperationException("Can't open stream for " + input);
  952. }
  953. public static void seen()
  954. {
  955. if (_inputStream == Console.In)
  956. return;
  957. _inputStream.Close();
  958. _inputStream = Console.In;
  959. }
  960. public static void tell(object output)
  961. {
  962. output = YP.getValue(output);
  963. if (output is TextWriter)
  964. {
  965. _outputStream = (TextWriter)output;
  966. return;
  967. }
  968. else if (output is Atom)
  969. {
  970. _outputStream = new StreamWriter(((Atom)output)._name);
  971. return;
  972. }
  973. else if (output is String)
  974. {
  975. _outputStream = new StreamWriter((String)output);
  976. return;
  977. }
  978. else
  979. throw new InvalidOperationException("Can't open stream for " + output);
  980. }
  981. public static void told()
  982. {
  983. if (_outputStream == Console.Out)
  984. return;
  985. _outputStream.Close();
  986. _outputStream = Console.Out;
  987. }
  988. public static IEnumerable<bool> current_output(object Stream)
  989. {
  990. return YP.unify(Stream, _outputStream);
  991. }
  992. public static void write(object x)
  993. {
  994. x = YP.getValue(x);
  995. if (x is double)
  996. _outputStream.Write(doubleToString((double)x));
  997. else
  998. _outputStream.Write(x.ToString());
  999. }
  1000. /// <summary>
  1001. /// Format x as a string, making sure that it will parse as an int later. I.e., for 1.0, don't just
  1002. /// use "1" which will parse as an int.
  1003. /// </summary>
  1004. /// <param name="x"></param>
  1005. /// <returns></returns>
  1006. private static string doubleToString(double x)
  1007. {
  1008. string xString = x.ToString();
  1009. // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
  1010. try
  1011. {
  1012. Convert.ToInt32(xString);
  1013. // The string will parse as an int, not a double, so re-format so that it does.
  1014. // Use float if possible, else exponential if it would be too big.
  1015. return x.ToString(x >= 100000.0 ? "E1" : "f1");
  1016. }
  1017. catch (FormatException)
  1018. {
  1019. // Assume it will parse as a double.
  1020. }
  1021. return xString;
  1022. }
  1023. public static void put_code(object x)
  1024. {
  1025. _outputStream.Write((char)YP.convertInt(x));
  1026. }
  1027. public static void nl()
  1028. {
  1029. _outputStream.WriteLine();
  1030. }
  1031. public static IEnumerable<bool> get_code(object code)
  1032. {
  1033. return YP.unify(code, _inputStream.Read());
  1034. }
  1035. public static void asserta(object Term, Type declaringClass)
  1036. {
  1037. assertDynamic(Term, declaringClass, true);
  1038. }
  1039. public static void assertz(object Term, Type declaringClass)
  1040. {
  1041. assertDynamic(Term, declaringClass, false);
  1042. }
  1043. public static void assertDynamic(object Term, Type declaringClass, bool prepend)
  1044. {
  1045. Term = getValue(Term);
  1046. if (Term is Variable)
  1047. throw new PrologException("instantiation_error", "Term to assert is an unbound variable");
  1048. Variable.CopyStore copyStore = new Variable.CopyStore();
  1049. object TermCopy = makeCopy(Term, copyStore);
  1050. object Head, Body;
  1051. if (TermCopy is Functor2 && ((Functor2)TermCopy)._name == Atom.RULE)
  1052. {
  1053. Head = YP.getValue(((Functor2)TermCopy)._arg1);
  1054. Body = YP.getValue(((Functor2)TermCopy)._arg2);
  1055. }
  1056. else
  1057. {
  1058. Head = TermCopy;
  1059. Body = Atom.a("true");
  1060. }
  1061. Atom name = getFunctorName(Head) as Atom;
  1062. if (name == null)
  1063. // name is a non-Atom, such as a number.
  1064. throw new PrologException
  1065. (new Functor2("type_error", Atom.a("callable"), Head), "Term to assert is not callable");
  1066. object[] args = getFunctorArgs(Head);
  1067. if (!isDynamic(name, args.Length))
  1068. throw new PrologException
  1069. (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
  1070. new Functor2(Atom.SLASH, name, args.Length)),
  1071. "Assert cannot modify static predicate " + name + "/" + args.Length);
  1072. if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true"))
  1073. {
  1074. // Debug: Until IndexedAnswers supports prepend, compile the fact so we can prepend it below.
  1075. if (!prepend)
  1076. {
  1077. // This is a fact with no unbound variables
  1078. // assertFact uses IndexedAnswers, so don't we don't need to compile.
  1079. assertFact(name, args);
  1080. return;
  1081. }
  1082. }
  1083. IClause clause = YPCompiler.compileAnonymousClause(Head, Body, declaringClass);
  1084. // Add the clause to the entry in _predicatesStore.
  1085. NameArity nameArity = new NameArity(name, args.Length);
  1086. List<IClause> clauses;
  1087. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1088. // Create an entry for the nameArity.
  1089. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1090. if (prepend)
  1091. clauses.Insert(0, clause);
  1092. else
  1093. clauses.Add(clause);
  1094. }
  1095. private static bool isDynamic(Atom name, int arity)
  1096. {
  1097. if (arity == 2 && (name == Atom.a(",") || name == Atom.a(";") || name == Atom.DOT))
  1098. return false;
  1099. // Use the same mapping to static predicates in YP as the compiler.
  1100. // disable warning: don't see how we can code this differently short
  1101. // of rewriting the whole thing
  1102. #pragma warning disable 0168
  1103. foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable()))
  1104. return false;
  1105. // Debug: Do we need to check if name._module is null?
  1106. #pragma warning restore 0168
  1107. return true;
  1108. }
  1109. /// <summary>
  1110. /// Assert values at the end of the set of facts for the predicate with the
  1111. /// name and with arity values.Length.
  1112. /// </summary>
  1113. /// <param name="name">must be an Atom</param>
  1114. /// <param name="values">the array of arguments to the fact predicate.
  1115. /// It is an error if an value has an unbound variable.</param>
  1116. public static void assertFact(Atom name, object[] values)
  1117. {
  1118. NameArity nameArity = new NameArity(name, values.Length);
  1119. List<IClause> clauses;
  1120. IndexedAnswers indexedAnswers;
  1121. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1122. {
  1123. // Create an IndexedAnswers as the first clause of the predicate.
  1124. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1125. clauses.Add(indexedAnswers = new IndexedAnswers());
  1126. }
  1127. else
  1128. {
  1129. indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers;
  1130. if (indexedAnswers == null)
  1131. // The latest clause is not an IndexedAnswers, so add one.
  1132. clauses.Add(indexedAnswers = new IndexedAnswers());
  1133. }
  1134. indexedAnswers.addAnswer(values);
  1135. }
  1136. /// <summary>
  1137. /// Match all clauses of the dynamic predicate with the name and with arity
  1138. /// arguments.Length.
  1139. /// It is an error if the predicate is not defined.
  1140. /// </summary>
  1141. /// <param name="name">must be an Atom</param>
  1142. /// <param name="arguments">an array of arity number of arguments</param>
  1143. /// <returns>an iterator which you can use in foreach</returns>
  1144. public static IEnumerable<bool> matchDynamic(Atom name, object[] arguments)
  1145. {
  1146. List<IClause> clauses;
  1147. if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses))
  1148. throw new UndefinedPredicateException
  1149. ("Undefined fact: " + name + "/" + arguments.Length, name,
  1150. arguments.Length);
  1151. if (clauses.Count == 1)
  1152. // Usually there is only one clause, so return it without needing to wrap it in an iterator.
  1153. return clauses[0].match(arguments);
  1154. else
  1155. return matchAllClauses(clauses, arguments);
  1156. }
  1157. /// <summary>
  1158. /// Call match(arguments) for each IClause in clauses. We make this a separate
  1159. /// function so that matchDynamic itself does not need to be an iterator object.
  1160. /// </summary>
  1161. /// <param name="clauses"></param>
  1162. /// <param name="arguments"></param>
  1163. /// <returns></returns>
  1164. private static IEnumerable<bool> matchAllClauses(List<IClause> clauses, object[] arguments)
  1165. {
  1166. // Debug: If the clause asserts another clause into this same predicate, the iterator
  1167. // over clauses will be corrupted. Should we take the time to copy clauses?
  1168. foreach (IClause clause in clauses)
  1169. {
  1170. foreach (bool lastCall in clause.match(arguments))
  1171. {
  1172. yield return false;
  1173. if (lastCall)
  1174. // This happens after a cut in a clause.
  1175. yield break;
  1176. }
  1177. }
  1178. }
  1179. /// <summary>
  1180. /// This is deprecated and just calls matchDynamic. This matches all clauses,
  1181. /// not just the ones defined with assertFact.
  1182. /// </summary>
  1183. /// <param name="name"></param>
  1184. /// <param name="arguments"></param>
  1185. /// <returns></returns>
  1186. public static IEnumerable<bool> matchFact(Atom name, object[] arguments)
  1187. {
  1188. return matchDynamic(name, arguments);
  1189. }
  1190. /// <summary>
  1191. /// This actually searches all clauses, not just
  1192. /// the ones defined with assertFact, but we keep the name for
  1193. /// backwards compatibility.
  1194. /// </summary>
  1195. /// <param name="name">must be an Atom</param>
  1196. /// <param name="arguments">an array of arity number of arguments</param>
  1197. public static void retractFact(Atom name, object[] arguments)
  1198. {
  1199. NameArity nameArity = new NameArity(name, arguments.Length);
  1200. List<IClause> clauses;
  1201. if (!_predicatesStore.TryGetValue(nameArity, out clauses))
  1202. // Can't find, so ignore.
  1203. return;
  1204. foreach (object arg in arguments)
  1205. {
  1206. if (!YP.var(arg))
  1207. throw new InvalidOperationException("All arguments must be unbound");
  1208. }
  1209. // Set to a fresh empty IndexedAnswers.
  1210. _predicatesStore[nameArity] = (clauses = new List<IClause>());
  1211. clauses.Add(new IndexedAnswers());
  1212. }
  1213. public static IEnumerable<bool> current_predicate(object NameSlashArity)
  1214. {
  1215. NameSlashArity = YP.getValue(NameSlashArity);
  1216. // First check if Name and Arity are nonvar so we can do a direct lookup.
  1217. if (YP.ground(NameSlashArity))
  1218. {
  1219. if (NameSlashArity is Functor2)
  1220. {
  1221. Functor2 NameArityFunctor = (Functor2)NameSlashArity;
  1222. if (NameArityFunctor._name == Atom.SLASH)
  1223. {
  1224. if (_predicatesStore.ContainsKey(new NameArity
  1225. ((Atom)YP.getValue(NameArityFunctor._arg1),
  1226. (int)YP.getValue(NameArityFunctor._arg2))))
  1227. // The predicate is defined.
  1228. yield return false;
  1229. }
  1230. }
  1231. yield break;
  1232. }
  1233. foreach (NameArity key in _predicatesStore.Keys)
  1234. {
  1235. // disable warning: don't see how we can code this differently short
  1236. // of rewriting the whole thing
  1237. #pragma warning disable 0168
  1238. foreach (bool l1 in YP.unify
  1239. (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity))
  1240. yield return false;
  1241. #pragma warning restore 0168
  1242. }
  1243. }
  1244. /// <summary>
  1245. /// Use YP.getFunctorName(Goal) and invoke the static method of this name in the
  1246. /// declaringClass, using arguments from YP.getFunctorArgs(Goal).
  1247. /// Note that Goal must be a simple functor, not a complex expression.
  1248. /// If not found, this throws UndefinedPredicateException.
  1249. /// </summary>
  1250. /// <param name="Goal"></param>
  1251. /// <param name="contextClass">the class for looking up default function references</param>
  1252. /// <returns></returns>
  1253. public static IEnumerable<bool> getIterator(object Goal, Type declaringClass)
  1254. {
  1255. Goal = YP.getValue(Goal);
  1256. if (Goal is Variable)
  1257. throw new PrologException("instantiation_error", "Goal to call is an unbound variable");
  1258. #if true
  1259. List<Variable> variableSetList = new List<Variable>();
  1260. addUniqueVariables(Goal, variableSetList);
  1261. Variable[] variableSet = variableSetList.ToArray();
  1262. // Use Atom.F since it is ignored.
  1263. return YPCompiler.compileAnonymousClause
  1264. (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet);
  1265. #else
  1266. Atom name;
  1267. object[] args;
  1268. while (true)
  1269. {
  1270. name = (Atom)YP.getFunctorName(Goal);
  1271. args = YP.getFunctorArgs(Goal);
  1272. if (name == Atom.HAT && args.Length == 2)
  1273. // Assume this is called from a bagof operation. Skip the leading qualifiers.
  1274. Goal = YP.getValue(((Functor2)Goal)._arg2);
  1275. else
  1276. break;
  1277. }
  1278. try
  1279. {
  1280. return (IEnumerable<bool>)declaringClass.InvokeMember
  1281. (name._name, BindingFlags.InvokeMethod, null, null, args);
  1282. }
  1283. catch (TargetInvocationException exception)
  1284. {
  1285. throw exception.InnerException;
  1286. }
  1287. catch (MissingMethodException)
  1288. {
  1289. throw new UndefinedPredicateException
  1290. ("Cannot find predicate function: " + name + "/" + args.Length + " in " +
  1291. declaringClass.FullName, name, args.Length);
  1292. }
  1293. #endif
  1294. }
  1295. public static void throwException(object Term)
  1296. {
  1297. throw new PrologException(Term);
  1298. }
  1299. /// <summary>
  1300. /// script_event calls hosting script with events as a callback method.
  1301. /// </summary>
  1302. /// <param name="script_event"></param>
  1303. /// <param name="script_params"></param>
  1304. /// <returns></returns>
  1305. public static void script_event(object script_event, object script_params)
  1306. {
  1307. // string function = ((Atom)YP.getValue(script_event))._name;
  1308. object[] array = ListPair.toArray(script_params);
  1309. if (array == null)
  1310. return; // YP.fail();
  1311. if (array.Length > 1)
  1312. {
  1313. //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue
  1314. //(localID, itemID, function, array);
  1315. // sortArray(array);
  1316. }
  1317. //return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array));
  1318. }
  1319. /// <summary>
  1320. /// An enumerator that does zero loops.
  1321. /// </summary>
  1322. private class Fail : IEnumerator<bool>, IEnumerable<bool>
  1323. {
  1324. public bool MoveNext()
  1325. {
  1326. return false;
  1327. }
  1328. public IEnumerator<bool> GetEnumerator()
  1329. {
  1330. return (IEnumerator<bool>)this;
  1331. }
  1332. IEnumerator IEnumerable.GetEnumerator()
  1333. {
  1334. return GetEnumerator();
  1335. }
  1336. public bool Current
  1337. {
  1338. get { return true; }
  1339. }
  1340. object IEnumerator.Current
  1341. {
  1342. get { return true; }
  1343. }
  1344. public void Dispose()
  1345. {
  1346. }
  1347. public void Reset()
  1348. {
  1349. throw new NotImplementedException();
  1350. }
  1351. }
  1352. /// <summary>
  1353. /// An enumerator that does one iteration.
  1354. /// </summary>
  1355. private class Succeed : IEnumerator<bool>, IEnumerable<bool>
  1356. {
  1357. private bool _didIteration = false;
  1358. public bool MoveNext()
  1359. {
  1360. if (!_didIteration)
  1361. {
  1362. _didIteration = true;
  1363. return true;
  1364. }
  1365. else
  1366. return false;
  1367. }
  1368. public IEnumerator<bool> GetEnumerator()
  1369. {
  1370. return (IEnumerator<bool>)this;
  1371. }
  1372. IEnumerator IEnumerable.GetEnumerator()
  1373. {
  1374. return GetEnumerator();
  1375. }
  1376. public bool Current
  1377. {
  1378. get { return false; }
  1379. }
  1380. object IEnumerator.Current
  1381. {
  1382. get { return false; }
  1383. }
  1384. public void Dispose()
  1385. {
  1386. }
  1387. public void Reset()
  1388. {
  1389. throw new NotImplementedException();
  1390. }
  1391. }
  1392. /// <summary>
  1393. /// An enumerator that repeats forever.
  1394. /// </summary>
  1395. private class Repeat : IEnumerator<bool>, IEnumerable<bool>
  1396. {
  1397. public bool MoveNext()
  1398. {
  1399. return true;
  1400. }
  1401. public IEnumerator<bool> GetEnumerator()
  1402. {
  1403. return (IEnumerator<bool>)this;
  1404. }
  1405. IEnumerator IEnumerable.GetEnumerator()
  1406. {
  1407. return GetEnumerator();
  1408. }
  1409. public bool Current
  1410. {
  1411. get { return false; }
  1412. }
  1413. object IEnumerator.Current
  1414. {
  1415. get { return false; }
  1416. }
  1417. public void Dispose()
  1418. {
  1419. }
  1420. public void Reset()
  1421. {
  1422. throw new NotImplementedException();
  1423. }
  1424. }
  1425. /// <summary>
  1426. /// An enumerator that wraps another enumerator in order to catch a PrologException.
  1427. /// </summary>
  1428. public class Catch : IEnumerator<bool>, IEnumerable<bool>
  1429. {
  1430. private IEnumerator<bool> _enumerator;
  1431. private PrologException _exception = null;
  1432. public Catch(IEnumerable<bool> iterator)
  1433. {
  1434. _enumerator = iterator.GetEnumerator();
  1435. }
  1436. /// <summary>
  1437. /// Call _enumerator.MoveNext(). If it throws a PrologException, set _exception
  1438. /// and return false. After this returns false, call unifyExceptionOrThrow.
  1439. /// Assume that, after this returns false, it will not be called again.
  1440. /// </summary>
  1441. /// <returns></returns>
  1442. public bool MoveNext()
  1443. {
  1444. try
  1445. {
  1446. return _enumerator.MoveNext();
  1447. }
  1448. catch (PrologException exception)
  1449. {
  1450. _exception = exception;
  1451. return false;
  1452. }
  1453. }
  1454. /// <summary>
  1455. /// Call this after MoveNext() returns false to check for an exception. If
  1456. /// MoveNext did not get a PrologException, don't yield.
  1457. /// Otherwise, unify the exception with Catcher and yield so the caller can
  1458. /// do the handler code. However, if can't unify with Catcher then throw the exception.
  1459. /// </summary>
  1460. /// <param name="Catcher"></param>
  1461. /// <returns></returns>
  1462. public IEnumerable<bool> unifyExceptionOrThrow(object Catcher)
  1463. {
  1464. if (_exception != null)
  1465. {
  1466. bool didUnify = false;
  1467. // disable warning: don't see how we can code this differently short
  1468. // of rewriting the whole thing
  1469. #pragma warning disable 0168
  1470. foreach (bool l1 in YP.unify(_exception._term, Catcher))
  1471. {
  1472. didUnify = true;
  1473. yield return false;
  1474. }
  1475. #pragma warning restore 0168
  1476. if (!didUnify)
  1477. throw _exception;
  1478. }
  1479. }
  1480. public IEnumerator<bool> GetEnumerator()
  1481. {
  1482. return (IEnumerator<bool>)this;
  1483. }
  1484. IEnumerator IEnumerable.GetEnumerator()
  1485. {
  1486. return GetEnumerator();
  1487. }
  1488. public bool Current
  1489. {
  1490. get { return _enumerator.Current; }
  1491. }
  1492. object IEnumerator.Current
  1493. {
  1494. get { return _enumerator.Current; }
  1495. }
  1496. public void Dispose()
  1497. {
  1498. _enumerator.Dispose();
  1499. }
  1500. public void Reset()
  1501. {
  1502. throw new NotImplementedException();
  1503. }
  1504. }
  1505. }
  1506. }