/* 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 Main program */ #include #include #include #include #include #include #include #include "resp.hpp" using namespace std; GC Object::pool(8 * 1024 * 1024); bool is_form(const AST* ast, const std::string& form) { const ATuple* call = ast->to_tuple(); if (!call || call->empty()) return false; const ASymbol* const sym = call->fst()->to_symbol(); if (!sym) return false; return form == sym->sym(); } bool is_primitive(const PEnv& penv, const AST* ast) { const ATuple* call = ast->to_tuple(); if (!call) return false; const ASymbol* const sym = call->fst()->to_symbol(); if (!sym) return false; return penv.primitives.find(sym->sym()) != penv.primitives.end(); } static int print_usage(char* name, bool error) { ostream& os = error ? cerr : cout; os << "Usage: " << name << " [OPTION]... [FILE]..." << endl; os << "Evaluate and/or compile Resp code" << endl; os << endl; os << " -a Annotate output with types" << endl; os << " -b BACKEND Use backend (llvm or c)" << endl; os << " -e EXPRESSION Evaluate EXPRESSION" << endl; os << " -g Debug (disable optimisation)" << endl; os << " -h Display this help and exit" << endl; os << " -o FILE Compile output to FILE (don't run)" << endl; os << " -r Enter REPL after evaluating files" << endl; os << " -P Parse only" << endl; os << " -E Expand macros only" << endl; os << " -T Type check only" << endl; os << " -R Reduce to simpler forms only" << endl; os << " -C Convert to CPS only" << endl; os << " -L Lambda lift only" << endl; os << " -D Depoly only" << endl; os << " -F Flatten only" << endl; os << " -S Compile to assembly only (do not execute)" << endl; return error ? 1 : 0; } int main(int argc, char** argv) { // Read command line arguments map args; typedef list Files; Files files; for (int i = 1; i < argc; ++i) { if (!strncmp(argv[i], "-h", 3)) { return print_usage(argv[0], false); } else if (argv[i][0] != '-') { files.push_back(argv[i]); } else if (!strncmp(argv[i], "-C", 3) || !strncmp(argv[i], "-F", 3) || !strncmp(argv[i], "-L", 3) || !strncmp(argv[i], "-D", 3) || !strncmp(argv[i], "-P", 3) || !strncmp(argv[i], "-R", 3) || !strncmp(argv[i], "-S", 3) || !strncmp(argv[i], "-T", 3) || !strncmp(argv[i], "-E", 3) || !strncmp(argv[i], "-a", 3) || !strncmp(argv[i], "-g", 3) || !strncmp(argv[i], "-r", 3)) { args.insert(make_pair(argv[i], "")); } else if (i == argc-1 || argv[i+1][0] == '-') { return print_usage(argv[0], true); } else { args.insert(make_pair(argv[i], argv[i+1])); ++i; } } PEnv penv; TEnv tenv(penv); initLang(penv, tenv); Engine* engine = NULL; map::const_iterator a = args.find("-b"); const string backend_name = (a != args.end() ? a->second : "llvm"); if (backend_name == "llvm") engine = resp_new_llvm_engine(); //else if (backend_name == "c") // engine = resp_new_c_engine(); if (!engine) { std::cerr << "Unable to open backend " << backend_name << std::endl; return 1; } CEnv* cenv = new CEnv(penv, tenv, engine); cenv->args = args; Object::pool.lock(); int ret = 0; a = args.find("-o"); const bool batch = (a != args.end()); string output = batch ? a->second : ""; if (args.find("-P") != args.end()) { // Pretty-print input ofstream fs; if (output != "") fs.open(output.c_str()); ostream& os = (output == "") ? std::cout : fs; for (auto f : files) { ifstream is(f); try { while (is.good() && !is.eof()) { Cursor loc(f, 1, 1); const AST* exp = cenv->penv.parse(loc, is); if (!exp || (exp->to_tuple() && exp->to_tuple()->empty())) break; const AST* ast = penv.expand(exp); pprint(os, ast, cenv, false); is.ignore(std::numeric_limits::max(), '\n'); // Skip newlines } } catch (Error e) { cerr << e.what() << endl; } is.close(); } ret = 0; } else if (args.find("-e") != args.end()) { // Evaluate argument as expression if (files.size() > 0) { std::cerr << "Illegal options: both -e and files given" << std::endl; delete cenv; delete engine; return print_usage(argv[0], true); } std::istringstream is(a->second); Cursor cursor("(command line)"); ret = eval(*cenv, cursor, is, !batch); } else if (files.size() == 0) { // Neither -e nor files given, run repl ret = repl(*cenv); } else { // Evalute (or just type check if -T, or just compile if -S all files for (std::string filename : files) { if (!batch) output = filename + ".out"; ifstream is(filename); if (is.good()) { Cursor cursor(filename, 1, 1); ret = ret | eval(*cenv, cursor, is, !batch); } else { cerr << argv[0] << ": " << filename << ": " << strerror(errno) << endl; ++ret; } is.close(); } } if (args.find("-r") != args.end()) // Run REPL after evaluations ret = repl(*cenv); delete cenv; delete engine; return ret; }