Variable.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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;
  32. using System.Collections.Generic;
  33. namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
  34. {
  35. public interface IUnifiable
  36. {
  37. IEnumerable<bool> unify(object arg);
  38. void addUniqueVariables(List<Variable> variableSet);
  39. object makeCopy(Variable.CopyStore copyStore);
  40. bool termEqual(object term);
  41. bool ground();
  42. }
  43. /// <summary>
  44. /// A Variable is passed to a function so that it can be unified with
  45. /// value or another Variable. See getValue and unify for details.
  46. /// </summary>
  47. public class Variable : IUnifiable
  48. {
  49. // Use _isBound separate from _value so that it can be bound to any value,
  50. // including null.
  51. private bool _isBound = false;
  52. private object _value;
  53. /// <summary>
  54. /// If this Variable is unbound, then just return this Variable.
  55. /// Otherwise, if this has been bound to a value with unify, return the value.
  56. /// If the bound value is another Variable, this follows the "variable chain"
  57. /// to the end and returns the final value, or the final Variable if it is unbound.
  58. /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
  59. /// </summary>
  60. /// <returns></returns>
  61. public object getValue()
  62. {
  63. if (!_isBound)
  64. return this;
  65. object result = _value;
  66. while (result is Variable)
  67. {
  68. if (!((Variable)result)._isBound)
  69. return result;
  70. // Keep following the Variable chain.
  71. result = ((Variable)result)._value;
  72. }
  73. return result;
  74. }
  75. /// <summary>
  76. /// If this Variable is bound, then just call YP.unify to unify this with arg.
  77. /// (Note that if arg is an unbound Variable, then YP.unify will bind it to
  78. /// this Variable's value.)
  79. /// Otherwise, bind this Variable to YP.getValue(arg) and yield once. After the
  80. /// yield, return this Variable to the unbound state.
  81. /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
  82. /// </summary>
  83. /// <param name="arg"></param>
  84. /// <returns></returns>
  85. public IEnumerable<bool> unify(object arg)
  86. {
  87. if (!_isBound)
  88. {
  89. _value = YP.getValue(arg);
  90. if (_value == this)
  91. // We are unifying this unbound variable with itself, so leave it unbound.
  92. yield return false;
  93. else
  94. {
  95. _isBound = true;
  96. try
  97. {
  98. yield return false;
  99. }
  100. finally
  101. {
  102. // Remove the binding.
  103. _isBound = false;
  104. }
  105. }
  106. }
  107. else
  108. {
  109. // disable warning on l1, don't see how we can
  110. // code this differently
  111. #pragma warning disable 0168, 0219
  112. foreach (bool l1 in YP.unify(this, arg))
  113. yield return false;
  114. #pragma warning restore 0168, 0219
  115. }
  116. }
  117. public override string ToString()
  118. {
  119. object value = getValue();
  120. if (value == this)
  121. return "_Variable";
  122. else
  123. return getValue().ToString();
  124. }
  125. /// <summary>
  126. /// If bound, call YP.addUniqueVariables on the value. Otherwise, if this unbound
  127. /// variable is not already in variableSet, add it.
  128. /// </summary>
  129. /// <param name="variableSet"></param>
  130. public void addUniqueVariables(List<Variable> variableSet)
  131. {
  132. if (_isBound)
  133. YP.addUniqueVariables(getValue(), variableSet);
  134. else
  135. {
  136. if (variableSet.IndexOf(this) < 0)
  137. variableSet.Add(this);
  138. }
  139. }
  140. /// <summary>
  141. /// If bound, return YP.makeCopy for the value, else return copyStore.getCopy(this).
  142. /// However, if copyStore is null, just return this.
  143. /// </summary>
  144. /// <param name="copyStore"></param>
  145. /// <returns></returns>
  146. public object makeCopy(Variable.CopyStore copyStore)
  147. {
  148. if (_isBound)
  149. return YP.makeCopy(getValue(), copyStore);
  150. else
  151. return copyStore == null ? this : copyStore.getCopy(this);
  152. }
  153. public bool termEqual(object term)
  154. {
  155. if (_isBound)
  156. return YP.termEqual(getValue(), term);
  157. else
  158. return this == YP.getValue(term);
  159. }
  160. public bool ground()
  161. {
  162. if (_isBound)
  163. // This is usually called by YP.ground which already did getValue, so this
  164. // should never be reached, but check anyway.
  165. return YP.ground(getValue());
  166. else
  167. return false;
  168. }
  169. /// <summary>
  170. /// A CopyStore is used by makeCopy to track which Variable objects have
  171. /// been copied.
  172. /// </summary>
  173. public class CopyStore
  174. {
  175. private List<Variable> _inVariableSet = new List<Variable>();
  176. private List<Variable> _outVariableSet = new List<Variable>();
  177. /// <summary>
  178. /// If inVariable has already been copied, return its copy. Otherwise,
  179. /// return a fresh Variable associated with inVariable.
  180. /// </summary>
  181. /// <param name="inVariable"></param>
  182. /// <returns></returns>
  183. public Variable getCopy(Variable inVariable)
  184. {
  185. int index = _inVariableSet.IndexOf(inVariable);
  186. if (index >= 0)
  187. return _outVariableSet[index];
  188. else
  189. {
  190. Variable outVariable = new Variable();
  191. _inVariableSet.Add(inVariable);
  192. _outVariableSet.Add(outVariable);
  193. return outVariable;
  194. }
  195. }
  196. /// <summary>
  197. /// Return the number of unique variables that have been copied.
  198. /// </summary>
  199. /// <returns></returns>
  200. public int getNUniqueVariables()
  201. {
  202. return _inVariableSet.Count;
  203. }
  204. }
  205. }
  206. }