Atom.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright (C) 2007-2008, Jeff Thompson
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  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
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. using System;
  31. using System.Collections.Generic;
  32. using System.Text;
  33. namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
  34. {
  35. public class Atom : IUnifiable
  36. {
  37. private static Dictionary<string, Atom> _atomStore = new Dictionary<string, Atom>();
  38. public readonly string _name;
  39. public readonly Atom _module;
  40. /// <summary>
  41. /// You should not call this constructor, but use Atom.a instead.
  42. /// </summary>
  43. /// <param name="name"></param>
  44. /// <param name="module"></param>
  45. private Atom(string name, Atom module)
  46. {
  47. _name = name;
  48. _module = module;
  49. }
  50. /// <summary>
  51. /// Return the unique Atom object for name where module is null. You should use this to create
  52. /// an Atom instead of calling the Atom constructor.
  53. /// </summary>
  54. /// <param name="name"></param>
  55. /// <returns></returns>
  56. public static Atom a(string name)
  57. {
  58. Atom atom;
  59. if (!_atomStore.TryGetValue(name, out atom))
  60. {
  61. atom = new Atom(name, null);
  62. _atomStore[name] = atom;
  63. }
  64. return atom;
  65. }
  66. /// <summary>
  67. /// Return an Atom object with the name and module. If module is null or Atom.NIL,
  68. /// this behaves like Atom.a(name) and returns the unique object where the module is null.
  69. /// If module is not null or Atom.NIL, this may or may not be the same object as another Atom
  70. /// with the same name and module.
  71. /// </summary>
  72. /// <param name="name"></param>
  73. /// <param name="module"></param>
  74. /// <returns></returns>
  75. public static Atom a(string name, Atom module)
  76. {
  77. if (module == null || module == Atom.NIL)
  78. return a(name);
  79. return new Atom(name, module);
  80. }
  81. /// <summary>
  82. /// If Obj is an Atom unify its _module with Module. If the Atom's _module is null, use Atom.NIL.
  83. /// </summary>
  84. /// <param name="Atom"></param>
  85. /// <param name="Module"></param>
  86. /// <returns></returns>
  87. public static IEnumerable<bool> module(object Obj, object Module)
  88. {
  89. Obj = YP.getValue(Obj);
  90. if (Obj is Atom)
  91. {
  92. if (((Atom)Obj)._module == null)
  93. return YP.unify(Module, Atom.NIL);
  94. else
  95. return YP.unify(Module, ((Atom)Obj)._module);
  96. }
  97. return YP.fail();
  98. }
  99. public static readonly Atom NIL = Atom.a("[]");
  100. public static readonly Atom DOT = Atom.a(".");
  101. public static readonly Atom F = Atom.a("f");
  102. public static readonly Atom SLASH = Atom.a("/");
  103. public static readonly Atom HAT = Atom.a("^");
  104. public static readonly Atom RULE = Atom.a(":-");
  105. public IEnumerable<bool> unify(object arg)
  106. {
  107. arg = YP.getValue(arg);
  108. if (arg is Atom)
  109. return Equals(arg) ? YP.succeed() : YP.fail();
  110. else if (arg is Variable)
  111. return ((Variable)arg).unify(this);
  112. else
  113. return YP.fail();
  114. }
  115. public void addUniqueVariables(List<Variable> variableSet)
  116. {
  117. // Atom does not contain variables.
  118. }
  119. public object makeCopy(Variable.CopyStore copyStore)
  120. {
  121. // Atom does not contain variables that need to be copied.
  122. return this;
  123. }
  124. public bool termEqual(object term)
  125. {
  126. return Equals(YP.getValue(term));
  127. }
  128. public bool ground()
  129. {
  130. // Atom is always ground.
  131. return true;
  132. }
  133. public override bool Equals(object obj)
  134. {
  135. if (obj is Atom)
  136. {
  137. if (_module == null && ((Atom)obj)._module == null)
  138. // When _declaringClass is null, we always use an identical object from _atomStore.
  139. return this == obj;
  140. // Otherwise, ignore _declaringClass and do a normal string compare on the _name.
  141. return _name == ((Atom)obj)._name;
  142. }
  143. return false;
  144. }
  145. public override string ToString()
  146. {
  147. return _name;
  148. }
  149. public override int GetHashCode()
  150. {
  151. // Debug: need to check _declaringClass.
  152. return _name.GetHashCode();
  153. }
  154. public string toQuotedString()
  155. {
  156. if (_name.Length == 0)
  157. return "''";
  158. else if (this == Atom.NIL)
  159. return "[]";
  160. StringBuilder result = new StringBuilder(_name.Length);
  161. bool useQuotes = false;
  162. foreach (char c in _name)
  163. {
  164. int cInt = (int)c;
  165. if (c == '\'')
  166. {
  167. result.Append("''");
  168. useQuotes = true;
  169. }
  170. else if (c == '_' || cInt >= (int)'a' && cInt <= (int)'z' ||
  171. cInt >= (int)'A' && cInt <= (int)'Z' || cInt >= (int)'0' && cInt <= (int)'9')
  172. result.Append(c);
  173. else
  174. {
  175. // Debug: Need to handle non-printable chars.
  176. result.Append(c);
  177. useQuotes = true;
  178. }
  179. }
  180. if (!useQuotes && (int)_name[0] >= (int)'a' && (int)_name[0] <= (int)'z')
  181. return result.ToString();
  182. else
  183. {
  184. // Surround in single quotes.
  185. result.Append('\'');
  186. return "'" + result;
  187. }
  188. }
  189. /// <summary>
  190. /// Return true if _name is lexicographically less than atom._name.
  191. /// </summary>
  192. /// <param name="atom"></param>
  193. /// <returns></returns>
  194. public bool lessThan(Atom atom)
  195. {
  196. return _name.CompareTo(atom._name) < 0;
  197. }
  198. }
  199. }