/* 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("__tag"); List def(match->loc, cenv.penv.sym("def"), tsym, tval.head, NULL); cenv.setType(tval.head, cenv.tenv.named("Symbol")); 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++; const ASymbol* consTag = cenv.penv.sym(pat->fst()->str(), pat->fst()->loc); const_cast(consTag)->tag(T_LITSYM); cenv.setType(consTag, cenv.tenv.named("Symbol")); List cond(Cursor(), cenv.penv.sym("="), tsym, consTag, 0); cenv.setType(cond, cenv.tenv.named("Bool")); copyIf.push_back(cond); copyIf.push_back(resp_simplify(cenv, body)); } copyIf.push_back(cenv.penv.sym("__unreachable")); cenv.setTypeSameAs(copyIf, match); List copy(match->loc, cenv.penv.sym("do"), def.head, simplify_if(cenv, copyIf), 0); 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; } static inline const AST* simplify_list_elem(CEnv& cenv, const ATuple* node, const AST* type) { if (!node) { const AST* empty = new ATuple(cenv.tenv.Empty, 0, Cursor()); cenv.setType(empty, type); return empty; } assert(cenv.type(node->fst())); const AST* const fst = tup(Cursor(), cenv.type(node->fst()), node->fst(), 0); const AST* const rst = simplify_list_elem(cenv, node->rst(), type); assert(node->fst()); assert(rst); List cons(node->loc, cenv.tenv.List, fst, rst, 0); cenv.setType(fst, tup(Cursor(), cenv.penv.sym("Expr"), 0)); cenv.setType(cons, type); return cons; } static const AST* simplify_quote(CEnv& cenv, const ATuple* call) throw() { switch (call->frst()->tag()) { case T_SYMBOL: // Symbols remain quoted so they are not interpreted as variables return call; case T_TUPLE: { // Lists are transformed into nested conses const ATuple* const list = call->frst()->as_tuple(); return simplify_list_elem(cenv, list, tup(Cursor(), cenv.tenv.List, cenv.penv.sym("Expr"), 0)); } default: // Other literals (e.g. numbers, strings) are self-evaluating, so the // quote can be removed, e.g. (quote 3) => 3 return call->frst(); } } 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->fst()->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 if (form == "quote") return simplify_quote(cenv, list); else return simplify_list(cenv, list); }