/***** * genv.cc * Andy Hammerlindl 2002/08/29 * * This is the global environment for the translation of programs. In * actuality, it is basically a module manager. When a module is * requested, it looks for the corresponding filename, and if found, * parses and translates the file, returning the resultant module. * * genv sets up the basic type bindings and function bindings for * builtin functions, casts and operators, and imports plain (if set), * but all other initialization is done by the local environment defined * in env.h. *****/ /* Implementation of templated modules: * * Translating an access declaration: * * access Map(Key=A, Value=B) as MapAB; * * run encodeLevel for both A and B * this should give the parent records for each struct * encode pushing the *number* of parents on the stack (i.e., push a * single int) * encode pushing the string "Map/1234567" on the stack * encode call to builtin loadTemplatedModule * also save into MapAB (varinit) * * build list of types (or tyEntry?) * * also ensure names match * * ***** * * At runtime, loadTemplatedModule pops the string * * if the module is already loaded, it pops the levels * and returns the already loaded module. * * if the module is not loaded, it leaves the levels on the stack * and calls the initializer for the templated module * * it might be easiest to give the number of pushed params as an argument * to loadTemplatedModule (ints and strings have no push/pop) * * ***** * * Translating a templated module * * we start translating a file with a list of (name, type) pairs * * for each record type, * build variables for each parent level * and encode bytecode to pop the parents off the stack into these vars * * build tyEntry for each templated type * if its a record, then use the above variables as ent->v * * from here, * translate the file as a module as usual * * */ #include #include #include "genv.h" #include "env.h" #include "dec.h" #include "stm.h" #include "types.h" #include "settings.h" #include "runtime.h" #include "asyparser.h" #include "locate.h" #include "interact.h" #include "builtin.h" #if !defined(_WIN32) #include #endif using namespace types; using settings::getSetting; using settings::Setting; namespace trans { genv::genv() : imap() { // Add settings as a module. This is so that the init file ~/.asy/config.asy // can set settings. imap[symbol::literalTrans("settings")]=settings::getSettingsModule(); // Translate plain in advance, if we're using autoplain. if(getSetting("autoplain")) { Setting("autoplain")=false; // Translate plain without autoplain. getModule(symbol::trans("plain"), "plain"); Setting("autoplain")=true; } #ifdef HAVE_LIBGSL imap[symbol::literalTrans("gsl")]=trans::getGSLModule(); #endif } bool endswith(string suffix, string str) { return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()); } record *genv::loadModule(symbol id, string filename) { // Get the abstract syntax tree. absyntax::file *ast = parser::parseFile(filename,"Loading"); inTranslation.push_front(filename); em.sync(); record *r=ast->transAsFile(*this, id); inTranslation.remove(filename); return r; } record *genv::loadTemplatedModule( symbol id, string filename, mem::vector *args ) { // Get the abstract syntax tree. absyntax::file *ast = parser::parseFile(filename,"Loading"); inTranslation.push_front(filename); em.sync(); record *r=ast->transAsTemplatedFile(*this, id, args); inTranslation.remove(filename); return r; } void genv::checkRecursion(string filename) { if (find(inTranslation.begin(), inTranslation.end(), filename) != inTranslation.end()) { em.sync(); em << "error: recursive loading of module '" << filename << "'\n"; em.sync(true); throw handled_error(); } } record *genv::getModule(symbol id, string filename) { checkRecursion(filename); symbol index=symbol::literalTrans(filename); record *r=imap[index]; if (r) return r; else { r=loadModule(id, filename); // Don't add an erroneous module to the dictionary in interactive mode, as // the user may try to load it again. if (!interact::interactive || !em.errors()) { imap[index]=r; } return r; } } record *genv::getTemplatedModule( string filename, mem::vector* args ) { checkRecursion(filename); types::signature* sig = new types::signature(); stringstream buf; buf << filename << "/"; for (auto arg : *args) { sig->add(formal(arg->t, arg->dest)); buf << arg->dest << "/"; } buf << sig->handle() << "/"; symbol index=symbol::literalTrans(buf.str()); record *r=imap[index]; if (r) return r; else { r=loadTemplatedModule(index, filename, args); // Don't add an erroneous module to the dictionary in interactive mode, as // the user may try to load it again. if (!interact::interactive || !em.errors()) { imap[index]=r; } return r; } } record *genv::getLoadedModule(symbol id) { return imap[id]; } typedef vm::stack::importInitMap importInitMap; importInitMap *genv::getInitMap() { struct initMap : public importInitMap, public gc { genv ≥ initMap(genv &ge) : ge(ge) {} lambda *operator[](string s) { record *r=ge.imap[symbol::literalTrans(s)]; return r ? r->getInit() : 0; } }; return new initMap(*this); } } // namespace trans