/* 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 Remove polymorphism (compilation pass 2) * After this pass: * - All functions definitions have concrete type */ #include "resp.hpp" using namespace std; AST* ATuple::depoly(CEnv& cenv, Code& code) throw() { ATuple* ret = new ATuple(*this); iterator ri = ret->begin(); FOREACHP(const_iterator, t, this) *ri++ = (*t)->depoly(cenv, code); return ret; } AST* AFn::depoly(CEnv& cenv, Code& code) throw() { return (cenv.type(this)->concrete()) ? this : NULL; } template AST* depoly_call(CEnv& cenv, T* call, Code& code) throw() { AST* head = cenv.resolve(call->head()); AFn* callee = head->to(); if (!callee || cenv.type(callee)->concrete()) return call; /*pair r = cenv.defs.equal_range(this); for (CEnv::Defs::iterator i = r.first; i != r.second; ++i) { if (*i->second.type == *cenv.type(this)) { ADef* def = i->second.def; cout << "CACHED LIFTED FN " << def << endl; return *(def->begin() + 2); } }*/ // Build arguments type AType argsT(call->loc); for (typename T::const_iterator i = call->begin() + 1; i != call->end(); ++i) argsT.push_back(const_cast(cenv.type(*i))); const AType* genericType = cenv.type(callee); Subst argsSubst = cenv.tenv.buildSubst(genericType, argsT); const AType* thisType = argsSubst.apply(genericType)->as(); // Create a new version of callee for this type AFn* concreteCallee = new AFn(callee); ASymbol* newName = cenv.penv.gensym(callee->name.c_str()); cenv.setType(concreteCallee, thisType); concreteCallee->name = newName->cppstr; ADef* def = tup(Cursor(), cenv.penv.sym("def"), newName, concreteCallee, NULL); cenv.setType(concreteCallee, thisType); cenv.setType(def, cenv.tenv.named("Nothing")); code.push_back(def); // Create copy of call that calls new concrete callee ATuple* copy = new T(call); *copy->begin() = newName; cenv.setType(copy, (*(thisType->begin() + 2))->as()); return copy; } AST* ADef::depoly(CEnv& cenv, Code& code) throw() { // Define stub first for recursion cenv.def(sym(), body(), cenv.type(body()), NULL); AFn* c = body()->to(); if (c) c->name = sym()->str(); ADef* copy = new ADef(ATuple::depoly(cenv, code)->as()); if (copy->body() == NULL) return NULL; // Don't attempt to compile polymorphic functions cenv.setType(copy, cenv.type(this)); return copy; } AST* ACall::depoly(CEnv& cenv, Code& code) throw() { return depoly_call(cenv, this, code); } AST* AIf::depoly(CEnv& cenv, Code& code) throw() { return depoly_call(cenv, this, code); } AST* ACons::depoly(CEnv& cenv, Code& code) throw() { return depoly_call(cenv, this, code); } AST* ADot::depoly(CEnv& cenv, Code& code) throw() { return depoly_call(cenv, this, code); } AST* APrimitive::depoly(CEnv& cenv, Code& code) throw() { return depoly_call(cenv, this, code); }