#pragma once
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <utility>
#include "common.h"
#include "makeUnique.h"
#include "LibLsp/lsp/lsPosition.h"
#include "LibLsp/lsp/textDocument/documentColor.h"
namespace AsymptoteLsp
{
struct SymbolLit
{
std::string name;
std::vector<std::string> scopes;
SymbolLit(std::string symName) :
name(std::move(symName))
{
}
SymbolLit(std::string symName, std::vector<std::string> scope) :
name(std::move(symName)), scopes(std::move(scope))
{
}
~SymbolLit() = default;
SymbolLit(SymbolLit const& sym) :
name(sym.name), scopes(sym.scopes)
{
}
SymbolLit& operator=(SymbolLit const& sym)
{
name = sym.name;
scopes = sym.scopes;
return *this;
}
SymbolLit(SymbolLit&& sym) noexcept :
name(std::move(sym.name)), scopes(std::move(sym.scopes))
{
}
SymbolLit& operator=(SymbolLit&& sym) noexcept
{
name = std::move(sym.name);
scopes = std::move(sym.scopes);
return *this;
}
bool operator==(SymbolLit const& other) const
{
return name == other.name and scopes == other.scopes;
}
bool matchesRaw(std::string const& sym) const
{
return name == sym;
}
};
} // namespace AsymptoteLsp
namespace std
{
using AsymptoteLsp::SymbolLit;
template<>
struct hash<SymbolLit>
{
std::size_t operator()(SymbolLit const& sym) const
{
size_t final_hash = 0;
final_hash ^= hash<std::string>()(sym.name);
for (auto const& accessor : sym.scopes)
{
final_hash = (final_hash << 1) ^ hash<std::string>()(accessor);
}
return final_hash;
}
};
} // namespace std
namespace AsymptoteLsp
{
using std::unordered_map;
struct SymbolContext;
typedef std::pair<std::string, SymbolContext*> contextedSymbol;
typedef std::pair<size_t, size_t> posInFile;
typedef std::pair<std::string, posInFile> filePos;
typedef std::tuple<std::string, posInFile, posInFile> posRangeInFile;
typedef std::tuple<SymbolLit, posInFile, posInFile> fullSymPosRangeInFile;
// NOTE: lsPosition is zero-indexed, while all Asymptote positions (incl this struct) is 1-indexed.
inline posInFile fromLsPosition(lsPosition const& inPos)
{
return std::make_pair(inPos.line + 1, inPos.character + 1);
}
inline lsPosition toLsPosition(posInFile const& inPos)
{
return lsPosition(inPos.first - 1, inPos.second - 1);
}
inline bool posLt(posInFile const& p1, posInFile const& p2)
{
return (p1.first < p2.first) or ((p1.first == p2.first) and (p1.second < p2.second));
}
std::string getPlainFile();
bool isVirtualFile(std::string const& filename);
// filename to positions
struct positions
{
std::unordered_map<std::string, std::vector<posInFile>> pos;
positions() = default;
explicit positions(filePos const& positionInFile);
void add(filePos const& positionInFile);
};
struct SymbolInfo
{
std::string name;
optional<std::string> type;
posInFile pos;
SymbolInfo() : type(nullopt), pos(1, 1) {}
SymbolInfo(std::string inName, posInFile position):
name(std::move(inName)), type(nullopt), pos(std::move(position)) {}
SymbolInfo(std::string inName, std::string inType, posInFile position):
name(std::move(inName)), type(std::move(inType)), pos(std::move(position)) {}
SymbolInfo(SymbolInfo const& symInfo) = default;
SymbolInfo& operator=(SymbolInfo const& symInfo) = default;
SymbolInfo(SymbolInfo&& symInfo) noexcept :
name(std::move(symInfo.name)), type(std::move(symInfo.type)), pos(std::move(symInfo.pos))
{
}
SymbolInfo& operator=(SymbolInfo&& symInfo) noexcept
{
name = std::move(symInfo.name);
type = std::move(symInfo.type);
pos = std::move(symInfo.pos);
return *this;
}
virtual ~SymbolInfo() = default;
bool operator==(SymbolInfo const& sym) const;
[[nodiscard]]
virtual std::string signature() const;
};
struct FunctionInfo: SymbolInfo
{
std::string returnType;
using typeName = std::pair<std::string, optional<std::string>>;
std::vector<typeName> arguments;
optional<typeName> restArgs;
FunctionInfo(std::string name, posInFile pos, std::string returnTyp):
SymbolInfo(std::move(name), std::move(pos)),
returnType(std::move(returnTyp)),
arguments(), restArgs(nullopt) {}
~FunctionInfo() override = default;
[[nodiscard]]
std::string signature() const override;
[[nodiscard]]
std::string signature(std::vector<std::string> const& scopes) const;
};
struct TypeDec
{
posInFile position;
std::string typeName;
TypeDec(): position(1, 1) {}
virtual ~TypeDec() = default;
TypeDec(posInFile pos, std::string typName):
position(std::move(pos)), typeName(std::move(typName))
{
}
TypeDec(TypeDec const& typDec) = default;
TypeDec& operator= (TypeDec const& typDec) = default;
TypeDec(TypeDec&& typDec) noexcept = default;
TypeDec& operator= (TypeDec&& typDec) = default;
[[nodiscard]]
virtual unique_ptr<TypeDec> clone() const
{
return make_unique<TypeDec>(*this);
}
};
struct TypedefDec : public TypeDec
{
std::string destName;
};
struct SymColorInfo
{
posInFile rangeBegin;
posInFile rangeEnd;
using RGBColor = std::tuple<double, double, double>;
using RGBAColor = std::tuple<double, double, double, double>;
void setLastArgPos(posInFile lastArgPos) { lastArgPosition = std::move(lastArgPos); }
SymColorInfo() = default;
virtual ~SymColorInfo() = default;
SymColorInfo(SymColorInfo const& col) = default;
SymColorInfo& operator=(SymColorInfo const& col) = default;
SymColorInfo(SymColorInfo&& col) noexcept = default;
SymColorInfo& operator=(SymColorInfo&& col) noexcept = default;
[[nodiscard]]
virtual RGBColor getRGBColor() const = 0;
[[nodiscard]]
virtual double getAlpha() const
{
return 1;
}
[[nodiscard]]
RGBAColor getRGBAColor() const
{
RGBColor c=getRGBColor();
auto const& red=std::get<0>(c);
auto const& green=std::get<1>(c);
auto const& blue=std::get<2>(c);
return RGBAColor(red,green,blue,getAlpha());
}
explicit operator TextDocument::Color() const
{
TextDocument::Color col;
RGBAColor c=getRGBAColor();
col.red=std::get<0>(c);
col.green=std::get<1>(c);
col.blue=std::get<2>(c);
col.alpha=std::get<3>(c);
return col;
}
[[nodiscard]]
virtual unique_ptr<SymColorInfo> clone() const = 0;
public:
posInFile lastArgPosition;
};
struct RGBSymColorInfo : SymColorInfo
{
double red, green, blue;
RGBSymColorInfo(): SymColorInfo(), red(0), green(0), blue(0) {}
RGBSymColorInfo(double redVal, double greenVal, double blueVal):
SymColorInfo(),
red(redVal), green(greenVal), blue(blueVal)
{
}
RGBSymColorInfo(RGBSymColorInfo const& col) = default;
RGBSymColorInfo& operator=(RGBSymColorInfo const& col) = default;
[[nodiscard]]
RGBColor getRGBColor() const override
{
return RGBColor(red, green, blue);
}
[[nodiscard]]
unique_ptr<SymColorInfo> clone() const override
{
return unique_ptr<SymColorInfo>(new RGBSymColorInfo(*this));
}
};
struct RGBASymColorInfo : RGBSymColorInfo
{
double alpha;
RGBASymColorInfo(): RGBSymColorInfo(), alpha(1) {}
RGBASymColorInfo(double redVal, double greenVal, double blueVal, double alphaVal):
RGBSymColorInfo(redVal, greenVal, blueVal), alpha(alphaVal)
{
}
[[nodiscard]]
double getAlpha() const override
{
return alpha;
}
[[nodiscard]]
unique_ptr<SymColorInfo> clone() const override
{
return unique_ptr<SymColorInfo>(new RGBASymColorInfo(*this));
}
};
struct StructDecs : public TypeDec
{
SymbolContext* ctx;
StructDecs(): TypeDec(), ctx(nullptr) {}
~StructDecs() override = default;
StructDecs(posInFile pos, std::string typName) :
TypeDec(std::move(pos), std::move(typName)), ctx(nullptr)
{
}
StructDecs(posInFile pos, std::string typName, SymbolContext* ctx) :
TypeDec(std::move(pos), std::move(typName)), ctx(ctx)
{
}
[[nodiscard]]
unique_ptr<TypeDec> clone() const override
{
return std::unique_ptr<TypeDec>(new StructDecs(*this));
}
};
struct SymbolMaps
{
unordered_map <std::string, SymbolInfo> varDec;
unordered_map <std::string, std::vector<FunctionInfo>> funDec;
// can refer to other files
unordered_map <SymbolLit, positions> varUsage;
unordered_map <std::string, unique_ptr<TypeDec>> typeDecs;
// python equivalent of dict[str, list[tuple(pos, sym)]]
// filename -> list[(position, symbol)]
std::vector<std::pair<posInFile, SymbolLit>> usageByLines;
SymbolMaps() = default;
~SymbolMaps() = default;
SymbolMaps(SymbolMaps const& symMap) :
varDec(symMap.varDec), funDec(symMap.funDec), varUsage(symMap.varUsage), typeDecs(),
usageByLines(symMap.usageByLines)
{
for(auto const& t : symMap.typeDecs)
{
auto const& ty=std::get<0>(t);
auto const& tyDec=std::get<1>(t);
typeDecs.emplace(ty, tyDec != nullptr ? tyDec->clone() : nullptr);
}
}
SymbolMaps& operator=(SymbolMaps const& symMap)
{
varDec = symMap.varDec;
funDec = symMap.funDec;
varUsage = symMap.varUsage;
usageByLines = symMap.usageByLines;
typeDecs.clear();
for(auto const& t : symMap.typeDecs)
{
auto const& ty=std::get<0>(t);
auto const& tyDec=std::get<1>(t);
typeDecs.emplace(ty, tyDec != nullptr ? tyDec->clone() : nullptr);
}
return *this;
}
SymbolMaps(SymbolMaps&& symMap) noexcept:
varDec(std::move(symMap.varDec)), funDec(std::move(symMap.funDec)), varUsage(std::move(symMap.varUsage)),
typeDecs(std::move(symMap.typeDecs)), usageByLines(std::move(symMap.usageByLines))
{
}
SymbolMaps& operator=(SymbolMaps&& symMap) noexcept
{
varDec = std::move(symMap.varDec);
funDec = std::move(symMap.funDec);
varUsage = std::move(symMap.varUsage);
usageByLines = std::move(symMap.usageByLines);
typeDecs = std::move(symMap.typeDecs);
return *this;
}
inline void clear()
{
varDec.clear();
funDec.clear();
varUsage.clear();
usageByLines.clear();
typeDecs.clear();
}
optional<fullSymPosRangeInFile> searchSymbol(posInFile const& inputPos);
FunctionInfo& addFunDef(std::string const& funcName, posInFile const& position, std::string const& returnType);
private:
friend ostream& operator<<(std::ostream& os, const SymbolMaps& sym);
};
struct ExternalRefs
{
// file interactions
// access -> (file, id)
// unravel -> id
// include -> file
// import = acccess + unravel
using extRefMap = std::unordered_map<std::string, SymbolContext*>;
extRefMap extFileRefs;
std::unordered_map<std::string, std::string> fileIdPair;
std::unordered_set<std::string> includeVals;
std::unordered_set<std::string> unraveledVals;
std::unordered_set<std::string> accessVals;
std::unordered_map<std::string, std::pair<std::string, std::string>> fromAccessVals;
ExternalRefs() = default;
virtual ~ExternalRefs() = default;
ExternalRefs(ExternalRefs const& exRef) = default;
ExternalRefs& operator=(ExternalRefs const& exRef) = default;
// ExternalRefs(ExternalRefs&& exRef) noexcept = default;
// ExternalRefs& operator=(ExternalRefs&& exRef) noexcept = default;
void clear()
{
extFileRefs.clear();
fileIdPair.clear();
includeVals.clear();
unraveledVals.clear();
accessVals.clear();
fromAccessVals.clear();
}
bool addEmptyExtRef(std::string const& fileName)
{
auto success=std::get<1>(extFileRefs.emplace(fileName, nullptr));
return success;
}
bool addAccessVal(std::string const& symbol)
{
auto success=std::get<1>(accessVals.emplace(symbol));
return success;
}
bool addUnravelVal(std::string const& symbol)
{
auto success=std::get<1>(unraveledVals.emplace(symbol));
return success;
}
bool addFromAccessVal(std::string const& fileName, std::string const& symbolSrc, std::string const& symbolDest)
{
auto success=std::get<1>(fromAccessVals.emplace(symbolDest, make_pair(symbolSrc, fileName)));
return success;
}
};
struct SymbolContext
{
optional<std::string> fileLoc;
posInFile contextLoc;
SymbolContext* parent;
SymbolMaps symMap;
// file interactions
// access -> (file, id)
// unravel -> id
// include -> file
// import = acccess + unravel
ExternalRefs extRefs;
std::vector<std::unique_ptr<SymColorInfo>> colorInformation;
std::vector<std::unique_ptr<SymbolContext>> subContexts;
SymbolContext():
parent(nullptr)
{
}
virtual ~SymbolContext() = default;
explicit SymbolContext(posInFile loc);
explicit SymbolContext(posInFile loc, std::string filename);
SymbolContext(posInFile loc, SymbolContext* contextParent):
fileLoc(nullopt), contextLoc(std::move(loc)), parent(contextParent)
{
}
template<typename T=SymbolContext, typename=std::enable_if<std::is_base_of<SymbolContext, T>::value>>
T* newContext(posInFile const& loc)
{
subContexts.emplace_back(make_unique<T>(loc, this));
return static_cast<T*>(subContexts.back().get());
}
template<typename T=TypeDec, typename=std::enable_if<std::is_base_of<TypeDec, T>::value>>
T* newTypeDec(std::string const& tyName, posInFile const& loc)
{
auto s=symMap.typeDecs.emplace(tyName, make_unique<T>(loc, tyName));
auto it=std::get<0>(s);
auto succ=std::get<1>(s);
return succ ? static_cast<T*>(it->second.get()) : static_cast<T*>(nullptr);
}
SymbolContext(SymbolContext const& symCtx) :
fileLoc(symCtx.fileLoc), contextLoc(symCtx.contextLoc),
parent(symCtx.parent), symMap(symCtx.symMap),
extRefs(symCtx.extRefs)
{
for (auto& ctx : symCtx.subContexts)
{
subContexts.push_back(make_unique<SymbolContext>(*ctx));
}
for (auto& col : symCtx.colorInformation)
{
colorInformation.emplace_back(col != nullptr ? col->clone() : nullptr);
}
}
SymbolContext& operator= (SymbolContext const& symCtx)
{
fileLoc = symCtx.fileLoc;
contextLoc = symCtx.contextLoc;
parent = symCtx.parent;
symMap = symCtx.symMap;
extRefs = symCtx.extRefs;
subContexts.clear();
for (auto& ctx : symCtx.subContexts)
{
subContexts.push_back(make_unique<SymbolContext>(*ctx));
}
colorInformation.clear();
for (auto& col : symCtx.colorInformation)
{
colorInformation.emplace_back(col != nullptr ? col->clone() : nullptr);
}
return *this;
}
SymbolContext(SymbolContext&& symCtx) noexcept :
fileLoc(std::move(symCtx.fileLoc)), contextLoc(std::move(symCtx.contextLoc)),
parent(symCtx.parent), symMap(std::move(symCtx.symMap)),
extRefs(std::move(symCtx.extRefs)),
colorInformation(std::move(symCtx.colorInformation)), subContexts(std::move(symCtx.subContexts))
{
}
SymbolContext& operator= (SymbolContext&& symCtx) noexcept
{
fileLoc = std::move(symCtx.fileLoc);
contextLoc = std::move(symCtx.contextLoc);
parent = symCtx.parent;
symMap = std::move(symCtx.symMap);
extRefs = std::move(symCtx.extRefs);
colorInformation = std::move(symCtx.colorInformation);
subContexts = std::move(symCtx.subContexts);
return *this;
}
// [file, start, end]
virtual std::pair<optional<fullSymPosRangeInFile>, SymbolContext*> searchSymbol(posInFile const& inputPos);
// declarations
optional<posRangeInFile> searchVarDecl(std::string const& symbol)
{
return searchVarDecl(symbol, nullopt);
}
virtual optional<posRangeInFile> searchVarDecl(std::string const& symbol,
optional<posInFile> const& position);
virtual optional<posRangeInFile> searchVarDeclFull(std::string const& symbol,
optional<posInFile> const& position=nullopt);
virtual SymbolInfo const* searchVarRaw(std::string const& symbol) const;
std::list<posRangeInFile> searchFuncDecls(std::string const& symbol);
virtual std::list<posRangeInFile> searchFuncDecls(
std::string const& symbol, optional<posInFile> const& position);
std::list<posRangeInFile> searchFuncDeclsFull(std::string const& symbol,
optional<posInFile> const& position=nullopt);
// variable signatures
optional<std::string> searchVarSignatureFull(std::string const& symbol);
virtual std::list<std::string> searchFuncSignature(std::string const& symbol);
virtual std::list<std::string> searchFuncSignatureFull(std::string const& symbol);
optional<std::string> searchLitSignature(SymbolLit const& symbol);
std::list<std::string> searchLitFuncSignature(SymbolLit const& symbol);
optional<posRangeInFile> searchLitPosition(
SymbolLit const& symbol, optional<posInFile> const& position=nullopt);
std::list<posRangeInFile> searchLitFuncPositions(
SymbolLit const& symbol, optional<posInFile> const& position=nullopt);
virtual std::list<ExternalRefs::extRefMap::iterator> getEmptyRefs();
optional<std::string> getFileName() const;
SymbolContext* getParent()
{
return parent == nullptr ? this : parent->getParent();
}
bool addEmptyExtRef(std::string const& fileName)
{
return extRefs.addEmptyExtRef(fileName);
}
void reset(std::string const& newFile)
{
fileLoc = newFile;
contextLoc = std::make_pair(1,1);
clear();
}
void clear()
{
parent = nullptr;
symMap.clear();
extRefs.clear();
clearColorInformation();
subContexts.clear();
}
void clearColorInformation()
{
colorInformation.clear();
}
void addRGBColor(
std::tuple<double, double, double> const& c,
posInFile const& posBegin,
posInFile const& lastArgs)
{
auto const& red=std::get<0>(c);
auto const& green=std::get<1>(c);
auto const& blue=std::get<2>(c);
colorInformation.emplace_back(make_unique<RGBSymColorInfo>(red,green,blue));
auto const& ptr=colorInformation.back();
ptr->rangeBegin = posBegin;
ptr->setLastArgPos(lastArgs);
}
void addRGBAColor(
std::tuple<double, double, double, double> const& c,
posInFile const& posBegin,
posInFile const& lastArgs)
{
auto const& red=std::get<0>(c);
auto const& green=std::get<1>(c);
auto const& blue=std::get<2>(c);
auto const& alpha=std::get<3>(c);
colorInformation.emplace_back(make_unique<RGBASymColorInfo>(red,green,blue,alpha));
auto const& ptr=colorInformation.back();
ptr->rangeBegin = posBegin;
ptr->setLastArgPos(lastArgs);
}
protected:
using SymCtxSet = std::unordered_set<SymbolContext*>;
// search var full
template<
typename TArg,
template<typename...> class TMapTraverse=std::unordered_map,
template<typename...> class TContainerArg=std::unordered_set
>
using SymbolArgContainer = TMapTraverse<std::string, TContainerArg<TArg>>;
template<
typename TArg,
template<typename...> class TMapTraverse=std::unordered_map,
template<typename...> class TContainerArg=std::unordered_set,
template<typename...> class TArgContainer=std::unordered_set
>
using FnCreateSymbolArgContainer =
std::function<SymbolArgContainer<TArg, TMapTraverse, TContainerArg>(SymbolContext*, TArgContainer<TArg> const&)>;
template<typename TArg>
SymbolArgContainer<TArg> defaultCreateTraverse(std::unordered_set<TArg> const& searchSet)
{
SymbolArgContainer<TArg> retVal;
for (auto const& traverseVal : createTraverseSet())
{
retVal.emplace(traverseVal, searchSet);
}
return retVal;
}
SymbolArgContainer<std::string> fromDeclCreateTraverse(std::unordered_set<std::string> const& symbols)
{
// base
SymbolArgContainer<std::string> base=defaultCreateTraverse(symbols);
for (auto const& sym : symbols)
{
auto aliasSearch = extRefs.fromAccessVals.find(sym);
if (aliasSearch != extRefs.fromAccessVals.end())
{
// there's an alias to dest -> [src, ctx].
auto const& src=std::get<0>(aliasSearch->second);
auto const& fileName=std::get<1>(aliasSearch->second);
auto baseTrav = base.find(fileName);
if (baseTrav == base.end())
{
base.emplace(fileName, std::unordered_set<std::string> { src });
}
else
{
baseTrav->second.emplace(src);
}
}
}
return base;
}
FnCreateSymbolArgContainer<std::string> const fnFromDeclCreateTrav =
std::mem_fn(&SymbolContext::fromDeclCreateTraverse);
template<typename TRet, typename TArg, typename TFn>
optional<TRet> _searchVarFull(
TArg init, TFn const& fnLocalPredicate,
FnCreateSymbolArgContainer<TArg> const& fnCreateTraverse=
std::mem_fn(&SymbolContext::defaultCreateTraverse<TArg>))
{
std::unordered_set<SymbolContext*> searched;
std::unordered_set<TArg> initSet { init };
return _searchVarFull<TRet, TArg, TFn, TFn>(
searched, initSet, fnLocalPredicate, fnLocalPredicate, fnCreateTraverse);
}
template<typename TRet, typename TArg, typename TFn, typename TFn2>
optional<TRet> _searchVarFull(
std::unordered_set<SymbolContext*>& searched,
std::unordered_set<TArg> const& searchArgs,
TFn const& fnLocalPredicate, TFn2 const& fnLocalPredicateFirst,
FnCreateSymbolArgContainer<TArg> const& fnCreateTraverse)
{
auto p=searched.emplace(getParent());
auto const& notSearched=std::get<1>(p);
if (not notSearched)
{
// a loop in the search path. Stop now.
return nullopt;
}
// local search first
for (TArg const& arg : searchArgs)
{
optional<TRet> returnVal=fnLocalPredicateFirst(this, arg);
if (returnVal.has_value())
{
return returnVal;
}
}
return searchVarExt<TRet, TArg, TFn>(searched, searchArgs, fnLocalPredicate, fnCreateTraverse);
}
template<typename TRet, typename TArg, typename TFn>
optional<TRet> searchVarExt(
std::unordered_set<SymbolContext*>& searched,
std::unordered_set<TArg> const& searchArgs,
TFn const& fnLocalPredicate,
FnCreateSymbolArgContainer<TArg> const& fnCreateTraverse)
{
using travType = std::pair<std::string, std::unordered_set<TArg>>;
for (travType const travArg : fnCreateTraverse(this, searchArgs))
{
std::string const traverseVal = travArg.first;
std::unordered_set<TArg> const argSet = travArg.second;
if (traverseVal == getFileName())
{
continue;
}
if (SymbolContext* ref=getExternalRef(traverseVal))
{
optional<TRet> returnValF = ref->_searchVarFull<TRet, TArg, TFn, TFn>(
searched, argSet,
fnLocalPredicate, fnLocalPredicate,
fnCreateTraverse);
if (returnValF.has_value())
{
return returnValF;
}
}
}
return nullopt;
}
// search all var full
template<typename TRet, typename TArg, typename TFn>
std::list<TRet> _searchAllVarFull(
TArg init,
TFn const& fnLocalPredicate,
FnCreateSymbolArgContainer<TArg> const& fnCreateTraverse=
std::mem_fn(&SymbolContext::defaultCreateTraverse<TArg>))
{
std::unordered_set<SymbolContext*> searched;
std::unordered_set<TArg> initSet { init };
return _searchAllVarFull<TRet, TArg, TFn, TFn>(
searched, initSet, fnLocalPredicate, fnLocalPredicate, fnCreateTraverse);
}
template<typename TRet, typename TArg, typename TFn, typename TFn2>
std::list<TRet> _searchAllVarFull(
std::unordered_set<SymbolContext*>& searched,
std::unordered_set<TArg> const& searchArgs,
TFn const& fnLocalPredicate, TFn2 const& fnLocalPredicateFirst,
FnCreateSymbolArgContainer<TArg> const& fnCreateTraverse)
{
auto p=searched.emplace(getParent());
auto const& notSearched=std::get<1>(p);
if (not notSearched)
{
// a loop in the search path. Stop now.
return std::list<TRet>();
}
std::list<TRet> returnVal;
// local search first
for (TArg const& arg : searchArgs)
{
returnVal.splice(returnVal.end(), fnLocalPredicateFirst(this, arg));
}
returnVal.splice(returnVal.end(), searchAllVarExt<TRet, TArg, TFn>(
searched, searchArgs, fnLocalPredicate, fnCreateTraverse));
return returnVal;
}
template<typename TRet, typename TArg, typename TFn>
std::list<TRet> searchAllVarExt(
std::unordered_set<SymbolContext*>& searched,
std::unordered_set<TArg> const& searchArgs,
TFn const& fnLocalPredicate,
FnCreateSymbolArgContainer<TArg> const& fnCreateTraverse)
{
using travType = std::pair<std::string, std::unordered_set<TArg>>;
std::list<TRet> finalList;
for (travType const travArg : fnCreateTraverse(this, searchArgs))
{
std::string const traverseVal = travArg.first;
std::unordered_set<TArg> const argSet = travArg.second;
if (traverseVal == getFileName())
{
continue;
}
if (SymbolContext* ref=getExternalRef(traverseVal))
{
auto returnValF=ref->_searchAllVarFull<TRet, TArg, TFn, TFn>(
searched, argSet,
fnLocalPredicate, fnLocalPredicate,
fnCreateTraverse);
finalList.splice(finalList.end(), std::move(returnValF));
}
}
return finalList;
}
virtual optional<SymbolContext*> searchStructContext(std::string const& tyVal) const;
SymbolContext* searchStructCtxFull(std::string const&);
optional<SymbolContext*> searchAccessDecls(std::string const&);
virtual std::pair<SymbolContext*, bool> searchLitContext(SymbolLit const& symbol);
virtual std::unordered_set<std::string> createTraverseSet();
virtual SymbolContext* getExternalRef(std::string const&);
std::list<std::string> searchFuncUnravelStruct(std::string const& symbol);
SymbolInfo* searchVarUnravelStructRaw(std::string const& symbol);
SymbolInfo* searchVarUnravelStructRaw(std::string const& symbol, optional<posInFile> const& position);
void addPlainFile();
};
struct AddDeclContexts: SymbolContext
{
unordered_map <std::string, SymbolInfo> additionalDecs;
AddDeclContexts(): SymbolContext() {}
explicit AddDeclContexts(posInFile loc):
SymbolContext(loc) {}
AddDeclContexts(posInFile loc, SymbolContext* contextParent):
SymbolContext(loc, contextParent) {}
~AddDeclContexts() override = default;
optional<posRangeInFile> searchVarDecl(std::string const& symbol, optional<posInFile> const& position) override;
SymbolInfo const* searchVarRaw(std::string const& symbol) const override;
};
}