/*****
* dec.h
* Andy Hammerlindl 2002/8/29
*
* Represents the abstract syntax tree for declarations in the language.
* Also included is abstract syntax for types as they are most often
* used with declarations.
*****/
namespace vm {
struct lambda;
}
namespace absyntax {
using trans::genv;
using trans::coenv;
using trans::protoenv;
using trans::varEntry;
using trans::access;
using sym::symbol;
class vardec;
enum class AutounravelOption {
Apply,
DoNotApply,
};
class astType : public absyn {
public:
astType(position pos)
: absyn(pos) {}
virtual void prettyprint(ostream &out, Int indent) = 0;
// If we introduced a new type, automatically add corresponding functions for
// that type.
virtual void
addOps(coenv&, record*, AutounravelOption opt= AutounravelOption::Apply)
{}
// Returns the internal representation of the type. This method can
// be called by exp::getType which does not report errors, so tacit is
// needed to silence errors in this case.
virtual types::ty *trans(coenv &e, bool tacit = false) = 0;
virtual trans::tyEntry *transAsTyEntry(coenv &e, record *where);
// Similar to varEntryExp, this helper class always translates to the same
// fixed type.
class tyEntryTy : public astType {
trans::tyEntry *ent;
public:
tyEntryTy(position pos, trans::tyEntry *ent)
: astType(pos), ent(ent) {}
tyEntryTy(position pos, types::ty *t);
void prettyprint(ostream &out, Int indent) override;
// Runnable is anything that can be executed by the program, including
// any declaration or statement.
class runnable : public absyn {
public:
runnable(position pos)
: absyn(pos) {}
virtual void prettyprint(ostream &out, Int indent) = 0;
/* Translates the stm or dec as if it were in a function definition. */
virtual void trans(coenv &e) {
transAsField(e, 0);
}
/* This can be overridden, to specify a special way of translating the code
* when it is run at the top of the interactive prompt.
*/
virtual void interactiveTrans(coenv &e) {
trans(e);
}
void markTransAsField(coenv &e, record *r)
{
markPos(e);
transAsField(e,r);
}
/* Translate the runnable as in the lowest lexical scope of a record
* definition. If it is simply a statement, it will be added to the
* record's initializer. A declaration, however, will also have to
* add a new type or field to the record.
*/
virtual void transAsField(coenv &e, record *) = 0;
virtual vm::lambda *transAsCodelet(coenv &e);
// For functions that return a value, we must guarantee that they end
// with a return statement. This checks for that condition.
virtual bool returns()
{ return false; }
// Returns true if it is syntactically allowable to modify this
// runnable by a PUBLIC or PRIVATE modifier.
virtual bool allowPermissions()
{ return false; }
};
// Forward declaration.
class formals;
class namedTy : public gc {
public:
symbol dest;
types::ty *t;
position pos;
namedTy(position pos, symbol dest, types::ty *t)
: dest(dest), t(t), pos(pos) {}
};
class receiveTypedefDec;
class block : public runnable {
public:
mem::list<runnable *> stms;
// If the runnables should be interpreted in their own scope.
bool scope;
protected:
void prettystms(ostream &out, Int indent);
private:
// If the first runnable exists and is a receiveTypedefDec*, return it;
// otherwise return nullptr.
receiveTypedefDec* getTypedefDec();
// To ensure list deallocates properly.
virtual ~block() {}
void add(runnable *r) {
stms.push_back(r);
}
void prettyprint(ostream &out, Int indent) override;
void trans(coenv &e) override;
void transAsField(coenv &e, record *r) override;
bool transAsTemplatedField(
coenv &e, record *r, mem::vector<absyntax::namedTy*>* args
);
types::record *transAsFile(genv& ge, symbol id);
types::record *transAsTemplatedFile(
genv& ge,
symbol id,
mem::vector<absyntax::namedTy*> *args
);
// If the block can be interpreted as a single vardec, return that vardec
// (otherwise 0).
vardec *asVardec();
// A block is guaranteed to return iff one of the runnables is guaranteed to
// return.
// This is conservative in that
//
// int f(int x)
// {
// if (x==1) return 0;
// if (x!=1) return 1;
// }
//
// is not guaranteed to return.
bool returns() override;
void add(trans::modifier m)
{
mods.push_back(m);
}
/* True if a static or dynamic modifier is present.
*/
bool staticSet();
/* Says if the modifiers indicate static or dynamic. Prints error if
* there are duplicates.
*/
trans::modifier getModifier();
/* Says if it is declared public, private, or read-only (default).
* Prints error if there are duplicates.
*/
trans::permission getPermission();
};
// Modifiers of static or dynamic can change the way declarations and
// statements are encoded.
class modifiedRunnable : public runnable {
modifierList *mods;
runnable *body;
// If a new type is formed by adding dimensions (or a function signature)
// after the id, this will add the standard functions for that new type.
virtual void addOps(types::ty *base, coenv &e, record *r);
struct idpair : public absyn {
symbol src; // The name of the module to access.
symbol dest; // What to call it in the local environment.
bool valid; // If it parsed properly.
idpair(position pos, symbol id)
: absyn(pos), src(id), dest(id), valid(true) {}
idpair(position pos, symbol src, symbol as, symbol dest)
: absyn(pos), src(src), dest(dest), valid(as==symbol::trans("as")) {}
idpair(position pos, string src, symbol as, symbol dest)
: absyn(pos), src(symbol::trans(src)), dest(dest),
valid(as==symbol::trans("as")) {}
void checkValidity() {
if (!valid) {
em.error(getPos());
em << "expected 'as'";
}
}
void prettyprint(ostream &out, Int indent) override;
// Translates as: access src as dest;
void transAsAccess(coenv &e, record *r);
// Translates as: from _ unravel src as dest;
// where _ is the qualifier record with source as its fields and types.
trans::tyEntry *transAsUnravel(coenv &e, record *r,
protoenv &source, varEntry *qualifier);
// Accesses the file with specified types added to the type environment.
class templateAccessDec : public dec {
symbol src; // The name of the module to access.
formals *args;
symbol dest; // What to call it in the local environment.
bool valid;
position expectedAsPos;
public:
templateAccessDec(position pos, symbol src, formals* args, symbol as,
symbol dest, position asPos)
: dec(pos), src(src), args(args), dest(dest),
valid(as == symbol::trans("as")), expectedAsPos(asPos) {}
bool checkValidity() {
if (!valid) {
em.error(expectedAsPos);
em << "expected 'as'";
return false;
}
return true;
}
void transAsField(coenv& e, record* r) override;
};
class typeParam : public absyn {
const symbol paramSym;
public:
typeParam(position pos, symbol paramSym)
: absyn(pos), paramSym(paramSym) {}
bool transAsParamMatcher(coenv &e, record *r, namedTy *arg);
void prettyprint(ostream &out, Int indent);
};
class typeParamList : public absyn {
mem::vector<typeParam*> params;
void transAsField(coenv& e, record *r) override;
bool transAsParamMatcher(
coenv& e, record *r, mem::vector<namedTy*> *args
);
};
// Abstract base class for
// from _ access _; (fromaccessdec)
// and
// from _ unravel _; (unraveldec)
class fromdec : public dec {
protected:
struct qualifier {
// The varEntry holds the location and the type of the highest framed
// structure that can be put on the stack. The record holds the actual
// type of the qualifier.
// For example:
// struct A {
// struct B {
// static int x;
// }
// }
// A a=new A;
// from a.B unravel x;
//
// Here, v->getType() will yield A and v->getLocation() will yield the
// location of the variable a, but the record type t will be B.
record *t;
varEntry *v;
// Return the qualifier from which the fields are taken. If t==0, it is
// assumed that an error occurred and was reported.
virtual qualifier getQualifier(coenv &e, record *r) = 0;
idpairlist *fields;
// A fromaccess declaration dumps fields and types of a module into the local
// scope. It does not add the module as a variable in the local scope.
class fromaccessdec : public fromdec {
symbol id;
formals *templateArgs;
qualifier getQualifier(coenv &e, record *r) override;
public:
fromaccessdec(
position pos, symbol id, idpairlist *fields, formals *templateArgs = 0
) : fromdec(pos, fields), id(id), templateArgs(templateArgs) {}
void prettyprint(ostream &out, Int indent) override;
// An import declaration dumps fields and types of a module into the local
// scope. It also adds the module as a variable in the local scope.
class importdec : public dec {
block base;
// Parses the file given, and translates the resulting runnables as if they
// occurred at this place in the code.
class includedec : public dec {
string filename;