/* 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 Compile all code (compilation pass 2) */ #include "resp.hpp" using namespace std; static CVal compile_symbol(CEnv& cenv, const ASymbol* sym) throw() { if (cenv.vals.topLevel(sym) && cenv.type(sym)->head()->str() != "Fn") { return cenv.engine()->getGlobal(cenv, sym->cppstr, *cenv.vals.ref(sym)); } else { return *cenv.vals.ref(sym); } } static CVal compile_fn(CEnv& cenv, const AFn* fn) throw() { const AType* type = cenv.type(fn); CFunc f = cenv.findImpl(fn, type); if (f) return f; // Write function declaration f = cenv.engine()->startFunction(cenv, fn->name, fn->prot(), type); // Create a new environment frame and bind argument values cenv.engine()->pushFunctionArgs(cenv, fn, type, f); assert(!cenv.currentFn); cenv.currentFn = f; // Write function body CVal retVal = NULL; for (AFn::const_iterator i = fn->iter_at(2); i != fn->end(); ++i) retVal = resp_compile(cenv, *i); // Write function conclusion cenv.engine()->finishFunction(cenv, f, retVal); // Pop environment frame cenv.pop(); cenv.currentFn = NULL; cenv.vals.def(cenv.penv.sym(fn->name), f); cenv.addImpl(fn, f); return f; } static CVal compile_type(CEnv& cenv, const AType* type) throw() { const ASymbol* sym = type->head()->as(); CVal* existing = cenv.vals.ref(sym); if (existing) { return *existing; } else { CVal compiled = cenv.engine()->compileString( cenv, (string("__T_") + type->head()->str()).c_str()); cenv.vals.def(sym, compiled); return compiled; } } static CVal compile_call(CEnv& cenv, const ACall* call) throw() { CFunc f = resp_compile(cenv, *call->begin()); if (!f) f = cenv.currentFn; // Recursive call (callee defined as a stub) vector args; for (ACall::const_iterator e = call->iter_at(1); e != call->end(); ++e) args.push_back(resp_compile(cenv, *e)); return cenv.engine()->compileCall(cenv, f, cenv.type(call->head()), args); } static CVal compile_def(CEnv& cenv, const ACall* def) throw() { const ASymbol* const sym = def->list_ref(1)->as(); const AST* const body = def->list_ref(2); cenv.def(sym, body, cenv.type(body), NULL); // define stub first for recursion CVal val = resp_compile(cenv, body); if (cenv.vals.size() == 1 && cenv.type(body)->head()->str() != "Fn") { val = cenv.engine()->compileGlobal( cenv, cenv.type(body), sym->str(), val); cenv.lock(def); } cenv.vals.def(sym, val); return NULL; } static CVal compile_cons(CEnv& cenv, const ACall* cons) throw() { AType* type = new AType(const_cast(cons->head()->as()), NULL, Cursor()); TList tlist(type); vector fields; for (ACons::const_iterator i = cons->iter_at(1); i != cons->end(); ++i) { tlist.push_back(const_cast(cenv.type(*i))); fields.push_back(resp_compile(cenv, *i)); } return cenv.engine()->compileTup(cenv, type, resp_compile(cenv, type), fields); } static CVal compile_dot(CEnv& cenv, const ACall* dot) throw() { ATuple::const_iterator i = dot->begin(); const AST* tup = *++i; const ALiteral* index = (*++i)->as*>(); CVal tupVal = resp_compile(cenv, tup); return cenv.engine()->compileDot(cenv, tupVal, index->val); } CVal resp_compile(CEnv& cenv, const AST* ast) throw() { if (ast->to*>() || ast->to*>() || ast->to*>()) return cenv.engine()->compileLiteral(cenv, ast); const AString* str = ast->to(); if (str) return cenv.engine()->compileString(cenv, str->c_str()); const ALexeme* lexeme = ast->to(); if (lexeme) return cenv.engine()->compileString(cenv, lexeme->c_str()); const ASymbol* sym = ast->to(); if (sym) return compile_symbol(cenv, sym); const AFn* fn = ast->to(); if (fn) return compile_fn(cenv, fn); const APrimitive* prim = ast->to(); if (prim) return cenv.engine()->compilePrimitive(cenv, prim); const AType* type = ast->to(); if (type) return compile_type(cenv, type); const ACall* const call = ast->to(); if (call) { const ASymbol* const sym = call->head()->to(); const std::string form = sym ? sym->cppstr : ""; if (form == "def") return compile_def(cenv, call); else if (form == "if") return cenv.engine()->compileIf(cenv, call); else if (form == "cons" || isupper(form[0])) return compile_cons(cenv, call); else if (form == ".") return compile_dot(cenv, call); else if (form == "quote") return resp_compile(cenv, call->list_ref(1)); else if (form == "match") return cenv.engine()->compileMatch(cenv, call); else if (form == "def-type") return NULL; else return compile_call(cenv, call); } cenv.err << "Attempt to compile unknown type" << endl; assert(false); return NULL; }