/* 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 Simplify (reduce to simpler forms, e.g. match => if) */ #include #include "resp.hpp" using namespace std; static const AST* simplify_if(CEnv& cenv, const ATuple* aif) throw() { List copy(aif->loc, cenv.penv.sym("if"), NULL); copy.push_back(aif->list_ref(1)); copy.push_back(aif->list_ref(2)); ATuple* tail = copy.tail; ATuple::const_iterator i = aif->iter_at(3); for (; ; ++i) { ATuple::const_iterator next = i; if (++next == aif->end()) break; List inner_if((*i)->loc, cenv.penv.sym("if"), *i, *next, NULL); tail->last(new ATuple(inner_if.head, NULL, Cursor())); tail = inner_if.tail; cenv.setTypeSameAs(inner_if, aif); i = next; // jump 2 elements (to the next predicate) } tail->last(new ATuple(*i, NULL, Cursor())); cenv.setTypeSameAs(copy, aif); return copy; } static const AST* simplify_match(CEnv& cenv, const ATuple* match) throw() { // Dot expression to get tag. Note index is -1 to compensate for the lift phase // which adds 1 to skip the RTTI, which we don't want here (FIXME: ick...) List tval; tval.push_back(cenv.penv.sym(".")); tval.push_back(resp_simplify(cenv, match->list_ref(1))); tval.push_back(new ALiteral(T_INT32, -1, Cursor())); const ASymbol* tsym = cenv.penv.gensym("_matchT"); List def(match->loc, cenv.penv.sym("def"), tsym, tval.head, NULL); List copyIf; copyIf.push_back(cenv.penv.sym("if")); for (ATuple::const_iterator i = match->iter_at(2); i != match->end();) { const ATuple* pat = (*i++)->as_tuple(); const AST* body = *i++; List cond; cond.push_back(cenv.penv.sym("__tag_is")); cond.push_back(tsym); cond.push_back(pat->head()); copyIf.push_back(cond); copyIf.push_back(resp_simplify(cenv, body)); } copyIf.push_back(cenv.penv.sym("__unreachable")); cenv.setTypeSameAs(copyIf, match); List copy; copy.push_back(cenv.penv.sym("do")); copy.push_back(def); copy.push_back(simplify_if(cenv, copyIf)); cenv.setTypeSameAs(copy, match); return copy; } static const AST* simplify_list(CEnv& cenv, const ATuple* call) throw() { List copy; for (ATuple::const_iterator i = call->begin(); i != call->end(); ++i) copy.push_back(resp_simplify(cenv, *i)); cenv.setTypeSameAs(copy.head, call); return copy; } static const AST* simplify_let(CEnv& cenv, const ATuple* call) throw() { const ATuple* vars = call->list_ref(1)->to_tuple(); List fn(Cursor(), cenv.penv.sym("fn"), NULL); List fnProt; List fnArgs; List fnProtT; for (ATuple::const_iterator i = vars->begin(); i != vars->end();) { const ASymbol* sym = (*i++)->to_symbol(); const AST* val = (*i++); fnProt.push_back(sym); fnArgs.push_back(resp_simplify(cenv, val)); fnProtT.push_back(cenv.type(val)); } fn.push_back(fnProt.head); fn.push_back(resp_simplify(cenv, call->list_ref(2))); List fnT; fnT.push_back(cenv.tenv.Fn); fnT.push_back(fnProtT); fnT.push_back(cenv.type(call->list_ref(2))); cenv.setType(fn, fnT); ATuple* copy = new ATuple(fn, fnArgs, call->loc); cenv.setTypeSameAs(copy, call); return copy; } const AST* resp_simplify(CEnv& cenv, const AST* ast) throw() { const ATuple* const list = ast->to_tuple(); if (!list) return ast; const ASymbol* const sym = list->head()->to_symbol(); const std::string form = sym ? sym->sym() : ""; if (form == "match") return simplify_match(cenv, list); else if (form == "if") return simplify_if(cenv, list); else if (form == "let") return simplify_let(cenv, list); else return simplify_list(cenv, list); }