PageRenderTime 64ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/YieldProlog/Modules/Variable.cs

https://bitbucket.org/VirtualReality/optional-modules
C# | 219 lines | 121 code | 16 blank | 82 comment | 16 complexity | b9bdd769a47d2300f83ff55e98adaf50 MD5 | raw file
  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the Aurora-Sim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
  31. {
  32. public interface IUnifiable
  33. {
  34. IEnumerable<bool> unify(object arg);
  35. void addUniqueVariables(List<Variable> variableSet);
  36. object makeCopy(Variable.CopyStore copyStore);
  37. bool termEqual(object term);
  38. bool ground();
  39. }
  40. /// <summary>
  41. /// A Variable is passed to a function so that it can be unified with
  42. /// value or another Variable. See getValue and unify for details.
  43. /// </summary>
  44. public class Variable : IUnifiable
  45. {
  46. // Use _isBound separate from _value so that it can be bound to any value,
  47. // including null.
  48. private bool _isBound = false;
  49. private object _value;
  50. /// <summary>
  51. /// If this Variable is unbound, then just return this Variable.
  52. /// Otherwise, if this has been bound to a value with unify, return the value.
  53. /// If the bound value is another Variable, this follows the "variable chain"
  54. /// to the end and returns the final value, or the final Variable if it is unbound.
  55. /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
  56. /// </summary>
  57. /// <returns></returns>
  58. public object getValue()
  59. {
  60. if (!_isBound)
  61. return this;
  62. object result = _value;
  63. while (result is Variable)
  64. {
  65. if (!((Variable)result)._isBound)
  66. return result;
  67. // Keep following the Variable chain.
  68. result = ((Variable)result)._value;
  69. }
  70. return result;
  71. }
  72. /// <summary>
  73. /// If this Variable is bound, then just call YP.unify to unify this with arg.
  74. /// (Note that if arg is an unbound Variable, then YP.unify will bind it to
  75. /// this Variable's value.)
  76. /// Otherwise, bind this Variable to YP.getValue(arg) and yield once. After the
  77. /// yield, return this Variable to the unbound state.
  78. /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html
  79. /// </summary>
  80. /// <param name="arg"></param>
  81. /// <returns></returns>
  82. public IEnumerable<bool> unify(object arg)
  83. {
  84. if (!_isBound)
  85. {
  86. _value = YP.getValue(arg);
  87. if (_value == this)
  88. // We are unifying this unbound variable with itself, so leave it unbound.
  89. yield return false;
  90. else
  91. {
  92. _isBound = true;
  93. try
  94. {
  95. yield return false;
  96. }
  97. finally
  98. {
  99. // Remove the binding.
  100. _isBound = false;
  101. }
  102. }
  103. }
  104. else
  105. {
  106. // disable warning on l1, don't see how we can
  107. // code this differently
  108. #pragma warning disable 0168, 0219
  109. foreach (bool l1 in YP.unify(this, arg))
  110. yield return false;
  111. #pragma warning restore 0168, 0219
  112. }
  113. }
  114. public override string ToString()
  115. {
  116. object value = getValue();
  117. if (value == this)
  118. return "_Variable";
  119. else
  120. return getValue().ToString();
  121. }
  122. /// <summary>
  123. /// If bound, call YP.addUniqueVariables on the value. Otherwise, if this unbound
  124. /// variable is not already in variableSet, add it.
  125. /// </summary>
  126. /// <param name="variableSet"></param>
  127. public void addUniqueVariables(List<Variable> variableSet)
  128. {
  129. if (_isBound)
  130. YP.addUniqueVariables(getValue(), variableSet);
  131. else
  132. {
  133. if (variableSet.IndexOf(this) < 0)
  134. variableSet.Add(this);
  135. }
  136. }
  137. /// <summary>
  138. /// If bound, return YP.makeCopy for the value, else return copyStore.getCopy(this).
  139. /// However, if copyStore is null, just return this.
  140. /// </summary>
  141. /// <param name="copyStore"></param>
  142. /// <returns></returns>
  143. public object makeCopy(Variable.CopyStore copyStore)
  144. {
  145. if (_isBound)
  146. return YP.makeCopy(getValue(), copyStore);
  147. else
  148. return copyStore == null ? this : copyStore.getCopy(this);
  149. }
  150. public bool termEqual(object term)
  151. {
  152. if (_isBound)
  153. return YP.termEqual(getValue(), term);
  154. else
  155. return this == YP.getValue(term);
  156. }
  157. public bool ground()
  158. {
  159. if (_isBound)
  160. // This is usually called by YP.ground which already did getValue, so this
  161. // should never be reached, but check anyway.
  162. return YP.ground(getValue());
  163. else
  164. return false;
  165. }
  166. /// <summary>
  167. /// A CopyStore is used by makeCopy to track which Variable objects have
  168. /// been copied.
  169. /// </summary>
  170. public class CopyStore
  171. {
  172. private List<Variable> _inVariableSet = new List<Variable>();
  173. private List<Variable> _outVariableSet = new List<Variable>();
  174. /// <summary>
  175. /// If inVariable has already been copied, return its copy. Otherwise,
  176. /// return a fresh Variable associated with inVariable.
  177. /// </summary>
  178. /// <param name="inVariable"></param>
  179. /// <returns></returns>
  180. public Variable getCopy(Variable inVariable)
  181. {
  182. int index = _inVariableSet.IndexOf(inVariable);
  183. if (index >= 0)
  184. return _outVariableSet[index];
  185. else
  186. {
  187. Variable outVariable = new Variable();
  188. _inVariableSet.Add(inVariable);
  189. _outVariableSet.Add(outVariable);
  190. return outVariable;
  191. }
  192. }
  193. /// <summary>
  194. /// Return the number of unique variables that have been copied.
  195. /// </summary>
  196. /// <returns></returns>
  197. public int getNUniqueVariables()
  198. {
  199. return _inVariableSet.Count;
  200. }
  201. }
  202. }
  203. }