/* 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 #include #include "resp.hpp" using namespace std; static CVal compile_symbol(CEnv& cenv, const ASymbol* sym) throw() { if (*sym == *cenv.penv.sym("__unreachable")) return NULL; if (cenv.repl && cenv.vals.topLevel(sym) && !is_form(cenv.type(sym), "Fn")) { CVal val = cenv.globals[sym->sym()]; return cenv.engine()->compileGlobalGet(cenv, sym->sym(), val); } else { return *cenv.vals.ref(sym); } } static CVal compile_literal_symbol(CEnv& cenv, const ASymbol* sym) throw() { CEnv::CSyms::iterator i = cenv.cSyms.find(sym->sym()); if (i != cenv.cSyms.end()) { return i->second; } else { CVal compiled = cenv.engine()->compileString(cenv, sym->sym()); cenv.cSyms.insert(make_pair(sym->sym(), compiled)); return compiled; } } static CVal compile_cons(CEnv& cenv, const ATuple* cons) throw() { const ASymbol* tname = cons->fst()->as_symbol(); ATuple* type = new ATuple(tname, NULL, Cursor()); List tlist(type); vector fields; for (ATuple::const_iterator i = cons->iter_at(1); i != cons->end(); ++i) { tlist.push_back(cenv.type(*i)); fields.push_back(resp_compile(cenv, *i)); } return cenv.engine()->compileCons( cenv, type, compile_literal_symbol(cenv, tname), fields); } static CVal compile_dot(CEnv& cenv, const ATuple* dot) throw() { ATuple::const_iterator i = dot->begin(); const AST* tup = *++i; const ALiteral* index = (ALiteral*)(*++i); assert(index->tag() == T_INT32); CVal tupVal = resp_compile(cenv, tup); assert((unsigned)index->val < cenv.type(dot->frst())->as_tuple()->list_len()); return cenv.engine()->compileDot(cenv, tupVal, index->val); } static CVal compile_def(CEnv& cenv, const ATuple* def) throw() { const ASymbol* const sym = def->list_ref(1)->as_symbol(); const AST* const body = def->list_ref(2); CVal val = resp_compile(cenv, body); if (cenv.repl && cenv.vals.topLevel(sym) && !is_form(cenv.type(sym), "Fn")) { CVal global = cenv.engine()->compileGlobalSet( cenv, sym->sym(), val, cenv.type(body)); cenv.globals.insert(make_pair(sym->sym(), global)); cenv.def(sym, body, cenv.type(body), global); } else { cenv.def(sym, body, cenv.type(body), val); } return NULL; } static CVal compile_def_type(CEnv& cenv, const ATuple* def) throw() { const ASymbol* name = def->frst()->to_symbol(); if (name) { cenv.engine()->compileType(cenv, name->sym(), def->frrst()); cenv.tenv.def(name, def->frrst()); } else { name = def->frst()->as_tuple()->fst()->as_symbol(); cenv.engine()->compileType(cenv, name->sym(), def->frst()); for (ATuple::const_iterator i = def->iter_at(2); i != def->end(); ++i) { const ATuple* exp = (*i)->as_tuple(); const ASymbol* tag = (*exp->begin())->as_symbol(); cenv.engine()->compileType(cenv, tag->sym(), exp); } } return NULL; } static CVal compile_quote(CEnv& cenv, const ATuple* quote) throw() { switch (quote->list_ref(1)->tag()) { case T_SYMBOL: return compile_literal_symbol(cenv, quote->list_ref(1)->as_symbol()); default: assert(false); return NULL; } } static CVal compile_call(CEnv& cenv, const ATuple* call) throw() { const ATuple* protT = cenv.type(call->fst())->as_tuple()->prot(); CFunc f = resp_compile(cenv, call->fst()); vector args; ATuple::const_iterator p = protT->iter_at(0); for (ATuple::const_iterator a = call->iter_at(1); a != call->end(); ++a, ++p) { CVal arg = resp_compile(cenv, *a); if (cenv.type(*a) != cenv.resolveType(*p)) { args.push_back(cenv.engine()->compileCast(cenv, arg, *p)); } else { args.push_back(arg); } } return cenv.engine()->compileCall(cenv, f, cenv.type(call->fst())->as_tuple(), args); } static CVal compile_fn_start(CEnv& cenv, const ATuple* call) throw() { const ASymbol* name = call->list_ref(1)->as_symbol(); const ATuple* type = cenv.type(name)->as_tuple(); const ATuple* args = call->rst()->rst(); cenv.engine()->startFn(cenv, name->sym(), args, type); return NULL; } static CVal compile_fn_end(CEnv& cenv, const ATuple* call) throw() { const AST* ret = (call->list_len() > 2) ? call->frrst() : NULL; const AST* retT = (ret) ? cenv.type(call->frst())->as_tuple()->frrst() : cenv.penv.sym("Nothing"); cenv.engine()->finishFn(cenv, resp_compile(cenv, ret), retT); cenv.pop(); return NULL; } CVal resp_compile(CEnv& cenv, const AST* ast) throw() { if (!ast) return NULL; switch (ast->tag()) { case T_UNKNOWN: return NULL; case T_BOOL: case T_FLOAT: case T_INT32: case T_TVAR: return cenv.engine()->compileLiteral(cenv, ast); case T_STRING: return cenv.engine()->compileString(cenv, ((AString*)ast)->cppstr.c_str()); case T_SYMBOL: return compile_symbol(cenv, ast->as_symbol()); case T_LITSYM: return compile_literal_symbol(cenv, (ASymbol*)ast); 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() : ""; if (is_primitive(cenv.penv, call)) return cenv.engine()->compilePrimitive(cenv, ast->as_tuple()); else if (form == "cons" || isupper(form[0])) return compile_cons(cenv, call); else if (form == ".") return compile_dot(cenv, call); else if (form == "def") return compile_def(cenv, call); else if (form == "def-type") return compile_def_type(cenv, call); else if (form == "quote") return compile_quote(cenv, call); else if (form == "fn-start") return compile_fn_start(cenv, call); else if (form == "fn-end") return compile_fn_end(cenv, call); else if (form == "if-start") return cenv.engine()->compileIfStart(cenv, call->frrst(), cenv.type(call)); else if (form == "if-then") return cenv.engine()->compileIfThen(cenv, resp_compile(cenv, call->frrst())); else if (form == "if-else") return cenv.engine()->compileIfElse(cenv, resp_compile(cenv, call->frrst())); else if (form == "if-end") return cenv.engine()->compileIfEnd(cenv); else return compile_call(cenv, call); } } cenv.err << "Attempt to compile unknown type: " << ast << endl; assert(false); return NULL; }