aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
diff options
context:
space:
mode:
authorCharles Krinke2008-08-13 14:13:49 +0000
committerCharles Krinke2008-08-13 14:13:49 +0000
commit323ada012d3bed0c6f7a6d5d0ee14b409b7457c7 (patch)
treed5a2e30707baba7804aefb341774d6d51ca7b439 /OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
parentThank you, tyre, for a patch that fixes a null reference in LSL (diff)
downloadopensim-SC_OLD-323ada012d3bed0c6f7a6d5d0ee14b409b7457c7.zip
opensim-SC_OLD-323ada012d3bed0c6f7a6d5d0ee14b409b7457c7.tar.gz
opensim-SC_OLD-323ada012d3bed0c6f7a6d5d0ee14b409b7457c7.tar.bz2
opensim-SC_OLD-323ada012d3bed0c6f7a6d5d0ee14b409b7457c7.tar.xz
Mantis#1931. Thank you kindly, Kinoc for a patch that:
* Yield Prolog 1.0.1 Released : it passes all but 9 of the 421 tests in the ISO Prolog test suite (97.8%) . * support dynamic predicates and rules. * support 'import' to use external static functions improves connection to C# functions * Matches Yield Prolog r831
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs319
1 files changed, 303 insertions, 16 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
index 76e307a..97c9087 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
@@ -52,6 +52,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
52 private static TextWriter _outputStream = System.Console.Out; 52 private static TextWriter _outputStream = System.Console.Out;
53 private static TextReader _inputStream = System.Console.In; 53 private static TextReader _inputStream = System.Console.In;
54 private static IndexedAnswers _operatorTable = null; 54 private static IndexedAnswers _operatorTable = null;
55 private static Dictionary<string, object> _prologFlags = new Dictionary<string, object>();
56 public const int MAX_ARITY = 255;
55 57
56 /// <summary> 58 /// <summary>
57 /// An IClause is used so that dynamic predicates can call match. 59 /// An IClause is used so that dynamic predicates can call match.
@@ -62,6 +64,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
62 IEnumerable<bool> clause(object Head, object Body); 64 IEnumerable<bool> clause(object Head, object Body);
63 } 65 }
64 66
67 /// <summary>
68 /// If value is a Variable, then return its getValue. Otherwise, just
69 /// return value. You should call YP.getValue on any object that
70 /// may be a Variable to get the value to pass to other functions in
71 /// your system that are not part of Yield Prolog, such as math functions
72 /// or file I/O.
73 /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
74 /// </summary>
75 /// <param name="value"></param>
76 /// <returns></returns>
65 public static object getValue(object value) 77 public static object getValue(object value)
66 { 78 {
67 if (value is Variable) 79 if (value is Variable)
@@ -70,6 +82,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
70 return value; 82 return value;
71 } 83 }
72 84
85 /// <summary>
86 /// If arg1 or arg2 is an object with a unify method (such as Variable or
87 /// Functor) then just call its unify with the other argument. The object's
88 /// unify method will bind the values or check for equals as needed.
89 /// Otherwise, both arguments are "normal" (atomic) values so if they
90 /// are equal then succeed (yield once), else fail (don't yield).
91 /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
92 /// </summary>
93 /// <param name="arg1"></param>
94 /// <param name="arg2"></param>
95 /// <returns></returns>
73 public static IEnumerable<bool> unify(object arg1, object arg2) 96 public static IEnumerable<bool> unify(object arg1, object arg2)
74 { 97 {
75 arg1 = getValue(arg1); 98 arg1 = getValue(arg1);
@@ -622,6 +645,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
622 if (args.Length == 0) 645 if (args.Length == 0)
623 // Return the Name, even if it is not an Atom. 646 // Return the Name, even if it is not an Atom.
624 return YP.unify(Term, Name); 647 return YP.unify(Term, Name);
648 if (args.Length > MAX_ARITY)
649 throw new PrologException
650 (new Functor1("representation_error", Atom.a("max_arity")),
651 "Functor arity " + args.Length + " may not be greater than " + MAX_ARITY);
625 if (!atom(Name)) 652 if (!atom(Name))
626 throw new PrologException 653 throw new PrologException
627 (new Functor2("type_error", Atom.a("atom"), Name), 654 (new Functor2("type_error", Atom.a("atom"), Name),
@@ -666,6 +693,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
666 } 693 }
667 else 694 else
668 { 695 {
696 if ((int)Arity > MAX_ARITY)
697 throw new PrologException
698 (new Functor1("representation_error", Atom.a("max_arity")),
699 "Functor arity " + Arity + " may not be greater than " + MAX_ARITY);
669 if (!(FunctorName is Atom)) 700 if (!(FunctorName is Atom))
670 throw new PrologException 701 throw new PrologException
671 (new Functor2("type_error", Atom.a("atom"), FunctorName), "FunctorName is not an atom"); 702 (new Functor2("type_error", Atom.a("atom"), FunctorName), "FunctorName is not an atom");
@@ -903,8 +934,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
903 _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") }); 934 _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") });
904 } 935 }
905 936
906 foreach (bool l1 in _operatorTable.match(new object[] { Priority, Specifier, Operator })) 937 return _operatorTable.match(new object[] { Priority, Specifier, Operator });
907 yield return false;
908 } 938 }
909 939
910 public static IEnumerable<bool> atom_length(object atom, object Length) 940 public static IEnumerable<bool> atom_length(object atom, object Length)
@@ -1491,9 +1521,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1491 return Term is Functor1 || Term is Functor2 || Term is Functor3 || Term is Functor; 1521 return Term is Functor1 || Term is Functor2 || Term is Functor3 || Term is Functor;
1492 } 1522 }
1493 1523
1524 /// <summary>
1525 /// If input is a TextReader, use it. If input is an Atom or String, create a StreamReader with the
1526 /// input as the filename. If input is a Prolog list, then read character codes from it.
1527 /// </summary>
1528 /// <param name="input"></param>
1494 public static void see(object input) 1529 public static void see(object input)
1495 { 1530 {
1496 input = YP.getValue(input); 1531 input = YP.getValue(input);
1532 if (input is Variable)
1533 throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable");
1534
1535 if (input == null)
1536 {
1537 _inputStream = null;
1538 return;
1539 }
1497 if (input is TextReader) 1540 if (input is TextReader)
1498 { 1541 {
1499 _inputStream = (TextReader)input; 1542 _inputStream = (TextReader)input;
@@ -1509,21 +1552,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1509 _inputStream = new StreamReader((String)input); 1552 _inputStream = new StreamReader((String)input);
1510 return; 1553 return;
1511 } 1554 }
1555 else if (input is Functor2 && ((Functor2)input)._name == Atom.DOT)
1556 {
1557 _inputStream = new CodeListReader(input);
1558 return;
1559 }
1512 else 1560 else
1513 throw new InvalidOperationException("Can't open stream for " + input); 1561 throw new PrologException
1562 (new Functor2("domain_error", Atom.a("stream_or_alias"), input),
1563 "Input stream specifier not recognized");
1514 } 1564 }
1515 1565
1516 public static void seen() 1566 public static void seen()
1517 { 1567 {
1568 if (_inputStream == null)
1569 return;
1518 if (_inputStream == Console.In) 1570 if (_inputStream == Console.In)
1519 return; 1571 return;
1520 _inputStream.Close(); 1572 _inputStream.Close();
1521 _inputStream = Console.In; 1573 _inputStream = Console.In;
1522 } 1574 }
1523 1575
1576 public static IEnumerable<bool> current_input(object Stream)
1577 {
1578 return YP.unify(Stream, _inputStream);
1579 }
1580
1581 /// <summary>
1582 /// If output is a TextWriter, use it. If output is an Atom or a String, create a StreamWriter
1583 /// with the input as the filename.
1584 /// </summary>
1585 /// <param name="output"></param>
1524 public static void tell(object output) 1586 public static void tell(object output)
1525 { 1587 {
1526 output = YP.getValue(output); 1588 output = YP.getValue(output);
1589 if (output is Variable)
1590 throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable");
1591
1592 if (output == null)
1593 {
1594 _outputStream = null;
1595 return;
1596 }
1527 if (output is TextWriter) 1597 if (output is TextWriter)
1528 { 1598 {
1529 _outputStream = (TextWriter)output; 1599 _outputStream = (TextWriter)output;
@@ -1540,11 +1610,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1540 return; 1610 return;
1541 } 1611 }
1542 else 1612 else
1543 throw new InvalidOperationException("Can't open stream for " + output); 1613 throw new PrologException
1614 (new Functor2("domain_error", Atom.a("stream_or_alias"), output),
1615 "Can't open stream for " + output);
1544 } 1616 }
1545 1617
1546 public static void told() 1618 public static void told()
1547 { 1619 {
1620 if (_outputStream == null)
1621 return;
1548 if (_outputStream == Console.Out) 1622 if (_outputStream == Console.Out)
1549 return; 1623 return;
1550 _outputStream.Close(); 1624 _outputStream.Close();
@@ -1558,6 +1632,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1558 1632
1559 public static void write(object x) 1633 public static void write(object x)
1560 { 1634 {
1635 if (_outputStream == null)
1636 return;
1561 x = YP.getValue(x); 1637 x = YP.getValue(x);
1562 if (x is double) 1638 if (x is double)
1563 _outputStream.Write(doubleToString((double)x)); 1639 _outputStream.Write(doubleToString((double)x));
@@ -1591,6 +1667,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1591 1667
1592 public static void put_code(object x) 1668 public static void put_code(object x)
1593 { 1669 {
1670 if (_outputStream == null)
1671 return;
1594 if (var(x)) 1672 if (var(x))
1595 throw new PrologException(Atom.a("instantiation_error"), "Arg 1 is an unbound variable"); 1673 throw new PrologException(Atom.a("instantiation_error"), "Arg 1 is an unbound variable");
1596 int xInt; 1674 int xInt;
@@ -1602,11 +1680,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1602 1680
1603 public static void nl() 1681 public static void nl()
1604 { 1682 {
1683 if (_outputStream == null)
1684 return;
1605 _outputStream.WriteLine(); 1685 _outputStream.WriteLine();
1606 } 1686 }
1607 1687
1608 public static IEnumerable<bool> get_code(object code) 1688 public static IEnumerable<bool> get_code(object code)
1609 { 1689 {
1690 if (_inputStream == null)
1691 return YP.unify(code, -1);
1692 else
1610 return YP.unify(code, _inputStream.Read()); 1693 return YP.unify(code, _inputStream.Read());
1611 } 1694 }
1612 1695
@@ -1763,7 +1846,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1763 /// <summary> 1846 /// <summary>
1764 /// Match all clauses of the dynamic predicate with the name and with arity 1847 /// Match all clauses of the dynamic predicate with the name and with arity
1765 /// arguments.Length. 1848 /// arguments.Length.
1766 /// It is an error if the predicate is not defined. 1849 /// If the predicate is not defined, return the result of YP.unknownPredicate.
1767 /// </summary> 1850 /// </summary>
1768 /// <param name="name">must be an Atom</param> 1851 /// <param name="name">must be an Atom</param>
1769 /// <param name="arguments">an array of arity number of arguments</param> 1852 /// <param name="arguments">an array of arity number of arguments</param>
@@ -1772,11 +1855,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1772 { 1855 {
1773 List<IClause> clauses; 1856 List<IClause> clauses;
1774 if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses)) 1857 if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses))
1775 throw new PrologException 1858 return unknownPredicate(name, arguments.Length,
1776 (new Functor2 1859 "Undefined dynamic predicate: " + name + "/" + arguments.Length);
1777 (Atom.a("existence_error"), Atom.a("procedure"),
1778 new Functor2(Atom.SLASH, name, arguments.Length)),
1779 "Undefined predicate: " + name + "/" + arguments.Length);
1780 1860
1781 if (clauses.Count == 1) 1861 if (clauses.Count == 1)
1782 // Usually there is only one clause, so return it without needing to wrap it in an iterator. 1862 // Usually there is only one clause, so return it without needing to wrap it in an iterator.
@@ -1809,6 +1889,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1809 } 1889 }
1810 1890
1811 /// <summary> 1891 /// <summary>
1892 /// If _prologFlags["unknown"] is fail then return fail(), else if
1893 /// _prologFlags["unknown"] is warning then write the message to YP.write and
1894 /// return fail(), else throw a PrologException for existence_error. .
1895 /// </summary>
1896 /// <param name="name"></param>
1897 /// <param name="arity"></param>
1898 /// <param name="message"></param>
1899 /// <returns></returns>
1900 public static IEnumerable<bool> unknownPredicate(Atom name, int arity, string message)
1901 {
1902 establishPrologFlags();
1903
1904 if (_prologFlags["unknown"] == Atom.a("fail"))
1905 return fail();
1906 else if (_prologFlags["unknown"] == Atom.a("warning"))
1907 {
1908 write(message);
1909 nl();
1910 return fail();
1911 }
1912 else
1913 throw new PrologException
1914 (new Functor2
1915 (Atom.a("existence_error"), Atom.a("procedure"),
1916 new Functor2(Atom.SLASH, name, arity)), message);
1917 }
1918
1919 /// <summary>
1812 /// This is deprecated and just calls matchDynamic. This matches all clauses, 1920 /// This is deprecated and just calls matchDynamic. This matches all clauses,
1813 /// not just the ones defined with assertFact. 1921 /// not just the ones defined with assertFact.
1814 /// </summary> 1922 /// </summary>
@@ -1951,7 +2059,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1951 _predicatesStore[nameArity] = new List<IClause>(); 2059 _predicatesStore[nameArity] = new List<IClause>();
1952 } 2060 }
1953 2061
1954 public static IEnumerable<bool> current_predicate(object NameSlashArity) 2062 /// <summary>
2063 /// If NameSlashArity is var, match with all the dynamic predicates using the
2064 /// Name/Artity form.
2065 /// If NameSlashArity is not var, check if the Name/Arity exists as a static or
2066 /// dynamic predicate.
2067 /// </summary>
2068 /// <param name="NameSlashArity"></param>
2069 /// <param name="declaringClass">if not null, used to resolve references to the default
2070 /// module Atom.a("")</param>
2071 /// <returns></returns>
2072 public static IEnumerable<bool> current_predicate(object NameSlashArity, Type declaringClass)
1955 { 2073 {
1956 NameSlashArity = YP.getValue(NameSlashArity); 2074 NameSlashArity = YP.getValue(NameSlashArity);
1957 // First check if Name and Arity are nonvar so we can do a direct lookup. 2075 // First check if Name and Arity are nonvar so we can do a direct lookup.
@@ -1976,7 +2094,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1976 (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity), 2094 (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
1977 "Arity may not be less than zero"); 2095 "Arity may not be less than zero");
1978 2096
1979 if (_predicatesStore.ContainsKey(new NameArity((Atom)name, (int)arity))) 2097 if (YPCompiler.isCurrentPredicate((Atom)name, (int)arity, declaringClass))
1980 // The predicate is defined. 2098 // The predicate is defined.
1981 yield return false; 2099 yield return false;
1982 } 2100 }
@@ -1991,6 +2109,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1991 } 2109 }
1992 } 2110 }
1993 2111
2112 /// <summary>
2113 /// Return true if the dynamic predicate store has an entry for the predicate
2114 /// with name and arity.
2115 /// </summary>
2116 /// <param name="name"></param>
2117 /// <param name="arity"></param>
2118 /// <returns></returns>
2119 public static bool isDynamicCurrentPredicate(Atom name, int arity)
2120 {
2121 return _predicatesStore.ContainsKey(new NameArity(name, arity));
2122 }
2123
1994 public static void abolish(object NameSlashArity) 2124 public static void abolish(object NameSlashArity)
1995 { 2125 {
1996 NameSlashArity = YP.getValue(NameSlashArity); 2126 NameSlashArity = YP.getValue(NameSlashArity);
@@ -2019,6 +2149,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
2019 throw new PrologException 2149 throw new PrologException
2020 (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity), 2150 (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
2021 "Arity may not be less than zero"); 2151 "Arity may not be less than zero");
2152 if ((int)arity > MAX_ARITY)
2153 throw new PrologException
2154 (new Functor1("representation_error", Atom.a("max_arity")),
2155 "Arity may not be greater than " + MAX_ARITY);
2022 2156
2023 if (isSystemPredicate((Atom)name, (int)arity)) 2157 if (isSystemPredicate((Atom)name, (int)arity))
2024 throw new PrologException 2158 throw new PrologException
@@ -2077,7 +2211,108 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
2077 { 2211 {
2078 throw new PrologException(Term); 2212 throw new PrologException(Term);
2079 } 2213 }
2214 /// <summary>
2215 /// This must be called by any function that uses YP._prologFlags to make sure
2216 /// the initial defaults are loaded.
2217 /// </summary>
2218 private static void establishPrologFlags()
2219 {
2220 if (_prologFlags.Count > 0)
2221 // Already established.
2222 return;
2223
2224 // List these in the order they appear in the ISO standard.
2225 _prologFlags["bounded"] = Atom.a("true");
2226 _prologFlags["max_integer"] = Int32.MaxValue;
2227 _prologFlags["min_integer"] = Int32.MinValue;
2228 _prologFlags["integer_rounding_function"] = Atom.a("toward_zero");
2229 _prologFlags["char_conversion"] = Atom.a("off");
2230 _prologFlags["debug"] = Atom.a("off");
2231 _prologFlags["max_arity"] = MAX_ARITY;
2232 _prologFlags["unknown"] = Atom.a("error");
2233 _prologFlags["double_quotes"] = Atom.a("codes");
2234 }
2235
2236 public static IEnumerable<bool> current_prolog_flag(object Key, object Value)
2237 {
2238 establishPrologFlags();
2239
2240 Key = YP.getValue(Key);
2241 Value = YP.getValue(Value);
2242
2243 if (Key is Variable)
2244 {
2245 // Bind all key values.
2246 foreach (string key in _prologFlags.Keys)
2247 {
2248 foreach (bool l1 in YP.unify(Key, Atom.a(key)))
2249 {
2250 foreach (bool l2 in YP.unify(Value, _prologFlags[key]))
2251 yield return false;
2252 }
2253 }
2254 }
2255 else
2256 {
2257 if (!(Key is Atom))
2258 throw new PrologException
2259 (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom");
2260 if (!_prologFlags.ContainsKey(((Atom)Key)._name))
2261 throw new PrologException
2262 (new Functor2("domain_error", Atom.a("prolog_flag"), Key),
2263 "Arg 1 Key is not a recognized flag");
2264
2265 foreach (bool l1 in YP.unify(Value, _prologFlags[((Atom)Key)._name]))
2266 yield return false;
2267 }
2268 }
2269
2270 public static void set_prolog_flag(object Key, object Value)
2271 {
2272 establishPrologFlags();
2273
2274 Key = YP.getValue(Key);
2275 Value = YP.getValue(Value);
2276
2277 if (Key is Variable)
2278 throw new PrologException(Atom.a("instantiation_error"),
2279 "Arg 1 Key is an unbound variable");
2280 if (Value is Variable)
2281 throw new PrologException(Atom.a("instantiation_error"),
2282 "Arg 1 Key is an unbound variable");
2283 if (!(Key is Atom))
2284 throw new PrologException
2285 (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom");
2286
2287 string keyName = ((Atom)Key)._name;
2288 if (!_prologFlags.ContainsKey(keyName))
2289 throw new PrologException
2290 (new Functor2("domain_error", Atom.a("prolog_flag"), Key),
2291 "Arg 1 Key " + Key + " is not a recognized flag");
2292
2293 bool valueIsOK = false;
2294 if (keyName == "char_conversion")
2295 valueIsOK = (Value == _prologFlags[keyName]);
2296 else if (keyName == "debug")
2297 valueIsOK = (Value == _prologFlags[keyName]);
2298 else if (keyName == "unknown")
2299 valueIsOK = (Value == Atom.a("fail") || Value == Atom.a("warning") ||
2300 Value == Atom.a("error"));
2301 else if (keyName == "double_quotes")
2302 valueIsOK = (Value == Atom.a("codes") || Value == Atom.a("chars") ||
2303 Value == Atom.a("atom"));
2304 else
2305 throw new PrologException
2306 (new Functor3("permission_error", Atom.a("modify"), Atom.a("flag"), Key),
2307 "May not modify Prolog flag " + Key);
2080 2308
2309 if (!valueIsOK)
2310 throw new PrologException
2311 (new Functor2("domain_error", Atom.a("flag_value"), new Functor2("+", Key, Value)),
2312 "May not set arg 1 Key " + Key + " to arg 2 Value " + Value);
2313
2314 _prologFlags[keyName] = Value;
2315 }
2081 /// <summary> 2316 /// <summary>
2082 /// script_event calls hosting script with events as a callback method. 2317 /// script_event calls hosting script with events as a callback method.
2083 /// </summary> 2318 /// </summary>
@@ -2303,19 +2538,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
2303 private IEnumerator<bool> _enumerator; 2538 private IEnumerator<bool> _enumerator;
2304 private PrologException _exception = null; 2539 private PrologException _exception = null;
2305 2540
2306 public Catch(IEnumerable<bool> iterator) 2541 /// <summary>
2542 /// Call YP.getIterator(Goal, declaringClass) and save the returned iterator.
2543 /// If getIterator throws an exception, save it the same as MoveNext().
2544 /// </summary>
2545 /// <param name="Goal"></param>
2546 /// <param name="declaringClass"></param>
2547 public Catch(object Goal, Type declaringClass)
2548 {
2549 try
2307 { 2550 {
2308 _enumerator = iterator.GetEnumerator(); 2551 _enumerator = getIterator(Goal, declaringClass).GetEnumerator();
2552 }
2553 catch (PrologException exception)
2554 {
2555 // MoveNext() will check this.
2556 _exception = exception;
2557 }
2309 } 2558 }
2310 2559
2311 /// <summary> 2560 /// <summary>
2312 /// Call _enumerator.MoveNext(). If it throws a PrologException, set _exception 2561 /// Call _enumerator.MoveNext(). If it throws a PrologException, set _exception
2313 /// and return false. After this returns false, call unifyExceptionOrThrow. 2562 /// and return false. After this returns false, call unifyExceptionOrThrow.
2314 /// Assume that, after this returns false, it will not be called again.
2315 /// </summary> 2563 /// </summary>
2316 /// <returns></returns> 2564 /// <returns></returns>
2317 public bool MoveNext() 2565 public bool MoveNext()
2318 { 2566 {
2567 if (_exception != null)
2568 return false;
2569
2319 try 2570 try
2320 { 2571 {
2321 return _enumerator.MoveNext(); 2572 return _enumerator.MoveNext();
@@ -2372,6 +2623,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
2372 2623
2373 public void Dispose() 2624 public void Dispose()
2374 { 2625 {
2626 if (_enumerator != null)
2375 _enumerator.Dispose(); 2627 _enumerator.Dispose();
2376 } 2628 }
2377 2629
@@ -2407,7 +2659,42 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
2407 foreach (bool l2 in YP.unify(Body, _Body)) 2659 foreach (bool l2 in YP.unify(Body, _Body))
2408 yield return false; 2660 yield return false;
2409 } 2661 }
2410 #pragma warning disable 0168 2662 #pragma warning restore 0168
2663 }
2664 }
2665
2666 /// <summary>
2667 /// CodeListReader extends TextReader and overrides Read to read the next code from
2668 /// the CodeList which is a Prolog list of integer character codes.
2669 /// </summary>
2670 public class CodeListReader : TextReader
2671 {
2672 private object _CodeList;
2673
2674 public CodeListReader(object CodeList)
2675 {
2676 _CodeList = YP.getValue(CodeList);
2677 }
2678
2679 /// <summary>
2680 /// If the head of _CodeList is an integer, return it and advance the list. Otherwise,
2681 /// return -1 for end of file.
2682 /// </summary>
2683 /// <returns></returns>
2684 public override int Read()
2685 {
2686 Functor2 CodeListPair = _CodeList as Functor2;
2687 int code;
2688 if (!(CodeListPair != null && CodeListPair._name == Atom.DOT &&
2689 getInt(CodeListPair._arg1, out code)))
2690 {
2691 _CodeList = Atom.NIL;
2692 return -1;
2693 }
2694
2695 // Advance.
2696 _CodeList = YP.getValue(CodeListPair._arg2);
2697 return code;
2411 } 2698 }
2412 } 2699 }
2413 } 2700 }