/* 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& print_to(ostream& out, const AST* ast, unsigned indent, CEnv* cenv, bool types); static void newline(ostream& out, unsigned indent) { out << endl; for (unsigned i = 0; i < indent; ++i) out << " "; } void print_tuple(ostream& out, const ATuple* tup, ATuple::const_iterator i, unsigned indent, bool newlines, CEnv* cenv, bool types, bool elem_types) { for (; i != tup->end(); ) { ATuple::const_iterator next = i; ++next; print_to(out, *i, newlines ? indent + 2 : indent, cenv, types); if (elem_types) out << " :" << cenv->tsubst.apply(cenv->tenv.var(*i)); if (next != tup->end()) { if (newlines) newline(out, indent + 2); else out << " "; } i = next; } } ostream& print_to(ostream& out, const AST* ast, unsigned indent, CEnv* cenv, bool types) { 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 << "("; ATuple::const_iterator i = tup->begin(); const ASymbol* head = (i == tup->end()) ? NULL : (*i)->to(); if (head) { if (head == cenv->penv.sym("def")) { out << (*i++) << " "; // Print symbol (possibly with type annotation) const AST* sym = *i++; out << sym; if (types) out << " :" << cenv->tsubst.apply(cenv->tenv.var(sym)); // Print value on following lines, indented newline(out, indent + 2); print_tuple(out, tup, i, indent, true, cenv, types, false); return out << ")"; } else if (head == cenv->penv.sym("fn")) { out << (*i++) << " "; const ATuple* pat = (*i++)->as(); // Print prototype (possibly with parameter type annotations) out << "("; print_tuple(out, pat, pat->begin(), indent, false, cenv, types, types); out << ")"; // Print body expression(s) on following lines, indented newline(out, indent + 2); print_tuple(out, tup, i, indent + 2, true, cenv, types, false); return out << ")"; } else if (head == cenv->penv.sym("if")) { out << (*i++) << " "; // Print each condition and consequent pair separated by blank lines for (; i != tup->end(); ) { ATuple::const_iterator next = i; ++next; print_to(out, *i, indent + 2, cenv, types); if (next != tup->end()) { newline(out, indent + 2); print_to(out, *next++, indent + 2, cenv, types); newline(out, 0); newline(out, indent + 2); } i = next; } } } // Print plain tuple print_tuple(out, tup, i, indent + 1, false, cenv, types, false); return out << ")"; } return out << "?"; } ostream& operator<<(ostream& out, const AST* ast) { return print_to(out, ast, 0, NULL, false); } /// Pretty-print @a ast to @a out void pprint(ostream& out, const AST* ast, CEnv* cenv, bool types) { print_to(out, ast, 0, cenv, types); out << endl; }