/* 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 REPL and eval */ #include #include #include #include #include #include "resp.hpp" using namespace std; static inline const AST* dump(CEnv& cenv, const Code& code) { for (auto c : code) pprint(cout, c, &cenv, (cenv.args.find("-a") != cenv.args.end())); return 0; } static const AST* readExpand(PEnv& penv, Cursor& cursor, istream& is, const AST*& exp) { try { exp = penv.parse(cursor, is); } catch (Error e) { cerr << e.what() << endl; is.ignore(std::numeric_limits::max(), '\n'); // Skip REPL junk throw e; } if (!exp) { return NULL; } return penv.expand(exp); } static bool constrainUnify(CEnv& cenv, const AST* ast) { Constraints c(cenv.tsubst); resp_constrain(cenv.tenv, c, ast); // Constrain types cenv.tsubst = unify(c); //cout << "(TSUBST " << endl << cenv.tsubst << ")" << endl; Object::pool.addRoot(ast); // Make parsed expression a GC root so it is not deleted return true; } static void callPrintCollect(CEnv& cenv, CFunc f, const AST* result, const AST* resultT, bool execute) { Object::pool.collect(Object::pool.roots()); if (execute) cenv.out << cenv.engine()->call(cenv, f, resultT); // Print type (if applicable) const std::string type_str = resultT->str(); if (type_str != "Nothing") cenv.out << " : " << type_str << endl; Object::pool.collect(Object::pool.roots()); } const AST* compile(CEnv& cenv, const Code& parsed, Code& defs, bool& hasMain, const char* mainName) { // Convert to CPS (currently not used in the compilation process) if (cenv.args.find("-C") != cenv.args.end()) { Code cps; for (auto i : parsed) { const AST* exp = resp_cps(cenv, i, cenv.penv.sym("display")); if (exp) { cps.push_back(exp); } } return dump(cenv, cps); } struct Pass { const RespPass* pass; ///< Pass function const char* option; ///< Command line option to stop and dump here }; const Pass passes[] = { { resp_simplify, "-R" }, { resp_lift, "-L" }, //{ resp_depoly, "-D" }, { NULL, NULL } }; // List of stages of code after each pass std::list stages; stages.push_back(parsed); // Apply each pass in turn and append to stages for (const Pass* p = passes; p->pass; ++p) { const Code& input = stages.back(); Code output; for (auto i : input) { const AST* exp = (*p->pass)(cenv, output, i); if (exp) { output.push_back(exp); } } stages.push_back(output); if (cenv.args.find(p->option) != cenv.args.end()) { return dump(cenv, output); } } // Flatten expressions const AST* retT = NULL; Code exprs; for (auto i : stages.back()) { const ATuple* call = i->to_tuple(); if (call && (is_form(i, "def-type") || (is_form(i, "define") && is_form(call->frrst(), "lambda")))) { resp_flatten(cenv, defs, call); } else if (call && is_form(i, "prot")) { defs.push_back(i); } else { const ATuple* tup = i->to_tuple(); if (!tup || !tup->empty()) { exprs.push_back(i); retT = cenv.type(i); } } } // Flatten top-level code into main function if (!exprs.empty()) { const ASymbol* main = cenv.penv.sym(mainName); List mainT(Cursor(), cenv.penv.sym("lambda"), new ATuple(Cursor()), retT, NULL); cenv.def(main, NULL, mainT, NULL); defs.push_back( tup(Cursor(), cenv.penv.sym("fn-start"), main, NULL)); const AST* mainRet = NULL; for (auto e : exprs) mainRet = resp_flatten(cenv, defs, e); defs.push_back( tup(Cursor(), cenv.penv.sym("fn-end"), main, mainRet, NULL)); } hasMain = !exprs.empty(); return retT; } /// Compile and evaluate code from @a is int eval(CEnv& cenv, Cursor& cursor, istream& is, bool execute) { const AST* exp = NULL; const AST* ast = NULL; try { // Read and expand all expressions Code expanded; while (!is.eof()) { if ((ast = readExpand(cenv.penv, cursor, is, exp))) expanded.push_back(ast); } if (cenv.args.find("-E") != cenv.args.end()) { dump(cenv, expanded); return 0; } // Type constrain and unify expanded code for (auto e : expanded) constrainUnify(cenv, e); if (cenv.args.find("-T") != cenv.args.end()) { dump(cenv, expanded); return 0; } Code defs; bool hasMain = false; const AST* retT = compile(cenv, expanded, defs, hasMain, "main"); if (cenv.args.find("-F") != cenv.args.end()) { dump(cenv, defs); return 0; } // Compile flattened code for (auto d : defs) { resp_compile(cenv, d); Object::pool.addRoot(d); } if (cenv.args.find("-S") != cenv.args.end()) { cenv.engine()->writeModule(cenv, cenv.out); return 0; } // Call main and print result if (hasMain) callPrintCollect(cenv, cenv.engine()->getFn(cenv, "main"), ast, retT, execute); } catch (Error& e) { cenv.err << e.what() << endl; return 1; } return 0; } /// Read Eval Print Loop int repl(CEnv& cenv) { cenv.repl = true; const AST* exp = NULL; const AST* ast = NULL; while (1) { cenv.out << "() "; cenv.out.flush(); Cursor cursor("(stdin)", 1, 1); try { // Read and expand expression Code expanded; if ((ast = readExpand(cenv.penv, cursor, std::cin, exp))) expanded.push_back(ast); else break; if (cenv.args.find("-E") != cenv.args.end()) { dump(cenv, expanded); return 0; } // Type constrain and unify expanded code for (auto e : expanded) constrainUnify(cenv, e); if (cenv.args.find("-T") != cenv.args.end()) { dump(cenv, expanded); return 0; } Code defs; bool hasMain; const std::string replName = cenv.penv.gensymstr("_repl"); const AST* retT = compile(cenv, expanded, defs, hasMain, replName.c_str()); if (cenv.args.find("-F") != cenv.args.end()) { dump(cenv, defs); continue; } // Compile flattened code for (auto d : defs) { resp_compile(cenv, d); } if (cenv.args.find("-S") != cenv.args.end()) { cenv.engine()->writeModule(cenv, cenv.out); continue; } // Call main and print result if (hasMain) { callPrintCollect(cenv, cenv.engine()->getFn(cenv, replName), ast, retT, true); } } catch (Error& e) { cenv.err << e.what() << endl; } } return 0; }