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 base class Symbol.
25 //
26 
27 //	utility stuff
28 #include "macros.hh"
29 #include "vector.hh"
30 #include "indent.hh"
31 
32 //      forward declarations
33 #include "interface.hh"
34 #include "core.hh"
35 #include "variable.hh"
36 #include "fullCompiler.hh"
37 
38 //      interface class definitions
39 #include "symbol.hh"
40 #include "dagNode.hh"
41 #include "term.hh"
42 
43 //      core class definitions
44 #include "argumentIterator.hh"
45 #include "dagArgumentIterator.hh"
46 #include "equation.hh"
47 #include "rule.hh"
48 #include "sortConstraint.hh"
49 
50 //	variable class definitions
51 #include "variableSymbol.hh"
52 
53 //	full compiler class definitions
54 #include "compilationContext.hh"
55 
56 int Symbol::symbolCount = 0;
57 const Vector<DagNode*> Symbol::noArgs;  // constant empty vector
58 
Symbol(int id,int arity,bool memoFlag)59 Symbol::Symbol(int id, int arity, bool memoFlag)
60   : NamedEntity(id),
61     SortTable(arity),
62     MemoTable(memoFlag),
63     orderInt(symbolCount++ | (arity << 24))
64 {
65   uniqueSortIndex = 0;
66   matchIndex = 0;
67 }
68 
~Symbol()69 Symbol::~Symbol()
70 {
71 }
72 
73 void
slowComputeTrueSort(DagNode * subject,RewritingContext & context)74 Symbol::slowComputeTrueSort(DagNode* subject, RewritingContext& context)
75 {
76   if (subject->getSortIndex() == Sort::SORT_UNKNOWN)
77     {
78       computeBaseSort(subject);
79       constrainToSmallerSort(subject, context);
80     }
81 }
82 
83 bool
mightMatchPattern(Term * pattern)84 Symbol::mightMatchPattern(Term* pattern)
85 {
86   if (mightMatchSymbol(pattern->symbol()))
87     return true;
88   const PointerSet& cs = pattern->collapseSymbols();
89   int cardinality = cs.cardinality();
90   for (int i = 0; i < cardinality; i++)
91     {
92       if (mightMatchSymbol(static_cast<Symbol*>(cs.index2Pointer(i))))
93 	return true;
94     }
95   return false;
96 }
97 
98 bool
mightMatchSymbol(Symbol * symbol)99 Symbol::mightMatchSymbol(Symbol* symbol)
100 {
101   if (symbol == this)
102     return true;
103   if (VariableSymbol* vs = dynamic_cast<VariableSymbol*>(symbol))
104     {
105       Sort* s = vs->getSort();
106       if (rangeComponent() == s->component())
107 	{
108 	  if (specialSortHandling())
109 	    return true;  // can't tell anything about a symbol with special sort handling
110 	  if (!safeToInspectSortConstraints())
111 	    return true;  // uninspected sort constraint may lower our symbols lowest sort
112 	  const Vector<OpDeclaration>& opDeclarations = getOpDeclarations();
113 	  int nrDeclarations = opDeclarations.length();
114 	  int nrArgs = arity();
115 	  for (int i = 0; i < nrDeclarations; i++)
116 	    {
117 	      if (leq(opDeclarations[i].getDomainAndRange()[nrArgs], s))
118 		return true;
119 	    }
120 	  const Vector<SortConstraint*>& sortConstraints = getSortConstraints();
121 	  int nrSortConstraints = sortConstraints.length();
122 	  for (int i = 0; i < nrSortConstraints; i++)
123 	    {
124 	      if (leq(sortConstraints[i]->getSort(), s))
125 		return true;
126 	    }
127 	}
128     }
129   return false;
130 }
131 
132 bool
acceptSortConstraint(SortConstraint * sortConstraint)133 Symbol::acceptSortConstraint(SortConstraint* sortConstraint)
134 {
135   return mightMatchPattern(sortConstraint->getLhs());
136 }
137 
138 bool
acceptEquation(Equation * equation)139 Symbol::acceptEquation(Equation* equation)
140 {
141   return mightMatchPattern(equation->getLhs());
142 }
143 
144 bool
acceptRule(Rule * rule)145 Symbol::acceptRule(Rule* rule)
146 {
147   return mightMatchPattern(rule->getLhs());
148 }
149 
150 void
fillInSortInfo(Term * subject)151 Symbol::fillInSortInfo(Term* subject)
152 {
153   Assert(this == subject->symbol(), "Bad Symbol");
154   ConnectedComponent* component = rangeComponent();  // should be const
155   Assert(component != 0, "couldn't get component");
156 
157   int nrArgs = arity();
158   if (nrArgs == 0)
159     {
160       subject->setSortInfo(component, traverse(0, 0));  // HACK
161       return;
162     }
163 
164   int step = 0;
165 #ifndef NO_ASSERT
166   int nrArgsSeen = 0;
167 #endif
168   for (ArgumentIterator a(*subject); a.valid(); a.next())
169     {
170       Term* t = a.argument();
171       t->symbol()->fillInSortInfo(t);
172       Assert(t->getComponent() == domainComponent(nrArgsSeen),
173 	     "component error on arg " << nrArgsSeen <<
174 	     " while computing sort of " << subject);
175       step = traverse(step, t->getSortIndex());
176 #ifndef NO_ASSERT
177       ++nrArgsSeen;
178 #endif
179     }
180   Assert(nrArgsSeen == nrArgs, "bad # of args for op");
181   subject->setSortInfo(component, step);
182 }
183 
184 bool
interSymbolPass()185 Symbol::interSymbolPass()
186 {
187   return false;
188 }
189 
190 void
postInterSymbolPass()191 Symbol::postInterSymbolPass()
192 {
193 }
194 
195 void
postOpDeclarationPass()196 Symbol::postOpDeclarationPass()
197 {
198 }
199 
200 /*
201 Term*
202 Symbol::termify(DagNode* dagNode)
203 {
204   Vector<Term*> args;
205 
206   for (DagArgumentIterator a(*dagNode); a.valid(); a.next())
207     {
208       DagNode* d = a.argument();
209       args.append(d->symbol()->termify(d));
210     }
211   return makeTerm(args);
212 }
213 */
214 
215 void
finalizeSortInfo()216 Symbol::finalizeSortInfo()
217 {
218   //
219   //	If a symbol has sort constraints we leave uniqueSortIndex = 0 for slowest, most general handling.
220   //	Otherwise we check if it can produces a unique sort and set uniqueSortIndex to the index of this sort if so.
221   //	If neither case applies we set uniqueSortIndex = -1, to run fast, theory dependent case.
222   //
223   if (sortConstraintFree())
224     {
225       Sort* s = getSingleNonErrorSort();
226       uniqueSortIndex = (s != 0 && !(canProduceErrorSort())) ? s->index() : -1;
227     }
228 }
229 
230 Instruction*
generateFinalInstruction(const Vector<int> &)231 Symbol::generateFinalInstruction(const Vector<int>& /* argumentSlots */)
232 {
233   return 0;
234 }
235 
236 Instruction*
generateInstruction(int,const Vector<int> &,Instruction *)237 Symbol::generateInstruction(int /* destination */,  const Vector<int>& /* argumentSlots */, Instruction* /* nextInstruction */)
238 {
239   return 0;
240 }
241 
242 void
stackMachinePostProcess()243 Symbol::stackMachinePostProcess()
244 {
245 }
246 
247 void
reset()248 Symbol::reset()
249 {
250   resetEachEquation();
251   resetEachRule();
252 }
253 
254 bool
rangeSortNeverLeqThan(Sort * sort)255 Symbol::rangeSortNeverLeqThan(Sort* sort)
256 {
257   //
258   //	Check to see that our range sort will never be less than or equal to
259   //	given sort; Equivalently a variable with given sort can never take a
260   //	term headed by us.
261   //
262   int nrArgs = arity();
263   const Vector<OpDeclaration>& opDecls = getOpDeclarations();
264   int nrOpDecls = opDecls.length();
265   for (int i = 0; i < nrOpDecls; i++)
266     {
267       if (leq(opDecls[i].getDomainAndRange()[nrArgs], sort))
268 	return false;
269     }
270   const Vector<SortConstraint*>& sortConstraints = getSortConstraints();
271   int nrSortConstraints = sortConstraints.length();
272   for (int i = 0; i < nrSortConstraints; i++)
273     {
274       if (leq(sortConstraints[i]->getSort(), sort))
275 	return false;
276     }
277   return true;
278 }
279 
280 bool
rangeSortAlwaysLeqThan(Sort * sort)281 Symbol::rangeSortAlwaysLeqThan(Sort* sort)
282 {
283   //
284   //	Check to see that our range sort will always be less than or equal to
285   //	given sort (except if it is in the error sort); Equivalently a variable
286   //	with given sort can always take a term headed by us unless it is in the
287   //	error sort.
288   //
289   int nrArgs = arity();
290   const Vector<OpDeclaration>& opDecls = getOpDeclarations();
291   int nrOpDecls = opDecls.length();
292   for (int i = 0; i < nrOpDecls; i++)
293     {
294       if (!leq(opDecls[i].getDomainAndRange()[nrArgs], sort))
295 	return false;
296     }
297   return true;
298 }
299 
300 bool
domainSortAlwaysLeqThan(Sort * sort,int argNr)301 Symbol::domainSortAlwaysLeqThan(Sort* sort, int argNr)
302 {
303   //
304   //	Check that any sort we could take in our argNr position and not end up
305   //	in the error sort is less or equal to the given sort.
306   //	The current definition will be seriously incorrect if sort constraints
307   //	are allowed to terms out of the error sort in the future.
308   //
309   const Vector<OpDeclaration>& opDecls = getOpDeclarations();
310   int nrOpDecls = opDecls.length();
311   for (int i = 0; i < nrOpDecls; i++)
312     {
313       if (!leq(opDecls[i].getDomainAndRange()[argNr], sort))
314 	return false;
315     }
316   return true;
317 }
318 
319 void
computePossibleDomainSorts(const NatSet & rangeSorts,Vector<NatSet> & domainSorts)320 Symbol::computePossibleDomainSorts(const NatSet& rangeSorts,
321 				   Vector<NatSet>& domainSorts)
322 {
323   Assert(!(rangeSorts.empty()), "shouldn't be empty");
324   //
325   //	We compute the set of sorts that the specified argument can possibly have
326   //	given that the range sort must be <= one of the specified range sorts.
327   //	We are conservative in that we may generate a larger set of domain sorts
328   //	than strictly necessary.
329   //
330   int nrArgs = arity();
331   domainSorts.resize(nrArgs);
332   if (specialSortHandling() ||
333       !safeToInspectSortConstraints() ||
334       rangeSorts.contains(Sort::KIND))
335     {
336       //
337       //	We can't safely compute anything in these cases so
338       //	return the complete set of domain sorts.
339       //
340       for (int i = 0; i < nrArgs; i++)
341 	domainSorts[i] = domainComponent(i)->sort(Sort::KIND)->getLeqSorts();
342       return;
343     }
344   NatSet allPossibleRangeSorts;
345   {
346     //
347     //	First throw in all sorts that are less or equal to given range sorts.
348     //
349     const ConnectedComponent* rc = rangeComponent();
350     const NatSet::const_iterator e = rangeSorts.end();
351     for (NatSet::const_iterator i = rangeSorts.begin(); i != e; ++i)
352       allPossibleRangeSorts.insert(rc->sort(*i)->getLeqSorts());
353   }
354   {
355     //
356     //	Now do a fixed point computation to see if we can get down from
357     //	other sorts to or below our given range sorts via a sort constraint.
358     //
359     const Vector<SortConstraint*>& sortConstraints = getSortConstraints();
360     int nrSortConstraints = sortConstraints.length();
361     bool changed;
362     do
363       {
364 	changed = false;
365 	for (int i = 0; i < nrSortConstraints; i++)
366 	  {
367 	    SortConstraint* sc = sortConstraints[i];
368 	    if (allPossibleRangeSorts.contains(sc->getSort()->index()))
369 	      {
370 		const NatSet& fromSorts = sc->getLhs()->getSort()->getLeqSorts();
371 		if (fromSorts.contains(Sort::KIND))
372 		  {
373 		    //
374 		    //	A sort constraint can pull us out of the kind!
375 		    //
376 		    for (int i = 0; i < nrArgs; i++)
377 		      domainSorts[i] = domainComponent(i)->sort(Sort::KIND)->getLeqSorts();
378 		    return;
379 		  }
380 		if (!(allPossibleRangeSorts.contains(fromSorts)))
381 		  {
382 		    allPossibleRangeSorts.insert(fromSorts);
383 		    changed = true;
384 		  }
385 	      }
386 	  }
387       }
388     while (changed);
389   }
390   Assert(!(allPossibleRangeSorts.contains(Sort::KIND)),
391 	 "shouldn't contain kind");
392   {
393     //
394     //	Now examine our declarations to see what domain sorts are possible
395     //	in each argument position.
396     //
397     for (int i = 0; i < nrArgs; i++)
398       domainSorts[i].clear();
399 
400     const Vector<OpDeclaration>& opDeclarations = getOpDeclarations();
401     int nrDeclarations = opDeclarations.length();
402     for (int i = 0; i < nrDeclarations; i++)
403       {
404 	const Vector<Sort*>& domainAndRange = opDeclarations[i].getDomainAndRange();
405 	if (allPossibleRangeSorts.contains(domainAndRange[nrArgs]->index()))
406 	  {
407 	    for (int j = 0; j < nrArgs; j++)
408 	      domainSorts[j].insert(domainAndRange[j]->getLeqSorts());
409 	  }
410       }
411   }
412 }
413 
414 bool
attachData(const Vector<Sort * > &,const char * purpose,const Vector<const char * > &)415 Symbol::attachData(const Vector<Sort*>& /* opDeclaration */,
416 		   const char* purpose,
417 		   const Vector<const char*>& /* data */)
418 {
419   IssueWarning(*this <<": failed to attach id-hook " << QUOTE(purpose) <<
420 	       " to " << QUOTE(this) << '.');
421   return false;
422 }
423 
424 bool
attachSymbol(const char * purpose,Symbol * symbol)425 Symbol::attachSymbol(const char* purpose, Symbol* symbol)
426 {
427   IssueWarning(*this <<": failed to attach op-hook " << QUOTE(purpose) <<
428 	       ' ' << QUOTE(symbol) << " to " << QUOTE(this) << '.');
429   return false;
430 }
431 
432 bool
attachTerm(const char * purpose,Term * term)433 Symbol::attachTerm(const char* purpose, Term* term)
434 {
435   IssueWarning(*this <<": failed to attach term-hook " << QUOTE(purpose) <<
436 	       ' ' << QUOTE(term) << " to " << QUOTE(this) << '.');
437   term->deepSelfDestruct();
438   return false;
439 }
440 
441 void
copyAttachments(Symbol *,SymbolMap *)442 Symbol::copyAttachments(Symbol* /* original */, SymbolMap* /* map */)
443 {
444 }
445 
446 void
getDataAttachments(const Vector<Sort * > &,Vector<const char * > &,Vector<Vector<const char * >> &)447 Symbol::getDataAttachments(const Vector<Sort*>& /* opDeclaration */,
448 			   Vector<const char*>& /* purposes */,
449 			   Vector<Vector<const char*> >& /* data */)
450 {
451 }
452 
453 void
getSymbolAttachments(Vector<const char * > &,Vector<Symbol * > &)454 Symbol::getSymbolAttachments(Vector<const char*>& /* purposes */,
455 			     Vector<Symbol*>& /* symbols */)
456 {
457 }
458 
459 void
getTermAttachments(Vector<const char * > &,Vector<Term * > &)460 Symbol::getTermAttachments(Vector<const char*>& /* purposes */,
461 			   Vector<Term*>& /* terms */)
462 {
463 }
464 
465 bool
isConstructor(DagNode * subject)466 Symbol::isConstructor(DagNode* subject)
467 {
468   if (specialSortHandling())
469     return false;  // HACK
470 
471   switch (getCtorStatus())
472     {
473     case SortTable::IS_CTOR:
474       return true;
475     case SortTable::IS_COMPLEX:
476       {
477 	if (arity() == 0)
478 	  return ctorTraverse(0, 0);  // HACK
479 
480 	int state = 0;
481 	for (DagArgumentIterator a(*subject); a.valid(); a.next())
482 	  {
483 	    int t = a.argument()->getSortIndex();
484 	    Assert(t != Sort::SORT_UNKNOWN, "Unknown sort");
485 	    state = ctorTraverse(state, t);
486 	  }
487 	return state;
488       }
489     default:
490       break;
491     }
492   return false;
493 }
494 
495 //
496 //	Putting this stuff here rather than the header file avoids gcc creating separate instances
497 //	for derived classes tht don't define their own versions.
498 //
499 
500 bool
canResolveTheoryClash()501 Symbol::canResolveTheoryClash()
502 {
503   //
504   //	The default is that we can't resolve theory clashes.
505   //
506   return false;
507 }
508 
509 UnificationSubproblem*
makeUnificationSubproblem()510 Symbol::makeUnificationSubproblem()
511 {
512   CantHappen("Not implemented"); return 0;
513 }
514 
515 int
unificationPriority() const516 Symbol::unificationPriority() const
517 {
518   return 100;
519 }
520 
521 #ifdef COMPILER
522 void
fullCompile(CompilationContext & context,bool inLine) const523 Symbol::fullCompile(CompilationContext& context, bool inLine) const
524 {
525   context.beginNewFunction();
526 #ifdef ANNOTATE
527   context.body() << "// " << this << '\n';
528 #endif
529   int nrArgs = arity();
530   int index = getIndexWithinModule();
531   //
532   //	Generate forward decl for C++ function.
533   //
534   context.head() << "Node* f" << index << '(';
535   for (int i = 0; i < nrArgs; i++)
536     {
537       if (i != 0)
538 	context.head() << ", ";
539       context.head() << "Node*";
540     }
541   context.head() << ");\n";
542   //
543   //	Generate C++ function.
544   //
545   if (inLine)
546     context.body() << "inline ";
547   context.body() << "Node*\nf" << index << '(';
548   for (int i = 0; i < nrArgs; i++)
549     {
550       if (i != 0)
551 	context.body() << ", ";
552       context.body() << "Node* a" << i;
553     }
554   context.body() << ")\n{\n  F" << index << ";\n";
555   generateCode(context);
556   context.body() << "}\n\n";
557   //
558   //	Generate #define for start label and/or safe slots if needed.
559   //
560   context.head() << "#define F" << getIndexWithinModule();
561   if (context.isTailRecursive())
562     context.head() << "\tstart:";
563   int maxSafe = context.getNrSafeSlots();
564   if (maxSafe > 0)
565     context.head() << "\tLink safe[" << maxSafe + 2 << ']';
566   context.head() << '\n';
567 }
568 
569 void
generateCode(CompilationContext & context) const570 Symbol::generateCode(CompilationContext& context) const
571 {
572   context.body() << "  // not implemented\n  return 0;\n";
573 }
574 #endif
575 
576 #ifdef DUMP
577 void
dump(ostream & s,int indentLevel)578 Symbol::dump(ostream& s, int indentLevel)
579 {
580   s << Indent(indentLevel) << "Dumping Symbol: \"" << this << "\"\n";
581   dumpSortDiagram(s, indentLevel);
582   dumpEquationTable(s, indentLevel);
583 }
584 #endif
585