/* 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 Expand built-in macros (i.e. def) */ #include "resp.hpp" using namespace std; static inline const ATuple* expand_list(PEnv& penv, const ATuple* e) { List ret; FOREACHP(ATuple::const_iterator, i, e) ret.push_back(penv.expand(*i)); ret.head->loc = e->loc; return ret.head; } static inline const AST* expand_fn(PEnv& penv, const AST* exp, void* arg) { const ATuple* tup = exp->to_tuple(); ATuple::const_iterator a = tup->begin(); THROW_IF(++a == tup->end(), exp->loc, "Unexpected end of `fn' form"); THROW_IF(!(*a)->to_tuple(), (*a)->loc, "First argument of `fn' is not a list"); const ATuple* prot = (*a++)->to_tuple(); List ret(new ATuple(penv.sym("fn"), NULL, exp->loc)); ret.push_back(prot); while (a != tup->end()) ret.push_back(penv.expand(*a++)); return ret.head; } static inline const AST* expand_def(PEnv& penv, const AST* exp, void* arg) { const ATuple* tup = exp->as_tuple(); THROW_IF(tup->list_len() < 3, tup->loc, "`def' requires at least 2 arguments"); ATuple::const_iterator i = tup->begin(); const AST* arg1 = *(++i); if (arg1->to_tuple()) { // (def (f x) y) => (def f (fn (x) y)) const ATuple* pat = arg1->to_tuple(); List argsExp; ATuple::const_iterator j = pat->begin(); for (++j; j != pat->end(); ++j) argsExp.push_back(*j); argsExp.head->loc = exp->loc; List fnExp; fnExp.push_back(penv.sym("fn")); fnExp.push_back(argsExp.head); for (++i; i != tup->end(); ++i) fnExp.push_back(*i); fnExp.head->loc = exp->loc; List ret; ret.push_back(tup->fst()); ret.push_back(pat->fst()); ret.push_back(fnExp.head); ret.head->loc = exp->loc; return expand_list(penv, ret.head); } else { return expand_list(penv, tup); } } const AST* PEnv::expand(const AST* exp) { const ATuple* tup = exp->to_tuple(); if (!tup) return exp; THROW_IF(tup->empty(), exp->loc, "Call to empty list"); if (is_form(tup, "def")) return expand_def(*this, exp, NULL); else if (is_form(tup, "fn")) return expand_fn(*this, exp, NULL); else return expand_list(*this, tup); } /*************************************************************************** * Language Definition * ***************************************************************************/ void initLang(PEnv& penv, TEnv& tenv) { // Types const char* types[] = { "Bool", "Float", "Int", "Nothing", "String", "Symbol", "List", "Expr", 0 }; for (const char** t = types; *t; ++t) { const ASymbol* sym = penv.sym(*t); tenv.def(sym, sym); // FIXME: define to NULL? } const char* primitives[] = { "+", "-", "*", "/", "%", "and", "or", "xor", "=", "!=", ">", ">=", "<", "<=", 0 }; for (const char** p = primitives; *p; ++p) penv.primitives.insert(*p); }