/*****
* 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
*
*
*/
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<bool>("autoplain")) {
Setting("autoplain")=false;
// Translate plain without autoplain.
getModule(symbol::trans("plain"), "plain");
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<absyntax::namedTy*> *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<absyntax::namedTy*>* 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;
}
};