aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
diff options
context:
space:
mode:
authorCharles Krinke2008-07-16 01:00:40 +0000
committerCharles Krinke2008-07-16 01:00:40 +0000
commit620f7926f3f2ad05fdb72050a87e49d0fa2357dd (patch)
tree848c3c4071ff70f6e24c7e46741bca67b39495c4 /OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
parentadd migration for SceneGroupID to char(36) plus add an index. This (diff)
downloadopensim-SC_OLD-620f7926f3f2ad05fdb72050a87e49d0fa2357dd.zip
opensim-SC_OLD-620f7926f3f2ad05fdb72050a87e49d0fa2357dd.tar.gz
opensim-SC_OLD-620f7926f3f2ad05fdb72050a87e49d0fa2357dd.tar.bz2
opensim-SC_OLD-620f7926f3f2ad05fdb72050a87e49d0fa2357dd.tar.xz
Mantis#1753. Thank you kindly, Kinoc for a patch that:
Brings Yield Prolog up to date with sourceforge version 0.9.10 Patched applies to both DotNet and XEngine.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs1221
1 files changed, 977 insertions, 244 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
index c212fb8..3d19d3e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/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.Shared.YieldProlog 40namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
38{ 41{
@@ -48,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.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.Shared.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.Shared.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.Shared.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.Shared.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.Shared.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.Shared.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.
@@ -561,6 +598,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
561 return _repeat; 598 return _repeat;
562 } 599 }
563 600
601 // disable warning on l1, don't see how we can
602 // code this differently
603 #pragma warning disable 0168
564 public static IEnumerable<bool> univ(object Term, object List) 604 public static IEnumerable<bool> univ(object Term, object List)
565 { 605 {
566 Term = YP.getValue(Term); 606 Term = YP.getValue(Term);
@@ -572,23 +612,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
572 612
573 Variable Name = new Variable(); 613 Variable Name = new Variable();
574 Variable ArgList = new Variable(); 614 Variable ArgList = new Variable();
575// disable warning: don't see how we can code this differently short
576// of rewriting the whole thing
577#pragma warning disable 0168
578 foreach (bool l1 in new ListPair(Name, ArgList).unify(List)) 615 foreach (bool l1 in new ListPair(Name, ArgList).unify(List))
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 }
591#pragma warning restore 0168
592 632
593 return YP.fail(); 633 return YP.fail();
594 } 634 }
@@ -599,43 +639,81 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
599 FunctorName = YP.getValue(FunctorName); 639 FunctorName = YP.getValue(FunctorName);
600 Arity = YP.getValue(Arity); 640 Arity = YP.getValue(Arity);
601 641
602 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
603 { 681 {
604// disable warning: don't see how we can code this differently short
605// of rewriting the whole thing
606#pragma warning disable 0168
607 foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term))) 682 foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term)))
608 { 683 {
609 foreach (bool l2 in YP.unify(Arity, getFunctorArgs(Term).Length)) 684 foreach (bool l2 in YP.unify(Arity, getFunctorArgs(Term).Length))
610 yield return false; 685 yield return false;
611 } 686 }
612#pragma warning restore 0168
613 } 687 }
614 else
615 throw new NotImplementedException("Debug: must finish functor/3");
616 } 688 }
617 689
618 public static IEnumerable<bool> arg(object ArgNumber, object Term, object Value) 690 public static IEnumerable<bool> arg(object ArgNumber, object Term, object Value)
619 { 691 {
620 if (YP.var(ArgNumber)) 692 if (var(ArgNumber))
621 throw new NotImplementedException("Debug: must finish arg/3"); 693 throw new PrologException(Atom.a("instantiation_error"), "Arg 1 ArgNumber is an unbound variable");
622 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)
623 { 713 {
624 int argNumberInt = convertInt(ArgNumber); 714 // The first ArgNumber is at 1, not 0.
625 if (argNumberInt < 0) 715 foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1]))
626 throw new Exception("ArgNumber must be non-negative"); 716 yield return false;
627 object[] termArgs = YP.getFunctorArgs(Term);
628 // Silently fail if argNumberInt is out of range.
629 if (argNumberInt >= 1 && argNumberInt <= termArgs.Length)
630 {
631 // The first ArgNumber is at 1, not 0.
632// disable warning: don't see how we can code this differently short
633// of rewriting the whole thing
634#pragma warning disable 0168
635 foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1]))
636 yield return false;
637#pragma warning restore 0168
638 }
639 } 717 }
640 } 718 }
641 719
@@ -665,8 +743,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
665 if (term1TypeCode == -2) 743 if (term1TypeCode == -2)
666 { 744 {
667 // Variable. 745 // Variable.
668 // 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
669 // that less than returns false if the terms are equal, in 747 // that less than returns false if the terms are equal, in
670 // 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.
671 if ((Variable)Term1 != (Variable)Term2) 749 if ((Variable)Term1 != (Variable)Term2)
672 // The hash code should be unique to a Variable object. 750 // The hash code should be unique to a Variable object.
@@ -709,8 +787,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
709 } 787 }
710 788
711 /// <summary> 789 /// <summary>
712 /// 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,
713 /// 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,
714 /// 4 if it is Functor. 792 /// 4 if it is Functor.
715 /// Otherwise, type code is -1. 793 /// Otherwise, type code is -1.
716 /// This does not call YP.getValue(term). 794 /// This does not call YP.getValue(term).
@@ -778,101 +856,303 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
778 if (_operatorTable == null) 856 if (_operatorTable == null)
779 { 857 {
780 // Initialize. 858 // Initialize.
781 _operatorTable = new List<object[]>(); 859 _operatorTable = new IndexedAnswers(3);
782 _operatorTable.Add(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") }); 860 _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") });
783 _operatorTable.Add(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") }); 861 _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") });
784 _operatorTable.Add(new object[] { 1200, Atom.a("fx"), Atom.a(":-") }); 862 _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a(":-") });
785 _operatorTable.Add(new object[] { 1200, Atom.a("fx"), Atom.a("?-") }); 863 _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a("?-") });
786 _operatorTable.Add(new object[] { 1100, Atom.a("xfy"), Atom.a(";") }); 864 _operatorTable.addAnswer(new object[] { 1100, Atom.a("xfy"), Atom.a(";") });
787 _operatorTable.Add(new object[] { 1050, Atom.a("xfy"), Atom.a("->") }); 865 _operatorTable.addAnswer(new object[] { 1050, Atom.a("xfy"), Atom.a("->") });
788 _operatorTable.Add(new object[] { 1000, Atom.a("xfy"), Atom.a(",") }); 866 _operatorTable.addAnswer(new object[] { 1000, Atom.a("xfy"), Atom.a(",") });
789 _operatorTable.Add(new object[] { 900, Atom.a("fy"), Atom.a("\\+") }); 867 _operatorTable.addAnswer(new object[] { 900, Atom.a("fy"), Atom.a("\\+") });
790 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=") }); 868 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=") });
791 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") }); 869 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") });
792 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("==") }); 870 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("==") });
793 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") }); 871 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") });
794 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@<") }); 872 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@<") });
795 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") }); 873 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") });
796 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@>") }); 874 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>") });
797 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") }); 875 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") });
798 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=..") }); 876 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=..") });
799 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("is") }); 877 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("is") });
800 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") }); 878 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") });
801 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") }); 879 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") });
802 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("<") }); 880 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("<") });
803 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a("=<") }); 881 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=<") });
804 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a(">") }); 882 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">") });
805 _operatorTable.Add(new object[] { 700, Atom.a("xfx"), Atom.a(">=") }); 883 _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">=") });
806 _operatorTable.Add(new object[] { 600, Atom.a("xfy"), Atom.a(":") }); 884 _operatorTable.addAnswer(new object[] { 600, Atom.a("xfy"), Atom.a(":") });
807 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("+") }); 885 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("+") });
808 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("-") }); 886 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("-") });
809 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") }); 887 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") });
810 _operatorTable.Add(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") }); 888 _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") });
811 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("*") }); 889 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("*") });
812 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("/") }); 890 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("/") });
813 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("//") }); 891 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("//") });
814 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("rem") }); 892 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("rem") });
815 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("mod") }); 893 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("mod") });
816 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a("<<") }); 894 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("<<") });
817 _operatorTable.Add(new object[] { 400, Atom.a("yfx"), Atom.a(">>") }); 895 _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a(">>") });
818 _operatorTable.Add(new object[] { 200, Atom.a("xfx"), Atom.a("**") }); 896 _operatorTable.addAnswer(new object[] { 200, Atom.a("xfx"), Atom.a("**") });
819 _operatorTable.Add(new object[] { 200, Atom.a("xfy"), Atom.a("^") }); 897 _operatorTable.addAnswer(new object[] { 200, Atom.a("xfy"), Atom.a("^") });
820 _operatorTable.Add(new object[] { 200, Atom.a("fy"), Atom.a("-") }); 898 _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("-") });
821 _operatorTable.Add(new object[] { 200, Atom.a("fy"), Atom.a("\\") }); 899 _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("\\") });
822 // 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.
823 _operatorTable.Add(new object[] { 20, Atom.a("xfx"), Atom.a("<--") }); 901 _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") });
824 } 902 }
825 903
826 object[] args = new object[] { Priority, Specifier, Operator }; 904 foreach (bool l1 in _operatorTable.match(new object[] { Priority, Specifier, Operator }))
827 foreach (object[] answer in _operatorTable) 905 yield return false;
828 {
829// disable warning: don't see how we can code this differently short
830// of rewriting the whole thing
831#pragma warning disable 0168
832 foreach (bool l1 in YP.unifyArrays(args, answer))
833 yield return false;
834#pragma warning restore 0168
835 }
836 } 906 }
837 907
838 public static IEnumerable<bool> atom_length(object atom, object Length) 908 public static IEnumerable<bool> atom_length(object atom, object Length)
839 { 909 {
840 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);
841 } 929 }
842 930
843 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)
844 { 932 {
845 // Debug: Should implement for var(Start) which is a kind of search.
846 // Debug: Should we try to preserve the _declaringClass? 933 // Debug: Should we try to preserve the _declaringClass?
847 return YP.unify(Whole, Atom.a(((Atom)YP.getValue(Start))._name + 934 Start = YP.getValue(Start);
848 ((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 }
849 } 999 }
850 1000
851 public static IEnumerable<bool> sub_atom 1001 public static IEnumerable<bool> sub_atom
852 (object atom, object Before, object Length, object After, object Sub_atom) 1002 (object atom, object Before, object Length, object After, object Sub_atom)
853 { 1003 {
854 // Debug: Should implement for var(atom) which is a kind of search.
855 // Debug: Should we try to preserve the _declaringClass? 1004 // Debug: Should we try to preserve the _declaringClass?
856 Atom atomAtom = (Atom)YP.getValue(atom); 1005 atom = YP.getValue(atom);
857 int beforeInt = YP.convertInt(Before); 1006 Before = YP.getValue(Before);
858 int lengthInt = YP.convertInt(Length); 1007 Length = YP.getValue(Length);
859 if (beforeInt < 0) 1008 After = YP.getValue(After);
860 throw new Exception("Before must be non-negative"); 1009 Sub_atom = YP.getValue(Sub_atom);
861 if (lengthInt < 0) 1010 if (atom is Variable)
862 throw new Exception("Length must be non-negative"); 1011 throw new PrologException(Atom.a("instantiation_error"),
863 int afterInt = atomAtom._name.Length - (beforeInt + lengthInt); 1012 "Expected atom(Arg1) but it is an unbound variable");
864 if (afterInt >= 0) 1013 if (!(atom is Atom))
865 { 1014 throw new PrologException
866// disable warning: don't see how we can code this differently short 1015 (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom");
867// of rewriting the whole thing 1016 if (!(Sub_atom is Variable))
868#pragma warning disable 0168 1017 {
869 foreach (bool l1 in YP.unify(After, afterInt)) 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)
870 { 1067 {
871 foreach (bool l2 in YP.unify 1068 foreach (bool l1 in YP.unify(After, xAfter))
872 (Sub_atom, Atom.a(atomAtom._name.Substring(beforeInt, lengthInt)))) 1069 {
873 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 }
874 } 1110 }
875#pragma warning restore 0168 1111 }
1112 }
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);
876 } 1156 }
877 } 1157 }
878 1158
@@ -881,38 +1161,141 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
881 atom = YP.getValue(atom); 1161 atom = YP.getValue(atom);
882 List = YP.getValue(List); 1162 List = YP.getValue(List);
883 1163
884 if (nonvar(atom)) 1164 if (atom is Variable)
885 { 1165 {
886 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;
887 object codeList = Atom.NIL; 1193 object codeList = Atom.NIL;
888 // Start from the back to make the list. 1194 // Start from the back to make the list.
889 for (int i = name.Length - 1; i >= 0; --i) 1195 for (int i = atomString.Length - 1; i >= 0; --i)
890 codeList = new ListPair((int)name[i], codeList); 1196 codeList = new ListPair((int)atomString[i], codeList);
891 return YP.unify(List, codeList); 1197 return YP.unify(List, codeList);
892 } 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)
893 { 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");
894 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
895 char[] charArray = new char[codeArray.Length]; 1216 char[] charArray = new char[codeArray.Length];
896 for (int i = 0; i < codeArray.Length; ++i) 1217 for (int i = 0; i < codeArray.Length; ++i)
897 charArray[i] = (char)YP.convertInt(codeArray[i]); 1218 {
898 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);
899 } 1253 }
900 } 1254 }
901 1255
902 public static IEnumerable<bool> number_codes(object number, object List) 1256 public static IEnumerable<bool> number_codes(object Number, object List)
903 { 1257 {
904 number = YP.getValue(number); 1258 Number = YP.getValue(Number);
905 List = YP.getValue(List); 1259 List = YP.getValue(List);
906 1260
907 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
908 { 1284 {
909 string numberString = null; 1285 string numberString = null;
910 // Try converting to an int first. 1286 // Try converting to an int first.
911 int intNumber; 1287 int intNumber;
912 if (YP.getInt(number, out intNumber)) 1288 if (YP.getInt(Number, out intNumber))
913 numberString = intNumber.ToString(); 1289 numberString = intNumber.ToString();
914 else 1290 else
915 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 }
916 1299
917 object codeList = Atom.NIL; 1300 object codeList = Atom.NIL;
918 // Start from the back to make the list. 1301 // Start from the back to make the list.
@@ -920,20 +1303,92 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
920 codeList = new ListPair((int)numberString[i], codeList); 1303 codeList = new ListPair((int)numberString[i], codeList);
921 return YP.unify(List, codeList); 1304 return YP.unify(List, codeList);
922 } 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"))
923 { 1321 {
924 object[] codeArray = ListPair.toArray(List);
925 char[] charArray = new char[codeArray.Length];
926 for (int i = 0; i < codeArray.Length; ++i)
927 charArray[i] = (char)YP.convertInt(codeArray[i]);
928 String numberString = new String(charArray);
929 // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception?
930 try 1322 try
931 { 1323 {
932 // Try an int first. 1324 return Int32.Parse
933 return YP.unify(number, Convert.ToInt32(numberString)); 1325 (numberString.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier);
934 } 1326 }
935 catch (FormatException) { } 1327 catch (FormatException)
936 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]);
937 } 1392 }
938 } 1393 }
939 1394
@@ -1109,7 +1564,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1109 } 1564 }
1110 1565
1111 /// <summary> 1566 /// <summary>
1112 /// 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
1113 /// use "1" which will parse as an int. 1568 /// use "1" which will parse as an int.
1114 /// </summary> 1569 /// </summary>
1115 /// <param name="x"></param> 1570 /// <param name="x"></param>
@@ -1134,7 +1589,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1134 1589
1135 public static void put_code(object x) 1590 public static void put_code(object x)
1136 { 1591 {
1137 _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);
1138 } 1599 }
1139 1600
1140 public static void nl() 1601 public static void nl()
@@ -1170,6 +1631,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1170 { 1631 {
1171 Head = YP.getValue(((Functor2)TermCopy)._arg1); 1632 Head = YP.getValue(((Functor2)TermCopy)._arg1);
1172 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");
1173 } 1638 }
1174 else 1639 else
1175 { 1640 {
@@ -1183,7 +1648,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1183 throw new PrologException 1648 throw new PrologException
1184 (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");
1185 object[] args = getFunctorArgs(Head); 1650 object[] args = getFunctorArgs(Head);
1186 if (!isDynamic(name, args.Length)) 1651 if (isSystemPredicate(name, args.Length))
1187 throw new PrologException 1652 throw new PrologException
1188 (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), 1653 (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"),
1189 new Functor2(Atom.SLASH, name, args.Length)), 1654 new Functor2(Atom.SLASH, name, args.Length)),
@@ -1191,17 +1656,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1191 1656
1192 if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true")) 1657 if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true"))
1193 { 1658 {
1194 // Debug: Until IndexedAnswers supports prepend, compile the fact so we can prepend it below. 1659 // This is a fact with no unbound variables
1195 if (!prepend) 1660 // assertFact and prependFact use IndexedAnswers, so don't we don't need to compile.
1196 { 1661 if (prepend)
1197 // This is a fact with no unbound variables 1662 prependFact(name, args);
1198 // assertFact uses IndexedAnswers, so don't we don't need to compile. 1663 else
1199 assertFact(name, args); 1664 assertFact(name, args);
1200 return; 1665
1201 } 1666 return;
1202 } 1667 }
1203 1668
1204 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);
1205 1674
1206 // Add the clause to the entry in _predicatesStore. 1675 // Add the clause to the entry in _predicatesStore.
1207 NameArity nameArity = new NameArity(name, args.Length); 1676 NameArity nameArity = new NameArity(name, args.Length);
@@ -1216,19 +1685,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1216 clauses.Add(clause); 1685 clauses.Add(clause);
1217 } 1686 }
1218 1687
1219 private static bool isDynamic(Atom name, int arity) 1688 private static bool isSystemPredicate(Atom name, int arity)
1220 { 1689 {
1221 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))
1222 return false; 1691 return true;
1223 // 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.
1224// disable warning: don't see how we can code this differently short
1225// of rewriting the whole thing
1226#pragma warning disable 0168
1227 foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable())) 1693 foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable()))
1228 return false; 1694 return true;
1229 // Debug: Do we need to check if name._module is null? 1695 // Debug: Do we need to check if name._module is null?
1230#pragma warning restore 0168 1696 return false;
1231 return true;
1232 } 1697 }
1233 1698
1234 /// <summary> 1699 /// <summary>
@@ -1245,22 +1710,55 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1245 IndexedAnswers indexedAnswers; 1710 IndexedAnswers indexedAnswers;
1246 if (!_predicatesStore.TryGetValue(nameArity, out clauses)) 1711 if (!_predicatesStore.TryGetValue(nameArity, out clauses))
1247 { 1712 {
1248 // Create an IndexedAnswers as the first clause of the predicate. 1713 // Create an IndexedAnswers as the only clause of the predicate.
1249 _predicatesStore[nameArity] = (clauses = new List<IClause>()); 1714 _predicatesStore[nameArity] = (clauses = new List<IClause>());
1250 clauses.Add(indexedAnswers = new IndexedAnswers()); 1715 clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
1251 } 1716 }
1252 else 1717 else
1253 { 1718 {
1254 indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers; 1719 indexedAnswers = null;
1720 if (clauses.Count >= 1)
1721 indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers;
1255 if (indexedAnswers == null) 1722 if (indexedAnswers == null)
1256 // The latest clause is not an IndexedAnswers, so add one. 1723 // The latest clause is not an IndexedAnswers, so add one.
1257 clauses.Add(indexedAnswers = new IndexedAnswers()); 1724 clauses.Add(indexedAnswers = new IndexedAnswers(values.Length));
1258 } 1725 }
1259 1726
1260 indexedAnswers.addAnswer(values); 1727 indexedAnswers.addAnswer(values);
1261 } 1728 }
1262 1729
1263 /// <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>
1264 /// 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
1265 /// arguments.Length. 1763 /// arguments.Length.
1266 /// It is an error if the predicate is not defined. 1764 /// It is an error if the predicate is not defined.
@@ -1272,9 +1770,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1272 { 1770 {
1273 List<IClause> clauses; 1771 List<IClause> clauses;
1274 if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses)) 1772 if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses))
1275 throw new UndefinedPredicateException 1773 throw new PrologException
1276 ("Undefined fact: " + name + "/" + arguments.Length, name, 1774 (new Functor2
1277 arguments.Length); 1775 (Atom.a("existence_error"), Atom.a("procedure"),
1776 new Functor2(Atom.SLASH, name, arguments.Length)),
1777 "Undefined predicate: " + name + "/" + arguments.Length);
1278 1778
1279 if (clauses.Count == 1) 1779 if (clauses.Count == 1)
1280 // 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.
@@ -1292,7 +1792,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1292 /// <returns></returns> 1792 /// <returns></returns>
1293 private static IEnumerable<bool> matchAllClauses(List<IClause> clauses, object[] arguments) 1793 private static IEnumerable<bool> matchAllClauses(List<IClause> clauses, object[] arguments)
1294 { 1794 {
1295 // 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
1296 // 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?
1297 foreach (IClause clause in clauses) 1797 foreach (IClause clause in clauses)
1298 { 1798 {
@@ -1318,16 +1818,122 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1318 return matchDynamic(name, arguments); 1818 return matchDynamic(name, arguments);
1319 } 1819 }
1320 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
1321 /// <summary> 1915 /// <summary>
1322 /// This actually searches all clauses, not just 1916 /// This is deprecated for backward compatibility. You should use retractall.
1323 /// the ones defined with assertFact, but we keep the name for
1324 /// backwards compatibility.
1325 /// </summary> 1917 /// </summary>
1326 /// <param name="name">must be an Atom</param> 1918 /// <param name="name">must be an Atom</param>
1327 /// <param name="arguments">an array of arity number of arguments</param> 1919 /// <param name="arguments">an array of arity number of arguments</param>
1328 public static void retractFact(Atom name, object[] arguments) 1920 public static void retractFact(Atom name, object[] arguments)
1329 { 1921 {
1330 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);
1331 List<IClause> clauses; 1937 List<IClause> clauses;
1332 if (!_predicatesStore.TryGetValue(nameArity, out clauses)) 1938 if (!_predicatesStore.TryGetValue(nameArity, out clauses))
1333 // Can't find, so ignore. 1939 // Can't find, so ignore.
@@ -1336,11 +1942,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1336 foreach (object arg in arguments) 1942 foreach (object arg in arguments)
1337 { 1943 {
1338 if (!YP.var(arg)) 1944 if (!YP.var(arg))
1339 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");
1340 } 1947 }
1341 // Set to a fresh empty IndexedAnswers. 1948 // Clear all clauses.
1342 _predicatesStore[nameArity] = (clauses = new List<IClause>()); 1949 _predicatesStore[nameArity] = new List<IClause>();
1343 clauses.Add(new IndexedAnswers());
1344 } 1950 }
1345 1951
1346 public static IEnumerable<bool> current_predicate(object NameSlashArity) 1952 public static IEnumerable<bool> current_predicate(object NameSlashArity)
@@ -1349,61 +1955,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1349 // 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.
1350 if (YP.ground(NameSlashArity)) 1956 if (YP.ground(NameSlashArity))
1351 { 1957 {
1352 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)
1353 { 1984 {
1354 Functor2 NameArityFunctor = (Functor2)NameSlashArity; 1985 foreach (bool l1 in YP.unify
1355 if (NameArityFunctor._name == Atom.SLASH) 1986 (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity))
1356 { 1987 yield return false;
1357 if (_predicatesStore.ContainsKey(new NameArity
1358 ((Atom)YP.getValue(NameArityFunctor._arg1),
1359 (int)YP.getValue(NameArityFunctor._arg2))))
1360 // The predicate is defined.
1361 yield return false;
1362 }
1363 } 1988 }
1364 yield break;
1365 } 1989 }
1990 }
1366 1991
1367 foreach (NameArity key in _predicatesStore.Keys) 1992 public static void abolish(object NameSlashArity)
1368 { 1993 {
1369// disable warning: don't see how we can code this differently short 1994 NameSlashArity = YP.getValue(NameSlashArity);
1370// of rewriting the whole thing 1995 if (NameSlashArity is Variable)
1371#pragma warning disable 0168 1996 throw new PrologException
1372 foreach (bool l1 in YP.unify 1997 ("instantiation_error", "Predicate indicator is an unbound variable");
1373 (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity)) 1998 Functor2 NameArityFunctor = NameSlashArity as Functor2;
1374 yield return false; 1999 if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH))
1375#pragma warning restore 0168 2000 throw new PrologException
1376 } 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));
1377 } 2027 }
1378 2028
1379 /// <summary> 2029 /// <summary>
1380 /// 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
1381 /// declaringClass, using arguments from YP.getFunctorArgs(Goal). 2031 /// YP.getFunctorArgs(Goal). If not found, this throws a PrologException for existence_error.
1382 /// 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.
1383 /// If not found, this throws UndefinedPredicateException.
1384 /// </summary> 2033 /// </summary>
1385 /// <param name="Goal"></param> 2034 /// <param name="Goal"></param>
1386 /// <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>
1387 /// <returns></returns> 2037 /// <returns></returns>
1388 public static IEnumerable<bool> getIterator(object Goal, Type declaringClass) 2038 public static IEnumerable<bool> getIterator(object Goal, Type declaringClass)
1389 { 2039 {
1390 Goal = YP.getValue(Goal);
1391 if (Goal is Variable)
1392 throw new PrologException("instantiation_error", "Goal to call is an unbound variable");
1393#if true
1394 List<Variable> variableSetList = new List<Variable>();
1395 addUniqueVariables(Goal, variableSetList);
1396 Variable[] variableSet = variableSetList.ToArray();
1397
1398 // Use Atom.F since it is ignored.
1399 return YPCompiler.compileAnonymousClause
1400 (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet);
1401#else
1402 Atom name; 2040 Atom name;
1403 object[] args; 2041 object[] args;
1404 while (true) 2042 while (true)
1405 { 2043 {
1406 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");
1407 args = YP.getFunctorArgs(Goal); 2051 args = YP.getFunctorArgs(Goal);
1408 if (name == Atom.HAT && args.Length == 2) 2052 if (name == Atom.HAT && args.Length == 2)
1409 // 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.
@@ -1411,22 +2055,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1411 else 2055 else
1412 break; 2056 break;
1413 } 2057 }
1414 try 2058
1415 { 2059 IEnumerable<bool> simpleIterator = YPCompiler.getSimpleIterator(name, args, declaringClass);
1416 return (IEnumerable<bool>)declaringClass.InvokeMember 2060 if (simpleIterator != null)
1417 (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.
1418 } 2062 return simpleIterator;
1419 catch (TargetInvocationException exception) 2063
1420 { 2064 // Compile the goal as a clause.
1421 throw exception.InnerException; 2065 List<Variable> variableSetList = new List<Variable>();
1422 } 2066 addUniqueVariables(Goal, variableSetList);
1423 catch (MissingMethodException) 2067 Variable[] variableSet = variableSetList.ToArray();
1424 { 2068
1425 throw new UndefinedPredicateException 2069 // Use Atom.F since it is ignored.
1426 ("Cannot find predicate function: " + name + "/" + args.Length + " in " + 2070 return YPCompiler.compileAnonymousClause
1427 declaringClass.FullName, name, args.Length); 2071 (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet);
1428 }
1429#endif
1430 } 2072 }
1431 2073
1432 public static void throwException(object Term) 2074 public static void throwException(object Term)
@@ -1440,12 +2082,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1440 /// <param name="script_event"></param> 2082 /// <param name="script_event"></param>
1441 /// <param name="script_params"></param> 2083 /// <param name="script_params"></param>
1442 /// <returns></returns> 2084 /// <returns></returns>
1443 public static void script_event(object script_event, object script_params) 2085 public static IEnumerable<bool> script_event(object script_event, object script_params)
1444 { 2086 {
1445 // string function = ((Atom)YP.getValue(script_event))._name; 2087 // string function = ((Atom)YP.getValue(script_event))._name;
1446 object[] array = ListPair.toArray(script_params); 2088 object[] array = ListPair.toArray(script_params);
1447 if (array == null) 2089 if (array == null)
1448 return; // YP.fail(); 2090 yield return false; // return; // YP.fail();
1449 if (array.Length > 1) 2091 if (array.Length > 1)
1450 { 2092 {
1451 //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue 2093 //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue
@@ -1453,8 +2095,76 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1453 // sortArray(array); 2095 // sortArray(array);
1454 } 2096 }
1455 //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;
1456 } 2113 }
1457 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 //}
1458 /// <summary> 2168 /// <summary>
1459 /// An enumerator that does zero loops. 2169 /// An enumerator that does zero loops.
1460 /// </summary> 2170 /// </summary>
@@ -1628,16 +2338,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1628 if (_exception != null) 2338 if (_exception != null)
1629 { 2339 {
1630 bool didUnify = false; 2340 bool didUnify = false;
1631// disable warning: don't see how we can code this differently short
1632// of rewriting the whole thing
1633#pragma warning disable 0168
1634 foreach (bool l1 in YP.unify(_exception._term, Catcher)) 2341 foreach (bool l1 in YP.unify(_exception._term, Catcher))
1635 { 2342 {
1636 didUnify = true; 2343 didUnify = true;
1637 yield return false; 2344 yield return false;
1638 } 2345 }
1639#pragma warning restore 0168
1640
1641 if (!didUnify) 2346 if (!didUnify)
1642 throw _exception; 2347 throw _exception;
1643 } 2348 }
@@ -1673,5 +2378,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
1673 throw new NotImplementedException(); 2378 throw new NotImplementedException();
1674 } 2379 }
1675 } 2380 }
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 }
1676 } 2409 }
1677} 2410}