/* Resp: A programming language * 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 #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 << " "; } ostream& print_list_one_line(ostream& out, const ATuple* tup, ATuple::const_iterator i, unsigned indent, CEnv* cenv, bool types, bool elem_types) { for (; i != tup->end(); ) { ATuple::const_iterator next = i; ++next; print_to(out, *i, indent, cenv, types); if (elem_types) out << " :" << cenv->tsubst.apply(cenv->tenv.var(*i)); if (next != tup->end()) out << " "; i = next; } return (out << ")"); } /** Print list arguments on separate lines, possibly in separated pairs, e.g.: * (elem one) * (elem two) * (elem three) * * or, if split_pairs is true: * * (elem one) * (elem two) * * (elem three) * (elem four) */ ostream& print_list(ostream& out, const ATuple* tup, ATuple::const_iterator i, unsigned indent, CEnv* cenv, bool types, bool split_pairs) { for (; i != tup->end(); ) { ATuple::const_iterator next = i; ++next; print_to(out, *i, indent, cenv, types); if (next != tup->end()) { newline(out, indent); print_to(out, *next++, indent, cenv, types); if (split_pairs) newline(out, 0); newline(out, indent); } i = next; } return out << ")"; } ostream& print_to(ostream& out, const AST* ast, unsigned indent, CEnv* cenv, bool types) { switch (ast->tag()) { case T_UNKNOWN: return out << "?"; case T_TYPE: { const AType* type = ast->as_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 } } case T_TUPLE: { const ATuple* tup = ast->as_tuple(); out << "("; ATuple::const_iterator i = tup->begin(); if (i == tup->end()) return out << ")"; std::string form = ""; const ASymbol* sym = (*i)->to_symbol(); if (sym) form = sym->sym(); out << (*i++); if (i != tup->end()) out << " "; if (form == "def") { out << (*i++) << " "; // Print symbol unsigned child_indent = types ? indent + 2 : indent; if (types) { out << ":" << cenv->type(tup->list_ref(2)) << " "; newline(out, child_indent); } print_to(out, (*i++), child_indent, cenv, types); out << ")"; newline(out, 0); } else if (form == "def-type") { out << (*i++); newline(out, indent + 2); print_list(out, tup, i, indent + 2, cenv, types, false); newline(out, 0); } else if (form == "fn") { // Print prototype (possibly with parameter type annotations) const ATuple* pat = (*i++)->as_tuple(); out << "("; print_list_one_line(out, pat, pat->begin(), indent, cenv, types, types); // Print body expression(s) indented on the following lines newline(out, indent + 2); print_list(out, tup, i, indent + 2, cenv, types, false); } else if (form == "if") { print_list(out, tup, i, indent + 4, cenv, types, true); } else if (form == "let") { out << "("; const ATuple* vars = (*i)->as_tuple(); for (ATuple::const_iterator v = vars->begin(); v != vars->end();) { out << (*v); if (types) out << " :" << cenv->tsubst.apply(cenv->tenv.var(*v)); out << " " << (*++v); if (++v != vars->end()) newline(out, indent + 6); else out << ")"; } newline(out, indent + 2); print_list(out, tup, tup->iter_at(2), indent + 2, cenv, types, false); out << ")"; if (types) out << " :" << cenv->tsubst.apply(cenv->tenv.var(tup->list_last())); } else if (form == "match") { out << (*i++); newline(out, indent + 2); print_list(out, tup, i, indent + 2, cenv, types, true); } else { print_list_one_line(out, tup, i, indent + 1, cenv, types, false); } return out; } case T_BOOL: return out << ((((const ALiteral*)ast)->val) ? "#t" : "#f"); case T_FLOAT: return out << showpoint << ((const ALiteral*)ast)->val; case T_INT32: return out << showpoint << ((const ALiteral*)ast)->val; case T_STRING: return out << '"' << ((const AString*)ast)->cppstr << '"'; case T_SYMBOL: return out << ((const ASymbol*)ast)->sym(); } 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; }