/* 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 Parsing (build a code AST from a textual AST) */ #include "resp.hpp" using namespace std; ATuple* parseTuple(PEnv& penv, const ATuple* e) { ATuple* ret = new ATuple(e->loc); FOREACHP(ATuple::const_iterator, i, e) ret->push_back(penv.parse(*i)); return ret; } AST* PEnv::parse(const AST* exp) { const ATuple* tup = exp->to(); if (tup) { THROW_IF(tup->empty(), exp->loc, "Call to empty list"); const ALexeme* form = tup->head()->to(); if (form) { MF mf = mac(*form); if (mf) { exp = mf(*this, exp)->as(); // Apply macro tup = exp->to(); } } } if (tup) { THROW_IF(tup->empty(), exp->loc, "Call to empty list"); const ALexeme* form = tup->head()->to(); if (form) { const PEnv::Handler* h = handler(true, *form); if (h) return h->func(*this, exp, h->arg); // Parse special form if (isupper(form->c_str()[0])) // Call constructor (any uppercase symbol) return new ACons(parseTuple(*this, tup)); } return new ACall(parseTuple(*this, tup)); // Parse regular call } const ALexeme* lex = exp->to(); assert(lex); if (isdigit((*lex)[0])) { const std::string& s = *lex; if (s.find('.') == string::npos) return new ALiteral(strtol(s.c_str(), NULL, 10), exp->loc); else return new ALiteral(strtod(s.c_str(), NULL), exp->loc); } else if ((*lex)[0] == '\"') { return new AString(exp->loc, lex->substr(1, lex->length() - 2)); } else { const PEnv::Handler* h = handler(false, *lex); if (h) return h->func(*this, exp, h->arg); } return sym(*lex, exp->loc); } /*************************************************************************** * Macro Functions * ***************************************************************************/ inline AST* macDef(PEnv& penv, const AST* exp) { const ATuple* tup = exp->to(); ATuple::const_iterator i = tup->begin(); THROW_IF(i == tup->end(), tup->loc, "Unexpected end of `def' macro call"); const AST* name = *(++i); THROW_IF(i == tup->end(), name->loc, "Unexpected end of `def' macro call"); if (name->to()) { return const_cast(exp); } else { const ATuple* pat = name->to(); name = pat->head(); // (def (f x) y) => (def f (fn (x) y)) ATuple* argsExp = new ATuple(exp->loc); ATuple::const_iterator j = pat->begin(); for (++j; j != pat->end(); ++j) argsExp->push_back(*j); const AST* body = *(++i); ATuple* fnExp = new ATuple(body->loc); fnExp->push_back(new ALexeme(exp->loc, "fn")); fnExp->push_back(argsExp); for (; i != tup->end(); ++i) fnExp->push_back(*i); ATuple* ret = new ATuple(exp->loc); ret->push_back(const_cast(tup->head())); ret->push_back(const_cast(name)); ret->push_back(fnExp); return ret; } } /*************************************************************************** * Parser Functions * ***************************************************************************/ template inline AST* parseCall(PEnv& penv, const AST* exp, void* arg) { return new C(parseTuple(penv, exp->to())); } template inline AST* parseLiteral(PEnv& penv, const AST* exp, void* arg) { return new ALiteral(*reinterpret_cast(arg), exp->loc); } inline AST* parseFn(PEnv& penv, const AST* exp, void* arg) { const ATuple* texp = exp->to(); ATuple::const_iterator a = texp->begin(); THROW_IF(++a == texp->end(), exp->loc, "Unexpected end of `fn' form"); ATuple* prot = parseTuple(penv, (*a++)->to()); AFn* ret = tup(exp->loc, penv.sym("fn"), prot, 0); while (a != texp->end()) ret->push_back(penv.parse(*a++)); return ret; } inline AST* parseQuote(PEnv& penv, const AST* exp, void* arg) { const ATuple* texp = exp->to(); THROW_IF(texp->size() != 2, exp->loc, "`quote' requires exactly 1 argument"); const AST* quotee = (*(texp->begin() + 1))->to(); THROW_IF(!quotee, exp->loc, "`quote' argument is not a lexeme"); return new AQuote(texp); } /*************************************************************************** * Language Definition * ***************************************************************************/ /// Set up language void initLang(PEnv& penv, TEnv& tenv) { // Types tenv.def(penv.sym("Nothing"), new AType(penv.sym("Nothing"), AType::PRIM)); tenv.def(penv.sym("Bool"), new AType(penv.sym("Bool"), AType::PRIM)); tenv.def(penv.sym("Int"), new AType(penv.sym("Int"), AType::PRIM)); tenv.def(penv.sym("Float"), new AType(penv.sym("Float"), AType::PRIM)); tenv.def(penv.sym("String"), new AType(penv.sym("String"), AType::PRIM)); tenv.def(penv.sym("Lexeme"), new AType(penv.sym("Lexeme"), AType::PRIM)); tenv.def(penv.sym("Quote"), new AType(penv.sym("Quote"), AType::PRIM)); // Literals static bool trueVal = true; static bool falseVal = false; penv.reg(false, "#t", PEnv::Handler(parseLiteral, &trueVal)); penv.reg(false, "#f", PEnv::Handler(parseLiteral, &falseVal)); // Macros penv.defmac("def", macDef); // Special forms penv.reg(true, "fn", PEnv::Handler(parseFn)); penv.reg(true, "quote", PEnv::Handler(parseQuote)); penv.reg(true, "if", PEnv::Handler(parseCall)); penv.reg(true, ".", PEnv::Handler(parseCall)); penv.reg(true, "def", PEnv::Handler(parseCall)); penv.reg(true, "def-type", PEnv::Handler(parseCall)); penv.reg(true, "match", PEnv::Handler(parseCall)); // Numeric primitives penv.reg(true, "+", PEnv::Handler(parseCall)); penv.reg(true, "-", PEnv::Handler(parseCall)); penv.reg(true, "*", PEnv::Handler(parseCall)); penv.reg(true, "/", PEnv::Handler(parseCall)); penv.reg(true, "%", PEnv::Handler(parseCall)); penv.reg(true, "and", PEnv::Handler(parseCall)); penv.reg(true, "or", PEnv::Handler(parseCall)); penv.reg(true, "xor", PEnv::Handler(parseCall)); penv.reg(true, "=", PEnv::Handler(parseCall)); penv.reg(true, "!=", PEnv::Handler(parseCall)); penv.reg(true, ">", PEnv::Handler(parseCall)); penv.reg(true, ">=", PEnv::Handler(parseCall)); penv.reg(true, "<", PEnv::Handler(parseCall)); penv.reg(true, "<=", PEnv::Handler(parseCall)); }