diff options
Diffstat (limited to 'Build/source/utils/asymptote/dec.cc')
-rw-r--r-- | Build/source/utils/asymptote/dec.cc | 325 |
1 files changed, 297 insertions, 28 deletions
diff --git a/Build/source/utils/asymptote/dec.cc b/Build/source/utils/asymptote/dec.cc index 84ccb937ce0..794af9b2f8e 100644 --- a/Build/source/utils/asymptote/dec.cc +++ b/Build/source/utils/asymptote/dec.cc @@ -18,6 +18,7 @@ #include "runtime.h" #include "locate.h" #include "parser.h" +// #include "builtin.h" // for trans::addRecordOps namespace absyntax { @@ -60,9 +61,9 @@ void dimensions::prettyprint(ostream &out, Int indent) out << "dimensions (" << depth << ")\n"; } -types::array *dimensions::truetype(types::ty *base) +types::array *dimensions::truetype(types::ty *base, bool tacit) { - if (base->kind == ty_void) { + if (!tacit && base->kind == ty_void) { em.error(getPos()); em << "cannot declare array of type void"; } @@ -109,7 +110,7 @@ types::ty *arrayTy::trans(coenv &e, bool tacit) if (ct->kind == types::ty_error) return ct; - types::array *t = dims->truetype(ct); + types::array *t = dims->truetype(ct,tacit); assert(t); return t; @@ -167,22 +168,63 @@ void block::prettyprint(ostream &out, Int indent) prettystms(out, indent+1); } +// Uses RAII to ensure scope is ended when function returns. +class Scope { + coenv* e; +public: + Scope(coenv &e, bool scope) : e(scope ? &e : nullptr) { + if (this->e) this->e->e.beginScope(); + } + ~Scope() { + if (this->e) e->e.endScope(); + } +}; + + void block::trans(coenv &e) { - if (scope) e.e.beginScope(); + Scope scopeHolder(e, scope); for (list<runnable *>::iterator p = stms.begin(); p != stms.end(); ++p) { (*p)->markTrans(e); } - if (scope) e.e.endScope(); } void block::transAsField(coenv &e, record *r) { - if (scope) e.e.beginScope(); + Scope scopeHolder(e, scope); for (list<runnable *>::iterator p = stms.begin(); p != stms.end(); ++p) { (*p)->markTransAsField(e, r); + if (em.errors() && !settings::getSetting<bool>("debug")) + break; + } +} + +bool block::transAsTemplatedField( + coenv &e, record *r, mem::vector<absyntax::namedTyEntry*>* args +) { + Scope scopeHolder(e, scope); + auto p = stms.begin(); + if (p == stms.end()) { + return true; // empty file + } + receiveTypedefDec *dec = dynamic_cast<receiveTypedefDec *>(*p); + if (!dec) { + em.error(getPos()); + em << "expected 'typedef import(<types>);'"; + em.sync(); + return false; + } + if(!dec->transAsParamMatcher(e, r, args)) + return false; + + while (++p != stms.end()) { + (*p)->markTransAsField(e, r); + if (em.errors() && !settings::getSetting<bool>("debug")) { + return false; + } } - if (scope) e.e.endScope(); + em.sync(); + return true; } void block::transAsRecordBody(coenv &e, record *r) @@ -191,6 +233,14 @@ void block::transAsRecordBody(coenv &e, record *r) e.c.closeRecord(); } +bool block::transAsTemplatedRecordBody( + coenv &e, record *r, mem::vector<absyntax::namedTyEntry*> *args +) { + bool succeeded = transAsTemplatedField(e, r, args); + e.c.closeRecord(); + return succeeded; +} + record *block::transAsFile(genv& ge, symbol id) { // Create the new module. @@ -208,10 +258,37 @@ record *block::transAsFile(genv& ge, symbol id) } transAsRecordBody(ce, r); em.sync(); + if (em.errors()) return nullptr; return r; } +record *block::transAsTemplatedFile( + genv& ge, symbol id, mem::vector<absyntax::namedTyEntry*>* args +) { + // Create the new module. + record *r = new record(id, new frame(id,0,0)); + + // Create coder and environment to translate the module. + // File-level modules have dynamic fields by default. + coder c(getPos(), r, 0); + env e(ge); + coenv ce(c, e); + + // Translate the abstract syntax. + if (settings::getSetting<bool>("autoplain")) { + autoplainRunnable()->transAsField(ce, r); + } + + bool succeeded = transAsTemplatedRecordBody(ce, r, args); + if (!succeeded) { + return nullptr; + } + + return r; +} + + bool block::returns() { // Search for a returning runnable, starting at the end for efficiency. for (list<runnable *>::reverse_iterator p=stms.rbegin(); @@ -386,9 +463,10 @@ trans::tyEntry *decidstart::getTyEntry(trans::tyEntry *base, coenv &e, void decidstart::addOps(types::ty *base, coenv &e, record *r) { if (dims) { - e.e.addArrayOps(dims->truetype(base)); + array *a=dims->truetype(base); + e.e.addArrayOps(a); if (r) - r->e.addArrayOps(dims->truetype(base)); + r->e.addArrayOps(a); } } @@ -409,8 +487,9 @@ void decidstart::createSymMap(AsymptoteLsp::SymbolContext* symContext) #endif } -void decidstart::createSymMapWType(AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base) -{ +void decidstart::createSymMapWType( + AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base +) { #ifdef HAVE_LSP std::string name(static_cast<std::string>(getName())); AsymptoteLsp::posInFile pos(getPos().LineColumn()); @@ -418,20 +497,26 @@ void decidstart::createSymMapWType(AsymptoteLsp::SymbolContext* symContext, absy { if (base == nullptr) { - decCtx->additionalDecs.emplace(std::piecewise_construct, std::forward_as_tuple(name), + decCtx->additionalDecs.emplace(std::piecewise_construct, + std::forward_as_tuple(name), std::forward_as_tuple(name, pos)); } else { - decCtx->additionalDecs.emplace(std::piecewise_construct, std::forward_as_tuple(name), - std::forward_as_tuple(name, static_cast<std::string>(*base), pos)); + decCtx->additionalDecs.emplace( + std::piecewise_construct, + std::forward_as_tuple(name), + std::forward_as_tuple(name, static_cast<std::string>(*base), pos) + ); } } else { symContext->symMap.varDec[name] = base == nullptr ? AsymptoteLsp::SymbolInfo(name, pos) : - AsymptoteLsp::SymbolInfo(name, static_cast<std::string>(*base), pos); + AsymptoteLsp::SymbolInfo(name, + static_cast<std::string>(*base), + pos); } #endif } @@ -550,14 +635,19 @@ types::ty *inferType(position pos, coenv &e, varinit *init) } exp *base = dynamic_cast<exp *>(init); + bool Void=false; + if (base) { types::ty *t = base->cgetType(e); - if (t->kind != ty_overloaded) + Void=t->kind == ty_void; + if (t->kind != ty_overloaded && !Void) return t; } em.error(pos); - em << "could not infer type of initializer"; + em << (Void ? "cannot infer from void" : + "could not infer type of initializer"); + return primError(); } @@ -639,8 +729,9 @@ void decid::createSymMap(AsymptoteLsp::SymbolContext* symContext) #endif } -void decid::createSymMapWType(AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base) -{ +void decid::createSymMapWType( + AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base +) { #ifdef HAVE_LSP start->createSymMapWType(symContext, base); if (init) @@ -680,7 +771,9 @@ void decidlist::createSymMap(AsymptoteLsp::SymbolContext* symContext) { #endif } -void decidlist::createSymMapWType(AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base) { +void decidlist::createSymMapWType( + AsymptoteLsp::SymbolContext* symContext, absyntax::ty* base +) { #ifdef HAVE_LSP for (auto const& p : decs) { @@ -690,7 +783,7 @@ void decidlist::createSymMapWType(AsymptoteLsp::SymbolContext* symContext, absyn } - void vardec::prettyprint(ostream &out, Int indent) +void vardec::prettyprint(ostream &out, Int indent) { prettyname(out, "vardec",indent, getPos()); @@ -738,7 +831,7 @@ class loadModuleExp : public exp { public: loadModuleExp(position pos, record *imp) - : exp(pos) {ft=new function(imp,primString());} + : exp(pos) {ft=new function(imp,primString(),primString());} void prettyprint(ostream &out, Int indent) { prettyname(out, "loadModuleExp", indent, getPos()); @@ -778,9 +871,55 @@ varEntry *accessModule(position pos, coenv &e, record *r, symbol id) } else { // Create a varinit that evaluates to the module. - // This is effectively the expression "loadModule(filename)". + // This is effectively the expression 'loadModule(filename,"")'. + callExp init(pos, new loadModuleExp(pos, imp), + new stringExp(pos, (string)id), new stringExp(pos, "")); + + // The varEntry should have whereDefined()==0 as it is not defined inside + // the record r. + varEntry *v=makeVarEntryWhere(e, r, imp, 0, pos); + initializeVar(pos, e, v, &init); + return v; + } +} + +// Creates a local variable to hold the import and translate the accessing of +// the import, but doesn't add the import to the environment. +varEntry *accessTemplatedModule(position pos, coenv &e, record *r, symbol id, + formals *args) +{ + stringstream s; + s << args->getSignature(e)->handle(); + string sigHandle=s.str(); + + auto *computedArgs = new mem::vector<namedTyEntry*>(); + mem::vector<tySymbolPair> *fields = args->getFields(); + for (auto p = fields->begin(); p != fields->end(); ++p) { + ty* theType = p->ty; + symbol theName = p->sym; + if (theName == symbol::nullsym) { + em.error(theType->getPos()); + em << "expected typename="; + em.sync(); + return nullptr; + } + computedArgs->push_back(new namedTyEntry( + theType->getPos(), theName, theType->transAsTyEntry(e, r) + )); + } + + record *imp=e.e.getTemplatedModule(id, (string) id, sigHandle, computedArgs); + if (!imp) { + em.error(pos); + em << "could not load module '" << id << "'"; + em.sync(); + return nullptr; + } + else { + // Create a varinit that evaluates to the module. + // This is effectively the expression 'loadModule(filename,index)'. callExp init(pos, new loadModuleExp(pos, imp), - new stringExp(pos, (string)id)); + new stringExp(pos, (string) id), new stringExp(pos, sigHandle)); // The varEntry should have whereDefined()==0 as it is not defined inside // the record r. @@ -833,7 +972,9 @@ void idpair::createSymMap(AsymptoteLsp::SymbolContext* symContext) } // add (dest, source) to reference map. - auto s = symContext->extRefs.fileIdPair.emplace(dest, (std::string) fullSrc.c_str()); + auto s = symContext->extRefs.fileIdPair.emplace( + dest, (std::string) fullSrc.c_str() + ); auto it=std::get<0>(s); auto success=std::get<1>(s); if (not success) @@ -898,6 +1039,126 @@ void accessdec::createSymMap(AsymptoteLsp::SymbolContext* symContext) #endif } +void templateAccessDec::transAsField(coenv& e, record* r) { + if (!this->checkValidity()) return; + + args->addOps(e, r); + + varEntry *v=accessTemplatedModule(getPos(), e, r, this->src, args); + if (v) + addVar(e, r, v, dest); +} + +void typeParam::prettyprint(ostream &out, Int indent) { + prettyindent(out, indent); + out << "typeParam (" << paramSym << ")\n"; +} + +bool typeParam::transAsParamMatcher(coenv &e, namedTyEntry* arg) { + if (arg->dest != paramSym) { + em.error(arg->pos); + em << "template argument name does not match module: passed " + << arg->dest + << ", expected " + << paramSym; + return false; + } + e.e.addType(paramSym, arg->ent); + // The code below would add e.g. operator== to the context, but potentially + // ignore overrides of operator==: + // + // types::ty *t = arg.ent->t; + // if (t->kind == types::ty_record) { + // record *r = dynamic_cast<record *>(t); + // if (r) { + // trans::addRecordOps(e.e.ve, r); + // } + // } else if (t->kind == types::ty_array) { + // array *a = dynamic_cast<array *>(t); + // if (a) { + // trans::addArrayOps(e.e.ve, a); + // } + // } else if (t->kind == types::ty_function) { + // function *f = dynamic_cast<function *>(t); + // if (f) { + // trans::addFunctionOps(e.e.ve, f); + // } + // } + return true; +} + +void typeParamList::prettyprint(ostream &out, Int indent) { + for (auto p = params.begin(); p != params.end(); ++p) { + (*p)->prettyprint(out, indent); + } +} + +void typeParamList::add(typeParam *tp) { + params.push_back(tp); +} + +bool typeParamList::transAsParamMatcher( + coenv &e, mem::vector<namedTyEntry*> *args +) { + if (args->size() != params.size()) { + position pos = getPos(); + if (args->size() >= 1) { + pos = (*args)[0]->pos; + } + em.error(pos); + if (args->size() > params.size()) { + em << "too many types passed: got " << args->size() << ", expected " + << params.size(); + } else { + em << "too few types passed: got " << args->size() << ", expected " + << params.size(); + } + return false; + } + for (size_t i = 0; i < params.size(); ++i) { + bool succeeded = params[i]->transAsParamMatcher(e, (*args)[i]); + if (!succeeded) return false; + } + return true; +} + +symbol intSymbol() { + const static symbol* intSymbol = new symbol(symbol::literalTrans("int")); + return *intSymbol; +} + +symbol templatedSymbol() { + const static symbol* templatedSymbol = + new symbol(symbol::literalTrans("/templated")); + return *templatedSymbol; +} + +bool receiveTypedefDec::transAsParamMatcher( + coenv& e, record *r, mem::vector<namedTyEntry*> *args +) { + bool succeeded = params->transAsParamMatcher(e, args); + + types::ty *intTy = e.e.lookupType(intSymbol()); + assert(intTy); + e.e.addVar(templatedSymbol(), + makeVarEntryWhere(e, nullptr, intTy, r, getPos()) + ); + + return succeeded; +} + +void receiveTypedefDec::transAsField(coenv& e, record *r) { + em.error(getPos()); + types::ty *intTy = e.e.lookupType(intSymbol()); + assert(intTy); + if (e.e.lookupVarByType(templatedSymbol(), intTy)) { + em << "'typedef import(<types>)' must precede any other code"; + } else { + em << "templated module access requires template parameters"; + } + em.sync(); +} + void fromdec::prettyprint(ostream &out, Int indent) { @@ -961,7 +1222,12 @@ void fromaccessdec::prettyprint(ostream &out, Int indent) fromdec::qualifier fromaccessdec::getQualifier(coenv &e, record *r) { - varEntry *v=accessModule(getPos(), e, r, id); + varEntry *v = 0; + if (templateArgs) { + v = accessTemplatedModule(getPos(), e, r, id, templateArgs); + } else { + v=accessModule(getPos(), e, r, id); + } if (v) { record *qt=dynamic_cast<record *>(v->getType()); if (!qt) { @@ -1035,7 +1301,9 @@ void includedec::transAsField(coenv &e, record *r) void includedec::createSymMap(AsymptoteLsp::SymbolContext* symContext) { #ifdef HAVE_LSP - std::string fullname((std::string) settings::locateFile(filename, true).c_str()); + std::string fullname( + (std::string) settings::locateFile(filename, true).c_str() + ); if (not AsymptoteLsp::isVirtualFile(fullname)) { symContext->addEmptyExtRef(fullname); @@ -1089,7 +1357,8 @@ void recorddec::transAsField(coenv &e, record *parent) record *r = parent ? parent->newRecord(id, e.c.isStatic()) : e.c.newRecord(id); - addTypeWithPermission(e, parent, new trans::tyEntry(r,0,parent,getPos()), id); + addTypeWithPermission(e, parent, new trans::tyEntry(r,0,parent,getPos()), + id); e.e.addRecordOps(r); if (parent) parent->e.addRecordOps(r); |