1 /*
2 
3     This file is part of the Maude 2 interpreter.
4 
5     Copyright 1997-2003 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 S_DagNode.
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 #include "S_Theory.hh"
36 
37 //      interface class definitions
38 #include "term.hh"
39 
40 //      core class definitions
41 #include "pendingUnificationStack.hh"
42 #include "unificationContext.hh"
43 
44 //	variable class definitions
45 #include "variableDagNode.hh"
46 
47 //      S theory class definitions
48 #include "S_Symbol.hh"
49 #include "S_DagNode.hh"
50 #include "S_DagArgumentIterator.hh"
51 #include "S_ExtensionInfo.hh"
52 #include "S_Subproblem.hh"
53 
S_DagNode(S_Symbol * symbol,const mpz_class & number,DagNode * arg)54 S_DagNode::S_DagNode(S_Symbol* symbol, const mpz_class& number, DagNode* arg)
55   : DagNode(symbol),
56     number(new mpz_class(number)),
57     arg(arg)
58 {
59   setCallDtor();  // need our dtor called when garbage collected to destruct number
60 }
61 
~S_DagNode()62 S_DagNode::~S_DagNode()
63 {
64   delete number;
65 }
66 
67 RawDagArgumentIterator*
arguments()68 S_DagNode::arguments()
69 {
70   return new S_DagArgumentIterator(arg);
71 }
72 
73 size_t
getHashValue()74 S_DagNode::getHashValue()
75 {
76   return hash(symbol()->getHashValue(),
77 	      arg->getHashValue(),
78 	      mpz_tdiv_ui(number->get_mpz_t(), INT_MAX));
79 }
80 
81 int
compareArguments(const DagNode * other) const82 S_DagNode::compareArguments(const DagNode* other) const
83 {
84   const S_DagNode* d = safeCast(const S_DagNode*, other);
85   int r = cmp(*number, *(d->number));
86   return (r == 0) ? arg->compare(d->arg) : r;
87 }
88 
89 DagNode*
markArguments()90 S_DagNode::markArguments()
91 {
92   return arg;
93 }
94 
95 DagNode*
copyEagerUptoReduced2()96 S_DagNode::copyEagerUptoReduced2()
97 {
98   S_Symbol* s = symbol();
99   DagNode* argCopy = (s->standardStrategy()) ? arg->copyEagerUptoReduced() : arg;
100   return new S_DagNode(s, *number, argCopy);
101 }
102 
103 void
clearCopyPointers2()104 S_DagNode::clearCopyPointers2()
105 {
106   arg->clearCopyPointers();
107 }
108 
109 void
overwriteWithClone(DagNode * old)110 S_DagNode::overwriteWithClone(DagNode* old)
111 {
112   S_DagNode* d = new(old) S_DagNode(symbol(), *number, arg);
113   d->copySetRewritingFlags(this);
114   d->setSortIndex(getSortIndex());
115 }
116 
117 DagNode*
makeClone()118 S_DagNode::makeClone()
119 {
120   S_DagNode* d = new S_DagNode(symbol(), *number, arg);
121   d->copySetRewritingFlags(this);
122   d->setSortIndex(getSortIndex());
123   return d;
124 }
125 
126 void
normalizeAtTop()127 S_DagNode::normalizeAtTop()
128 {
129   if (arg->symbol() == symbol())
130     {
131       S_DagNode* a = safeCast(S_DagNode*, arg);
132       *number += *(a->number);
133       arg = a->arg;
134     }
135 }
136 
137 DagNode*
copyWithReplacement(int argIndex,DagNode * replacement)138 S_DagNode::copyWithReplacement(int argIndex, DagNode* replacement)
139 {
140   Assert(argIndex == 0, "bad arg index");
141   return new S_DagNode(symbol(), *number, replacement);
142 }
143 
144 DagNode*
copyWithReplacement(Vector<RedexPosition> & redexStack,int first,int last)145 S_DagNode::copyWithReplacement(Vector<RedexPosition>& redexStack,
146 			       int first,
147 			       int last)
148 {
149   Assert(first == last, "nrArgs clash");
150   return new S_DagNode(symbol(), *number, redexStack[first].node());
151 }
152 
153 void
stackArguments(Vector<RedexPosition> & stack,int parentIndex,bool respectFrozen)154 S_DagNode::stackArguments(Vector<RedexPosition>& stack,
155 			  int parentIndex,
156 			  bool respectFrozen)
157 {
158   if (!(respectFrozen && symbol()->getFrozen().contains(0)) &&
159       !(arg->isUnstackable()))
160     stack.append(RedexPosition(arg, parentIndex, 0));
161 }
162 
163 void
partialReplace(DagNode * replacement,ExtensionInfo * extensionInfo)164 S_DagNode::partialReplace(DagNode* replacement, ExtensionInfo* extensionInfo)
165 {
166   *number = safeCast(S_ExtensionInfo*, extensionInfo)->getUnmatched();
167   arg = replacement;
168   repudiateSortInfo();
169 }
170 
171 DagNode*
partialConstruct(DagNode * replacement,ExtensionInfo * extensionInfo)172 S_DagNode::partialConstruct(DagNode* replacement, ExtensionInfo* extensionInfo)
173 {
174   return new S_DagNode(symbol(),
175 		       safeCast(S_ExtensionInfo*, extensionInfo)->getUnmatched(),
176 		       replacement);
177 }
178 
179 ExtensionInfo*
makeExtensionInfo()180 S_DagNode::makeExtensionInfo()
181 {
182   return new S_ExtensionInfo(this);
183 }
184 
185 bool
matchVariableWithExtension(int index,const Sort * sort,Substitution &,Subproblem * & returnedSubproblem,ExtensionInfo * extensionInfo)186 S_DagNode::matchVariableWithExtension(int index,
187 				      const Sort* sort,
188 				      Substitution& /* solution */,
189 				      Subproblem*& returnedSubproblem,
190 				      ExtensionInfo* extensionInfo)
191 {
192   //
193   //	Because we have not matched a S_Theory operator, we cannot put
194   //	put all the S_Theory operator into the extension and therefore we
195   //	pass mustMatchAtLeast = 1 rather than the default value of 0.
196   //
197   returnedSubproblem =
198     new S_Subproblem(this,
199 		     *number,
200 		     index,
201 		     sort,
202 		     safeCast(S_ExtensionInfo*, extensionInfo),
203 		     1);
204   return true;
205 }
206 
207 //
208 //	Unification code.
209 //
210 
211 DagNode::ReturnResult
computeBaseSortForGroundSubterms()212 S_DagNode::computeBaseSortForGroundSubterms()
213 {
214   ReturnResult r = arg->computeBaseSortForGroundSubterms();
215   if (r == GROUND)
216     symbol()->computeBaseSort(this);
217   return r;
218 }
219 
220 bool
computeSolvedForm2(DagNode * rhs,UnificationContext & solution,PendingUnificationStack & pending)221 S_DagNode::computeSolvedForm2(DagNode* rhs, UnificationContext& solution, PendingUnificationStack& pending)
222 {
223   S_Symbol* s = symbol();
224   if (s == rhs->symbol())
225     {
226       S_DagNode* rhs2 = safeCast(S_DagNode*, rhs);
227       mpz_class diff = *(rhs2->number) - *number;
228       if (diff == 0)
229 	return arg->computeSolvedForm(rhs2->arg, solution, pending);
230       //
231       //	Decompose by peeling the side with greatest iteration count.
232       //
233       if (diff > 0)
234 	{
235 	  DagNode* d = new S_DagNode(s, diff, rhs2->arg);
236 	  if (rhs2->arg->getSortIndex() != Sort::SORT_UNKNOWN)
237 	    s->computeBaseSort(d);
238 	  return arg->computeSolvedForm(d, solution, pending);
239 	}
240       DagNode* d = new S_DagNode(s, -diff, arg);
241       if (arg->getSortIndex() != Sort::SORT_UNKNOWN)
242 	s->computeBaseSort(d);
243       return rhs2->arg->computeSolvedForm(d, solution, pending);
244     }
245   if (VariableDagNode* v = dynamic_cast<VariableDagNode*>(rhs))
246     {
247       //
248       //	Get representative variable.
249       //
250       VariableDagNode* r = v->lastVariableInChain(solution);
251       if (DagNode* value = solution.value(r->getIndex()))
252 	return computeSolvedForm2(value, solution, pending);
253       //
254       //	We need to bind the variable to our purified form.
255       //
256       //	We assume we are in normal form - thus our subject can only be
257       //	an alien or a variable, and only aliens need to be variable abstracted.
258       //
259       S_DagNode* purified;
260       if (VariableDagNode* a = dynamic_cast<VariableDagNode*>(arg))
261 	{
262 	  //
263 	  //	Already pure but need to do an occurs check.
264 	  //
265 	  if (a->lastVariableInChain(solution)->equal(r))
266 	    return false;  // occurs check fail
267 	  purified = this;
268 	}
269       else
270 	{
271 	  //
272 	  //	Abstract away alien.
273 	  //
274 	  VariableDagNode* abstractionVariable = solution.makeFreshVariable(s->domainComponent(0));
275 	  //
276 	  //	solution.unificationBind(abstractionVariable, arg) not safe since arg might be impure.
277 	  //
278 	  arg->computeSolvedForm(abstractionVariable, solution, pending);
279 	  purified = new S_DagNode(s, *number, abstractionVariable);
280 	}
281       solution.unificationBind(r, purified);
282       return true;
283     }
284   return pending.resolveTheoryClash(this, rhs);
285 }
286 
287 void
insertVariables2(NatSet & occurs)288 S_DagNode::insertVariables2(NatSet& occurs)
289 {
290   arg->insertVariables(occurs);
291 }
292 
293 DagNode*
instantiate2(const Substitution & substitution)294 S_DagNode::instantiate2(const Substitution& substitution)
295 {
296   if (DagNode* n = arg->instantiate(substitution))
297     {
298       mpz_class num = *number;
299       S_Symbol* s = symbol();
300       if (s == n->symbol())
301 	{
302 	  //
303 	  //	Our argument instantiated into our theory so we need
304 	  //	to do theory normalization.
305 	  //
306 	  S_DagNode* t = safeCast(S_DagNode*, n);
307 	  num += *(t->number);
308 	  n = t->arg;
309 	}
310       DagNode* d =  new S_DagNode(s, num, n);
311       if (n->isGround())
312 	{
313 	  s->computeBaseSort(d);
314 	  d->setGround();
315 	}
316       return d;
317     }
318   return 0;
319 }
320 
321 //
322 //	Narrowing code.
323 //
324 
325 DagNode*
instantiateWithReplacement(const Substitution &,const Vector<DagNode * > &,int argIndex,DagNode * newDag)326 S_DagNode::instantiateWithReplacement(const Substitution& /* substitution */, const Vector<DagNode*>& /* eagerCopies */, int argIndex, DagNode* newDag)
327 {
328   Assert(argIndex == 0, "bad arg index");
329   return new S_DagNode(symbol(), *number, newDag);
330 }
331 
332 DagNode*
instantiateWithCopies2(const Substitution & substitution,const Vector<DagNode * > & eagerCopies)333 S_DagNode::instantiateWithCopies2(const Substitution& substitution, const Vector<DagNode*>& eagerCopies)
334 {
335   S_Symbol* s = symbol();
336   DagNode* n = s->eagerArgument(0) ?
337 	arg->instantiateWithCopies(substitution, eagerCopies) :
338 	arg->instantiate(substitution);
339   if (n != 0)
340     {
341       mpz_class num = *number;
342       if (s == n->symbol())
343 	{
344 	  //
345 	  //	Our argument instantiated into our theory so we need
346 	  //	to do theory normalization.
347 	  //
348 	  S_DagNode* t = safeCast(S_DagNode*, n);
349 	  num += *(t->number);
350 	  n = t->arg;
351 	}
352       DagNode* d =  new S_DagNode(s, num, n);
353       if (n->isGround())
354 	{
355 	  s->computeBaseSort(d);
356 	  d->setGround();
357 	}
358       return d;
359     }
360   return 0;
361 }
362 
363