diff options
author | David Robillard <d@drobilla.net> | 2011-05-14 05:35:11 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2011-05-14 05:35:11 +0000 |
commit | 82eeba6aca368aa04a6650b6ee7cefe4b28804b8 (patch) | |
tree | 2f2c8c7ad5e2717e3563e41c2a7612926e9304d9 /src/flatten.cpp | |
parent | 8dac0b237cd376ab9bd3bfe14ee0f4b24ea1834f (diff) | |
download | resp-82eeba6aca368aa04a6650b6ee7cefe4b28804b8.tar.gz resp-82eeba6aca368aa04a6650b6ee7cefe4b28804b8.tar.bz2 resp-82eeba6aca368aa04a6650b6ee7cefe4b28804b8.zip |
Add flatten stage to generate flat s-expression IR for the (now simpler) compilation stage.
git-svn-id: http://svn.drobilla.net/resp/trunk@417 ad02d1e2-f140-0410-9f75-f8b11f17cedd
Diffstat (limited to 'src/flatten.cpp')
-rw-r--r-- | src/flatten.cpp | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/src/flatten.cpp b/src/flatten.cpp new file mode 100644 index 0000000..59748f3 --- /dev/null +++ b/src/flatten.cpp @@ -0,0 +1,196 @@ +/* Resp: A programming language + * Copyright (C) 2008-2011 David Robillard <http://drobilla.net> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** @file + * @brief Flatten code (raise all nested expressions) + */ + +#include <string> +#include <vector> + +#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, 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, 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; +} |