aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs1184
1 files changed, 973 insertions, 211 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs
index 31f007f..6c981bb 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/YP.cs
@@ -1,20 +1,20 @@
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
@@ -33,6 +33,9 @@ using System.Collections;
33using System.Collections.Generic; 33using System.Collections.Generic;
34using System.IO; 34using System.IO;
35using System.Reflection; 35using System.Reflection;
36using System.Net.Sockets;
37using System.Text;
38using System.Text.RegularExpressions;
36 39
37namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog 40namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
38{ 41{
@@ -48,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
48 new Dictionary<NameArity, List<IClause>>(); 51 new Dictionary<NameArity, List<IClause>>();
49 private static TextWriter _outputStream = System.Console.Out; 52 private static TextWriter _outputStream = System.Console.Out;
50 private static TextReader _inputStream = System.Console.In; 53 private static TextReader _inputStream = System.Console.In;
51 private static List<object[]> _operatorTable = null; 54 private static IndexedAnswers _operatorTable = null;
52 55
53 /// <summary> 56 /// <summary>
54 /// An IClause is used so that dynamic predicates can call match. 57 /// An IClause is used so that dynamic predicates can call match.
@@ -56,6 +59,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
56 public interface IClause 59 public interface IClause
57 { 60 {
58 IEnumerable<bool> match(object[] args); 61 IEnumerable<bool> match(object[] args);
62 IEnumerable<bool> clause(object Head, object Body);
59 } 63 }
60 64
61 public static object getValue(object value) 65 public static object getValue(object value)
@@ -120,7 +124,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
120 /// <summary> 124 /// <summary>
121 /// Convert term to an int. 125 /// Convert term to an int.
122 /// If term is a single-element List, use its first element 126 /// 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. 127 /// (to handle the char types like "a").
128 /// If can't convert, throw a PrologException for type_error evaluable (because this is only
129 /// called from arithmetic functions).
124 /// </summary> 130 /// </summary>
125 /// <param name="term"></param> 131 /// <param name="term"></param>
126 /// <returns></returns> 132 /// <returns></returns>
@@ -131,14 +137,30 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
131 YP.getValue(((Functor2)term)._arg2) == Atom.NIL) 137 YP.getValue(((Functor2)term)._arg2) == Atom.NIL)
132 // Assume it is a char type like "a". 138 // Assume it is a char type like "a".
133 term = YP.getValue(((Functor2)term)._arg1); 139 term = YP.getValue(((Functor2)term)._arg1);
140 if (term is Variable)
141 throw new PrologException(Atom.a("instantiation_error"),
142 "Expected a number but the argument is an unbound variable");
134 143
135 return (int)term; 144 try
145 {
146 return (int)term;
147 }
148 catch (InvalidCastException)
149 {
150 throw new PrologException
151 (new Functor2
152 ("type_error", Atom.a("evaluable"),
153 new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)),
154 "Term must be an integer");
155 }
136 } 156 }
137 157
138 /// <summary> 158 /// <summary>
139 /// Convert term to a double. This may convert an int to a double, etc. 159 /// 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 160 /// 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. 161 /// (to handle the char types like "a").
162 /// If can't convert, throw a PrologException for type_error evaluable (because this is only
163 /// called from arithmetic functions).
142 /// </summary> 164 /// </summary>
143 /// <param name="term"></param> 165 /// <param name="term"></param>
144 /// <returns></returns> 166 /// <returns></returns>
@@ -153,7 +175,18 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
153 throw new PrologException(Atom.a("instantiation_error"), 175 throw new PrologException(Atom.a("instantiation_error"),
154 "Expected a number but the argument is an unbound variable"); 176 "Expected a number but the argument is an unbound variable");
155 177
156 return Convert.ToDouble(term); 178 try
179 {
180 return Convert.ToDouble(term);
181 }
182 catch (InvalidCastException)
183 {
184 throw new PrologException
185 (new Functor2
186 ("type_error", Atom.a("evaluable"),
187 new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)),
188 "Term must be an integer");
189 }
157 } 190 }
158 191
159 /// <summary> 192 /// <summary>
@@ -260,6 +293,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
260 return Math.Sign(convertDouble(x)); 293 return Math.Sign(convertDouble(x));
261 } 294 }
262 295
296 // Use toFloat instead of float because it is a reserved keyword.
297 public static object toFloat(object x)
298 {
299 return convertDouble(x);
300 }
301
263 /// <summary> 302 /// <summary>
264 /// The ISO standard returns an int. 303 /// The ISO standard returns an int.
265 /// </summary> 304 /// </summary>
@@ -485,8 +524,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
485 return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array)); 524 return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array));
486 } 525 }
487 526
488
489
490 /// <summary> 527 /// <summary>
491 /// Use YP.unify to unify each of the elements of the two arrays, and yield 528 /// Use YP.unify to unify each of the elements of the two arrays, and yield
492 /// once if they all unify. 529 /// once if they all unify.
@@ -579,12 +616,16 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
579 { 616 {
580 object[] args = ListPair.toArray(ArgList); 617 object[] args = ListPair.toArray(ArgList);
581 if (args == null) 618 if (args == null)
582 throw new Exception("Expected a list. Got: " + ArgList.getValue()); 619 throw new PrologException
620 (new Functor2("type_error", Atom.a("list"), ArgList),
621 "Expected a list. Got: " + ArgList.getValue());
583 if (args.Length == 0) 622 if (args.Length == 0)
584 // Return the Name, even if it is not an Atom. 623 // Return the Name, even if it is not an Atom.
585 return YP.unify(Term, Name); 624 return YP.unify(Term, Name);
586 if (!atom(Name)) 625 if (!atom(Name))
587 throw new Exception("Expected an atom. Got: " + Name.getValue()); 626 throw new PrologException
627 (new Functor2("type_error", Atom.a("atom"), Name),
628 "Expected an atom. Got: " + Name.getValue());
588 629
589 return YP.unify(Term, Functor.make((Atom)YP.getValue(Name), args)); 630 return YP.unify(Term, Functor.make((Atom)YP.getValue(Name), args));
590 } 631 }
@@ -598,7 +639,45 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
598 FunctorName = YP.getValue(FunctorName); 639 FunctorName = YP.getValue(FunctorName);
599 Arity = YP.getValue(Arity); 640 Arity = YP.getValue(Arity);
600 641
601 if (!(Term is Variable)) 642 if (Term is Variable)
643 {
644 if (FunctorName is Variable)
645 throw new PrologException(Atom.a("instantiation_error"),
646 "Arg 2 FunctorName is an unbound variable");
647 if (Arity is Variable)
648 throw new PrologException(Atom.a("instantiation_error"),
649 "Arg 3 Arity is an unbound variable");
650 if (!(Arity is int))
651 throw new PrologException
652 (new Functor2("type_error", Atom.a("integer"), Arity), "Arity is not an integer");
653 if (!YP.atomic(FunctorName))
654 throw new PrologException
655 (new Functor2("type_error", Atom.a("atomic"), FunctorName), "FunctorName is not atomic");
656
657 if ((int)Arity < 0)
658 throw new PrologException
659 (new Functor2("domain_error", Atom.a("not_less_than_zero"), Arity),
660 "Arity may not be less than zero");
661 else if ((int)Arity == 0)
662 {
663 // Just unify Term with the atomic FunctorName.
664 foreach (bool l1 in YP.unify(Term, FunctorName))
665 yield return false;
666 }
667 else
668 {
669 if (!(FunctorName is Atom))
670 throw new PrologException
671 (new Functor2("type_error", Atom.a("atom"), FunctorName), "FunctorName is not an atom");
672 // Construct a functor with unbound variables.
673 object[] args = new object[(int)Arity];
674 for (int i = 0; i < args.Length; ++i)
675 args[i] = new Variable();
676 foreach (bool l1 in YP.unify(Term, Functor.make((Atom)FunctorName, args)))
677 yield return false;
678 }
679 }
680 else
602 { 681 {
603 foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term))) 682 foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term)))
604 { 683 {
@@ -606,27 +685,35 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
606 yield return false; 685 yield return false;
607 } 686 }
608 } 687 }
609 else
610 throw new NotImplementedException("Debug: must finish functor/3");
611 } 688 }
612 689
613 public static IEnumerable<bool> arg(object ArgNumber, object Term, object Value) 690 public static IEnumerable<bool> arg(object ArgNumber, object Term, object Value)
614 { 691 {
615 if (YP.var(ArgNumber)) 692 if (var(ArgNumber))
616 throw new NotImplementedException("Debug: must finish arg/3"); 693 throw new PrologException(Atom.a("instantiation_error"), "Arg 1 ArgNumber is an unbound variable");
617 else 694 int argNumberInt;
695 if (!getInt(ArgNumber, out argNumberInt))
696 throw new PrologException
697 (new Functor2("type_error", Atom.a("integer"), ArgNumber), "Arg 1 ArgNumber must be integer");
698 if (argNumberInt < 0)
699 throw new PrologException
700 (new Functor2("domain_error", Atom.a("not_less_than_zero"), argNumberInt),
701 "ArgNumber may not be less than zero");
702
703 if (YP.var(Term))
704 throw new PrologException(Atom.a("instantiation_error"),
705 "Arg 2 Term is an unbound variable");
706 if (!YP.compound(Term))
707 throw new PrologException
708 (new Functor2("type_error", Atom.a("compound"), Term), "Arg 2 Term must be compound");
709
710 object[] termArgs = YP.getFunctorArgs(Term);
711 // Silently fail if argNumberInt is out of range.
712 if (argNumberInt >= 1 && argNumberInt <= termArgs.Length)
618 { 713 {
619 int argNumberInt = convertInt(ArgNumber); 714 // The first ArgNumber is at 1, not 0.
620 if (argNumberInt < 0) 715 foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1]))
621 throw new Exception("ArgNumber must be non-negative"); 716 yield return false;
622 object[] termArgs = YP.getFunctorArgs(Term);
623 // Silently fail if argNumberInt is out of range.
624 if (argNumberInt >= 1 && argNumberInt <= termArgs.Length)
625 {
626 // The first ArgNumber is at 1, not 0.
627 foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1]))
628 yield return false;
629 }
630 } 717 }
631 } 718 }
632 719
@@ -656,8 +743,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
656 if (term1TypeCode == -2) 743 if (term1TypeCode == -2)
657 { 744 {
658 // Variable. 745 // Variable.
659 // We always check for equality first because we want to be sure 746 // We always check for equality first because we want to be sure
660 // that less than returns false if the terms are equal, in 747 // that less than returns false if the terms are equal, in
661 // case that the less than check really behaves like less than or equal. 748 // case that the less than check really behaves like less than or equal.
662 if ((Variable)Term1 != (Variable)Term2) 749 if ((Variable)Term1 != (Variable)Term2)
663 // The hash code should be unique to a Variable object. 750 // The hash code should be unique to a Variable object.
@@ -700,8 +787,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
700 } 787 }
701 788
702 /// <summary> 789 /// <summary>
703 /// Type code is -2 if term is a Variable, 0 if it is an Atom, 790 /// Type code is -2 if term is a Variable, 0 if it is an Atom,
704 /// 1 if it is a Functor1, 2 if it is a Functor2, 3 if it is a Functor3, 791 /// 1 if it is a Functor1, 2 if it is a Functor2, 3 if it is a Functor3,
705 /// 4 if it is Functor. 792 /// 4 if it is Functor.
706 /// Otherwise, type code is -1. 793 /// Otherwise, type code is -1.
707 /// This does not call YP.getValue(term). 794 /// This does not call YP.getValue(term).
@@ -769,133 +856,446 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
769 if (_operatorTable == null) 856 if (_operatorTable == null)
770 { 857 {
771 // Initialize. 858 // Initialize.
772 _operatorTable = new List<object[]>(); 859 _operatorTable = new IndexedAnswers(3);
773 _operatorTable.Add(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") }); 860 _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") });
774 _operatorTable.Add(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") }); 861 _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") });
775 _operatorTable.Add(new object[] { 1200, Atom.a("fx"), Atom.a(":-") }); 862 _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a(":-") });
776 _operatorTable.Add(new object[] { 1200, Atom.a("fx"), Atom.a("?-") }); 863 _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a("?-") });
777 _operatorTable.Add(new object[] { 1100, Atom.a("xfy"), Atom.a(";") }); 864 _operatorTable.addAnswer(new object[] { 1100, Atom.a("xfy"), Atom.a(";") });
778 _operatorTable.Add(new object[] { 1050, Atom.a("xfy"), Atom.a("->") }); 865 _operatorTable.addAnswer(new object[] { 1050, Atom.a("xfy"), Atom.a("->") });
779 _operatorTable.Add(new object[] { 1000, Atom.a("xfy"), Atom.a(",") }); 866 _operatorTable.addAnswer(new object[] { 1000, Atom.a("xfy"), Atom.a(",") });
780 _operatorTable.Add(new object[] { 900, Atom.a("fy"), Atom.a("\\+") }); 867 _operatorTable.addAnswer(new object[] { 900, Atom.a("fy"), Atom.a("\\+") });
781 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=") }); 868 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=") });
782 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") }); 869 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") });
783 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("==") }); 870 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("==") });
784 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") }); 871 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") });
785 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@<") }); 872 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@<") });
786 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") }); 873 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") });
787 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@>") }); 874 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>") });
788 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") }); 875 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") });
789 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=..") }); 876 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=..") });
790 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("is") }); 877 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("is") });
791 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") }); 878 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") });
792 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") }); 879 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") });
793 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("<") }); 880 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("<") });
794 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=<") }); 881 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=<") });
795 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a(">") }); 882 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">") });
796 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a(">=") }); 883 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">=") });
797 _operatorTable.Add(new object[] { 600, Atom.a("xfy"), Atom.a(":") }); 884 _operatorTable.addAnswer(new object[] { 600, Atom.a("xfy"), Atom.a(":") });
798 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("+") }); 885 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("+") });
799 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("-") }); 886 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("-") });
800 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") }); 887 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") });
801 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") }); 888 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") });
802 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("*") }); 889 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("*") });
803 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("/") }); 890 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("/") });
804 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("//") }); 891 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("//") });
805 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("rem") }); 892 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("rem") });
806 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("mod") }); 893 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("mod") });
807 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("<<") }); 894 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("<<") });
808 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a(">>") }); 895 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a(">>") });
809 _operatorTable.Add(new object[] { 200, Atom.a("xfx"), Atom.a("**") }); 896 _operatorTable.addAnswer(new object[] { 200, Atom.a("xfx"), Atom.a("**") });
810 _operatorTable.Add(new object[] { 200, Atom.a("xfy"), Atom.a("^") }); 897 _operatorTable.addAnswer(new object[] { 200, Atom.a("xfy"), Atom.a("^") });
811 _operatorTable.Add(new object[] { 200, Atom.a("fy"), Atom.a("-") }); 898 _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("-") });
812 _operatorTable.Add(new object[] { 200, Atom.a("fy"), Atom.a("\\") }); 899 _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("\\") });
813 // Debug: This is hacked in to run the Prolog test suite until we implement op/3. 900 // Debug: This is hacked in to run the Prolog test suite until we implement op/3.
814 _operatorTable.Add(new object[] { 20, Atom.a("xfx"), Atom.a("<--") }); 901 _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") });
815 } 902 }
816 903
817 object[] args = new object[] { Priority, Specifier, Operator }; 904 foreach (bool l1 in _operatorTable.match(new object[] { Priority, Specifier, Operator }))
818 foreach (object[] answer in _operatorTable) 905 yield return false;
819 {
820 foreach (bool l1 in YP.unifyArrays(args, answer))
821 yield return false;
822 }
823 } 906 }
824 907
825 public static IEnumerable<bool> atom_length(object atom, object Length) 908 public static IEnumerable<bool> atom_length(object atom, object Length)
826 { 909 {
827 return YP.unify(Length, ((Atom)YP.getValue(atom))._name.Length); 910 atom = YP.getValue(atom);
911 Length = YP.getValue(Length);
912 if (atom is Variable)
913 throw new PrologException(Atom.a("instantiation_error"),
914 "Expected atom(Arg1) but it is an unbound variable");
915 if (!(atom is Atom))
916 throw new PrologException
917 (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom");
918 if (!(Length is Variable))
919 {
920 if (!(Length is int))
921 throw new PrologException
922 (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer");
923 if ((int)Length < 0)
924 throw new PrologException
925 (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length),
926 "Length must not be less than zero");
927 }
928 return YP.unify(Length, ((Atom)atom)._name.Length);
828 } 929 }
829 930
830 public static IEnumerable<bool> atom_concat(object Start, object End, object Whole) 931 public static IEnumerable<bool> atom_concat(object Start, object End, object Whole)
831 { 932 {
832 // Debug: Should implement for var(Start) which is a kind of search.
833 // Debug: Should we try to preserve the _declaringClass? 933 // Debug: Should we try to preserve the _declaringClass?
834 return YP.unify(Whole, Atom.a(((Atom)YP.getValue(Start))._name + 934 Start = YP.getValue(Start);
835 ((Atom)YP.getValue(End))._name)); 935 End = YP.getValue(End);
936 Whole = YP.getValue(Whole);
937 if (Whole is Variable)
938 {
939 if (Start is Variable)
940 throw new PrologException(Atom.a("instantiation_error"),
941 "Arg 1 Start and arg 3 Whole are both var");
942 if (End is Variable)
943 throw new PrologException(Atom.a("instantiation_error"),
944 "Arg 2 End and arg 3 Whole are both var");
945 if (!(Start is Atom))
946 throw new PrologException
947 (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not an atom");
948 if (!(End is Atom))
949 throw new PrologException
950 (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not an atom");
951
952 foreach (bool l1 in YP.unify(Whole, Atom.a(((Atom)Start)._name + ((Atom)End)._name)))
953 yield return false;
954 }
955 else
956 {
957 if (!(Whole is Atom))
958 throw new PrologException
959 (new Functor2("type_error", Atom.a("atom"), Whole), "Arg 3 Whole is not an atom");
960 bool gotStartLength = false;
961 int startLength = 0;
962 if (!(Start is Variable))
963 {
964 if (!(Start is Atom))
965 throw new PrologException
966 (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not var or atom");
967 startLength = ((Atom)Start)._name.Length;
968 gotStartLength = true;
969 }
970
971 bool gotEndLength = false;
972 int endLength = 0;
973 if (!(End is Variable))
974 {
975 if (!(End is Atom))
976 throw new PrologException
977 (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not var or atom");
978 endLength = ((Atom)End)._name.Length;
979 gotEndLength = true;
980 }
981
982 // We are doing a search through all possible Start and End which concatenate to Whole.
983 string wholeString = ((Atom)Whole)._name;
984 for (int i = 0; i <= wholeString.Length; ++i)
985 {
986 // If we got either startLength or endLength, we know the lengths have to match so check
987 // the lengths instead of constructing an Atom to do it.
988 if (gotStartLength && startLength != i)
989 continue;
990 if (gotEndLength && endLength != wholeString.Length - i)
991 continue;
992 foreach (bool l1 in YP.unify(Start, Atom.a(wholeString.Substring(0, i))))
993 {
994 foreach (bool l2 in YP.unify(End, Atom.a(wholeString.Substring(i, wholeString.Length - i))))
995 yield return false;
996 }
997 }
998 }
836 } 999 }
837 1000
838 public static IEnumerable<bool> sub_atom 1001 public static IEnumerable<bool> sub_atom
839 (object atom, object Before, object Length, object After, object Sub_atom) 1002 (object atom, object Before, object Length, object After, object Sub_atom)
840 { 1003 {
841 // Debug: Should implement for var(atom) which is a kind of search.
842 // Debug: Should we try to preserve the _declaringClass? 1004 // Debug: Should we try to preserve the _declaringClass?
843 Atom atomAtom = (Atom)YP.getValue(atom); 1005 atom = YP.getValue(atom);
844 int beforeInt = YP.convertInt(Before); 1006 Before = YP.getValue(Before);
845 int lengthInt = YP.convertInt(Length); 1007 Length = YP.getValue(Length);
846 if (beforeInt < 0) 1008 After = YP.getValue(After);
847 throw new Exception("Before must be non-negative"); 1009 Sub_atom = YP.getValue(Sub_atom);
848 if (lengthInt < 0) 1010 if (atom is Variable)
849 throw new Exception("Length must be non-negative"); 1011 throw new PrologException(Atom.a("instantiation_error"),
850 int afterInt = atomAtom._name.Length - (beforeInt + lengthInt); 1012 "Expected atom(Arg1) but it is an unbound variable");
851 if (afterInt >= 0) 1013 if (!(atom is Atom))
852 { 1014 throw new PrologException
853 foreach (bool l1 in YP.unify(After, afterInt)) 1015 (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom");
1016 if (!(Sub_atom is Variable))
1017 {
1018 if (!(Sub_atom is Atom))
1019 throw new PrologException
1020 (new Functor2("type_error", Atom.a("atom"), Sub_atom), "Sub_atom is not var or atom");
1021 }
1022
1023 bool beforeIsInt = false;
1024 bool lengthIsInt = false;
1025 bool afterIsInt = false;
1026 if (!(Before is Variable))
1027 {
1028 if (!(Before is int))
1029 throw new PrologException
1030 (new Functor2("type_error", Atom.a("integer"), Before), "Before must be var or integer");
1031 beforeIsInt = true;
1032 if ((int)Before < 0)
1033 throw new PrologException
1034 (new Functor2("domain_error", Atom.a("not_less_than_zero"), Before),
1035 "Before must not be less than zero");
1036 }
1037 if (!(Length is Variable))
1038 {
1039 if (!(Length is int))
1040 throw new PrologException
1041 (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer");
1042 lengthIsInt = true;
1043 if ((int)Length < 0)
1044 throw new PrologException
1045 (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length),
1046 "Length must not be less than zero");
1047 }
1048 if (!(After is Variable))
1049 {
1050 if (!(After is int))
1051 throw new PrologException
1052 (new Functor2("type_error", Atom.a("integer"), After), "After must be var or integer");
1053 afterIsInt = true;
1054 if ((int)After < 0)
1055 throw new PrologException
1056 (new Functor2("domain_error", Atom.a("not_less_than_zero"), After),
1057 "After must not be less than zero");
1058 }
1059
1060 Atom atomAtom = (Atom)atom;
1061 int atomLength = atomAtom._name.Length;
1062 if (beforeIsInt && lengthIsInt)
1063 {
1064 // Special case: the caller is just trying to extract a substring, so do it quickly.
1065 int xAfter = atomLength - (int)Before - (int)Length;
1066 if (xAfter >= 0)
854 { 1067 {
855 foreach (bool l2 in YP.unify 1068 foreach (bool l1 in YP.unify(After, xAfter))
856 (Sub_atom, Atom.a(atomAtom._name.Substring(beforeInt, lengthInt)))) 1069 {
857 yield return false; 1070 foreach (bool l2 in YP.unify
1071 (Sub_atom, Atom.a(atomAtom._name.Substring((int)Before, (int)Length))))
1072 yield return false;
1073 }
1074 }
1075 }
1076 else if (afterIsInt && lengthIsInt)
1077 {
1078 // Special case: the caller is just trying to extract a substring, so do it quickly.
1079 int xBefore = atomLength - (int)After - (int)Length;
1080 if (xBefore >= 0)
1081 {
1082 foreach (bool l1 in YP.unify(Before, xBefore))
1083 {
1084 foreach (bool l2 in YP.unify
1085 (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, (int)Length))))
1086 yield return false;
1087 }
1088 }
1089 }
1090 else
1091 {
1092 // We are underconstrained and doing a search, so go through all possibilities.
1093 for (int xBefore = 0; xBefore <= atomLength; ++xBefore)
1094 {
1095 foreach (bool l1 in YP.unify(Before, xBefore))
1096 {
1097 for (int xLength = 0; xLength <= (atomLength - xBefore); ++xLength)
1098 {
1099 foreach (bool l2 in YP.unify(Length, xLength))
1100 {
1101 foreach (bool l3 in YP.unify(After, atomLength - (xBefore + xLength)))
1102 {
1103 foreach (bool l4 in YP.unify
1104 (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, xLength))))
1105 yield return false;
1106 }
1107 }
1108 }
1109 }
858 } 1110 }
859 } 1111 }
860 } 1112 }
861 1113
1114 public static IEnumerable<bool> atom_chars(object atom, object List)
1115 {
1116 atom = YP.getValue(atom);
1117 List = YP.getValue(List);
1118
1119 if (atom is Variable)
1120 {
1121 if (List is Variable)
1122 throw new PrologException(Atom.a("instantiation_error"),
1123 "Arg 1 Atom and arg 2 List are both unbound variables");
1124 object[] codeArray = ListPair.toArray(List);
1125 if (codeArray == null)
1126 throw new PrologException
1127 (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
1128
1129 char[] charArray = new char[codeArray.Length];
1130 for (int i = 0; i < codeArray.Length; ++i)
1131 {
1132 object listAtom = YP.getValue(codeArray[i]);
1133 if (listAtom is Variable)
1134 throw new PrologException(Atom.a("instantiation_error"),
1135 "Arg 2 List has an element which is an unbound variable");
1136 if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1))
1137 throw new PrologException
1138 (new Functor2("type_error", Atom.a("character"), listAtom),
1139 "Arg 2 List has an element which is not a one character atom");
1140 charArray[i] = ((Atom)listAtom)._name[0];
1141 }
1142 return YP.unify(atom, Atom.a(new String(charArray)));
1143 }
1144 else
1145 {
1146 if (!(atom is Atom))
1147 throw new PrologException
1148 (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom");
1149
1150 string atomString = ((Atom)atom)._name;
1151 object charList = Atom.NIL;
1152 // Start from the back to make the list.
1153 for (int i = atomString.Length - 1; i >= 0; --i)
1154 charList = new ListPair(Atom.a(atomString.Substring(i, 1)), charList);
1155 return YP.unify(List, charList);
1156 }
1157 }
1158
862 public static IEnumerable<bool> atom_codes(object atom, object List) 1159 public static IEnumerable<bool> atom_codes(object atom, object List)
863 { 1160 {
864 atom = YP.getValue(atom); 1161 atom = YP.getValue(atom);
865 List = YP.getValue(List); 1162 List = YP.getValue(List);
866 1163
867 if (nonvar(atom)) 1164 if (atom is Variable)
868 { 1165 {
869 string name = ((Atom)atom)._name; 1166 if (List is Variable)
1167 throw new PrologException(Atom.a("instantiation_error"),
1168 "Arg 1 Atom and arg 2 List are both unbound variables");
1169 object[] codeArray = ListPair.toArray(List);
1170 if (codeArray == null)
1171 throw new PrologException
1172 (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
1173
1174 char[] charArray = new char[codeArray.Length];
1175 for (int i = 0; i < codeArray.Length; ++i)
1176 {
1177 int codeInt;
1178 if (!getInt(codeArray[i], out codeInt) || codeInt < 0)
1179 throw new PrologException
1180 (new Functor1("representation_error", Atom.a("character_code")),
1181 "Element of Arg 2 List is not a character code");
1182 charArray[i] = (char)codeInt;
1183 }
1184 return YP.unify(atom, Atom.a(new String(charArray)));
1185 }
1186 else
1187 {
1188 if (!(atom is Atom))
1189 throw new PrologException
1190 (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom");
1191
1192 string atomString = ((Atom)atom)._name;
870 object codeList = Atom.NIL; 1193 object codeList = Atom.NIL;
871 // Start from the back to make the list. 1194 // Start from the back to make the list.
872 for (int i = name.Length - 1; i >= 0; --i) 1195 for (int i = atomString.Length - 1; i >= 0; --i)
873 codeList = new ListPair((int)name[i], codeList); 1196 codeList = new ListPair((int)atomString[i], codeList);
874 return YP.unify(List, codeList); 1197 return YP.unify(List, codeList);
875 } 1198 }
1199 }
1200
1201 public static IEnumerable<bool> number_chars(object Number, object List)
1202 {
1203 Number = YP.getValue(Number);
1204 List = YP.getValue(List);
1205
1206 if (Number is Variable)
876 { 1207 {
1208 if (List is Variable)
1209 throw new PrologException(Atom.a("instantiation_error"),
1210 "Arg 1 Number and arg 2 List are both unbound variables");
877 object[] codeArray = ListPair.toArray(List); 1211 object[] codeArray = ListPair.toArray(List);
1212 if (codeArray == null)
1213 throw new PrologException
1214 (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
1215
878 char[] charArray = new char[codeArray.Length]; 1216 char[] charArray = new char[codeArray.Length];
879 for (int i = 0; i < codeArray.Length; ++i) 1217 for (int i = 0; i < codeArray.Length; ++i)
880 charArray[i] = (char)YP.convertInt(codeArray[i]); 1218 {
881 return YP.unify(atom, Atom.a(new String(charArray))); 1219 object listAtom = YP.getValue(codeArray[i]);
1220 if (listAtom is Variable)
1221 throw new PrologException(Atom.a("instantiation_error"),
1222 "Arg 2 List has an element which is an unbound variable");
1223 if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1))
1224 throw new PrologException
1225 (new Functor2("type_error", Atom.a("character"), listAtom),
1226 "Arg 2 List has an element which is not a one character atom");
1227 charArray[i] = ((Atom)listAtom)._name[0];
1228 }
1229 return YP.unify(Number, parseNumberString(charArray));
1230 }
1231 else
1232 {
1233 string numberString = null;
1234 // Try converting to an int first.
1235 int intNumber;
1236 if (YP.getInt(Number, out intNumber))
1237 numberString = intNumber.ToString();
1238 else
1239 {
1240 if (!YP.number(Number))
1241 throw new PrologException
1242 (new Functor2("type_error", Atom.a("number"), Number),
1243 "Arg 1 Number is not var or number");
1244 // We just checked, so convertDouble shouldn't throw an exception.
1245 numberString = YP.doubleToString(YP.convertDouble(Number));
1246 }
1247
1248 object charList = Atom.NIL;
1249 // Start from the back to make the list.
1250 for (int i = numberString.Length - 1; i >= 0; --i)
1251 charList = new ListPair(Atom.a(numberString.Substring(i, 1)), charList);
1252 return YP.unify(List, charList);
882 } 1253 }
883 } 1254 }
884 1255
885 public static IEnumerable<bool> number_codes(object number, object List) 1256 public static IEnumerable<bool> number_codes(object Number, object List)
886 { 1257 {
887 number = YP.getValue(number); 1258 Number = YP.getValue(Number);
888 List = YP.getValue(List); 1259 List = YP.getValue(List);
889 1260
890 if (nonvar(number)) 1261 if (Number is Variable)
1262 {
1263 if (List is Variable)
1264 throw new PrologException(Atom.a("instantiation_error"),
1265 "Arg 1 Number and arg 2 List are both unbound variables");
1266 object[] codeArray = ListPair.toArray(List);
1267 if (codeArray == null)
1268 throw new PrologException
1269 (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list");
1270
1271 char[] charArray = new char[codeArray.Length];
1272 for (int i = 0; i < codeArray.Length; ++i)
1273 {
1274 int codeInt;
1275 if (!getInt(codeArray[i], out codeInt) || codeInt < 0)
1276 throw new PrologException
1277 (new Functor1("representation_error", Atom.a("character_code")),
1278 "Element of Arg 2 List is not a character code");
1279 charArray[i] = (char)codeInt;
1280 }
1281 return YP.unify(Number, parseNumberString(charArray));
1282 }
1283 else
891 { 1284 {
892 string numberString = null; 1285 string numberString = null;
893 // Try converting to an int first. 1286 // Try converting to an int first.
894 int intNumber; 1287 int intNumber;
895 if (YP.getInt(number, out intNumber)) 1288 if (YP.getInt(Number, out intNumber))
896 numberString = intNumber.ToString(); 1289 numberString = intNumber.ToString();
897 else 1290 else
898 numberString = YP.doubleToString(YP.convertDouble(number)); 1291 {
1292 if (!YP.number(Number))
1293 throw new PrologException
1294 (new Functor2("type_error", Atom.a("number"), Number),
1295 "Arg 1 Number is not var or number");
1296 // We just checked, so convertDouble shouldn't throw an exception.
1297 numberString = YP.doubleToString(YP.convertDouble(Number));
1298 }
899 1299
900 object codeList = Atom.NIL; 1300 object codeList = Atom.NIL;
901 // Start from the back to make the list. 1301 // Start from the back to make the list.
@@ -903,20 +1303,92 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
903 codeList = new ListPair((int)numberString[i], codeList); 1303 codeList = new ListPair((int)numberString[i], codeList);
904 return YP.unify(List, codeList); 1304 return YP.unify(List, codeList);
905 } 1305 }
1306 }
1307
1308 /// <summary>
1309 /// Used by number_chars and number_codes. Return the number in charArray or
1310 /// throw an exception if can't parse.
1311 /// </summary>
1312 /// <param name="numberString"></param>
1313 /// <returns></returns>
1314 private static object parseNumberString(char[] charArray)
1315 {
1316 string numberString = new String(charArray);
1317 if (charArray.Length == 3 && numberString.StartsWith("0'"))
1318 // This is a char code.
1319 return (int)charArray[2];
1320 if (numberString.StartsWith("0x"))
906 { 1321 {
907 object[] codeArray = ListPair.toArray(List);
908 char[] charArray = new char[codeArray.Length];
909 for (int i = 0; i < codeArray.Length; ++i)
910 charArray[i] = (char)YP.convertInt(codeArray[i]);
911 String numberString = new String(charArray);
912 // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
913 try 1322 try
914 { 1323 {
915 // Try an int first. 1324 return Int32.Parse
916 return YP.unify(number, Convert.ToInt32(numberString)); 1325 (numberString.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier);
917 } 1326 }
918 catch (FormatException) { } 1327 catch (FormatException)
919 return YP.unify(number, Convert.ToDouble(numberString)); 1328 {
1329 throw new PrologException
1330 (new Functor1("syntax_error", Atom.a("number_format: " + numberString)),
1331 "Arg 2 List is not a list for a hexadecimal number");
1332 }
1333 }
1334 // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
1335 try
1336 {
1337 // Try an int first.
1338 return Convert.ToInt32(numberString);
1339 }
1340 catch (FormatException) { }
1341 try
1342 {
1343 return Convert.ToDouble(numberString);
1344 }
1345 catch (FormatException)
1346 {
1347 throw new PrologException
1348 (new Functor1("syntax_error", Atom.a("number_format: " + numberString)),
1349 "Arg 2 List is not a list for a number");
1350 }
1351 }
1352
1353 public static IEnumerable<bool> char_code(object Char, object Code)
1354 {
1355 Char = YP.getValue(Char);
1356 Code = YP.getValue(Code);
1357
1358 int codeInt = 0;
1359 if (!(Code is Variable))
1360 {
1361 // Get codeInt now so we type check it whether or not Char is Variable.
1362 if (!getInt(Code, out codeInt))
1363 throw new PrologException
1364 (new Functor2("type_error", Atom.a("integer"), Code),
1365 "Arg 2 Code is not var or a character code");
1366 if (codeInt < 0)
1367 throw new PrologException
1368 (new Functor1("representation_error", Atom.a("character_code")),
1369 "Arg 2 Code is not a character code");
1370 }
1371
1372 if (Char is Variable)
1373 {
1374 if (Code is Variable)
1375 throw new PrologException(Atom.a("instantiation_error"),
1376 "Arg 1 Char and arg 2 Code are both unbound variables");
1377
1378 return YP.unify(Char, Atom.a(new String(new char[] {(char)codeInt} )));
1379 }
1380 else
1381 {
1382 if (!(Char is Atom) || ((Atom)Char)._name.Length != 1)
1383 throw new PrologException
1384 (new Functor2("type_error", Atom.a("character"), Char),
1385 "Arg 1 Char is not var or one-character atom");
1386
1387 if (Code is Variable)
1388 return YP.unify(Code, (int)((Atom)Char)._name[0]);
1389 else
1390 // Use codeInt to handle whether Code is supplied as, e.g., 97 or 0'a .
1391 return YP.unify(codeInt, (int)((Atom)Char)._name[0]);
920 } 1392 }
921 } 1393 }
922 1394
@@ -1092,7 +1564,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1092 } 1564 }
1093 1565
1094 /// <summary> 1566 /// <summary>
1095 /// Format x as a string, making sure that it will parse as an int later. I.e., for 1.0, don't just 1567 /// Format x as a string, making sure that it won't parse as an int later. I.e., for 1.0, don't just
1096 /// use "1" which will parse as an int. 1568 /// use "1" which will parse as an int.
1097 /// </summary> 1569 /// </summary>
1098 /// <param name="x"></param> 1570 /// <param name="x"></param>
@@ -1117,7 +1589,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1117 1589
1118 public static void put_code(object x) 1590 public static void put_code(object x)
1119 { 1591 {
1120 _outputStream.Write((char)YP.convertInt(x)); 1592 if (var(x))
1593 throw new PrologException(Atom.a("instantiation_error"), "Arg 1 is an unbound variable");
1594 int xInt;
1595 if (!getInt(x, out xInt))
1596 throw new PrologException
1597 (new Functor2("type_error", Atom.a("integer"), x), "Arg 1 must be integer");
1598 _outputStream.Write((char)xInt);
1121 } 1599 }
1122 1600
1123 public static void nl() 1601 public static void nl()
@@ -1153,6 +1631,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1153 { 1631 {
1154 Head = YP.getValue(((Functor2)TermCopy)._arg1); 1632 Head = YP.getValue(((Functor2)TermCopy)._arg1);
1155 Body = YP.getValue(((Functor2)TermCopy)._arg2); 1633 Body = YP.getValue(((Functor2)TermCopy)._arg2);
1634 if (Head is Variable)
1635 throw new PrologException("instantiation_error", "Head to assert is an unbound variable");
1636 if (Body is Variable)
1637 throw new PrologException("instantiation_error", "Body to assert is an unbound variable");
1156 } 1638 }
1157 else 1639 else
1158 { 1640 {
@@ -1166,7 +1648,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1166 throw new PrologException 1648 throw new PrologException
1167 (new Functor2("type_error", Atom.a("callable"), Head), "Term to assert is not callable"); 1649 (new Functor2("type_error", Atom.a("callable"), Head), "Term to assert is not callable");
1168 object[] args = getFunctorArgs(Head); 1650 object[] args = getFunctorArgs(Head);
1169 if (!isDynamic(name, args.Length)) 1651 if (isSystemPredicate(name, args.Length))
1170 throw new PrologException 1652 throw new PrologException
1171 (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), 1653 (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
1172 new Functor2(Atom.SLASH, name, args.Length)), 1654 new Functor2(Atom.SLASH, name, args.Length)),
@@ -1174,17 +1656,21 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1174 1656
1175 if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true")) 1657 if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true"))
1176 { 1658 {
1177 // Debug: Until IndexedAnswers supports prepend, compile the fact so we can prepend it below. 1659 // This is a fact with no unbound variables
1178 if (!prepend) 1660 // assertFact and prependFact use IndexedAnswers, so don't we don't need to compile.
1179 { 1661 if (prepend)
1180 // This is a fact with no unbound variables 1662 prependFact(name, args);
1181 // assertFact uses IndexedAnswers, so don't we don't need to compile. 1663 else
1182 assertFact(name, args); 1664 assertFact(name, args);
1183 return; 1665
1184 } 1666 return;
1185 } 1667 }
1186 1668
1187 IClause clause = YPCompiler.compileAnonymousClause(Head, Body, declaringClass); 1669 IClause clause = YPCompiler.compileAnonymousClause(Head, Body, declaringClass);
1670 // We expect clause to be a ClauseHeadAndBody (from Compiler.compileAnonymousFunction)
1671 // so we can set the Head and Body.
1672 if (clause is ClauseHeadAndBody)
1673 ((ClauseHeadAndBody)clause).setHeadAndBody(Head, Body);
1188 1674
1189 // Add the clause to the entry in _predicatesStore. 1675 // Add the clause to the entry in _predicatesStore.
1190 NameArity nameArity = new NameArity(name, args.Length); 1676 NameArity nameArity = new NameArity(name, args.Length);
@@ -1199,15 +1685,15 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1199 clauses.Add(clause); 1685 clauses.Add(clause);
1200 } 1686 }
1201 1687
1202 private static bool isDynamic(Atom name, int arity) 1688 private static bool isSystemPredicate(Atom name, int arity)
1203 { 1689 {
1204 if (arity == 2 && (name == Atom.a(",") || name == Atom.a(";") || name == Atom.DOT)) 1690 if (arity == 2 && (name == Atom.a(",") || name == Atom.a(";") || name == Atom.DOT))
1205 return false; 1691 return true;
1206 // Use the same mapping to static predicates in YP as the compiler. 1692 // Use the same mapping to static predicates in YP as the compiler.
1207 foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable())) 1693 foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable()))
1208 return false; 1694 return true;
1209 // Debug: Do we need to check if name._module is null? 1695 // Debug: Do we need to check if name._module is null?
1210 return true; 1696 return false;
1211 } 1697 }
1212 1698
1213 /// <summary> 1699 /// <summary>
@@ -1224,22 +1710,55 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1224 IndexedAnswers indexedAnswers; 1710 IndexedAnswers indexedAnswers;
1225 if (!_predicatesStore.TryGetValue(nameArity, out clauses)) 1711 if (!_predicatesStore.TryGetValue(nameArity, out clauses))
1226 { 1712 {
1227 // Create an IndexedAnswers as the first clause of the predicate. 1713 // Create an IndexedAnswers as the only clause of the predicate.
1228 _predicatesStore[nameArity] = (clauses = new List<IClause>()); 1714 _predicatesStore[nameArity] = (clauses = new List<IClause>());
1229 clauses.Add(indexedAnswers = new IndexedAnswers()); 1715 clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
1230 } 1716 }
1231 else 1717 else
1232 { 1718 {
1233 indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers; 1719 indexedAnswers = null;
1720 if (clauses.Count >= 1)
1721 indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers;
1234 if (indexedAnswers == null) 1722 if (indexedAnswers == null)
1235 // The latest clause is not an IndexedAnswers, so add one. 1723 // The latest clause is not an IndexedAnswers, so add one.
1236 clauses.Add(indexedAnswers = new IndexedAnswers()); 1724 clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
1237 } 1725 }
1238 1726
1239 indexedAnswers.addAnswer(values); 1727 indexedAnswers.addAnswer(values);
1240 } 1728 }
1241 1729
1242 /// <summary> 1730 /// <summary>
1731 /// Assert values, prepending to the front of the set of facts for the predicate with the
1732 /// name and with arity values.Length.
1733 /// </summary>
1734 /// <param name="name">must be an Atom</param>
1735 /// <param name="values">the array of arguments to the fact predicate.
1736 /// It is an error if an value has an unbound variable.</param>
1737 public static void prependFact(Atom name, object[] values)
1738 {
1739 NameArity nameArity = new NameArity(name, values.Length);
1740 List<IClause> clauses;
1741 IndexedAnswers indexedAnswers;
1742 if (!_predicatesStore.TryGetValue(nameArity, out clauses))
1743 {
1744 // Create an IndexedAnswers as the only clause of the predicate.
1745 _predicatesStore[nameArity] = (clauses = new List<IClause>());
1746 clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
1747 }
1748 else
1749 {
1750 indexedAnswers = null;
1751 if (clauses.Count >= 1)
1752 indexedAnswers = clauses[0] as IndexedAnswers;
1753 if (indexedAnswers == null)
1754 // The first clause is not an IndexedAnswers, so prepend one.
1755 clauses.Insert(0, indexedAnswers = new IndexedAnswers(values.Length));
1756 }
1757
1758 indexedAnswers.prependAnswer(values);
1759 }
1760
1761 /// <summary>
1243 /// Match all clauses of the dynamic predicate with the name and with arity 1762 /// Match all clauses of the dynamic predicate with the name and with arity
1244 /// arguments.Length. 1763 /// arguments.Length.
1245 /// It is an error if the predicate is not defined. 1764 /// It is an error if the predicate is not defined.
@@ -1251,9 +1770,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1251 { 1770 {
1252 List<IClause> clauses; 1771 List<IClause> clauses;
1253 if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses)) 1772 if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses))
1254 throw new UndefinedPredicateException 1773 throw new PrologException
1255 ("Undefined fact: " + name + "/" + arguments.Length, name, 1774 (new Functor2
1256 arguments.Length); 1775 (Atom.a("existence_error"), Atom.a("procedure"),
1776 new Functor2(Atom.SLASH, name, arguments.Length)),
1777 "Undefined predicate: " + name + "/" + arguments.Length);
1257 1778
1258 if (clauses.Count == 1) 1779 if (clauses.Count == 1)
1259 // Usually there is only one clause, so return it without needing to wrap it in an iterator. 1780 // Usually there is only one clause, so return it without needing to wrap it in an iterator.
@@ -1271,7 +1792,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1271 /// <returns></returns> 1792 /// <returns></returns>
1272 private static IEnumerable<bool> matchAllClauses(List<IClause> clauses, object[] arguments) 1793 private static IEnumerable<bool> matchAllClauses(List<IClause> clauses, object[] arguments)
1273 { 1794 {
1274 // Debug: If the clause asserts another clause into this same predicate, the iterator 1795 // Debug: If the caller asserts another clause into this same predicate during yield, the iterator
1275 // over clauses will be corrupted. Should we take the time to copy clauses? 1796 // over clauses will be corrupted. Should we take the time to copy clauses?
1276 foreach (IClause clause in clauses) 1797 foreach (IClause clause in clauses)
1277 { 1798 {
@@ -1297,16 +1818,122 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1297 return matchDynamic(name, arguments); 1818 return matchDynamic(name, arguments);
1298 } 1819 }
1299 1820
1821 public static IEnumerable<bool> clause(object Head, object Body)
1822 {
1823 Head = getValue(Head);
1824 Body = getValue(Body);
1825 if (Head is Variable)
1826 throw new PrologException("instantiation_error", "Head is an unbound variable");
1827
1828 Atom name = getFunctorName(Head) as Atom;
1829 if (name == null)
1830 // name is a non-Atom, such as a number.
1831 throw new PrologException
1832 (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable");
1833 object[] args = getFunctorArgs(Head);
1834 if (isSystemPredicate(name, args.Length))
1835 throw new PrologException
1836 (new Functor3("permission_error", Atom.a("access"), Atom.a("private_procedure"),
1837 new Functor2(Atom.SLASH, name, args.Length)),
1838 "clause cannot access private predicate " + name + "/" + args.Length);
1839 if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom))
1840 throw new PrologException
1841 (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable");
1842
1843 List<IClause> clauses;
1844 if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses))
1845 yield break;
1846 // The caller can assert another clause into this same predicate during yield, so we have to
1847 // make a copy of the clauses.
1848 foreach (IClause predicateClause in clauses.ToArray())
1849 {
1850 foreach (bool l1 in predicateClause.clause(Head, Body))
1851 yield return false;
1852 }
1853 }
1854
1855 public static IEnumerable<bool> retract(object Term)
1856 {
1857 Term = getValue(Term);
1858 if (Term is Variable)
1859 throw new PrologException("instantiation_error", "Term to retract is an unbound variable");
1860
1861 object Head, Body;
1862 if (Term is Functor2 && ((Functor2)Term)._name == Atom.RULE)
1863 {
1864 Head = YP.getValue(((Functor2)Term)._arg1);
1865 Body = YP.getValue(((Functor2)Term)._arg2);
1866 }
1867 else
1868 {
1869 Head = Term;
1870 Body = Atom.a("true");
1871 }
1872 if (Head is Variable)
1873 throw new PrologException("instantiation_error", "Head is an unbound variable");
1874
1875 Atom name = getFunctorName(Head) as Atom;
1876 if (name == null)
1877 // name is a non-Atom, such as a number.
1878 throw new PrologException
1879 (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable");
1880 object[] args = getFunctorArgs(Head);
1881 if (isSystemPredicate(name, args.Length))
1882 throw new PrologException
1883 (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
1884 new Functor2(Atom.SLASH, name, args.Length)),
1885 "clause cannot access private predicate " + name + "/" + args.Length);
1886 if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom))
1887 throw new PrologException
1888 (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable");
1889
1890 List<IClause> clauses;
1891 if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses))
1892 yield break;
1893 // The caller can assert another clause into this same predicate during yield, so we have to
1894 // make a copy of the clauses.
1895 foreach (IClause predicateClause in clauses.ToArray())
1896 {
1897 if (predicateClause is IndexedAnswers)
1898 {
1899 // IndexedAnswers handles its own retract. Even if it removes all of its
1900 // answers, it is OK to leave it empty as one of the elements in clauses.
1901 foreach (bool l1 in ((IndexedAnswers)predicateClause).retract(Head, Body))
1902 yield return false;
1903 }
1904 else
1905 {
1906 foreach (bool l1 in predicateClause.clause(Head, Body))
1907 {
1908 clauses.Remove(predicateClause);
1909 yield return false;
1910 }
1911 }
1912 }
1913 }
1914
1300 /// <summary> 1915 /// <summary>
1301 /// This actually searches all clauses, not just 1916 /// This is deprecated for backward compatibility. You should use retractall.
1302 /// the ones defined with assertFact, but we keep the name for
1303 /// backwards compatibility.
1304 /// </summary> 1917 /// </summary>
1305 /// <param name="name">must be an Atom</param> 1918 /// <param name="name">must be an Atom</param>
1306 /// <param name="arguments">an array of arity number of arguments</param> 1919 /// <param name="arguments">an array of arity number of arguments</param>
1307 public static void retractFact(Atom name, object[] arguments) 1920 public static void retractFact(Atom name, object[] arguments)
1308 { 1921 {
1309 NameArity nameArity = new NameArity(name, arguments.Length); 1922 retractall(Functor.make(name, arguments));
1923 }
1924
1925 /// <summary>
1926 /// Retract all dynamic clauses which unify with Head. If this matches all clauses in a predicate,
1927 /// the predicate is still defined. To completely remove the predicate, see abolish.
1928 /// </summary>
1929 /// <param name="Head"></param>
1930 public static void retractall(object Head)
1931 {
1932 object name = YP.getFunctorName(Head);
1933 object[] arguments = getFunctorArgs(Head);
1934 if (!(name is Atom))
1935 return;
1936 NameArity nameArity = new NameArity((Atom)name, arguments.Length);
1310 List<IClause> clauses; 1937 List<IClause> clauses;
1311 if (!_predicatesStore.TryGetValue(nameArity, out clauses)) 1938 if (!_predicatesStore.TryGetValue(nameArity, out clauses))
1312 // Can't find, so ignore. 1939 // Can't find, so ignore.
@@ -1315,11 +1942,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1315 foreach (object arg in arguments) 1942 foreach (object arg in arguments)
1316 { 1943 {
1317 if (!YP.var(arg)) 1944 if (!YP.var(arg))
1318 throw new InvalidOperationException("All arguments must be unbound"); 1945 throw new InvalidOperationException
1946 ("Until matching retractall is supported, all arguments must be unbound to retract all clauses");
1319 } 1947 }
1320 // Set to a fresh empty IndexedAnswers. 1948 // Clear all clauses.
1321 _predicatesStore[nameArity] = (clauses = new List<IClause>()); 1949 _predicatesStore[nameArity] = new List<IClause>();
1322 clauses.Add(new IndexedAnswers());
1323 } 1950 }
1324 1951
1325 public static IEnumerable<bool> current_predicate(object NameSlashArity) 1952 public static IEnumerable<bool> current_predicate(object NameSlashArity)
@@ -1328,57 +1955,99 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1328 // First check if Name and Arity are nonvar so we can do a direct lookup. 1955 // First check if Name and Arity are nonvar so we can do a direct lookup.
1329 if (YP.ground(NameSlashArity)) 1956 if (YP.ground(NameSlashArity))
1330 { 1957 {
1331 if (NameSlashArity is Functor2) 1958 Functor2 NameArityFunctor = NameSlashArity as Functor2;
1959 if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH))
1960 throw new PrologException
1961 (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
1962 "Must be a name/arity predicate indicator");
1963 object name = YP.getValue(NameArityFunctor._arg1);
1964 object arity = YP.getValue(NameArityFunctor._arg2);
1965 if (name is Variable || arity is Variable)
1966 throw new PrologException
1967 ("instantiation_error", "Predicate indicator name or arity is an unbound variable");
1968 if (!(name is Atom && arity is int))
1969 throw new PrologException
1970 (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
1971 "Must be a name/arity predicate indicator");
1972 if ((int)arity < 0)
1973 throw new PrologException
1974 (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
1975 "Arity may not be less than zero");
1976
1977 if (_predicatesStore.ContainsKey(new NameArity((Atom)name, (int)arity)))
1978 // The predicate is defined.
1979 yield return false;
1980 }
1981 else
1982 {
1983 foreach (NameArity key in _predicatesStore.Keys)
1332 { 1984 {
1333 Functor2 NameArityFunctor = (Functor2)NameSlashArity; 1985 foreach (bool l1 in YP.unify
1334 if (NameArityFunctor._name == Atom.SLASH) 1986 (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity))
1335 { 1987 yield return false;
1336 if (_predicatesStore.ContainsKey(new NameArity
1337 ((Atom)YP.getValue(NameArityFunctor._arg1),
1338 (int)YP.getValue(NameArityFunctor._arg2))))
1339 // The predicate is defined.
1340 yield return false;
1341 }
1342 } 1988 }
1343 yield break;
1344 } 1989 }
1990 }
1345 1991
1346 foreach (NameArity key in _predicatesStore.Keys) 1992 public static void abolish(object NameSlashArity)
1347 { 1993 {
1348 foreach (bool l1 in YP.unify 1994 NameSlashArity = YP.getValue(NameSlashArity);
1349 (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity)) 1995 if (NameSlashArity is Variable)
1350 yield return false; 1996 throw new PrologException
1351 } 1997 ("instantiation_error", "Predicate indicator is an unbound variable");
1998 Functor2 NameArityFunctor = NameSlashArity as Functor2;
1999 if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH))
2000 throw new PrologException
2001 (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity),
2002 "Must be a name/arity predicate indicator");
2003 object name = YP.getValue(NameArityFunctor._arg1);
2004 object arity = YP.getValue(NameArityFunctor._arg2);
2005 if (name is Variable || arity is Variable)
2006 throw new PrologException
2007 ("instantiation_error", "Predicate indicator name or arity is an unbound variable");
2008 if (!(name is Atom))
2009 throw new PrologException
2010 (new Functor2("type_error", Atom.a("atom"), name),
2011 "Predicate indicator name must be an atom");
2012 if (!(arity is int))
2013 throw new PrologException
2014 (new Functor2("type_error", Atom.a("integer"), arity),
2015 "Predicate indicator arity must be an integer");
2016 if ((int)arity < 0)
2017 throw new PrologException
2018 (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity),
2019 "Arity may not be less than zero");
2020
2021 if (isSystemPredicate((Atom)name, (int)arity))
2022 throw new PrologException
2023 (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
2024 new Functor2(Atom.SLASH, name, arity)),
2025 "Abolish cannot modify static predicate " + name + "/" + arity);
2026 _predicatesStore.Remove(new NameArity((Atom)name, (int)arity));
1352 } 2027 }
1353 2028
1354 /// <summary> 2029 /// <summary>
1355 /// Use YP.getFunctorName(Goal) and invoke the static method of this name in the 2030 /// If Goal is a simple predicate, call YP.getFunctorName(Goal) using arguments from
1356 /// declaringClass, using arguments from YP.getFunctorArgs(Goal). 2031 /// YP.getFunctorArgs(Goal). If not found, this throws a PrologException for existence_error.
1357 /// Note that Goal must be a simple functor, not a complex expression. 2032 /// Otherwise, compile the goal as a single clause predicate and invoke it.
1358 /// If not found, this throws UndefinedPredicateException.
1359 /// </summary> 2033 /// </summary>
1360 /// <param name="Goal"></param> 2034 /// <param name="Goal"></param>
1361 /// <param name="contextClass">the class for looking up default function references</param> 2035 /// <param name="declaringClass">if not null, used to resolve references to the default
2036 /// module Atom.a("")</param>
1362 /// <returns></returns> 2037 /// <returns></returns>
1363 public static IEnumerable<bool> getIterator(object Goal, Type declaringClass) 2038 public static IEnumerable<bool> getIterator(object Goal, Type declaringClass)
1364 { 2039 {
1365 Goal = YP.getValue(Goal);
1366 if (Goal is Variable)
1367 throw new PrologException("instantiation_error", "Goal to call is an unbound variable");
1368#if true
1369 List<Variable> variableSetList = new List<Variable>();
1370 addUniqueVariables(Goal, variableSetList);
1371 Variable[] variableSet = variableSetList.ToArray();
1372
1373 // Use Atom.F since it is ignored.
1374 return YPCompiler.compileAnonymousClause
1375 (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet);
1376#else
1377 Atom name; 2040 Atom name;
1378 object[] args; 2041 object[] args;
1379 while (true) 2042 while (true)
1380 { 2043 {
1381 name = (Atom)YP.getFunctorName(Goal); 2044 Goal = YP.getValue(Goal);
2045 if (Goal is Variable)
2046 throw new PrologException("instantiation_error", "Goal to call is an unbound variable");
2047 name = YP.getFunctorName(Goal) as Atom;
2048 if (name == null)
2049 throw new PrologException
2050 (new Functor2("type_error", Atom.a("callable"), Goal), "Goal to call is not callable");
1382 args = YP.getFunctorArgs(Goal); 2051 args = YP.getFunctorArgs(Goal);
1383 if (name == Atom.HAT && args.Length == 2) 2052 if (name == Atom.HAT && args.Length == 2)
1384 // Assume this is called from a bagof operation. Skip the leading qualifiers. 2053 // Assume this is called from a bagof operation. Skip the leading qualifiers.
@@ -1386,22 +2055,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1386 else 2055 else
1387 break; 2056 break;
1388 } 2057 }
1389 try 2058
1390 { 2059 IEnumerable<bool> simpleIterator = YPCompiler.getSimpleIterator(name, args, declaringClass);
1391 return (IEnumerable<bool>)declaringClass.InvokeMember 2060 if (simpleIterator != null)
1392 (name._name, BindingFlags.InvokeMethod, null, null, args); 2061 // We don't need to compile since the goal is a simple predicate which we call directly.
1393 } 2062 return simpleIterator;
1394 catch (TargetInvocationException exception) 2063
1395 { 2064 // Compile the goal as a clause.
1396 throw exception.InnerException; 2065 List<Variable> variableSetList = new List<Variable>();
1397 } 2066 addUniqueVariables(Goal, variableSetList);
1398 catch (MissingMethodException) 2067 Variable[] variableSet = variableSetList.ToArray();
1399 { 2068
1400 throw new UndefinedPredicateException 2069 // Use Atom.F since it is ignored.
1401 ("Cannot find predicate function: " + name + "/" + args.Length + " in " + 2070 return YPCompiler.compileAnonymousClause
1402 declaringClass.FullName, name, args.Length); 2071 (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet);
1403 }
1404#endif
1405 } 2072 }
1406 2073
1407 public static void throwException(object Term) 2074 public static void throwException(object Term)
@@ -1415,12 +2082,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1415 /// <param name="script_event"></param> 2082 /// <param name="script_event"></param>
1416 /// <param name="script_params"></param> 2083 /// <param name="script_params"></param>
1417 /// <returns></returns> 2084 /// <returns></returns>
1418 public static void script_event(object script_event, object script_params) 2085 public static IEnumerable<bool> script_event(object script_event, object script_params)
1419 { 2086 {
1420 // string function = ((Atom)YP.getValue(script_event))._name; 2087 // string function = ((Atom)YP.getValue(script_event))._name;
1421 object[] array = ListPair.toArray(script_params); 2088 object[] array = ListPair.toArray(script_params);
1422 if (array == null) 2089 if (array == null)
1423 return; // YP.fail(); 2090 yield return false; // return; // YP.fail();
1424 if (array.Length > 1) 2091 if (array.Length > 1)
1425 { 2092 {
1426 //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue 2093 //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue
@@ -1428,8 +2095,76 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1428 // sortArray(array); 2095 // sortArray(array);
1429 } 2096 }
1430 //return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array)); 2097 //return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array));
2098 yield return false;
2099 }
2100
2101 /* Non-prolog-ish functions for inline coding */
2102 public static string regexString(string inData, string inPattern, string presep,string postsep)
2103 {
2104 //string str=cycMessage;
2105 //string strMatch = @"\. \#\$(.*)\)";
2106 string results = "";
2107 for (Match m = Regex.Match(inData,inPattern); m.Success; m=m.NextMatch())
2108 {
2109 //Console.WriteLine( m );
2110 results += presep+ m + postsep;
2111 }
2112 return results;
1431 } 2113 }
1432 2114
2115 public static string cycComm(object msgobj)
2116 {
2117 string cycInputString = msgobj.ToString();
2118 string cycOutputString="";
2119 TcpClient socketForServer;
2120
2121 try
2122 {
2123 socketForServer = new TcpClient("localHost", 3601);
2124 }
2125 catch
2126 {
2127 Console.WriteLine("Failed to connect to server at {0}:999", "localhost");
2128 return "";
2129 }
2130
2131 NetworkStream networkStream = socketForServer.GetStream();
2132
2133 System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
2134
2135 System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
2136
2137 try
2138 {
2139 // read the data from the host and display it
2140
2141 {
2142
2143 streamWriter.WriteLine(cycInputString);
2144 streamWriter.Flush();
2145
2146 cycOutputString = streamReader.ReadLine();
2147 Console.WriteLine("Cycoutput:" + cycOutputString);
2148 //streamWriter.WriteLine("Client Message");
2149 //Console.WriteLine("Client Message");
2150 streamWriter.Flush();
2151 }
2152
2153 }
2154 catch
2155 {
2156 Console.WriteLine("Exception reading from Server");
2157 return "";
2158 }
2159 // tidy up
2160 networkStream.Close();
2161 return cycOutputString;
2162
2163 }
2164 //public static void throwException(object Term)
2165 //{
2166 // throw new PrologException(Term);
2167 //}
1433 /// <summary> 2168 /// <summary>
1434 /// An enumerator that does zero loops. 2169 /// An enumerator that does zero loops.
1435 /// </summary> 2170 /// </summary>
@@ -1644,5 +2379,32 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog
1644 } 2379 }
1645 } 2380 }
1646 #pragma warning restore 0168 2381 #pragma warning restore 0168
2382 /// <summary>
2383 /// A ClauseHeadAndBody is used in Compiler.compileAnonymousFunction as a base class
2384 /// in order to implement YP.IClause. After creating the object, you must call setHeadAndBody.
2385 /// </summary>
2386 public class ClauseHeadAndBody
2387 {
2388 private object _Head;
2389 private object _Body;
2390
2391 public void setHeadAndBody(object Head, object Body)
2392 {
2393 _Head = Head;
2394 _Body = Body;
2395 }
2396
2397 public IEnumerable<bool> clause(object Head, object Body)
2398 {
2399 if (_Head == null || _Body == null)
2400 yield break;
2401
2402 foreach (bool l1 in YP.unify(Head, _Head))
2403 {
2404 foreach (bool l2 in YP.unify(Body, _Body))
2405 yield return false;
2406 }
2407 }
2408 }
1647 } 2409 }
1648} 2410}