diff options
author | Jeff Ames | 2008-06-01 03:01:33 +0000 |
---|---|---|
committer | Jeff Ames | 2008-06-01 03:01:33 +0000 |
commit | d22a54a19568f8d5e9b6dab1f76f9c5c58682aa5 (patch) | |
tree | 2311b4c6ad2617cc71b975460c48e723a7e027ee /OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs | |
parent | * Committing some stuff I'm working to make it so I can commit an upcoming pa... (diff) | |
download | opensim-SC-d22a54a19568f8d5e9b6dab1f76f9c5c58682aa5.zip opensim-SC-d22a54a19568f8d5e9b6dab1f76f9c5c58682aa5.tar.gz opensim-SC-d22a54a19568f8d5e9b6dab1f76f9c5c58682aa5.tar.bz2 opensim-SC-d22a54a19568f8d5e9b6dab1f76f9c5c58682aa5.tar.xz |
Update svn properties.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs | 2880 |
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 | ||
31 | using System; | 31 | using System; |
32 | using System.Collections; | 32 | using System.Collections; |
33 | using System.Collections.Generic; | 33 | using System.Collections.Generic; |
34 | using System.IO; | 34 | using System.IO; |
35 | using System.Reflection; | 35 | using System.Reflection; |
36 | 36 | ||
37 | namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog | 37 | namespace 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 | } |