/* Resp: A programming language * Copyright (C) 2008-2012 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 Lift instances of parametric types */ #include #include #include "resp.hpp" using namespace std; static bool is_concrete(const AST* type) { if (type->tag() == T_TVAR) { return false; } else if (type->tag() == T_SYMBOL) { return isupper(type->as_symbol()->str()[0]); } else { const ATuple* tup = type->as_tuple(); for (auto i : *tup) { if (!is_concrete(i)) { return false; } } } return true; } static const AST* depoly_def_type(CEnv& cenv, Code& code, const ATuple* def) throw() { if (!def->rrst()) { return def; // Forward declaration } const ASymbol* name = def->frst()->to_symbol(); if (name) { cenv.tenv.def(name, def->frrst()); return def; } else if (is_concrete(def->frst())) { name = def->frst()->as_tuple()->fst()->as_symbol(); cenv.tenv.def(name, def->frrst()); return def; } return NULL; } // Create concrete type definitions for a parametric type instantation static void raise_type(CEnv& cenv, Code& code, const ATuple* type) { const ASymbol* tag = type->fst()->as_symbol(); if (tag->str() == "Tup" || !type->rst()) { return; } const ATuple* exp = (*cenv.tenv.ref(tag))->as_tuple(); const ATuple* prot = exp->frst()->as_tuple(); List def(Cursor(), cenv.penv.sym("def-type"), type, NULL); // Build a substitution for each type parameter to its instantiation Subst subst; ATuple::const_iterator t = type->iter_at(1); for (ATuple::const_iterator p = prot->iter_at(0); p != prot->end() && t != type->end(); ++p, ++t) { subst.add(*p, *t); } // Apply substitution to each clause and add it to the new type definition for (ATuple::const_iterator i = exp->iter_at(2); i != exp->end(); ++i) { def.push_back(subst.apply(*i)); } code.push_back(def); } static const AST* depoly_args(CEnv& cenv, Code& code, const ATuple* call) throw() { for (auto i : *call) { const AST* type = cenv.type(i); if (type && type->to_tuple()) { if (is_concrete(type)) { raise_type(cenv, code, type->as_tuple()); } } } return call; } const AST* resp_depoly(CEnv& cenv, Code& code, const AST* ast) throw() { switch (ast->tag()) { case T_TUPLE: { const ATuple* const call = ast->as_tuple(); const ASymbol* const sym = call->fst()->to_symbol(); const std::string form = sym ? sym->sym() : ""; assert(form != "lambda"); if (form == "quote") return ast; else if (form == "def-type") return depoly_def_type(cenv, code, call); else return depoly_args(cenv, code, call); } default: return ast; } cenv.err << "Attempt to depoly unknown form: " << ast << endl; assert(false); return NULL; }