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