diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs | 317 |
1 files changed, 302 insertions, 15 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs index ac56875..b69f9c4 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs | |||
@@ -52,6 +52,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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); | ||
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); | ||
2080 | 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.DotNetEngine.Compiler.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.DotNetEngine.Compiler.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 | ||
@@ -2410,5 +2662,40 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog | |||
2410 | #pragma warning restore 0168 | 2662 | #pragma warning restore 0168 |
2411 | } | 2663 | } |
2412 | } | 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; | ||
2698 | } | ||
2699 | } | ||
2413 | } | 2700 | } |
2414 | } | 2701 | } |