/***** * dec.h * Andy Hammerlindl 2002/8/29 * * Represents the abstract syntax tree for declatations in the language. * Also included is abstract syntax for types as they are most often * used with declarations. *****/ #ifndef DEC_H #define DEC_H #include "symbol.h" #include "absyn.h" #include "name.h" #include "varinit.h" #include "modifier.h" namespace trans { class coenv; class genv; class protoenv; class varEntry; class access; } namespace types { class ty; struct formal; struct signature; struct function; } 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; class ty : public absyn { public: ty(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 *) {} // 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); virtual operator string() const = 0; #ifdef USEGC operator std::string() const { return mem::stdString(this->operator string()); } #endif }; class nameTy : public ty { name *id; public: nameTy(position pos, name *id) : ty(pos), id(id) {} nameTy(name *id) : ty(id->getPos()), id(id) {} void prettyprint(ostream &out, Int indent) override; types::ty *trans(coenv &e, bool tacit = false) override; trans::tyEntry *transAsTyEntry(coenv &e, record *where) override; virtual operator string() const override; }; class dimensions : public absyn { size_t depth; public: dimensions(position pos) : absyn(pos), depth(1) {} void prettyprint(ostream &out, Int indent); void increase() { depth++; } size_t size() { return depth; } types::array *truetype(types::ty *base, bool tacit=false); }; class arrayTy : public ty { ty *cell; dimensions *dims; public: arrayTy(position pos, ty *cell, dimensions *dims) : ty(pos), cell(cell), dims(dims) {} arrayTy(name *id, dimensions *dims) : ty(dims->getPos()), cell(new nameTy(id)), dims(dims) {} void prettyprint(ostream &out, Int indent) override; void addOps(coenv &e, record *r) override; types::ty *trans(coenv &e, bool tacit = false) override; operator string() const override; }; // Similar to varEntryExp, this helper class always translates to the same // fixed type. class tyEntryTy : public ty { trans::tyEntry *ent; public: tyEntryTy(position pos, trans::tyEntry *ent) : ty(pos), ent(ent) {} tyEntryTy(position pos, types::ty *t); void prettyprint(ostream &out, Int indent) override; types::ty *trans(coenv &e, bool tacit = false) override; trans::tyEntry *transAsTyEntry(coenv &, record *) override { return ent; } operator string() const 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; void markTrans(coenv &e) { markPos(e); trans(e); } /* 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 syntatically allowable to modify this // runnable by a PUBLIC or PRIVATE modifier. virtual bool allowPermissions() { return false; } }; // Forward declaration. class formals; class namedTyEntry : public gc { public: symbol dest; trans::tyEntry *ent; position pos; namedTyEntry(position pos, symbol dest, trans::tyEntry *ent) : dest(dest), ent(ent), pos(pos) {} }; class block : public runnable { public: mem::list stms; // If the runnables should be interpreted in their own scope. bool scope; protected: void prettystms(ostream &out, Int indent); public: block(position pos, bool scope=true) : runnable(pos), scope(scope) {} // 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* args ); void transAsRecordBody(coenv &e, record *r); bool transAsTemplatedRecordBody( coenv &e, record *r, mem::vector *args ); types::record *transAsFile(genv& ge, symbol id); types::record *transAsTemplatedFile( genv& ge, symbol id, mem::vector *args, trans::frame *parent ); // 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 createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; class modifierList : public absyn { mem::list perms; mem::list mods; public: modifierList(position pos) : absyn(pos) {} virtual ~modifierList() {} void prettyprint(ostream &out, Int indent); void add(trans::permission p) { perms.push_back(p); } 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; public: modifiedRunnable(position pos, modifierList *mods, runnable *body) : runnable(pos), mods(mods), body(body) {} modifiedRunnable(position pos, trans::permission perm, runnable *body) : runnable(pos), mods(new modifierList(pos)), body(body) { mods->add(perm); } void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *r); bool returns() { return body->returns(); } }; class decidstart : public absyn { protected: symbol id; dimensions *dims; public: decidstart(position pos, symbol id, dimensions *dims = 0) : absyn(pos), id(id), dims(dims) {} virtual void prettyprint(ostream &out, Int indent) override; virtual types::ty *getType(types::ty *base, coenv &, bool = false); virtual trans::tyEntry *getTyEntry(trans::tyEntry *base, coenv &e, record *where); // 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); virtual symbol getName() { return id; } void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; void createSymMapWType( AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base ); }; class fundecidstart : public decidstart { formals *params; public: fundecidstart(position pos, symbol id, dimensions *dims = 0, formals *params = 0) : decidstart(pos, id, dims), params(params) {} void prettyprint(ostream &out, Int indent); types::ty *getType(types::ty *base, coenv &e, bool tacit = false); trans::tyEntry *getTyEntry(trans::tyEntry *base, coenv &e, record *where); void addOps(types::ty *base, coenv &e, record *r); }; class decid : public absyn { decidstart *start; varinit *init; // Returns the default initializer for the type. access *defaultInit(coenv &e, types::ty *t); public: decid(position pos, decidstart *start, varinit *init = 0) : absyn(pos), start(start), init(init) {} virtual void prettyprint(ostream &out, Int indent) override; virtual void transAsField(coenv &e, record *r, types::ty *base); // Translate, but add the names in as types rather than variables. virtual void transAsTypedefField(coenv &e, trans::tyEntry *base, record *r); decidstart *getStart() { return start; } void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; void createSymMapWType( AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base ); }; class decidlist : public absyn { mem::list decs; public: decidlist(position pos) : absyn(pos) {} virtual ~decidlist() {} void add(decid *p) { decs.push_back(p); } virtual void prettyprint(ostream &out, Int indent) override; virtual void transAsField(coenv &e, record *r, types::ty *base); // Translate, but add the names in as types rather than variables. virtual void transAsTypedefField(coenv &e, trans::tyEntry *base, record *r); // If the list consists of a single entry, return it. decid *singleEntry() { if (decs.size() == 1) return decs.front(); else return 0; } void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; void createSymMapWType( AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base ); }; class dec : public runnable { public: dec(position pos) : runnable(pos) {} void prettyprint(ostream &out, Int indent) override; // Declarations can be public or private. bool allowPermissions() override { return true; } }; void createVar(position pos, coenv &e, record *r, symbol id, types::ty *t, varinit *init); class vardec : public dec { ty *base; decidlist *decs; public: vardec(position pos, ty *base, decidlist *decs) : dec(pos), base(base), decs(decs) {} vardec(position pos, ty *base, decid *di) : dec(pos), base(base), decs(new decidlist(pos)) { decs->add(di); } void prettyprint(ostream &out, Int indent) override; void transAsField(coenv &e, record *r) override { base->addOps(e, r); decs->transAsField(e, r, base->trans(e)); } // Translate, but add the names in as types rather than variables. virtual void transAsTypedefField(coenv &e, record *r); // If the vardec encodes a single declaration, return the name of that // declaration (otherwise nullsym). symbol singleName(); // If the vardec encodes a single declaration, return the type of that // declaration (otherwise 0). types::ty *singleGetType(coenv& e); void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; 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. void transAsUnravel(coenv &e, record *r, protoenv &source, varEntry *qualifier); void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; struct idpairlist : public gc { mem::list base; void add(idpair *x) { base.push_back(x); } void prettyprint(ostream &out, Int indent); void transAsAccess(coenv &e, record *r); void transAsUnravel(coenv &e, record *r, protoenv &source, varEntry *qualifier); void createSymMap(AsymptoteLsp::SymbolContext* symContext); template void processListFn(TFn const& fn) { for (auto* idp : base) { fn(idp->src, idp->dest); } } }; extern idpairlist * const WILDCARD; class accessdec : public dec { idpairlist *base; public: accessdec(position pos, idpairlist *base) : dec(pos), base(base) {} void prettyprint(ostream &out, Int indent) override; void transAsField(coenv &e, record *r) override { base->transAsAccess(e,r); } void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; class badDec : public dec { position errorPos; string errorMessage; public: badDec(position pos, position errorPos, string errorMessage) : dec(pos), errorPos(errorPos), errorMessage(errorMessage) {} void transAsField(coenv&, record*) override { em.error(errorPos); em << errorMessage; } }; // 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, namedTyEntry *arg); void prettyprint(ostream &out, Int indent); }; class typeParamList : public absyn { mem::vector params; public: typeParamList(position pos) : absyn(pos) {} void add(typeParam *tp); bool transAsParamMatcher(coenv &e, record *r, mem::vector *args); void prettyprint(ostream &out, Int indent); }; class receiveTypedefDec : public dec { typeParamList* params; public: receiveTypedefDec(position pos, typeParamList* params) : dec(pos), params(params) {} void transAsField(coenv& e, record *r) override; bool transAsParamMatcher( coenv& e, record *r, mem::vector *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 the variable a, but the record type t will be B. record *t; varEntry *v; qualifier(record *t, varEntry *v) : t(t), v(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; public: fromdec(position pos, idpairlist *fields) : dec(pos), fields(fields) {} void prettyprint(ostream &out, Int indent) override; void transAsField(coenv &e, record *r) override; }; // An unravel declaration dumps fields and types of a record into the local // scope. class unraveldec : public fromdec { name *id; qualifier getQualifier(coenv &e, record *) override; public: unraveldec(position pos, name *id, idpairlist *fields) : fromdec(pos, fields), id(id) {} void prettyprint(ostream &out, Int indent) override; void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; // 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; void createSymMap(AsymptoteLsp::SymbolContext* symContext) 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; public: importdec(position pos, idpair *id) : dec(pos), base(pos, false) { idpairlist *i=new idpairlist; i->add(id); base.add(new accessdec(pos, i)); base.add(new unraveldec(pos, new simpleName(pos, id->dest), WILDCARD)); } void trans(coenv &e) override { base.trans(e); } void transAsField(coenv &e, record *r) override { base.transAsField(e, r); } void prettyprint(ostream &out, Int indent) override; void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; // 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; public: includedec(position pos, string filename) : dec(pos), filename(filename) {} includedec(position pos, symbol id) : dec(pos), filename(id) {} void prettyprint(ostream &out, Int indent) override; void loadFailed(coenv &e); void transAsField(coenv &e, record *r) override; void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; // Types defined from others in typedef. class typedec : public dec { vardec *body; public: typedec(position pos, vardec *body) : dec(pos), body(body) {} void prettyprint(ostream &out, Int indent); void transAsField(coenv &e, record *r) { body->transAsTypedefField(e,r); } }; // A struct declaration. class recorddec : public dec { symbol id; block *body; void transRecordInitializer(coenv &e, record *parent); void addPostRecordEnvironment(coenv &e, record *r, record *parent); public: recorddec(position pos, symbol id, block *body) : dec(pos), id(id), body(body) {} virtual ~recorddec() {} void prettyprint(ostream &out, Int indent) override; void transAsField(coenv &e, record *parent) override; void createSymMap(AsymptoteLsp::SymbolContext* symContext) override; }; // Returns a runnable that facilitates the autoplain feature. runnable *autoplainRunnable(); void addVar(coenv &e, record *r, varEntry *v, symbol id); } // namespace absyntax #endif