aboutsummaryrefslogtreecommitdiffstats
path: root/src/flatten.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-05-14 05:35:11 +0000
committerDavid Robillard <d@drobilla.net>2011-05-14 05:35:11 +0000
commit82eeba6aca368aa04a6650b6ee7cefe4b28804b8 (patch)
tree2f2c8c7ad5e2717e3563e41c2a7612926e9304d9 /src/flatten.cpp
parent8dac0b237cd376ab9bd3bfe14ee0f4b24ea1834f (diff)
downloadresp-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.cpp196
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;
+}