/* Resp Serialisation * Copyright (C) 2008-2009 David Robillard * * Resp is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * Resp is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General * Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Resp. If not, see . */ /** @file * @brief Pretty-print AST expressions */ #include "resp.hpp" ostream& operator<<(ostream& out, const AST* ast) { const ALexeme* lexeme = ast->to(); if (lexeme) return out << *lexeme; const ALiteral* flit = ast->to*>(); if (flit) return out << showpoint << flit->val; const ALiteral* ilit = ast->to*>(); if (ilit) return out << ilit->val; const ALiteral* blit = ast->to*>(); if (blit) return out << (blit->val ? "#t" : "#f"); const AString* str = ast->to(); if (str) return out << '"' << *str << '"'; const ASymbol* sym = ast->to(); if (sym) return out << sym->cppstr; const AType* type = ast->to(); if (type) { switch (type->kind) { case AType::VAR: return out << "?" << type->id; case AType::NAME: return out << type->head(); case AType::PRIM: return out << type->head(); case AType::DOTS: return out << "..."; case AType::EXPR: break; // will catch Tuple case below } } const ATuple* tup = ast->to(); if (tup) { out << "("; for (ATuple::const_iterator i = tup->begin(); i != tup->end(); ) { ATuple::const_iterator next = i; ++next; out << (*i) << ((next != tup->end()) ? " " : ""); i = next; } return out << ")"; } return out << "?"; } enum TupleStyle { STYLE_ONE_LINE, // Entire tuple printed on one line STYLE_ALIGN, // Align all elements aligned after opening '(' STYLE_CALL // Call with all arguments aligned after head }; static bool can_one_line(const AST* ast, const unsigned max_width, unsigned& width, unsigned& depth) { static const unsigned MAX_DEPTH = 3; ostringstream ss; ss << ast; if ((width += ss.str().length()) >= max_width) return false; const ATuple* tup = ast->to(); if (tup) { if (++depth >= MAX_DEPTH) return false; for (ATuple::const_iterator i = tup->begin(); i != tup->end(); ++i) { ostringstream ss; ss << *i; width += ss.str().length(); if (!can_one_line(*i, max_width, width, depth)) return false; } } return true; } static TupleStyle tuple_style(const ATuple* tup, const unsigned max_width, unsigned& indent) { unsigned depth = 0; unsigned width = indent; if (can_one_line(tup, max_width, width, depth)) return STYLE_ONE_LINE; if (tup->to() || tup->to()) { indent += 2; return STYLE_CALL; } if (tup->to()) { indent += tup->head()->str().length() + 1; return STYLE_CALL; } return STYLE_ALIGN; } static void newline(ostream& out, unsigned indent) { out << endl; for (unsigned i = 0; i < indent; ++i) out << " "; } void pprint_internal(ostream& out, const AST* ast, unsigned indent) { const ATuple* tup = ast->to(); if (tup) { out << "("; unsigned child_indent = indent + 1; ATuple::const_iterator i = tup->begin(); if (i != tup->end()) { const TupleStyle style = tuple_style(tup, 80, child_indent); pprint_internal(out, *i++, indent + 1); // Print head switch (style) { case STYLE_ONE_LINE: while (i != tup->end()) out << " " << *i++; break; case STYLE_ALIGN: while (i != tup->end()) { newline(out, indent + 1); pprint_internal(out, *i++, child_indent); } break; case STYLE_CALL: out << " "; pprint_internal(out, *i, child_indent); // Print first argument while (++i != tup->end()) { newline(out, child_indent); pprint_internal(out, *i, child_indent); } break; } } out << ")"; } else { out << ast; } } /// Pretty-print @a ast to @a out void pprint(ostream& out, const AST* ast) { pprint_internal(out, ast, 0); out << endl; }