1 /*
2 
3     This file is part of the Maude 2 interpreter.
4 
5     Copyright 1997-2014 SRI International, Menlo Park, CA 94025, USA.
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20 
21 */
22 
23 //
24 //      Implementation for class VariableDagNode
25 //
26 
27 //	utility stuff
28 #include "macros.hh"
29 #include "vector.hh"
30 
31 //	forward declarations
32 #include "interface.hh"
33 #include "core.hh"
34 #include "variable.hh"
35 
36 //	interface class definitions
37 #include "symbol.hh"
38 #include "dagNode.hh"
39 
40 //      core class definitions
41 #include "substitution.hh"
42 #include "narrowingVariableInfo.hh"
43 #include "unificationContext.hh"
44 
45 //	variable class definitions
46 #include "variableSymbol.hh"
47 #include "variableDagNode.hh"
48 
49 RawDagArgumentIterator*
arguments()50 VariableDagNode::arguments()
51 {
52   return 0;
53 }
54 
55 size_t
getHashValue()56 VariableDagNode::getHashValue()
57 {
58   return hash(symbol()->getHashValue(), id());
59 }
60 
61 int
compareArguments(const DagNode * other) const62 VariableDagNode::compareArguments(const DagNode* other) const
63 {
64   return id() - safeCast(const VariableDagNode*, other)->id();
65 }
66 
67 DagNode*
markArguments()68 VariableDagNode::markArguments()
69 {
70   return 0;
71 }
72 
73 DagNode*
copyEagerUptoReduced2()74 VariableDagNode::copyEagerUptoReduced2()
75 {
76   return new VariableDagNode(symbol(), id(), index);
77 }
78 
79 void
clearCopyPointers2()80 VariableDagNode::clearCopyPointers2()
81 {
82 }
83 
84 void
overwriteWithClone(DagNode * old)85 VariableDagNode::overwriteWithClone(DagNode* old)
86 {
87 
88   VariableDagNode* d = new(old) VariableDagNode(symbol(), id(), index);
89   d->copySetRewritingFlags(this);
90   d->setSortIndex(getSortIndex());
91 }
92 
93 DagNode*
makeClone()94 VariableDagNode::makeClone()
95 {
96   VariableDagNode* d = new VariableDagNode(symbol(), id(), index);
97   d->copySetRewritingFlags(this);
98   d->setSortIndex(getSortIndex());
99   return d;
100 }
101 
102 DagNode*
copyWithReplacement(int,DagNode *)103 VariableDagNode::copyWithReplacement(int /* argIndex */, DagNode* /* replacement */)
104 {
105   CantHappen("should never be called");
106   return 0;
107 }
108 
109 DagNode*
copyWithReplacement(Vector<RedexPosition> &,int,int)110 VariableDagNode::copyWithReplacement(Vector<RedexPosition>& /* redexStack  */,
111 				     int /* first */,
112 				     int /* last */)
113 {
114   CantHappen("should never be called");
115   return 0;
116 }
117 
118 void
stackArguments(Vector<RedexPosition> &,int,bool)119 VariableDagNode::stackArguments(Vector<RedexPosition>& /* stack */,
120 				int /* parentIndex */,
121 				bool /* respectFrozen */)
122 {
123 }
124 
125 //
126 //	Unification code.
127 //
128 
129 DagNode::ReturnResult
computeBaseSortForGroundSubterms()130 VariableDagNode::computeBaseSortForGroundSubterms()
131 {
132   return NONGROUND;
133 }
134 
135 bool
computeSolvedForm2(DagNode * rhs,UnificationContext & solution,PendingUnificationStack & pending)136 VariableDagNode::computeSolvedForm2(DagNode* rhs, UnificationContext& solution, PendingUnificationStack& pending)
137 {
138   //
139   //	In this version we only handle variable vs variable unfication and
140   //	punt on everything else.
141   //
142   if (VariableDagNode* v = dynamic_cast<VariableDagNode*>(rhs))
143     {
144       VariableDagNode* lv = lastVariableInChain(solution);
145       VariableDagNode* rv = v->lastVariableInChain(solution);
146       if (lv->equal(rv))
147 	return true;
148       //
149       //	Need to replace one variable by the other throughout the problem. We do this
150       //	virtually and must check for implicit occurs check problems.
151       //
152       //	Might need to check we never map an original variable to a fresh variable.
153       //
154       DagNode* lt = solution.value(lv->index);
155       if (lt == 0)
156 	return safeVirtualReplacement(lv, rv, solution, pending);
157 
158       DagNode* rt = solution.value(rv->index);
159       if (rt == 0)
160 	return safeVirtualReplacement(rv, lv, solution, pending);
161       //
162       //	Both variables are bound.
163       //
164       return safeVirtualReplacement(lv, rv, solution, pending) && lt->computeSolvedForm(rt, solution, pending);
165     }
166   //
167   //	Calling computeSolvedForm() would just kick the problem back to us if
168   //	rhs is ground, since this is a variable, and this would cause an infinite recursion.
169   //
170   return rhs->computeSolvedForm2(this, solution, pending);
171 }
172 
173 bool
safeVirtualReplacement(VariableDagNode * oldVar,VariableDagNode * newVar,UnificationContext & solution,PendingUnificationStack & pending)174 VariableDagNode::safeVirtualReplacement(VariableDagNode* oldVar, VariableDagNode* newVar, UnificationContext& solution, PendingUnificationStack& pending)
175 {
176   //
177   //	We want to replace all occurrences of oldVar by newVar. We assume oldVar is the last
178   //	variable in its chain and is unbound (or has a binding which can be ignored because the
179   //	caller is dealing with it) and newVar is the last variable in its chain.
180   //	We do this by binding oldVar to newVar and since whenever we access a variable,
181   //	we look for the last variable in the chain, accessing oldVar will give us newVar.
182   //
183   //	There is however a problem. If newVar is bound and its binding contains oldVar
184   //	(or a variable equivalent to it) we generate an implicit occur check issue. We
185   //    could un-solve and re-solve its binding, but if there is no occur check issue,
186   //	re-solving could give us a similar variable replacement problem, also resulting in
187   //	non-termination.
188   //
189   //	So we check the binding of newVar to see if it contains oldVar, and only then
190   //	do we unsolve it.
191   //
192   solution.unificationBind(oldVar, newVar);
193   DagNode* newBinding = solution.value(newVar->index);
194   if (newBinding == 0 || newBinding->isGround())
195     return true;
196 
197   NatSet occurs;
198   newBinding->insertVariables(occurs);
199   FOR_EACH_CONST(i, NatSet, occurs)
200     {
201       if (VariableDagNode* v = dynamic_cast<VariableDagNode*>(solution.value(*i)))
202 	{
203 	  if (v->lastVariableInChain(solution)->equal(newVar))
204 	    {
205 	      //
206 	      //	We have an occur check issue. We unsolve newVar |-> newBinding and re-solve it.
207 	      //
208 	      solution.bind(newVar->index, 0);
209 	      return newBinding->computeSolvedForm2(newVar, solution, pending);
210 	    }
211 	}
212     }
213   //
214   //	No implicit occurs check issue found. Leave the binding of newVar as it was.
215   //
216   return true;
217 }
218 
219 void
insertVariables2(NatSet & occurs)220 VariableDagNode::insertVariables2(NatSet& occurs)
221 {
222   occurs.insert(index);
223 }
224 
225 DagNode*
instantiate2(const Substitution & substitution)226 VariableDagNode::instantiate2(const Substitution& substitution)
227 {
228   return substitution.value(index);
229 }
230 
231 VariableDagNode*
lastVariableInChain(Substitution & solution)232 VariableDagNode::lastVariableInChain(Substitution& solution)
233 {
234   //
235   //	If a variable has been bound to anther variable, it is notionally
236   //	replaced by that variable thoughout the problem, and in particular
237   //	we need chase the replacement chain and find out what variable is
238   //	notionally in its place.
239   //
240   VariableDagNode* v = this;
241   for (;;)
242     {
243       DagNode* d = solution.value(v->index);
244       if (d == 0)
245 	break;
246       VariableDagNode* n = dynamic_cast<VariableDagNode*>(d);
247       if (n == 0)
248 	break;
249       if (v == n)
250 	{
251 	  cerr << "variable " << (DagNode*) v << " is bound to itself in a chain starting at " << (DagNode*) this << endl;
252 	  abort();
253 	}
254       v = n;
255     }
256   return v;
257 }
258 
259 //
260 //	Narrowing code.
261 //
262 
263 bool
indexVariables2(NarrowingVariableInfo & indices,int baseIndex)264 VariableDagNode::indexVariables2(NarrowingVariableInfo& indices, int baseIndex)
265 {
266   index = baseIndex + indices.variable2Index(this);
267   return false;
268 }
269 
270 DagNode*
instantiateWithCopies2(const Substitution &,const Vector<DagNode * > & eagerCopies)271 VariableDagNode::instantiateWithCopies2(const Substitution& /* substitution */, const Vector<DagNode*>& eagerCopies)
272 {
273   //
274   //	We must be in an eager position so use the eager copy.
275   //
276   return eagerCopies[index];
277 }
278