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 Term.
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 "fullCompiler.hh"
36 
37 //	interface class definitions
38 #include "symbol.hh"
39 #include "dagNode.hh"
40 #include "term.hh"
41 
42 //	core class definitions
43 #include "argumentIterator.hh"
44 #include "bindingLhsAutomaton.hh"
45 #include "termBag.hh"
46 #include "rhsBuilder.hh"
47 #include "trivialRhsAutomaton.hh"
48 #include "copyRhsAutomaton.hh"
49 #include "symbolMap.hh"
50 #include "stackMachineRhsCompiler.hh"
51 
52 //	variable class definitions
53 #include "variableSymbol.hh"
54 #include "variableTerm.hh"
55 #include "variableInfo.hh"
56 
57 //	full compiler class definitions
58 #include "compilationContext.hh"
59 #include "variableName.hh"
60 
61 Vector<DagNode*> Term::subDags;
62 TermSet Term::converted;
63 bool Term::setSortInfoFlag;
64 bool Term::discard;
65 
66 DagNode*
term2Dag(bool setSortInfo)67 Term::term2Dag(bool setSortInfo)
68 {
69   setSortInfoFlag = setSortInfo;
70   subDags.clear();
71   converted.makeEmpty();
72   return dagify();
73 }
74 
75 void
computeMatchIndices() const76 Term::computeMatchIndices() const
77 {
78   //
79   //	Default is we do nothing; thus this term cannot be safely compiled for index based matching.
80   //
81 }
82 
83 int
compileRhs(RhsBuilder & rhsBuilder,VariableInfo & variableInfo,TermBag & availableTerms,bool eagerContext)84 Term::compileRhs(RhsBuilder& rhsBuilder,
85 		 VariableInfo& variableInfo,
86 		 TermBag& availableTerms,
87 		 bool eagerContext)
88 {
89   if (Term* t = availableTerms.findTerm(this, eagerContext))
90     {
91       //
92       //	We have seen this term before either in a lhs or
93       //	in a rhs (perhaps of a condition fragment) and we
94       //	can reuse it.
95       //
96       if (t->saveIndex == NONE)  // must be lhs term/variable
97 	{
98 	  if (VariableTerm* vt = dynamic_cast<VariableTerm*>(this))
99 	    return vt->getIndex();  // lhs varible
100 	  t->saveIndex = variableInfo.makeProtectedVariable();  // left->right sharing
101 	}
102       return t->saveIndex;
103     }
104   if (VariableTerm* vt = dynamic_cast<VariableTerm*>(this))
105     {
106       //
107       //	Variable must be either unbound (because we didn't see it during matching) OR
108       //	we're in eager context and variable was only matched in a lazy context.
109       //
110       int varIndex = vt->getIndex();
111       if (eagerContext)
112 	{
113 	  //
114 	  //	Since we're using an unbound or lazy variable in
115 	  //	an eager context we must arrange to copy its binding.
116 	  //
117 	  DebugAdvisory("made CopyRhsAutomaton for " << this);
118 	  int index = variableInfo.makeConstructionIndex();
119 	  rhsBuilder.addRhsAutomaton(new CopyRhsAutomaton(varIndex, index));
120 	  saveIndex = index;
121 	  availableTerms.insertBuiltTerm(this, true);
122 	  return index;
123 	}
124       return varIndex;  // unbound variable in lazy context
125     }
126   //
127   //	Previously unseen non-variable term - let its theory compile it.
128   //
129   int index = compileRhs2(rhsBuilder, variableInfo, availableTerms, eagerContext);
130   //
131   //	Save the term and the index it was placed at so we can share its
132   //	instantiation if we encounter an equal term later on.
133   //
134   saveIndex = index;
135   availableTerms.insertBuiltTerm(this, eagerContext);
136   return index;
137 }
138 
139 void
compileTopRhs(RhsBuilder & rhsBuilder,VariableInfo & variableInfo,TermBag & availableTerms)140 Term::compileTopRhs(RhsBuilder& rhsBuilder,
141 		    VariableInfo& variableInfo,
142 		    TermBag& availableTerms)
143 {
144   int index = compileRhs(rhsBuilder, variableInfo, availableTerms, true);
145   variableInfo.useIndex(index);
146   //
147   //	If we don't have any automata we must create one, if only to do the
148   //	replacement.
149   //
150   if (rhsBuilder.empty())
151     rhsBuilder.addRhsAutomaton(new TrivialRhsAutomaton(index));
152 }
153 
154 void
indexVariables(VariableInfo & indicies)155 Term::indexVariables(VariableInfo& indicies)
156 {
157   if (VariableTerm* vt = dynamic_cast<VariableTerm*>(this))
158     {
159       int index = indicies.variable2Index(vt);
160       vt->setIndex(index);
161       occursSet.insert(index);
162     }
163   else
164     {
165       for (ArgumentIterator a(*this); a.valid(); a.next())
166 	{
167 	  Term* t = a.argument();
168 	  t->indexVariables(indicies);
169 	  occursSet.insert(t->occursSet);
170 	}
171     }
172 }
173 
174 int
computeSize()175 Term::computeSize()
176 {
177   if (cachedSize == UNDEFINED)
178     {
179       int size = 1;
180       for (ArgumentIterator a(*this); a.valid(); a.next())
181 	size += a.argument()->computeSize();
182       cachedSize = size;
183     }
184   return cachedSize;
185 }
186 
187 void
determineContextVariables()188 Term::determineContextVariables()
189 {
190   for (ArgumentIterator a(*this); a.valid(); a.next())
191     {
192       Term* t = a.argument();
193       t->contextSet.insert(contextSet);  // insert parents context set
194       for (ArgumentIterator b(*this); b.valid(); b.next())
195 	{
196 	  Term* u = b.argument();
197 	  if (u != t)
198 	    t->contextSet.insert(u->occursSet);  // insert siblings occurs set
199 	}
200       t->determineContextVariables();
201     }
202 }
203 
204 void
analyseCollapses()205 Term::analyseCollapses()
206 {
207   analyseCollapses2();
208   if (dynamic_cast<VariableSymbol*>(topSymbol) == 0 && collapseSet.empty())
209     flags |= STABLE;
210 }
211 
212 void
analyseCollapses2()213 Term::analyseCollapses2()
214 {
215   for (ArgumentIterator a(*this); a.valid(); a.next())
216     a.argument()->analyseCollapses();
217 }
218 
219 void
insertAbstractionVariables(VariableInfo & variableInfo)220 Term::insertAbstractionVariables(VariableInfo& variableInfo)
221 {
222   setHonorsGroundOutMatch(true);
223   for (ArgumentIterator a(*this); a.valid(); a.next())
224     {
225       Term* t = a.argument();
226       t->insertAbstractionVariables(variableInfo);
227       if (!(t->honorsGroundOutMatch()))
228 	setHonorsGroundOutMatch(false);
229     }
230 }
231 
232 LhsAutomaton*
compileLhs(bool matchAtTop,const VariableInfo & variableInfo,NatSet & boundUniquely,bool & subproblemLikely)233 Term::compileLhs(bool matchAtTop,
234 		 const VariableInfo& variableInfo,
235 		 NatSet& boundUniquely,
236 		 bool& subproblemLikely)
237 {
238   LhsAutomaton* a = compileLhs2(matchAtTop, variableInfo, boundUniquely, subproblemLikely);
239   if (saveIndex != NONE)
240     a = new BindingLhsAutomaton(saveIndex, a);
241   return a;
242 }
243 
244 bool
earlyMatchFailOnInstanceOf(const Term * other) const245 Term::earlyMatchFailOnInstanceOf(const Term* other) const
246 {
247   if (stable() && other->stable() && topSymbol != other->topSymbol)
248     return true;
249   return false;
250 }
251 
252 bool
subsumes(const Term * other,bool sameVariableSet) const253 Term::subsumes(const Term* other, bool sameVariableSet) const
254 {
255   return false;
256 }
257 
258 int
partialCompareUnstable(const Substitution &,DagNode *) const259 Term::partialCompareUnstable(const Substitution& /* partialSubstitution */,
260 			      DagNode* /* other */) const
261 {
262   return UNDECIDED;
263 }
264 
265 int
partialCompareArguments(const Substitution &,DagNode *) const266 Term::partialCompareArguments(const Substitution& /* partialSubstitution */,
267 			      DagNode* /* other */) const
268 {
269   return UNDECIDED;
270 }
271 
272 void
commonSymbols(Vector<Term * > & patterns,PointerSet & common)273 Term::commonSymbols(Vector<Term*>& patterns, PointerSet& common)
274 {
275   //
276   //	Generate set of symbols that could be at the top of subject which matches
277   //	all patterns. Patterns are assumed to have had their collapse analysis done
278   //	and we assume they are in the same connected component.
279   //	We make no assumption about where sort constraints have been indexed.
280   //	If there in any doubt about some symbol we add it anyway.
281   //	Variables are handled in a special way: a variable v which is in one patterns
282   //	collapse set (or which is that pattern) is added if for each other pattern
283   //	p_i there is some variable v_i which is p_i of is in p_i's collapse set
284   //	with sort greater, equal or incomparable to v's sort.
285   //
286   Assert(common.empty(), "common not empty to start with");
287   int nrPatterns = patterns.length();
288   for (int i = 0; i < nrPatterns; i++)
289     {
290       Term* p = patterns[i];
291       PointerSet cs(p->collapseSet);
292       (void) cs.insert(p->topSymbol);
293       int nrSymbols = cs.cardinality();
294       for (int j = 0; j < nrSymbols; j++)
295 	{
296 	  Symbol* s = static_cast<Symbol*>(cs.index2Pointer(j));
297 	  if (commonWithOtherPatterns(patterns, i, s))
298 	    (void) common.insert(s);
299 	}
300     }
301 }
302 
303 bool
commonWithOtherPatterns(Vector<Term * > & patterns,int excluded,Symbol * symbol)304 Term::commonWithOtherPatterns(Vector<Term*>& patterns, int excluded, Symbol* symbol)
305 {
306   int nrPatterns = patterns.length();
307   VariableSymbol* v = dynamic_cast<VariableSymbol*>(symbol);
308   if (v == 0)
309     {
310       for (int i = 0; i < nrPatterns; i++)
311 	{
312 	  if (i != excluded && !(symbol->mightMatchPattern(patterns[i])))
313 	    return false;
314 	}
315     }
316   else
317     {
318       for (int i = 0; i < nrPatterns; i++)
319 	{
320 	  if (i != excluded && !hasGeqOrIncomparableVariable(patterns[i], v))
321 	    return false;
322 	}
323     }
324   return true;
325 }
326 
327 bool
hasGeqOrIncomparableVariable(Term * pattern,VariableSymbol * v)328 Term::hasGeqOrIncomparableVariable(Term* pattern, VariableSymbol* v)
329 {
330   const Sort*s = v->getSort();
331   VariableSymbol* v2 = dynamic_cast<VariableSymbol*>(pattern->topSymbol);
332   if (v2 != 0)
333     {
334       const Sort* s2 = v2->getSort();
335       return s2 == s || !::leq(s2, s);
336     }
337   const PointerSet& cs = pattern->collapseSet;
338   int cardinality = cs.cardinality();
339   for (int i = 0; i < cardinality; i++)
340     {
341       Symbol* s2 = static_cast<Symbol*>(cs.index2Pointer(i));
342       v2 = dynamic_cast<VariableSymbol*>(s2);
343       if (v2 != 0)
344 	{
345 	  const Sort* s2 = v2->getSort();
346 	  if (s2 == s || !::leq(s2, s))
347 	    return true;
348 	}
349     }
350   return false;
351 }
352 
353 bool
greedySafe(const VariableInfo & variableInfo,const NatSet & boundUniquely) const354 Term::greedySafe(const VariableInfo& variableInfo, const NatSet& boundUniquely) const
355 {
356   NatSet badVariables(variableInfo.getConditionVariables());
357   badVariables.insert(contextSet);
358   badVariables.intersect(occursSet);
359   return boundUniquely.contains(badVariables);
360 }
361 
362 Term*
instantiate2(const Vector<Term * > & varBindings,SymbolMap * translator)363 Term::instantiate2(const Vector<Term*>& varBindings, SymbolMap* translator)
364 {
365   //
366   //	Naive implementation. Doesn't work for variables or any subclass
367   //	with hidden data. Possibly inefficient in other cases.
368   //
369   Vector<Term*> args;
370   for (ArgumentIterator a(*this); a.valid(); a.next())
371     args.append(a.argument()->instantiate2(varBindings, translator));
372   return translator->findTargetVersionOfSymbol(topSymbol)->makeTerm(args);
373 }
374 
375 Instruction*
term2InstructionSequence()376 Term::term2InstructionSequence()
377 {
378   StackMachineRhsCompiler compiler;
379   TermSet visited;
380 
381   recordSubterms(compiler, visited);
382   return compiler.compileInstructionSequence();
383 }
384 
385 int
recordSubterms2(StackMachineRhsCompiler & compiler,TermSet & visited)386 Term::recordSubterms2(StackMachineRhsCompiler& compiler, TermSet& visited)
387 {
388   //
389   //	Super naive version.
390   //
391   Vector<int> argumentSlots;
392   for (ArgumentIterator a(*this); a.valid(); a.next())
393     argumentSlots.append(a.argument()->recordSubterms(compiler, visited));
394 
395   int destination = visited.insert(this);
396   compiler.recordFunctionEval(symbol(), destination, argumentSlots);
397   return destination;
398 }
399 
400 #ifdef COMPILER
401 int
gatherPartialResults(int nrVariables,TermSet & compiled,Vector<Symbol * > & symbols,Vector<Vector<int>> & argLists)402 Term::gatherPartialResults(int nrVariables,
403 			   TermSet& compiled,
404 			   Vector<Symbol*>& symbols,
405 			   Vector<Vector<int> >& argLists)
406 {
407   VariableTerm* v = dynamic_cast<VariableTerm*>(this);
408   if (v != 0)
409     return v->getIndex();
410   int source = compiled.term2Index(this);
411   if (source >= 0)
412     return source + nrVariables;
413   //
414   //	Need to generate new partial result
415   //
416   Symbol* s = symbol();
417   Vector<int> args;
418   for (ArgumentIterator a(*this); a.valid(); a.next())
419     {
420       int source = a.argument()->
421 	gatherPartialResults(nrVariables, compiled, symbols, argLists);
422       args.append(source);
423     }
424   int index = symbols.length();
425   compiled.insert(this);
426   symbols.append(s);
427   argLists.append(args);
428   return index + nrVariables;
429 }
430 
431 void
generateRhs(CompilationContext & context,int indentLevel,const Vector<VariableName> & varNames,Symbol * lhsSymbol)432 Term::generateRhs(CompilationContext& context,
433 		  int indentLevel,
434 		  const Vector<VariableName>& varNames,
435 		  Symbol* lhsSymbol)
436 {
437   //
438   //	First we generate the a convenient DAG representation of the term.
439   //
440   TermSet compiled;
441   Vector<Symbol*> symbols;
442   Vector<Vector<int> > argLists;
443   int nrVariables = varNames.length();
444   int index = gatherPartialResults(nrVariables, compiled, symbols, argLists);
445   int nrPartialResults = symbols.length();
446   if (nrPartialResults == 0)
447     {
448       //
449       //	Handle bare variable case.
450       //
451       context.generateIncrement(indentLevel);
452       context.body() << Indent(indentLevel) << "return " << varNames[index] << ";\n";
453       return;
454     }
455   //
456   //	Now find out which partial result is the last user of each
457   //	variable and partial result.
458   //
459   int nrItems = nrVariables + nrPartialResults - 1;  // final partial result not used
460   Vector<int> lastUse(nrItems);
461   for (int i = 0; i < nrItems; i++)
462     lastUse[i] = UNUSED;
463   for (int i = 0; i < nrPartialResults; i++)
464     {
465       Vector<int> args = argLists[i];
466       int nrArgs = args.length();
467       for (int j = 0; j < nrArgs; j++)
468 	lastUse[args[j]] = i;
469     }
470   //
471   //	Then we decide what pointers will need to be placed in safe slots
472   //	across each function call.
473   //
474   Vector<Vector<int> > safeSlots(nrPartialResults - 1);
475   if (nrPartialResults > 1)
476     {
477       Vector<int>& safe = safeSlots[0];
478       for (int i = 0; i < nrVariables; i++)
479 	{
480 	  if (lastUse[i] > 0)
481 	    safe.append(i);
482 	}
483     }
484   for (int i = 1; i < nrPartialResults - 1; i++)
485     {
486       int prevResult = i - 1 + nrVariables;
487       bool needToSavePrevResult = lastUse[prevResult] > i;
488       Vector<int>& prevSaved = safeSlots[i - 1];
489       Vector<int>& save = safeSlots[i];
490       int nrPrevSaved = prevSaved.length();
491       for (int j = 0; j < nrPrevSaved; j++)
492 	{
493 	  int ps = prevSaved[j];
494 	  if (ps == UNUSED)
495 	    save.append(UNUSED);
496 	  else
497 	    {
498 	      if (lastUse[ps] > i)
499 		save.append(ps);
500 	      else
501 		{
502 		  if (needToSavePrevResult)
503 		    {
504 		      save.append(prevResult);
505 		      needToSavePrevResult = false;
506 		    }
507 		  else
508 		    save.append(UNUSED);
509 		}
510 	    }
511 	}
512       if (needToSavePrevResult)
513 	{
514 	  for (int j = 0; j < nrPrevSaved; j++)
515 	    {
516 	      if (save[j] == UNUSED)
517 		{
518 		  save[j] = prevResult;
519 		  needToSavePrevResult = false;
520 		  break;
521 		}
522 	    }
523 	}
524       if (needToSavePrevResult)
525 	save.append(prevResult); // need extra slot
526     }
527   //
528   //	Now we can generate code.
529   //
530   //context.body() << Indent(indentLevel) << "{\n";
531   //
532   //	Declare partial result variables.
533   //
534   for (int i = 0; i < nrPartialResults - 1; i++)
535     context.body() << Indent(indentLevel + 1) << "Node* p" << i << ";\n";
536   //
537   //	Set up safe slots.
538   //
539   context.generateIncrement(indentLevel + 1);
540   int nrSafeSlots = nrPartialResults >= 2 ? safeSlots[nrPartialResults - 2].length() : 0;
541   context.setNrSafeSlots(nrSafeSlots);
542   if (nrSafeSlots > 0)
543     {
544       context.body() << Indent(indentLevel + 1) << "safe[0].l = g.safePtr;\n";
545       context.body() << Indent(indentLevel + 1) << "g.safePtr = safe;\n";
546       context.body() << Indent(indentLevel + 1) << "safe[1].i = " << nrSafeSlots << ";\n";
547       Vector<int>& firstSlots = safeSlots[0];
548       int nrFirstSlots = firstSlots.length();
549       for (int i = 0; i < nrSafeSlots; i++)
550 	{
551 	  context.body() << Indent(indentLevel + 1) << "safe[" << i + 2 << "].n = ";
552 	  if (i < nrFirstSlots)
553 	    context.body() << varNames[firstSlots[i]];
554 	  else
555 	    context.body() << '0';
556 	  context.body() << ";\n";
557 	}
558     }
559   //
560   //	Generate first partial result.
561   //
562   {
563     Symbol* symbol = symbols[0];
564     int nrArgs = symbol->arity();
565     Vector<int>& argList = argLists[0];
566     context.body() << Indent(indentLevel + 1) << "{\n";
567     if (nrPartialResults == 1 && symbol == lhsSymbol)
568       {
569 	//
570 	//	Tail recursion case.
571 	//
572 	for (int i = 0; i < nrArgs; i++)
573 	  {
574 	    context.body() << Indent(indentLevel + 2) << 'a' << i << " = " <<
575 	      varNames[argList[i]] << ";\n";
576 	  }
577 	context.body() << Indent(indentLevel + 2) << "goto start;\n";
578 	context.setTailRecursive();
579       }
580     else
581       {
582 	if (nrPartialResults > 1)
583 	  context.body() << Indent(indentLevel + 2) << "p0 =";
584 	else
585 	  context.body() << Indent(indentLevel + 2) << "return";
586 	context.body() << " f" << symbol->getIndexWithinModule() << '(';
587 	for (int i = 0; i < nrArgs; i++)
588 	  {
589 	    context.body() << varNames[argList[i]];
590 	    if (i + 1 < nrArgs)
591 	      context.body() << ", ";
592 	  }
593 	context.body() << ");\n";
594       }
595     context.body() << Indent(indentLevel + 1) << "}\n";
596   }
597   //
598   //	Generate remaining partial results.
599   //
600   for (int i = 1; i < nrPartialResults; i++)
601     {
602       Symbol* symbol = symbols[i];
603       int nrArgs = symbol->arity();
604       Vector<int>& argList = argLists[i];
605       Vector<int>& prevSaved = safeSlots[i - 1];
606       int nrSlots = prevSaved.length();
607 
608       context.body() << Indent(indentLevel + 1) << "{\n";
609       //
610       //	Copy saved values needed for args into local 'b' variables.
611       //
612       int bCount = 1;
613       for (int j = 0; j < nrSlots; j++)
614 	{
615 	  int contents = prevSaved[j];
616 	  if (contents != UNUSED)
617 	    {
618 	      int localCopy = NONE;
619 	      for (int k = 0; k < nrArgs; k++)
620 		{
621 		  if (argList[k] == contents)
622 		    {
623 		      if (localCopy == NONE)
624 			{
625 			  localCopy = bCount++;
626 			  context.body() << Indent(indentLevel + 2) << "Node* b" << localCopy <<
627 			    " = safe[" << j + 2 << "].n;\n";
628 			}
629 		      argList[k] = -localCopy;
630 		    }
631 		}
632 	    }
633 	}
634       if (i < nrPartialResults - 1)
635 	{
636 	  //
637 	  //	Clear saves values no longer needed, and save previous
638 	  //	partial result if need after our function call.
639 	  //
640 	  Vector<int>& toSave = safeSlots[i];
641 	  for (int j = 0; j < nrSlots; j++)
642 	    {
643 	      int ps = prevSaved[j];
644 	      int ts = toSave[j];
645 	      if (ps != ts)
646 		{
647 		  if (ts == UNUSED)
648 		    context.body() << Indent(indentLevel + 2) << "safe[" << j + 2 << "].n = 0;\n";
649 		  else
650 		    {
651 		      context.body() << Indent(indentLevel + 2) << "safe[" << j + 2 <<
652 			"].n = p" << i - 1 << ";\n";
653 		    }
654 		}
655 	    }
656 	  if (toSave.length() > nrSlots)
657 	    {
658 	      context.body() << Indent(indentLevel + 2) << "safe[" << nrSlots + 2 <<
659 		"].n = p" << i - 1 << ";\n";
660 	    }
661 	  context.body() << Indent(indentLevel + 2) << 'p' << i <<  " =";
662 	}
663       else
664 	{
665 	  if (nrSafeSlots > 0)
666 	    context.body() << Indent(indentLevel + 2) << "g.safePtr = safe[0].l;\n";
667 	  if (symbol == lhsSymbol)
668 	    {
669 	      //
670 	      //	Tail recursion case.
671 	      //
672 	      for (int j = 0; j < nrArgs; j++)
673 		{
674 		  context.body() << Indent(indentLevel + 2) << 'a' << j << " = ";
675 		  int a = argList[j];
676 		  if (a < 0)
677 		    context.body() << 'b' << -a;
678 		  else
679 		    context.body() << 'p' << i - 1;
680 		  context.body() << ";\n";
681 		}
682 	      context.body() << Indent(indentLevel + 2) << "goto start;\n";
683 	      context.body() << Indent(indentLevel + 1) << "}\n";
684 	      context.setTailRecursive();
685 	      break;
686 	    }
687 	  context.body() << Indent(indentLevel + 2) << "return";
688 	}
689       context.body() << " f" << symbol->getIndexWithinModule() << '(';
690       for (int j = 0; j < nrArgs; j++)
691 	{
692 	  int a = argList[j];
693 	  if (a < 0)
694 	    context.body() << 'b' << -a;
695 	  else
696 	    context.body() << 'p' << i - 1;
697 	  if (j + 1 < nrArgs)
698 	    context.body() << ", ";
699 	}
700       context.body() << ");\n";
701       context.body() << Indent(indentLevel + 1) << "}\n";
702     }
703   //  context.body() << Indent(indentLevel) << "}\n";
704   return;
705 }
706 #endif
707 
708 #ifdef DUMP
709 void
dump(ostream & s,const VariableInfo & variableInfo,int indentLevel)710 Term::dump(ostream& s, const VariableInfo& variableInfo, int indentLevel)
711 {
712   s << Indent(indentLevel) << "Begin{Term}\n";
713   ++indentLevel;
714   dumpCommon(s, variableInfo, indentLevel);
715   s << Indent(indentLevel) << "arguments:\n";
716   ++indentLevel;
717   for (ArgumentIterator a(*this); a.valid(); a.next())
718     a.argument()->dump(s, variableInfo, indentLevel);
719   s << Indent(indentLevel - 2) << "End{Term}\n";
720 }
721 
722 void
dumpCommon(ostream & s,const VariableInfo & variableInfo,int indentLevel)723 Term::dumpCommon(ostream& s, const VariableInfo& variableInfo, int indentLevel)
724 {
725   s << Indent(indentLevel) << "topSymbol = " << topSymbol <<
726     "\thonorsGroundOutMatch = " << honorsGroundOutMatch() <<
727     "\teagerContext = " << hasEagerContext() << '\n';
728   if (sortIndex == Sort::SORT_UNKNOWN)
729     s << Indent(indentLevel) << "sort information not valid\n";
730   else
731     s << Indent(indentLevel) << "sortIndex = " << sortIndex << '\n';
732   s << Indent(indentLevel) << "occursSet = ";
733   dumpVariableSet(s, occursSet, variableInfo);
734   s << Indent(indentLevel) << "contextSet = ";
735   dumpVariableSet(s, contextSet, variableInfo);
736   s << Indent(indentLevel) << "collapseSet = ";
737   dumpSymbolSet(s, collapseSet);
738 }
739 
740 void
dumpVariableSet(ostream & s,const NatSet & variableSet,const VariableInfo & variableInfo)741 Term::dumpVariableSet(ostream& s,
742 		      const NatSet& variableSet,
743 		      const VariableInfo& variableInfo)
744 {
745   int m = variableSet.max();
746   for (int i = 0; i <= m; i++)
747     {
748       if (variableSet.contains(i))
749 	s << ' ' << variableInfo.index2Variable(i);
750     }
751   s << '\n';
752 }
753 
754 void
dumpSymbolSet(ostream & s,const PointerSet & symbolSet)755 Term::dumpSymbolSet(ostream& s, const PointerSet& symbolSet)
756 {
757   int c = symbolSet.cardinality();
758   for (int i = 0; i < c; i++)
759     s << ' ' << static_cast<Symbol*>(symbolSet.index2Pointer(i));
760   s << '\n';
761 }
762 #endif
763