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