YP.cs 95 KB

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