/* tree.cc: Basic Abstract Syntax Tree Implementations. */ #include #include #include "AST.h" #include "UniqueId.h" #include "code-util.h" #include "code-commonsub.h" #include "decls.h" #include "pseudocode.h" #include "streq.h" #include "utils.h" TreeNode* const TreeNode::omitted = new OmittedNode; void indent(ostream& os, int depth) { while (depth-- > 0) os << ' ' << ' '; } static void append( string &texts, Common::Modifiers &flags, int mask, const char text[] ) { if ((flags & mask) == mask) { flags = (Common::Modifiers) (flags & ~mask); if (!texts.empty()) texts += ' '; texts += text; } } string stringifyModifiers (Common::Modifiers flags) { string result; append(result, flags, Common::Public, "public"); append(result, flags, Common::Private, "private"); append(result, flags, Common::Protected, "protected"); append(result, flags, Common::Static, "static"); append(result, flags, Common::Final, "final"); append(result, flags, Common::Synchronized, "synchronized"); append(result, flags, Common::Volatile, "volatile"); append(result, flags, Common::Transient, "transient"); append(result, flags, Common::Native, "native"); append(result, flags, Common::Interface, "interface"); append(result, flags, Common::Abstract, "abstract"); append(result, flags, Common::Single, "single"); append(result, flags, Common::Local | Common::LocalInferred, "(local)"); append(result, flags, Common::Local, "local"); append(result, flags, Common::Immutable, "immutable"); append(result, flags, Common::Sglobal, "sglobal"); append(result, flags, Common::Inline, "inline"); append(result, flags, Common::CompilerGenerated, "(compiler-generated)"); append(result, flags, Common::NonsharedQ | Common::SharingInferred, "(nonshared)"); append(result, flags, Common::PolysharedQ | Common::SharingInferred, "(polyshared)"); append(result, flags, Common::NonsharedQ, "nonshared"); append(result, flags, Common::PolysharedQ, "polyshared"); assert( !flags ); return result; } /* Print a representation of *this on OS, indenting each line */ /* after the first by INDENT spaces. */ void TreeNode::print (ostream& os, unsigned depth) const { indent(os, depth); os << '(' << oper_name(); os << '<'; if(position().file) os << *position().file; else os << "unknown"; os << ' ' << position().posn << ',' << (position().posn+1) << "> @ " << this; for (int i = 0; i < arity(); i += 1) { os << '\n'; children[i]->print (os, depth + 1); } os << ')'; } bool TreeNode::compare(const TreeNode *t) const { cerr << "Internal error: compare() undefined on:\n"; print(cerr, 4); cerr << '\n'; undefined("compare"); return false; } /* When true, indicates an optional node that is absent (that is, */ /* that the node comes from the static constant omitted, defined */ /* below). */ bool TreeNode::absent() const { return false; } /* The printed name of the operator for *this. */ const char* TreeNode::oper_name() const { return "-*-"; } /* The number of children this node possesses. */ int TreeNode::arity() const { return 0; } /* Report a fatal error and exit. */ void TreeNode::fatal (const string& msg) const { cout.flush(); cerr << position() << " fatal error: " << msg << " in a " << oper_name() << endl << "Offending node: " << pseudocode(this) << endl << "parent of offending node: " << pseudocode(parent()) << endl << endl; /* if (DEBUG) */ assert(0); exit(1); } /* Report that name is undefined and exit. */ void TreeNode::undefined (const string& name) const { fatal(name + " undefined"); } /* Report that a feature is not yet implemented and exit. */ void TreeNode::unimplemented( const string& feature ) const { cerr << position() << "feature not yet implemented: " << feature << endl; exit(1); } /* Set line number from children, if not determined by P. */ void TreeNode::setWhere (SourcePosn p) { int i; where = p; i = 0; while (where.unknown() && i < arity()) { if (children[i]) where = children[i]->position(); i += 1; } } /* An iterator over all children of *THIS. */ TreeNode::ChildIter TreeNode::allChildren() { return ChildIter (children, arity()); } TreeNode::ConstChildIter TreeNode::allChildren() const { return ConstChildIter (children, arity()); } /* An iterator over all children of *THIS, assuming they are TypeNodes. */ TreeNode::TypeIter TreeNode::allTypes() { return TypeIter ((TypeNode **)children, arity()); } TreeNode::ConstTypeIter TreeNode::allTypes() const { return ConstTypeIter ((TypeNode **)children, arity()); } const string TreeNode::emitExpression( CodeContext & ) { undefined( "emitExpression" ); return ""; } bool TreeNode::isLocalLvalue() { undefined( "isLocalLvalue" ); return false; } bool TreeNode::isSimpleLvalue() { return false; } const string TreeNode::simpleVar( CodeContext & ) { undefined( "simpleVar" ); return ""; } const string TreeNode::getLvalue( CodeContext & ) { undefined( "getLvalue" ); return ""; } const string TreeNode::declareTemporary( LocalVars & ) { undefined( "declareTemporary" ); return ""; } void TreeNode::emitCatchTable( ostream & ) const { undefined("emitCatchTable"); } const string TreeNode::emitUse( LocalVars &context, const ObjectNode &subject ) const { return parent()->emitUse( context, subject ); } const string TreeNode::emitMethodCall( CodeContext &, TreeListNode & ) { undefined( "emitMethodCall" ); return ""; } bool TreeNode::selectedForCodeGen(bool) const { return true; } /* TreeListNode */ size_t list_recovery = 0; void TreeListNode::initialize( llist *childList ) { if (childList) { _arity = childList->size(); children = new PASS_RETADR TreeNode * [ _arity ]; for (int slot = 0; slot < (int)_arity; ++slot) { TreeNode * const adoptee = childList->front(); childList = childList->free(); child( slot, adoptee ); if (where.unknown()) where = adoptee->position(); } assert( !childList ); list_recovery += _arity; } else { children = 0; _arity = 0; } } const char* TreeListNode::oper_name() const { return "*list*"; } void TreeListNode::print (ostream& os, unsigned depth) const { indent(os, depth); os << '('; foriter (p, allChildren(), ConstChildIter) { os << '\n'; (*p)->print (os, depth + 1); } os << ')'; } bool apparentlyIdenticalChildren(const TreeNode *u, const TreeNode *t) { if (!streq(u->oper_name(), t->oper_name())) return false; if (u->arity() != t->arity()) return false; for (int i = u->arity(); --i >= 0; ) if (!COMPARE(u->child(i), t->child(i))) return false; return true; } bool TreeListNode::compare(const TreeNode *t) const { return apparentlyIdenticalChildren(this, t); } int TreeListNode::arity() const { return _arity; } template class llist; llist *appendTreeList(TreeListNode *l1, llist *l2) { for (int i = l1->arity() - 1; i >= 0; i--) l2 = cons(l1->child(i), l2); return l2; } // OmittedNode void OmittedNode::print (ostream& os, unsigned depth) const { indent(os, depth); os << "-*-"; } TypeNode* OmittedNode::type() { return theVoidType; } const string OmittedNode::emitExpression( CodeContext & ) { return "void"; } // The errorName method /* Return a string representing this node suitable for printing */ /* in an error message */ string TreeNode::errorName() const { return "(unnamed)"; // Shouldn't be called, but fatal() seems a bad move }