diff options
author | Norbert Preining <norbert@preining.info> | 2021-12-28 03:01:00 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2021-12-28 03:01:00 +0000 |
commit | ecdf859b6ce481abfd530425dcf6f0f764bd0001 (patch) | |
tree | 13bc161dc046876ac6c92fce5f9f5034ba9aa573 /graphics/asymptote/symbolmaps.cc | |
parent | 790995b7e79697514364450bf9c04f1b8d500838 (diff) |
CTAN sync 202112280300
Diffstat (limited to 'graphics/asymptote/symbolmaps.cc')
-rw-r--r-- | graphics/asymptote/symbolmaps.cc | 828 |
1 files changed, 828 insertions, 0 deletions
diff --git a/graphics/asymptote/symbolmaps.cc b/graphics/asymptote/symbolmaps.cc new file mode 100644 index 0000000000..27c073e70b --- /dev/null +++ b/graphics/asymptote/symbolmaps.cc @@ -0,0 +1,828 @@ +#include "common.h" + +#ifdef HAVE_LSP + +#include "symbolmaps.h" +#include "locate.h" +#include <unordered_map> + +namespace AsymptoteLsp +{ + [[nodiscard]] + bool isVirtualFile(std::string const& filename) + { + bool isSettings=filename=="settings"; +#ifdef HAVE_LIBGSL + bool isGSL=filename=="gsl" and settings::getSetting<bool>("gsl"); +#else + bool isGSL=false; +#endif + return isSettings || isGSL; + } + + std::string getPlainFile() + { + return std::string((std::string) settings::locateFile("plain", true).c_str()); + } + + positions::positions(filePos const& positionInFile) + { + add(positionInFile); + } + + void positions::add(const filePos &positionInFile) + { + auto fileLoc=pos.find(positionInFile.first); + if (fileLoc == pos.end()) + { + pos.emplace(positionInFile.first, std::vector<posInFile>{positionInFile.second}); + } else + { + fileLoc->second.push_back(positionInFile.second); + } + } + + ostream& operator <<(std::ostream& os, const SymbolMaps& sym) + { + os << "var decs:" << endl; + for (auto const& s : sym.varDec) + { + auto const& key=std::get<0>(s); + auto const& value=std::get<1>(s); + os << key << " " << value.pos.first << ":" << value.pos.second << endl; + } + return os; + } + + optional<fullSymPosRangeInFile> SymbolMaps::searchSymbol(posInFile const& inputPos) + { + // FIXME: can be optimized by binary search. + for (auto const& s : usageByLines) + { + auto const& pos=std::get<0>(s); + auto const& syLit=std::get<1>(s); + size_t endCharacter = pos.second + syLit.name.length() - 1; + bool posMatches = + pos.first == inputPos.first and + pos.second <= inputPos.second and + inputPos.second <= endCharacter; + bool isOperator = syLit.name.find("operator ") == 0; + if (posMatches and !isOperator) + { + posInFile endPos(pos.first, endCharacter + 1); + return boost::make_optional(std::make_tuple(syLit, pos, endPos)); + } + } + return nullopt; + } + + FunctionInfo& SymbolMaps::addFunDef( + std::string const& funcName, posInFile const& position, std::string const& returnType) + { + auto fit=std::get<0>(funDec.emplace(std::piecewise_construct, + std::forward_as_tuple(funcName), std::forward_as_tuple())); + + fit->second.emplace_back(funcName, position, returnType); + return fit->second.back(); + } + + std::pair<optional<fullSymPosRangeInFile>, SymbolContext*> SymbolContext::searchSymbol(posInFile const& inputPos) + { + auto currCtxSym = symMap.searchSymbol(inputPos); + if (currCtxSym.has_value()) + { + return make_pair(currCtxSym, this); + } + // else, not found in currCtx; + for (auto& subContext : subContexts) + { + if (!posLt(inputPos, subContext->contextLoc)) + { + auto v=subContext->searchSymbol(inputPos); + auto subCtxSym=std::get<0>(v);; + auto ctx=std::get<1>(v); + if (subCtxSym.has_value()) + { + return make_pair(subCtxSym, ctx); + } + } + } + return make_pair(nullopt, nullptr); + } + + SymbolInfo const* SymbolContext::searchVarRaw(std::string const& symbol) const + { + // local variable declarations + auto pt = symMap.varDec.find(symbol); + if (pt != symMap.varDec.end()) + { + return &pt->second; + } + + // otherwise, search parent. + return parent != nullptr ? parent->searchVarRaw(symbol) : nullptr; + } + + optional<posRangeInFile> SymbolContext::searchVarDecl( + std::string const& symbol, optional<posInFile> const& position) + { + auto pt = symMap.varDec.find(symbol); + if (pt != symMap.varDec.end()) + { + auto line = std::get<0>(pt->second.pos); + auto ch = std::get<1>(pt->second.pos); + if ((not position.has_value()) or (!posLt(position.value(), pt->second.pos))) + { + return std::make_tuple(getFileName().value_or(""), + pt->second.pos, std::make_pair(line, ch + symbol.length())); + } + } + + auto ptFn = symMap.funDec.find(symbol); + if (ptFn != symMap.funDec.end() and !ptFn->second.empty()) + { + // FIXME: Right now, we have no way of knowing the exact position of the + // start of where the function name is. As an example, we do not know + // where the exact position of + // real testFunction(...) { ... + // ^ + auto ptValue = ptFn->second[0]; + if ((not position.has_value()) or (!posLt(position.value(), ptValue.pos))) + { + return std::make_tuple(getFileName().value_or(""), ptValue.pos, ptValue.pos); + } + } + + // otherwise, search parent. + return parent != nullptr ? parent->searchVarDecl(symbol, position) : nullopt; + } + + void SymbolContext::addPlainFile() + { + std::string plainFile = getPlainFile(); + addEmptyExtRef(plainFile); + } + + SymbolContext::SymbolContext(posInFile loc): + fileLoc(nullopt), contextLoc(std::move(loc)), parent(nullptr) + { + addPlainFile(); + } + + SymbolContext::SymbolContext(posInFile loc, std::string filename): + fileLoc(std::move(filename)), contextLoc(std::move(loc)), parent(nullptr) + { + addPlainFile(); + } + + optional<posRangeInFile> + SymbolContext::searchVarDeclFull(std::string const& symbol, optional<posInFile> const& position) + { + std::unordered_set<SymbolContext*> searched; + std::unordered_set<std::string> symbolSearch { symbol }; + + auto returnVal = _searchVarFull<posRangeInFile>( + searched, symbolSearch, + [&position](SymbolContext* ctx, std::string const& sym) + { + return ctx->searchVarDecl(sym, position); + }, + [](SymbolContext* ctx, std::string const& sym) + { + return ctx->searchVarDecl(sym); + }, + fnFromDeclCreateTrav); + if (returnVal.has_value()) + { + return returnVal; + } + + return _searchVarFull<posRangeInFile>( + symbol, + [](SymbolContext* ctx, std::string const& sym) -> optional<posRangeInFile> + { + for (auto const& unravelVal : ctx->extRefs.unraveledVals) + { + if (auto* pctx=ctx->searchStructCtxFull(unravelVal)) + { + auto retVal = pctx->searchVarDecl(sym); + if (retVal.has_value()) + { + return retVal; + } + } + } + return nullopt; + }); + } + + std::list<ExternalRefs::extRefMap::iterator> SymbolContext::getEmptyRefs() + { + std::list<ExternalRefs::extRefMap::iterator> finalList; + + for (auto it = extRefs.extFileRefs.begin(); it != extRefs.extFileRefs.end(); it++) + { + if (it->second == nullptr) + { + // cerr << it->first << endl; + finalList.emplace_back(it); + } + } + + for (auto& ctx : subContexts) + { + finalList.splice(finalList.end(), ctx->getEmptyRefs()); + } + + return finalList; + } + + optional<std::string> SymbolContext::getFileName() const + { + if (fileLoc.has_value()) + { + return fileLoc; + } + else + { + return parent == nullptr ? fileLoc : parent->getFileName(); + } + } + + optional<std::string> SymbolContext::searchVarSignatureFull(std::string const& symbol) + { + std::unordered_set<SymbolContext*> searched; + auto retVal = _searchVarFull<std::string>( + symbol, + [](SymbolContext const* ctx, std::string const& sym) -> optional<std::string> + { + if (auto const* info = ctx->searchVarRaw(sym)) + { + return info->signature(); + } + return nullopt; + }, + fnFromDeclCreateTrav); + + if (retVal.has_value()) + { + return retVal; + } + + // else, + // search every unravel values possible (not only here, but also in every includes + unravels as well). + // If an unravel value match a struct, then see if symbol matches the struct. If yes, return otherwise skip. + + return _searchVarFull<std::string>( + symbol, + [](SymbolContext* ctx, std::string const& sym) -> optional<std::string> + { + if (SymbolInfo* info=ctx->searchVarUnravelStructRaw(sym)) + { + return info->signature(); + } + return nullopt; + }); + } + + SymbolInfo* SymbolContext::searchVarUnravelStructRaw(std::string const& symbol) + { + return searchVarUnravelStructRaw(symbol, nullopt); + } + + SymbolInfo* SymbolContext::searchVarUnravelStructRaw(std::string const& symbol, optional<posInFile> const& position) + { + for (auto const& unravelVal : extRefs.unraveledVals) + { + if (auto* ctx=searchStructCtxFull(unravelVal)) + { + // ctx points to a struct. + auto it=ctx->symMap.varDec.find(symbol); + if (it != ctx->symMap.varDec.end()) + { + if (((not position.has_value()) or (!posLt(position.value(), it->second.pos)))) + { + return &it->second; + } + } + } + } + return parent != nullptr ? parent->searchVarUnravelStructRaw(symbol) : nullptr; + } + + std::list<std::string> SymbolContext::searchFuncUnravelStruct(std::string const& symbol) + { + std::list<std::string> finalList; + + for (auto const& unravelVal : extRefs.unraveledVals) + { + if (auto* ctx=searchStructCtxFull(unravelVal)) + { + // ctx points to a struct. + auto it=ctx->symMap.funDec.find(symbol); + if (it != ctx->symMap.funDec.end() and not it->second.empty()) + { + std::transform( + it->second.begin(), it->second.end(), std::back_inserter(finalList), + [](FunctionInfo const& fnInfo) + { + return fnInfo.signature(); + }); + } + } + } + if (parent != nullptr) + { + finalList.splice(finalList.end(), parent->searchFuncUnravelStruct(symbol)); + } + return finalList; + } + + + std::list<std::string> SymbolContext::searchFuncSignature(std::string const& symbol) + { + std::list<std::string> funcSigs; + auto pt = symMap.funDec.find(symbol); + if (pt != symMap.funDec.end()) + { + std::transform(pt->second.begin(), pt->second.end(), + std::back_inserter(funcSigs), + [](FunctionInfo const& fnInfo) { + return fnInfo.signature(); + }); + } + + if (parent != nullptr) + { + funcSigs.splice(funcSigs.end(), parent->searchFuncSignature(symbol)); + } + return funcSigs; + } + + std::list<std::string> SymbolContext::searchFuncSignatureFull(std::string const& symbol) + { + auto base_list = _searchAllVarFull<std::string>( + symbol, std::mem_fn(&SymbolContext::searchFuncSignature), fnFromDeclCreateTrav); + + base_list.splice(base_list.end(), _searchAllVarFull<std::string>( + symbol, std::mem_fn(&SymbolContext::searchFuncUnravelStruct))); + return base_list; + } + + optional<SymbolContext*> SymbolContext::searchStructContext(std::string const& tyVal) const + { + auto stCtx = symMap.typeDecs.find(tyVal); + if (stCtx != symMap.typeDecs.end()) + { + if (auto* stDec = dynamic_cast<StructDecs*>(stCtx->second.get())) + { + return make_optional(stDec->ctx); + } + } + + return parent != nullptr ? parent->searchStructContext(tyVal) : nullopt; + }; + + optional<std::string> SymbolContext::searchLitSignature(SymbolLit const& symbol) + { + if (symbol.scopes.empty()) + { + return searchVarSignatureFull(symbol.name); + } + else + { + auto ctx=std::get<0>(searchLitContext(symbol)); + auto isStruct=std::get<1>(searchLitContext(symbol)); + if (ctx) + { + if (isStruct) + { + // ctx is a struct declaration. should not search beyond this struct. + auto varDec=ctx->symMap.varDec.find(symbol.name); + return varDec != ctx->symMap.varDec.end() ? + optional<std::string>(varDec->second.signature()) : nullopt; + } + else + { + return ctx->searchVarSignatureFull(symbol.name); + } + } + } + + return nullopt; + } + + std::list<std::string> SymbolContext::searchLitFuncSignature(SymbolLit const& symbol) + { + std::list<std::string> signatures; + if (symbol.scopes.empty()) + { + signatures.splice(signatures.end(), searchFuncSignatureFull(symbol.name)); + } + else + { + auto ctx=std::get<0>(searchLitContext(symbol)); + auto isStruct=std::get<1>(searchLitContext(symbol)); + if (ctx) + { + if (isStruct) + { + // ctx is a struct declaration. should not search beyond this struct. + auto fnDecs=ctx->symMap.funDec.find(symbol.name); + if (fnDecs != ctx->symMap.funDec.end()) + { + std::transform( + fnDecs->second.begin(), fnDecs->second.end(), + std::back_inserter(signatures), + [&scopes=symbol.scopes](FunctionInfo const& fnInf) + { + return fnInf.signature(scopes); + }); + } + } + else + { + signatures.splice(signatures.end(), searchFuncSignatureFull(symbol.name)); + } + } + } + + return signatures; + } + + optional<posRangeInFile> SymbolContext::searchLitPosition( + SymbolLit const& symbol, + optional<posInFile> const& position) + { + if (symbol.scopes.empty()) + { + return searchVarDeclFull(symbol.name, position); + } + else + { + auto ctx=std::get<0>(searchLitContext(symbol)); + auto isStruct=std::get<1>(searchLitContext(symbol)); + if (ctx) // ctx is a struct declaration. should not search beyond this struct. + { + if (isStruct) + { + auto varDec=ctx->symMap.varDec.find(symbol.name); + if (varDec != ctx->symMap.varDec.end()) + { + auto line=std::get<0>(varDec->second.pos); + auto ch=std::get<1>(varDec->second.pos); + return std::make_tuple(ctx->getFileName().value_or(""), + varDec->second.pos, std::make_pair(line, ch + symbol.name.length())); + } + } + else + { + return searchVarDeclFull(symbol.name, position); + } + } + return nullopt; + } + } + + std::list<posRangeInFile> + SymbolContext::searchLitFuncPositions(SymbolLit const& symbol, optional<posInFile> const& position) + { + if (symbol.scopes.empty()) + { + return searchFuncDeclsFull(symbol.name, position); + } + else + { + std::list<posRangeInFile> fnDecls; + auto v=searchLitContext(symbol); + auto ctx=std::get<0>(v); + auto isStruct=std::get<1>(v); + if (ctx) // ctx is a struct declaration. should not search beyond this struct. + { + if (isStruct) + { + auto fnDec=ctx->symMap.funDec.find(symbol.name); + if (fnDec != ctx->symMap.funDec.end()) + { + for (auto const& ptValue : fnDec->second) + { + fnDecls.emplace_back(getFileName().value_or(""), ptValue.pos, ptValue.pos); + } + } + } + else + { + return searchFuncDeclsFull(symbol.name, position); + } + } + return fnDecls; + } + } + + SymbolContext* SymbolContext::searchStructCtxFull(std::string const& symbol) + { + std::unordered_set<SymbolContext*> searched; + optional<std::string> tyInfo=_searchVarFull<std::string, std::string>( + symbol, + [](SymbolContext const* ctx, std::string const& sym) -> optional<std::string> + { + if (auto const* info = ctx->searchVarRaw(sym)) + { + return info->type; + } + return nullopt; + }, + fnFromDeclCreateTrav); + + + if (not tyInfo.has_value()) + { + return nullptr; + } + + return _searchVarFull<SymbolContext*>( + tyInfo.value(), std::mem_fn(&SymbolContext::searchStructContext)).value_or(nullptr); + } + + optional<SymbolContext*> SymbolContext::searchAccessDecls(std::string const& accessVal) + { + // fileIdPair includes accessVals + + auto src=extRefs.fileIdPair.find(accessVal); + if (src != extRefs.fileIdPair.end()) + { + std::string& fileSrc=src->second; + auto ctxMap=extRefs.extFileRefs.find(fileSrc); + if (ctxMap != extRefs.extFileRefs.end() && ctxMap->second != nullptr) + { + return ctxMap->second; + } + } + + return parent != nullptr ? parent->searchAccessDecls(accessVal) : nullopt; + } + + /** + * Fully search context for source structs or source file in access + * @param symbol Symbol to search + * @return pair of <code>[context, isStruct]</code>, where <code>isStruct</code> is true + * if the <code>context</code> is a struct, and false if the context is a file from access declaration. + * If context is nullptr, <code>isStruct</code>'s return does not have defined behavior. + */ + std::pair<SymbolContext*, bool> SymbolContext::searchLitContext(SymbolLit const& symbol) + { + if (symbol.scopes.empty()) + { + // if the symbol is empty, then we can access every variable, not just those in the struct context + // and hence should be treated as "not a struct", even if the variable is accessed in the struct. + // for example, + // int z; struct St { int x; int y=x+z; } + // here, x and z can be accessed in the struct context. + return std::make_pair(this, false); + } + else + { + std::vector<std::string> scopes(symbol.scopes); + bool isStruct=false; + + // search in struct + auto* ctx=searchStructCtxFull(scopes.back()); + if (ctx) + { + isStruct = true; + scopes.pop_back(); + } + else + { + // search in access declarations + ctx =_searchVarFull<SymbolContext*>( + scopes.back(), std::mem_fn(&SymbolContext::searchAccessDecls)).value_or(nullptr); + + if (ctx) + { + scopes.pop_back(); + } + } + + for (auto it = scopes.rbegin(); it != scopes.rend() and ctx != nullptr; it++) + { + // FIXME: Impelemnt scope searching + // example: + // varx.vary.varz => go into varx's type context (struct or external file), repeat. + // struct and extfile handled very differently + + // get next variable declaration loc. + // assumes struct, hence we do not search entire workspace + SymbolContext* newCtx=nullptr; + + auto locVarDec = ctx->symMap.varDec.find(*it); + if (locVarDec != ctx->symMap.varDec.end() and locVarDec->second.type.has_value()) + { + newCtx = ctx->_searchVarFull<SymbolContext*>( + locVarDec->second.type.value(), std::mem_fn(&SymbolContext::searchStructContext) + ).value_or(nullptr); + } + + // here, we searched for a struct context and did not find anything. + // If we are in a struct context, we hit a dead end. + // otherwise, we search for access declaration contexts. + if (newCtx == nullptr) + { + if (isStruct) + { + return make_pair(nullptr, false); + } + else + { + ctx =_searchVarFull<SymbolContext*>( + *it, std::mem_fn(&SymbolContext::searchAccessDecls)).value_or(nullptr); + } + } + else + { + isStruct = true; + } + + ctx = newCtx; + } + return make_pair(ctx, isStruct); + } + } + + std::unordered_set<std::string> SymbolContext::createTraverseSet() + { + std::unordered_set<std::string> traverseSet(extRefs.includeVals); + traverseSet.emplace(getPlainFile()); + for (auto const& unravelVal : extRefs.unraveledVals) + { + auto it = extRefs.fileIdPair.find(unravelVal); + if (it != extRefs.fileIdPair.end()) + { + traverseSet.emplace(it->second); + } + } + return traverseSet; + } + + SymbolContext* SymbolContext::getExternalRef(std::string const& symbol) + { + auto symRef = extRefs.extFileRefs.find(symbol); + if (symRef != extRefs.extFileRefs.end()) + { + return symRef->second; + } + + return parent != nullptr ? parent->getExternalRef(symbol) : nullptr; + } + + std::list<posRangeInFile> SymbolContext::searchFuncDecls(std::string const& symbol) + { + return searchFuncDecls(symbol, nullopt); + } + + std::list<posRangeInFile> + SymbolContext::searchFuncDecls(std::string const& symbol, optional<posInFile> const& position) + { + std::list<posRangeInFile> funcDecls; + auto pt = symMap.funDec.find(symbol); + if (pt != symMap.funDec.end()) + { + for (auto const& fnInfo : pt->second) + { + if ((not position.has_value()) or (!posLt(position.value(), fnInfo.pos))) + { + funcDecls.emplace_back(getFileName().value_or(""), fnInfo.pos, fnInfo.pos); + } + } + } + + if (parent != nullptr) + { + funcDecls.splice(funcDecls.end(), parent->searchFuncDecls(symbol, position)); + } + return funcDecls; + } + + std::list<posRangeInFile> + SymbolContext::searchFuncDeclsFull(std::string const& symbol, optional<posInFile> const& position) + { + std::unordered_set<SymbolContext*> searched; + auto retVal = _searchAllVarFull<posRangeInFile>( + searched, + std::unordered_set<std::string> { symbol }, + [&position](SymbolContext* ctx, std::string const& symbol) + { + return ctx->searchFuncDecls(symbol, position); + }, + [](SymbolContext* ctx, std::string const& symbol) + { + return ctx->searchFuncDecls(symbol); + }, + fnFromDeclCreateTrav); + + auto retValStruct =_searchAllVarFull<posRangeInFile>( + symbol, + [](SymbolContext* ctx, std::string const& sym) -> std::list<posRangeInFile> + { + std::list<posRangeInFile> finalList; + for (auto const& unravelVal : ctx->extRefs.unraveledVals) + { + if (auto* pctx=ctx->searchStructCtxFull(unravelVal)) + { + finalList.splice(finalList.end(), pctx->searchFuncDecls(sym)); + } + } + return finalList; + }); + retVal.splice(retVal.end(), std::move(retValStruct)); + return retVal; + } + + optional<posRangeInFile> AddDeclContexts::searchVarDecl( + std::string const& symbol, optional<posInFile> const& position) + { + auto pt = additionalDecs.find(symbol); + if (pt != additionalDecs.end()) + { + auto line=std::get<0>(pt->second.pos); + auto ch=std::get<1>(pt->second.pos); + if ((not position.has_value()) or (!posLt(position.value(), pt->second.pos))) + { + return std::make_tuple(getFileName().value_or(""), + pt->second.pos, + std::make_pair(line, ch + symbol.length())); + } + } + + return SymbolContext::searchVarDecl(symbol, position); + } + + SymbolInfo const* AddDeclContexts::searchVarRaw(std::string const& symbol) const + { + auto pt = additionalDecs.find(symbol); + return pt != additionalDecs.end() ? &pt->second : SymbolContext::searchVarRaw(symbol); + } + + bool SymbolInfo::operator==(SymbolInfo const& sym) const + { + return name==sym.name and type==sym.type and pos == sym.pos; + } + + std::string SymbolInfo::signature() const + { + return type.value_or("<decl-unknown>") + " " + name + ";"; + } + + std::string FunctionInfo::signature() const + { + return signature(std::vector<std::string>()); + } + + std::string FunctionInfo::signature(std::vector<std::string> const& scopes) const + { + std::stringstream ss; + ss << returnType << " "; + for (auto it=scopes.crbegin(); it!=scopes.crend(); it++) + { + ss << *it << "."; + } + ss << name << "("; + for (auto it = arguments.begin(); it != arguments.end(); it++) + { + auto const& argtype=std::get<0>(*it); + auto const& argname=std::get<1>(*it); + ss << argtype; + if (argname.has_value()) + { + ss << " " << argname.value(); + } + + if (std::next(it) != arguments.end()) + { + ss << ","; + } + + if (std::next(it) != arguments.end() or restArgs.has_value()) + { + ss << " "; + } + } + + if (restArgs.has_value()) + { + auto const& v=restArgs.value(); + auto const& argtype=std::get<0>(v); + auto const& argname=std::get<1>(v); + ss << "... " << argtype; + + if (argname.has_value()) + { + ss << " " << argname.value(); + } + } + ss << ");"; + return ss.str(); + } +} + +#endif |