001: package org.ofbiz.rules.engine;
002:
003: /**
004: * <p><b>Title:</b> Variable
005: * <p><b>Description:</b> None
006: * <p>Copyright (c) 1999 Steven J. Metsker.
007: * <p>Copyright (c) 2001 The Open For Business Project - www.ofbiz.org
008: *
009: * <p>Permission is hereby granted, free of charge, to any person obtaining a
010: * copy of this software and associated documentation files (the "Software"),
011: * to deal in the Software without restriction, including without limitation
012: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
013: * and/or sell copies of the Software, and to permit persons to whom the
014: * Software is furnished to do so, subject to the following conditions:
015: *
016: * <p>The above copyright notice and this permission notice shall be included
017: * in all copies or substantial portions of the Software.
018: *
019: * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
020: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
021: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
022: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
023: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
024: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
025: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
026: *
027: * <br>
028: * <p>A variable is a named term that can unify with other
029: * terms.
030: * <p>
031: * A variable has a name, such as "X" or "Person", and an
032: * instantiation. When a variable unifies with a term, it
033: * "instantiates" to it, taking the term as its value. The
034: * instantiation of a variable may be another variable, or a
035: * structure.
036: * <p>
037: * The scope of a variable is the rule in which it is
038: * contained. For example, consider the member program:
039: * <blockquote><pre>
040: * member(X, [X | Rest]);
041: * member(X, [Y | Rest]) :- member(X, Rest);
042: * </pre></blockquote>
043: * In this program, the variable "X" in the first rule is the
044: * same variable both times it appears in the rule. However,
045: * this variable is completely independent of the variable
046: * named "X" in the second rule. Variables with the same name
047: * in a rule are the same variable, but variables with the
048: * same name in different rules are different variables. This
049: * is another way of saying that a variable's scope is the
050: * rule in which it appears.
051: * <p>
052: * To be more specific, the scope of a variable is the
053: * <i>dynamic</i> rule in which the variable appears. Since
054: * rules may execute recursively, dynamic rules each need an
055: * independent copy of a defining rule's variables. In the
056: * member program, for example, the second rule may prove
057: * itself by reinvoking itself, with a (slightly) different
058: * set of variable instantiations.
059: * <p>
060: * Consider the query <code>member(c, [a, b, c])</code>. This
061: * query will unify with the second rule, and try to prove the
062: * second rule's tail, which will be <code>member(c, [b,
063: * c])</code>. This structure will try to prove itself, and it
064: * too will unify with the second rule. At this point, the
065: * proof of <code>member(c, [a, b, c])</code> will be waiting
066: * upon the proof of <code>member(c, [b, c]). That is, the two
067: * dynamic copies of the rule, will be in different states,
068: * because of their variables. For example, the instantiation
069: * of <code>Rest</code> in the first execution of the rule
070: * will be <code>[b, c]<code>, and the value of
071: * <code>Rest</code> in the second rule will <code>[c]</code>.
072: * <p>
073: * Variables have a name and an instantiation which is unique
074: * within a scope; each dynamic version of a rule has a unique
075: * Scope.
076: *
077: * @author Steven J. Metsker
078: *
079: * @version 1.0
080: */
081:
082: public class Variable implements ArithmeticTerm, ComparisonTerm {
083: public final String name;
084: protected Term instantiation;
085:
086: /**
087: * Create a variable with the given name.
088: */
089: public Variable(String name) {
090: this .name = name;
091: }
092:
093: /**
094: * Create a copy that uses the provided scope.
095: *
096: * @param AxiomSource ignored
097: *
098: * @param Scope the scope to use for variables in the
099: * copy
100: *
101: * @return a copy that uses the provided scope
102: */
103: public Term copyForProof(AxiomSource ignored, Scope scope) {
104: return scope.lookup(name);
105: }
106:
107: /**
108: * Returns string representation of this variable, showing
109: * both its name and its value.
110: *
111: * @return a string representation of this variable, showing
112: * both its name and its value.
113: */
114: public String definitionString() {
115: if (instantiation != null) {
116: return name + " = " + instantiation;
117: }
118: return name;
119: }
120:
121: /**
122: * Returns true if the supplied object is an equivalent
123: * variable.
124: *
125: * @param object the object to compare
126: *
127: * @return true, if the supplied object has the same
128: * name, and it the two variables' instantiations
129: * are equal
130: */
131: public boolean equals(Object o) {
132: if (!(o instanceof Variable))
133: return false;
134: Variable v = (Variable) o;
135:
136: if (!name.equals(v.name)) {
137: return false;
138: }
139: if (instantiation == null) {
140: return v.instantiation == null;
141: }
142: return instantiation.equals(instantiation);
143: }
144:
145: /**
146: * Returns the value of this variable.
147: *
148: * @return the value of this variable
149: *
150: * @exception EvaluationException if this variable's
151: * value is undefined
152: */
153: public Object eval() {
154: if (instantiation == null) {
155: throw new EvaluationException("Variable " + name
156: + " is undefined");
157: }
158: return instantiation.eval();
159: }
160:
161: /**
162: * Returns true if this variable is uninstantiated, or if it
163: * contains a list.
164: *
165: * @Returns true if this variable is uninstantiated, or if
166: * it contains a list
167: */
168: public boolean isList() {
169: if (instantiation != null) {
170: return instantiation.isList();
171: }
172: return true;
173: }
174:
175: /**
176: * Returns a string representation of this variable as the
177: * tail of a list.
178: *
179: * @return a string representation of this variable as the
180: * tail of a list
181: */
182: public String listTailString() {
183: if (instantiation != null) {
184: return instantiation.listTailString();
185: }
186: return "|" + name;
187: }
188:
189: /**
190: * Returns a string representation of this variable.
191: *
192: * @return a string representation of this variable
193: */
194: public String toString() {
195: if (instantiation != null) {
196: return instantiation.toString();
197: }
198: return name;
199: }
200:
201: /**
202: * Marks this variable as no longer having an instantiated
203: * value.
204: */
205: public void unbind() {
206: instantiation = null;
207: }
208:
209: /**
210: * Instantiates this variable with the supplied structure, or
211: * forwards the request to its instantiation if it already has
212: * one.
213: *
214: * @param Structure a structure to unify with
215: *
216: * @return a unification. If this variable is already
217: * instantiated, the unification is the result of
218: * unifying with the input structure. Otherwise, the
219: * result is a new unification containing just this
220: * variable, instantiated to the input structure.
221: */
222: public Unification unify(Structure s) {
223: if (instantiation != null) {
224: return instantiation.unify(s);
225: }
226: instantiation = s;
227: return new Unification(this );
228: }
229:
230: /**
231: * Unifies this variable with the supplied term.
232: * <p>
233: * This method dispatches the unify request to either a
234: * structure or a variable. The receiver will get a signature
235: * match from this object as a Variable, not just a Term.
236: *
237: * @param Term a term to unify with
238: *
239: * @return the sum of the variables that bind to values to
240: * make the unification work; Returns null if the
241: * unification fails.
242: */
243: public Unification unify(Term t) {
244: return t.unify(this );
245: }
246:
247: /**
248: * Instantiates this variable with the supplied variable, or
249: * forwards the request to its instantiation if it already has
250: * one.
251: *
252: * @param Variable a variable to unify with
253: *
254: * @return the sum of the variables that bind to values to make
255: * the unification work; Returns null if the
256: * unification fails.
257: */
258: public Unification unify(Variable v) {
259: if (this == v) {
260: return new Unification();
261: }
262: if (instantiation != null) {
263: return instantiation.unify(v);
264: }
265: if (v.instantiation != null) {
266: return v.instantiation.unify(this );
267: }
268: instantiation = v;
269: return new Unification(this );
270: }
271:
272: /**
273: * Returns a unification containing just this variable.
274: *
275: * @return a unification containing just this variable
276: */
277: public Unification variables() {
278: return new Unification(this);
279: }
280: }
|