/* Resp: A programming language * Copyright (C) 2008-2011 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 Flatten code (raise all nested expressions) */ #include #include #include "resp.hpp" using namespace std; static const AST* flatten_def(CEnv& cenv, Code& code, const ATuple* def) throw() { const ASymbol* const sym = def->list_ref(1)->as_symbol(); const AST* const body = def->list_ref(2); if (!is_form(body, "fn")) { code.push_back(def); return NULL; } const ATuple* fn = (*def->iter_at(2))->as_tuple(); const ATuple* prot = fn->frst()->as_tuple(); List pre(Cursor(), cenv.penv.sym("fn-start"), sym, 0); for (ATuple::const_iterator i = prot->begin(); i != prot->end(); ++i) pre.push_back(*i); code.push_back(pre); cenv.def(sym, body, cenv.type(body), NULL); // define stub first for recursion const AST* retVal = NULL; const AST* retT = NULL; for (ATuple::const_iterator i = fn->iter_at(2); i != fn->end(); ++i) { retVal = resp_flatten(cenv, code, *i); retT = cenv.type(*i); } cenv.setTypeSameAs(retVal, retT); List post(Cursor(), cenv.penv.sym("fn-end"), sym, retVal, 0); code.push_back(post); return NULL; } static const AST* flatten_def_type(CEnv& cenv, Code& code, const ATuple* def) throw() { const ASymbol* name = def->frst()->to_symbol(); if (name) { cenv.tenv.def(name, def->frrst()); } else { name = def->frst()->as_tuple()->fst()->as_symbol(); cenv.tenv.def(name, def->frrst()); } code.push_back(def); return NULL; } static const AST* flatten_do(CEnv& cenv, Code& code, const ATuple* ado) throw() { const AST* ret = NULL; for (ATuple::const_iterator i = ado->iter_at(1); i != ado->end(); ++i) { ret = resp_flatten(cenv, code, *i); if (ret) code.push_back(ret); } const ASymbol* sym = cenv.penv.gensym("doval"); List def(Cursor(), cenv.penv.sym("def"), sym, ret, NULL); code.push_back(def); cenv.setTypeSameAs(sym, ado); return sym; } static const AST* flatten_if(CEnv& cenv, Code& code, const ATuple* aif) throw() { const ASymbol* cond = NULL; if (aif->frst()->to_symbol()) { cond = aif->frst()->as_symbol(); } else { cond = cenv.penv.gensym("ifcond"); List def(Cursor(), cenv.penv.sym("def"), cond, resp_flatten(cenv, code, aif->frst()), 0); cenv.setTypeSameAs(cond, aif->frst()); code.push_back(def); } const ASymbol* if_lab = cenv.penv.gensym("if"); const ASymbol* result = cenv.penv.gensym("ifval"); List pre(Cursor(), cenv.penv.sym("if-start"), if_lab, cond, /*then_lab, else_lab,*/ NULL); code.push_back(pre); cenv.setTypeSameAs(pre, aif); const AST* athen = *aif->iter_at(2); const AST* aelse = *aif->iter_at(3); const AST* then_val = resp_flatten(cenv, code, athen); cenv.setTypeSameAs(then_val, athen); List then_goto(Cursor(), cenv.penv.sym("if-then"), if_lab, then_val, NULL); code.push_back(then_goto); const AST* else_val = resp_flatten(cenv, code, aelse); cenv.setTypeSameAs(else_val, aelse); List else_goto(Cursor(), cenv.penv.sym("if-else"), if_lab, else_val, NULL); code.push_back(else_goto); List end(Cursor(), cenv.penv.sym("if-end"), if_lab, NULL); List def(Cursor(), cenv.penv.sym("def"), result, end.head, NULL); code.push_back(def); cenv.setTypeSameAs(end, aif); cenv.setTypeSameAs(result, aif); return result; } static const AST* flatten_call(CEnv& cenv, Code& code, const ATuple* call) throw() { List copy; for (ATuple::const_iterator i = call->begin(); i != call->end(); ++i) { const AST* flat_i = resp_flatten(cenv, code, *i); const AST* arg = NULL; if (!flat_i->to_tuple()) { arg = flat_i; } else { const ASymbol* sym = cenv.penv.gensym(); List def(Cursor(), cenv.penv.sym("def"), sym, flat_i, NULL); code.push_back(def); arg = sym; cenv.setTypeSameAs(sym, *i); } cenv.setTypeSameAs(flat_i, *i); copy.push_back(arg); } const ASymbol* sym = cenv.penv.gensym(); List def(Cursor(), cenv.penv.sym("def"), sym, copy.head, NULL); code.push_back(def); cenv.setTypeSameAs(copy, call); cenv.setTypeSameAs(sym, call); return sym; } const AST* resp_flatten(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 != "fn"); if (form == "cast" || form == "quote") return ast; else if (form == "def") return flatten_def(cenv, code, call); else if (form == "def-type") return flatten_def_type(cenv, code, call); else if (form == "do") return flatten_do(cenv, code, call); else if (form == "if") return flatten_if(cenv, code, call); else return flatten_call(cenv, code, call); } default: return ast; } cenv.err << "Attempt to compile unknown type: " << ast << endl; assert(false); return NULL; }