* @file
*
* This file implements name mangling utils.
*/
#include "cangjie/Mangle/BaseMangler.h"
#include <sstream>
#include "Compression.h"
#include "cangjie/AST/Match.h"
#include "cangjie/AST/Types.h"
#include "cangjie/AST/Utils.h"
#include "cangjie/AST/Walker.h"
#include "cangjie/Basic/Match.h"
#include "cangjie/Utils/FileUtil.h"
#include "cangjie/Utils/StdUtils.h"
using namespace Cangjie;
using namespace AST;
using namespace Meta;
namespace {
Ptr<const Decl> GetParentDecl(const FuncDecl& funcDecl)
{
auto fd = RawStaticCast<const FuncDecl*>(&funcDecl);
auto outerDecl = funcDecl.outerDecl;
if (fd->funcBody->parentClassLike != nullptr) {
outerDecl = fd->funcBody->parentClassLike;
} else if (fd->funcBody->parentStruct != nullptr) {
outerDecl = fd->funcBody->parentStruct;
} else if (fd->funcBody->parentEnum != nullptr) {
outerDecl = fd->funcBody->parentEnum;
}
return outerDecl;
}
const std::unordered_map<std::string, std::unordered_map<std::string, std::string>> SPECIAL_FUNC_NAMES = {
{CORE_PACKAGE_NAME,
{
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
{"throwGlobalOutOfMemoryError", "rt$ThrowGlobalOutOfMemoryError"},
{"throwStackOverflowError", "rt$ThrowStackOverflowError"},
#endif
{"throwOutOfMemoryError", "rt$ThrowOutOfMemoryError"},
{"throwImplicitException", "rt$ThrowImplicitException"},
{"throwArithmeticException", "rt$ThrowArithmeticException"},
{"throwArithmeticExceptionMsg", "rt$ThrowArithmeticException_msg"},
{"createArithmeticExceptionMsg", "rt$CreateArithmeticException_msg"},
{"createOverflowExceptionMsg", "rt$CreateOverflowException_msg"},
{"throwOverflowException", "rt$ThrowOverflowException"},
{"throwIndexOutOfBoundsException", "rt$ThrowIndexOutOfBoundsException"},
{"throwNegativeArraySizeException", "rt$ThrowNegativeArraySizeException"},
{"callToString", "rt$CallToString"},
{"checkIsError", "rt$CheckIsError"},
{"throwError", "rt$ThrowError"},
{"callPrintStackTrace", "rt$CallPrintStackTrace"},
{"callPrintStackTraceError", "rt$CallPrintStackTraceError"},
}},
};
std::optional<std::string> GetSpecialFuncName(const FuncDecl& fd)
{
auto found = SPECIAL_FUNC_NAMES.find(fd.fullPackageName);
if (found == SPECIAL_FUNC_NAMES.end()) {
return std::nullopt;
}
auto& nameMap = found->second;
if (auto has = nameMap.find(fd.identifier); has != nameMap.end()) {
return {has->second};
}
return std::nullopt;
}
inline std::string ToHex(uint64_t val)
{
std::stringstream ss;
constexpr int width = 2;
ss << MANGLE_DOLLAR_PREFIX << std::hex << std::uppercase << std::setfill('0') << std::setw(width) << val;
return ss.str();
}
bool IsMangledToExportForTestBefore(const Decl& decl, const std::vector<Ptr<Node>>& prefix)
{
if (decl.TestAttr(Attribute::FOR_TEST)) {
return true;
}
for (auto& node : prefix) {
if (node->TestAttr(Attribute::FOR_TEST)) {
return true;
}
}
return false;
}
uint32_t Fnv1aHash(const std::string& str)
{
constexpr uint32_t fnvOffsetBasis = 2166136261;
constexpr uint32_t fnvPrime = 16777619;
uint32_t hash = fnvOffsetBasis;
for (char c : str) {
hash ^= static_cast<uint8_t>(c);
hash *= fnvPrime;
}
return hash;
}
std::string ToBase62(uint64_t value)
{
const std::string base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string result;
while (value > 0) {
result.push_back(base62Chars[value % base62Chars.size()]);
value /= base62Chars.size();
}
size_t length = 13;
while (result.size() < length) {
result.push_back(base62Chars[0]);
}
std::reverse(result.begin(), result.end());
return result.size() > length ? result.substr(0, length) : result;
}
}
namespace Cangjie::MangleUtils {
std::string MangleFilePrivate(const AST::Decl& decl)
{
constexpr size_t cjExtLen = 3;
constexpr size_t maxLen = 16;
CJC_NULLPTR_CHECK(decl.curFile);
const size_t filenameLen = decl.curFile->fileName.size();
if (filenameLen <= maxLen + cjExtLen) {
return MangleUtils::MangleName(MANGLE_DOLLAR_PREFIX + decl.curFile->fileName.substr(0, filenameLen - cjExtLen));
}
return MangleUtils::MangleName(ToHex(decl.curFile->fileHash));
}
std::string DecimalToManglingNumber(const std::string& decimal)
{
const std::string base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const int base62num = static_cast<int>(base62Chars.size());
for (size_t i = 0; i < decimal.length(); i++) {
if (!std::isdigit(decimal[i])) {
return "";
}
}
auto numOpt = Stoi(decimal);
if (!numOpt.has_value()) {
return "";
}
int num = *numOpt - 1;
if (num < 0) {
return MANGLE_WILDCARD_PREFIX;
}
std::string base62 = num > 0 ? "" : "0";
while (num > 0) {
base62 += base62Chars[static_cast<size_t>(num % base62num)];
num /= base62num;
}
return base62 + MANGLE_WILDCARD_PREFIX;
}
}
std::string BaseMangler::MangleFullPackageName(const std::string& packageName) const
{
std::string orgName;
std::string newPkgName = packageName;
size_t pos = packageName.find(TOKENS[static_cast<int>(TokenKind::DOUBLE_COLON)]);
if (pos != std::string::npos) {
orgName = packageName.substr(0, pos + 1);
auto sz = std::string_view{TOKENS[static_cast<int>(TokenKind::DOUBLE_COLON)]}.size();
if (packageName.length() > pos + sz) {
newPkgName = packageName.substr(pos + sz, packageName.length() - pos - sz);
} else {
newPkgName = "";
}
}
if (MangleUtils::STD_PKG_MANGLE.find(newPkgName) != MangleUtils::STD_PKG_MANGLE.end()) {
return MangleUtils::STD_PKG_MANGLE.at(newPkgName);
}
return MangleUtils::MangleName(orgName + newPkgName);
}
std::string BaseMangler::MangleFullPackageName(const AST::Decl& decl) const
{
return MangleFullPackageName(decl.GetFullPackageName());
}
std::string BaseMangler::GetPrefixOfType(const AST::Ty& ty) const
{
switch (ty.kind) {
case TypeKind::TYPE_ENUM: {
return MANGLE_TYPE_ENUM_PREFIX;
}
case TypeKind::TYPE_INTERFACE:
case TypeKind::TYPE_CLASS: {
return MANGLE_TYPE_CLASS_PREFIX;
}
case TypeKind::TYPE_STRUCT: {
return MANGLE_TYPE_STRUCT_PREFIX;
}
default: {
CJC_ASSERT(false && "unexpected type to be mangled");
return "";
}
}
}
std::string BaseMangler::MangleUserDefinedType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack,
bool declare, bool isCollectGTy) const
{
static const std::set<TypeKind> SUPPORT_TYS = {
TypeKind::TYPE_ENUM, TypeKind::TYPE_STRUCT, TypeKind::TYPE_CLASS, TypeKind::TYPE_INTERFACE};
if (SUPPORT_TYS.find(ty.kind) == SUPPORT_TYS.end()) {
CJC_ASSERT(false && "unexpected type to be mangled");
return "";
}
auto decl = Ty::GetDeclOfTy(&ty);
CJC_NULLPTR_CHECK(decl);
if (MangleUtils::IsAutoBoxedBaseDecl(*decl)) {
return decl->mangledName;
}
auto mangledName = GetPrefixOfType(ty) + MANGLE_NESTED_PREFIX;
std::string genericPkgName = ManglePackageNameForGeneric(*decl);
mangledName += genericPkgName.empty() ? MangleFullPackageName(*decl) : genericPkgName;
if (decl->TestAttr(Attribute::PRIVATE) && decl->linkage == Linkage::INTERNAL) {
std::string fileName = decl->curFile->fileName;
mangledName += MANGLE_FILE_ID_PREFIX +
(IsHashable(fileName) ? HashToBase62(fileName)
: (FileNameWithoutExtension(fileName) + MANGLE_DOLLAR_PREFIX));
}
mangledName += MangleUtils::MangleName(decl->identifier);
if (decl->GetGeneric()) {
mangledName += MANGLE_GENERIC_PREFIX;
}
for (auto arg : ty.typeArgs) {
mangledName += MangleType(*arg, genericsTypeStack, declare, isCollectGTy);
}
mangledName += MANGLE_SUFFIX;
return mangledName;
}
std::string BaseMangler::MangleType(const AST::Ty& ty) const
{
std::vector<std::string> genericsTypeStack;
return MangleType(ty, genericsTypeStack, true);
}
std::string BaseMangler::MangleType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack,
bool declare, bool isCollectGTy) const
{
if (MangleUtils::PRIMITIVE_TYPE_MANGLE.count(ty.kind) != 0) {
return MangleUtils::PRIMITIVE_TYPE_MANGLE.at(ty.kind);
}
if (ty.kind == TypeKind::TYPE_GENERICS) {
if (declare || isCollectGTy) {
return MangleGenericType(ty, genericsTypeStack, declare);
} else {
return MangleGenericType(ty);
}
} else if (ty.kind == TypeKind::TYPE_POINTER) {
return MangleCPointerType(ty, genericsTypeStack, declare, isCollectGTy);
} else if (ty.kind == TypeKind::TYPE_ENUM) {
return MangleEnumType(ty, genericsTypeStack, declare, isCollectGTy);
} else if (ty.kind == TypeKind::TYPE_ARRAY) {
return MangleRawArrayType(ty, genericsTypeStack, declare, isCollectGTy);
} else if (ty.kind == TypeKind::TYPE_VARRAY) {
return MangleVArrayType(ty, genericsTypeStack, declare, isCollectGTy);
} else if (ty.kind == TypeKind::TYPE_TUPLE) {
return MangleTupleType(ty, genericsTypeStack, declare, isCollectGTy);
} else if (ty.kind == TypeKind::TYPE_FUNC) {
return MangleFuncType(ty, genericsTypeStack, declare, isCollectGTy);
} else if (ty.kind == TypeKind::TYPE_STRUCT || ty.kind == TypeKind::TYPE_INTERFACE ||
ty.kind == TypeKind::TYPE_CLASS) {
return MangleUserDefinedType(ty, genericsTypeStack, declare, isCollectGTy);
} else if (ty.kind == TypeKind::TYPE_CSTRING) {
return MangleCStringType();
}
return "";
}
std::string BaseMangler::MangleGenericArgumentsHelper(const Decl& decl, std::vector<std::string>& genericsTypeStack,
bool declare, bool isCollectGTy) const
{
std::string mangled;
std::vector<Ptr<Ty>> args;
if (decl.GetTy() && !decl.GetTy()->IsFunc()) {
args = decl.GetTy()->typeArgs;
} else if (decl.astKind == ASTKind::FUNC_DECL) {
auto& fd = StaticCast<const FuncDecl&>(decl);
if (fd.funcBody->generic) {
for (auto& arg : fd.funcBody->generic->typeParameters) {
args.push_back(arg->GetTy());
}
}
}
if (args.empty()) {
return "";
}
mangled += MANGLE_GENERIC_PREFIX;
for (auto it : args) {
mangled += MangleType(*it, genericsTypeStack, declare, isCollectGTy);
}
return mangled;
}
std::string BaseMangler::MangleGenericArguments(const Decl& decl, std::vector<std::string>& genericsTypeStack,
bool declare) const
{
return MangleGenericArgumentsHelper(decl, genericsTypeStack, declare, false);
}
std::string BaseMangler::MangleVarDecl(const AST::Decl& decl, const std::vector<Ptr<AST::Node>>& prefix) const
{
std::string mangleStr = MANGLE_CANGJIE_PREFIX + MANGLE_NESTED_PREFIX;
std::vector<std::string> genericsTypeStack;
mangleStr += ManglePrefix(decl, prefix, genericsTypeStack, false);
mangleStr += MangleUtils::MangleName(decl.identifier.Val());
if (IsLocalVariable(decl) && manglerCtxTable.find(decl.fullPackageName) != manglerCtxTable.end()) {
mangleStr += MANGLE_COUNT_PREFIX;
auto manglerCtx = manglerCtxTable.at(decl.fullPackageName).get();
if (!manglerCtx) {
return "";
}
auto findOuterNodeOfLocalVariable = [&prefix]() {
for (auto item = prefix.rbegin(); item != prefix.rend(); ++item) {
auto curPrefix = *item;
if (curPrefix->astKind == AST::ASTKind::FUNC_DECL ||
curPrefix->astKind == AST::ASTKind::PRIMARY_CTOR_DECL ||
curPrefix->astKind == AST::ASTKind::LAMBDA_EXPR ||
curPrefix->astKind == AST::ASTKind::CLASS_DECL ||
curPrefix->astKind == AST::ASTKind::INTERFACE_DECL ||
curPrefix->astKind == AST::ASTKind::STRUCT_DECL ||
(Is<VarDeclAbstract>(curPrefix) && curPrefix->TestAttr(Attribute::GLOBAL))) {
return curPrefix;
}
}
return Ptr<AST::Node>();
};
Ptr<Node> outerNode = findOuterNodeOfLocalVariable();
if (outerNode) {
if (outerNode->astKind == AST::ASTKind::CLASS_DECL ||
outerNode->astKind == AST::ASTKind::INTERFACE_DECL ||
outerNode->astKind == AST::ASTKind::STRUCT_DECL) {
mangleStr += MangleUtils::DecimalToManglingNumber("0");
} else {
std::optional<size_t> index = manglerCtx->GetIndexOfVar(outerNode,
StaticCast<const AST::VarDecl*>(&decl));
CJC_ASSERT(index.has_value() && "index of local variable is not found.");
mangleStr += MangleUtils::DecimalToManglingNumber(std::to_string(index.value()));
}
}
}
mangleStr += MANGLE_SUFFIX;
return mangleStr;
}
std::optional<size_t> BaseMangler::GetIndexOfWildcard(
const AST::VarWithPatternDecl& vwpDecl, const std::vector<Ptr<AST::Node>>& prefix) const
{
CJC_ASSERT(ManglerContext::CheckAllElementsWildcard(vwpDecl.irrefutablePattern.get()));
std::string pkgName = ManglerContext::ReduceUnitTestPackageName(vwpDecl.fullPackageName);
CJC_ASSERT(!pkgName.empty() && "pkgName of varWithPatternDecl is empty.");
CJC_ASSERT(manglerCtxTable.find(pkgName) != manglerCtxTable.end() && "can not find pkgName in manglerCtxTable.");
auto mangleCtx = manglerCtxTable.at(pkgName);
CJC_NULLPTR_CHECK(mangleCtx.get());
std::optional<size_t> index = {};
if (vwpDecl.TestAttr(Attribute::GLOBAL)) {
index = mangleCtx->GetIndexOfGlobalWildcardVar(vwpDecl.curFile, &vwpDecl);
} else {
for (auto item = prefix.rbegin(); item != prefix.rend(); ++item) {
auto curPrefix = *item;
if (curPrefix->astKind == AST::ASTKind::FUNC_DECL ||
curPrefix->astKind == AST::ASTKind::PRIMARY_CTOR_DECL ||
curPrefix->astKind == AST::ASTKind::LAMBDA_EXPR || curPrefix->astKind == AST::ASTKind::CLASS_DECL ||
curPrefix->astKind == AST::ASTKind::INTERFACE_DECL || curPrefix->astKind == AST::ASTKind::STRUCT_DECL ||
(Is<VarDeclAbstract>(curPrefix) && curPrefix->TestAttr(Attribute::GLOBAL))) {
index = mangleCtx->GetIndexOfLocalWildcardVar(curPrefix, &vwpDecl);
break;
}
}
}
CJC_ASSERT(index.has_value() && "index of varWithPatternDecl has no value.");
return index;
}
std::string BaseMangler::MangleVarWithPatternDecl(
const AST::VarWithPatternDecl& vwpDecl, const ::std::vector<Ptr<AST::Node>>& prefix) const
{
std::string mangleStr = "";
std::function<void(Pattern*)> patternWalkThrough = [this, &patternWalkThrough, &prefix, &mangleStr](
Pattern* pattern) {
if (!mangleStr.empty()) {
return;
}
if (auto varPattern = DynamicCast<VarPattern*>(pattern); varPattern) {
mangleStr = MangleVarDecl(*varPattern->varDecl, prefix);
}
if (auto tuplePattern = DynamicCast<TuplePattern*>(pattern); tuplePattern) {
for (auto& item : tuplePattern->patterns) {
patternWalkThrough(item.get());
}
} else if (auto enumPattern = DynamicCast<EnumPattern*>(pattern); enumPattern) {
for (auto& item : enumPattern->patterns) {
patternWalkThrough(item.get());
}
}
};
if (auto tp = DynamicCast<TuplePattern>(vwpDecl.irrefutablePattern.get())) {
for (auto& pattern : tp->patterns) {
patternWalkThrough(pattern.get());
if (!mangleStr.empty()) {
return mangleStr;
}
}
} else if (auto ep = DynamicCast<EnumPattern>(vwpDecl.irrefutablePattern.get())) {
for (auto& pattern : ep->patterns) {
patternWalkThrough(pattern.get());
if (!mangleStr.empty()) {
return mangleStr;
}
}
}
std::optional<size_t> index = GetIndexOfWildcard(vwpDecl, prefix);
CJC_ASSERT_WITH_MSG(index.has_value(), "Index of wildcard should not be empty");
mangleStr += MANGLE_CANGJIE_PREFIX + MANGLE_NESTED_PREFIX;
std::vector<std::string> genericsTypeStack;
mangleStr += ManglePrefix(vwpDecl, prefix, genericsTypeStack, true);
if (vwpDecl.TestAttr(Attribute::GLOBAL)) {
auto fileName = vwpDecl.curFile->fileName;
mangleStr += MANGLE_FILE_ID_PREFIX +
(IsHashable(fileName) ? HashToBase62(fileName)
: (FileNameWithoutExtension(fileName) + MANGLE_DOLLAR_PREFIX));
}
mangleStr += MANGLE_ANONYMOUS_VARIABLE_PREFIX;
mangleStr += MangleUtils::DecimalToManglingNumber(std::to_string(index.value()));
mangleStr += MANGLE_SUFFIX;
return mangleStr;
}
std::optional<std::string> BaseMangler::MangleEntryFunction(const FuncDecl& funcDecl) const
{
if (funcDecl.identifier == MAIN_INVOKE && funcDecl.TestAttr(Attribute::GLOBAL)) {
return USER_MAIN_MANGLED_NAME;
}
if (funcDecl.identifier == TEST_ENTRY_NAME) {
return std::string(TEST_ENTRY_NAME);
}
return std::nullopt;
}
std::string BaseMangler::Mangle(const Decl& decl) const
{
std::vector<Ptr<Node>> prefix = {};
auto outerDecl = decl.outerDecl;
while (outerDecl) {
prefix.insert(prefix.begin(), outerDecl);
outerDecl = outerDecl->outerDecl;
}
return Mangle(decl, prefix);
}
std::string BaseMangler::Mangle(const Decl& decl, const std::vector<Ptr<Node>>& prefix) const
{
if (decl.TestAttr(Attribute::NO_MANGLE)) {
return decl.identifier;
}
std::vector<std::string> genericsTypeStack;
switch (decl.astKind) {
case ASTKind::VAR_DECL:
return Compression::CJMangledCompression(MangleVarDecl(decl, prefix));
case ASTKind::FUNC_DECL:
return Compression::CJMangledCompression(MangleFunctionDecl(StaticCast<const FuncDecl&>(decl), prefix,
genericsTypeStack, true));
case ASTKind::VAR_WITH_PATTERN_DECL:
return Compression::CJMangledCompression(MangleVarWithPatternDecl(
StaticCast<const AST::VarWithPatternDecl&>(decl), prefix));
default:
return Compression::CJMangledCompression(MangleDecl(decl, prefix, genericsTypeStack, true));
}
}
std::string BaseMangler::MangleFunctionDecl(const FuncDecl& funcDecl, const std::vector<Ptr<Node>>& prefix,
std::vector<std::string>& genericsTypeStack, bool ) const
{
if (!funcDecl.mangledName.empty()) {
return funcDecl.mangledName;
}
if (funcDecl.TestAttr(Attribute::GENERIC_INSTANTIATED) && prefix.empty()) {
auto outerDecl = funcDecl.outerDecl;
std::vector<Ptr<Node>> newPrefix;
while (outerDecl != nullptr) {
newPrefix.insert(newPrefix.begin(), outerDecl);
outerDecl = outerDecl->outerDecl;
}
std::string mangled = MangleDecl(funcDecl, newPrefix, genericsTypeStack, true, false);
mangled += MANGLE_FUNC_PARAM_TYPE_PREFIX;
mangled += MangleFuncParams(funcDecl, genericsTypeStack, false);
return mangled;
}
if (funcDecl.outerDecl == nullptr) {
if (auto specialName = GetSpecialFuncName(funcDecl); specialName) {
return specialName.value();
}
}
std::string mangled = MangleEntryFunction(funcDecl).value_or("");
if (!mangled.empty()) {
return mangled;
}
if (funcDecl.TestAttr(Attribute::HAS_INITIAL)) {
std::string param = funcDecl.identifier;
CJC_NULLPTR_CHECK(funcDecl.ownerFunc);
auto outerDecl = funcDecl.ownerFunc->outerDecl;
std::vector<Ptr<Node>> newPrefix;
newPrefix.insert(newPrefix.begin(), funcDecl.ownerFunc);
while (outerDecl != nullptr) {
newPrefix.insert(newPrefix.begin(), outerDecl);
outerDecl = outerDecl->outerDecl;
}
std::string mangledPrefix = MANGLE_CANGJIE_PREFIX + MANGLE_NESTED_PREFIX;
std::string mangledOwnerFunc = MangleDecl(funcDecl, newPrefix, genericsTypeStack, true, true);
mangled += MANGLE_CANGJIE_PREFIX + MANGLE_FUNC_PARA_INIT_PREFIX +
mangledOwnerFunc.substr(mangledPrefix.size(), mangledOwnerFunc.size() - mangledPrefix.size() - 1);
mangled += MANGLE_FUNC_PARAM_TYPE_PREFIX;
} else {
mangled = MangleDecl(funcDecl, prefix, genericsTypeStack, true, false);
mangled += MANGLE_FUNC_PARAM_TYPE_PREFIX;
}
mangled += MangleFuncParams(funcDecl, genericsTypeStack, false);
return mangled;
}
std::string BaseMangler::MangleDecl(const Decl& decl, const std::vector<Ptr<Node>>& prefix,
std::vector<std::string>& genericsTypeStack, bool , bool withSuffix) const
{
if (!decl.mangledName.empty() && IsMangledToExportForTestBefore(decl, prefix)) {
return decl.mangledName;
}
std::string newMangled = MANGLE_CANGJIE_PREFIX + MANGLE_NESTED_PREFIX;
if (decl.astKind == ASTKind::VAR_WITH_PATTERN_DECL) {
newMangled += ManglePackage(decl);
if (DynamicCast<const AST::VarWithPatternDecl*>(&decl) != nullptr) {
newMangled += MangleVarWithPatternDecl(*DynamicCast<const AST::VarWithPatternDecl*>(&decl), prefix);
}
} else if (decl.astKind == ASTKind::EXTEND_DECL) {
newMangled += ManglePrefix(decl, prefix, genericsTypeStack, true);
newMangled += MangleExtendEntity(StaticCast<const ExtendDecl&>(decl), genericsTypeStack, true);
newMangled += MangleGenericArguments(decl, genericsTypeStack, true);
} else {
newMangled = newMangled + ManglePrefix(decl, prefix, genericsTypeStack, true);
bool useInternalIdent = decl.TestAnyAttr(Attribute::CONSTRUCTOR, Attribute::MAIN_ENTRY) &&
decl.astKind != ASTKind::PRIMARY_CTOR_DECL;
if (useInternalIdent) {
std::string staticPrefix = decl.TestAttr(Attribute::STATIC)
&& decl.identifier != STATIC_INIT_FUNC ? "static." : "";
newMangled += MangleUtils::MangleName(MANGLE_LT_PREFIX + staticPrefix + decl.identifier +
MANGLE_GT_PREFIX);
} else if (decl.TestAnyAttr(AST::Attribute::OPERATOR) &&
MangleUtils::OPERATOR_TYPE_MANGLE.count(decl.identifier) != 0) {
newMangled += MangleUtils::OPERATOR_TYPE_MANGLE.at(decl.identifier);
} else if (decl.identifier.Val().find(MANGLE_DOLLAR_PREFIX, 0) == 0 &&
(decl.identifier.Val().rfind(SPECIAL_NAME_FOR_SET) ==
(decl.identifier.Val().size() - MANGLE_PROP_LEN) ||
decl.identifier.Val().rfind(SPECIAL_NAME_FOR_GET) ==
(decl.identifier.Val().size() - MANGLE_PROP_LEN))) {
newMangled += MangleUtils::MangleName(decl.identifier.Val().substr(MANGLE_CHAR_LEN,
decl.identifier.Val().size() - MANGLE_CHAR_LEN - MANGLE_PROP_LEN));
newMangled += decl.identifier.Val().rfind(SPECIAL_NAME_FOR_SET) ==
(decl.identifier.Val().size() - MANGLE_PROP_LEN) ? "ps" : "pg";
} else {
std::string name = decl.identifier;
if (decl.astKind == ASTKind::GENERIC_PARAM_DECL && decl.outerDecl &&
decl.outerDecl->TestAnyAttr(Attribute::COMMON, Attribute::SPECIFIC) &&
decl.outerDecl->TestAttr(Attribute::GENERIC)) {
auto genericsTy = StaticCast<const GenericsTy*>(decl.GetTy());
auto result = std::find_if(genericsTypeStack.rbegin(), genericsTypeStack.rend(),
[&genericsTy](const std::string& name) { return name == genericsTy->name; });
auto index = static_cast<size_t>(std::distance(result, genericsTypeStack.rend())) - MANGLE_CHAR_LEN;
CJC_ASSERT(result != genericsTypeStack.rend() && "Using undeclared generic type!");
auto number = MangleUtils::DecimalToManglingNumber(std::to_string(index));
name = MANGLE_GENERIC_TYPE_PREFIX + number;
} else if (decl.TestAttr(Attribute::HAS_INITIAL)) {
size_t pos = decl.identifier.Val().find(MANGLE_DOT_PREFIX);
name = decl.identifier.Val().substr(0, pos);
}
newMangled += MangleUtils::MangleName(name);
if (decl.IsFunc()) {
auto& funcDecl = StaticCast<const AST::FuncDecl&>(decl);
newMangled +=
IsLocalFunc(funcDecl) ? GetMangledLocalFuncIndex(StaticCast<const FuncDecl&>(decl)) : "";
}
}
newMangled += MangleGenericArguments(decl, genericsTypeStack, true);
}
if (withSuffix) {
newMangled += MANGLE_SUFFIX;
}
return newMangled;
}
std::string BaseMangler::MangleExtendEntity(const AST::ExtendDecl& extendDecl,
std::vector<std::string>& genericsTypeStack, bool declare) const
{
CJC_NULLPTR_CHECK(extendDecl.extendedType);
CJC_NULLPTR_CHECK(extendDecl.extendedType->GetTy());
std::string mangled;
mangled += MANGLE_EXTEND_PREFIX + MangleType(*extendDecl.extendedType->GetTy(), genericsTypeStack, declare);
auto ctx = manglerCtxTable.find(ManglerContext::ReduceUnitTestPackageName(extendDecl.fullPackageName));
CJC_ASSERT(ctx != manglerCtxTable.end());
std::string fileName = extendDecl.curFile->fileName;
mangled += MANGLE_FILE_ID_PREFIX +
(IsHashable(fileName) ? HashToBase62(fileName) : (FileNameWithoutExtension(fileName) + MANGLE_DOLLAR_PREFIX));
auto index = ctx->second->GetIndexOfExtend(extendDecl.curFile, &extendDecl);
CJC_ASSERT(index.has_value());
mangled += MANGLE_COUNT_PREFIX+ MangleUtils::DecimalToManglingNumber(std::to_string(index.value()));
return mangled;
}
std::string BaseMangler::ManglePrefix(const Node& node, const std::vector<Ptr<Node>>& prefix,
std::vector<std::string>& genericsTypeStack, bool declare) const
{
std::string mangled = "";
Ptr<Node> outerMostNode = nullptr;
for (auto item = prefix.begin(); item != prefix.end(); ++item) {
auto curPrefix = *item;
switch (curPrefix->astKind) {
case ASTKind::CLASS_DECL:
case ASTKind::INTERFACE_DECL:
case ASTKind::ENUM_DECL:
case ASTKind::STRUCT_DECL:
case ASTKind::BUILTIN_DECL: {
auto& decl = StaticCast<const Decl&>(*curPrefix);
mangled += MangleUtils::MangleName(decl.identifier);
if (auto genericArgs = MangleGenericArgumentsHelper(decl, genericsTypeStack, true);
!genericArgs.empty()) {
mangled += genericArgs + MANGLE_SUFFIX;
}
break;
}
case ASTKind::VAR_DECL:
if (curPrefix->TestAttr(Attribute::GLOBAL)) {
mangled += MangleUtils::MangleName(StaticCast<const Decl&>(*curPrefix).identifier);
}
break;
case ASTKind::FUNC_DECL: {
auto& decl = StaticCast<const FuncDecl&>(*curPrefix);
mangled += MangleUtils::MangleName(decl.identifier);
if (IsLocalFunc(decl)) {
mangled += GetMangledLocalFuncIndex(decl);
}
mangled += MangleGenericArgumentsHelper(decl, genericsTypeStack, true) + MANGLE_FUNC_PARAM_TYPE_PREFIX +
MangleFuncParams(decl, genericsTypeStack, false) + MANGLE_SUFFIX;
break;
}
case ASTKind::EXTEND_DECL: {
auto& decl = StaticCast<const ExtendDecl&>(*curPrefix);
bool isInitFunc = node.astKind == ASTKind::FUNC_DECL && node.TestAttr(Attribute::HAS_INITIAL);
bool isExtend = (node.astKind == ASTKind::GENERIC_PARAM_DECL) ||
(node.TestAttr(Attribute::PRIVATE) && !isInitFunc) ||
(isInitFunc && StaticCast<const FuncDecl&>(node).ownerFunc->TestAttr(Attribute::PRIVATE));
if (isExtend) {
mangled += MangleExtendEntity(decl, genericsTypeStack, declare);
} else {
mangled += MANGLE_EXTEND_PREFIX + MangleType(*decl.extendedType->GetTy(), genericsTypeStack, true);
}
break;
}
case ASTKind::LAMBDA_EXPR: {
auto& lambda = StaticCast<const LambdaExpr&>(*curPrefix);
auto outerNode = FindOuterNodeOfLambda(item, prefix);
std::string pkgName = "";
if (auto decl = dynamic_cast<Decl*>(outerNode.get()); decl) {
pkgName = decl->fullPackageName;
} else {
for (size_t i = 0; i < prefix.size(); i++) {
if (auto prefixDecl = dynamic_cast<Decl*>(prefix[i].get()); prefixDecl) {
pkgName = prefixDecl->fullPackageName;
break;
}
}
}
pkgName = ManglerContext::ReduceUnitTestPackageName(pkgName);
CJC_ASSERT(!pkgName.empty() && "pkgName of lambda is empty.");
CJC_ASSERT(manglerCtxTable.find(pkgName) != manglerCtxTable.end()
&& "can not find pkgName in manglerCtxTable.");
auto mangleCtx = manglerCtxTable.at(pkgName);
CJC_NULLPTR_CHECK(mangleCtx.get());
std::optional<size_t> index = mangleCtx->GetIndexOfLambda(outerNode, &lambda);
mangled += MANGLE_LAMBDA_PREFIX + MangleUtils::DecimalToManglingNumber(std::to_string(index.value()));
break;
}
case ASTKind::VAR_WITH_PATTERN_DECL: {
if (!curPrefix->TestAttr(Attribute::GLOBAL)) {
break;
}
std::string mangleStr = "";
bool patternContainsVar = false;
std::unordered_set<VarDecl*> varDeclCollection;
auto& vwpDecl = StaticCast<const VarWithPatternDecl&>(*curPrefix);
std::function<void (Pattern*)> patternWalkThrough;
std::function<void (Pattern*)> collectAllVarPattern;
patternWalkThrough =
[&patternWalkThrough, &mangleStr, &patternContainsVar, &varDeclCollection](Pattern* pattern) {
if (!mangleStr.empty()) {
return;
}
if (auto varPattern = DynamicCast<VarPattern*>(pattern); varPattern) {
mangleStr = MangleUtils::MangleName(varPattern->varDecl->identifier);
if (varDeclCollection.find(varPattern->varDecl.get()) != varDeclCollection.end() ) {
patternContainsVar = true;
}
}
if (auto tuplePattern = DynamicCast<TuplePattern*>(pattern); tuplePattern) {
for (auto& item : tuplePattern->patterns) {
patternWalkThrough(item.get());
}
} else if (auto enumPattern = DynamicCast<EnumPattern*>(pattern); enumPattern) {
for (auto& item : enumPattern->patterns) {
patternWalkThrough(item.get());
}
}
};
collectAllVarPattern = [&collectAllVarPattern, &varDeclCollection](Pattern* pattern) {
if (auto vp = DynamicCast<VarPattern*>(pattern); vp) {
varDeclCollection.emplace(vp->varDecl.get());
return;
}
if (auto tuplePattern = DynamicCast<TuplePattern*>(pattern); tuplePattern) {
for (auto& item : tuplePattern->patterns) {
collectAllVarPattern(item.get());
}
} else if (auto enumPattern = DynamicCast<EnumPattern*>(pattern); enumPattern) {
for (auto& item : enumPattern->patterns) {
collectAllVarPattern(item.get());
}
}
};
if (auto tp = DynamicCast<TuplePattern>(vwpDecl.irrefutablePattern.get())) {
for (auto& pattern : tp->patterns) {
collectAllVarPattern(pattern.get());
}
} else if (auto ep = DynamicCast<EnumPattern>(vwpDecl.irrefutablePattern.get())) {
for (auto& pattern : ep->patterns) {
collectAllVarPattern(pattern.get());
}
}
if (auto tp = DynamicCast<TuplePattern>(vwpDecl.irrefutablePattern.get())) {
for (auto& pattern : tp->patterns) {
patternWalkThrough(pattern.get());
if (!mangleStr.empty()) {
break;
}
}
} else if (auto ep = DynamicCast<EnumPattern>(vwpDecl.irrefutablePattern.get())) {
for (auto& pattern : ep->patterns) {
patternWalkThrough(pattern.get());
if (!mangleStr.empty()) {
break;
}
}
}
if (patternContainsVar) {
break;
}
if (!mangleStr.empty()) {
mangled += mangleStr;
break;
}
std::optional<size_t> index = GetIndexOfWildcard(vwpDecl, prefix);
CJC_ASSERT_WITH_MSG(index.has_value(), "Index of wildcard should not be empty");
mangleStr += MANGLE_ANONYMOUS_VARIABLE_PREFIX;
mangleStr += MangleUtils::DecimalToManglingNumber(std::to_string(index.value()));
mangled += mangleStr;
break;
}
default:
break;
}
if (outerMostNode == nullptr) {
outerMostNode = curPrefix;
}
}
auto& outerMostNodeRef = outerMostNode ? static_cast<const Node&>(*outerMostNode) : node;
if (outerMostNodeRef.TestAttr(Attribute::PRIVATE)) {
std::string fileName = outerMostNodeRef.curFile.get()->fileName;
mangled = MANGLE_FILE_ID_PREFIX +
(IsHashable(fileName) ? HashToBase62(fileName) :
(FileNameWithoutExtension(fileName) + MANGLE_DOLLAR_PREFIX)) + mangled;
}
if (node.astKind == ASTKind::LAMBDA_EXPR) {
for (auto it = prefix.rbegin(); it != prefix.rend(); ++it) {
if (auto decl = dynamic_cast<const Decl*>(it->get()); decl) {
mangled = ManglePackage(*decl) + mangled;
break;
}
}
} else {
mangled = ManglePackage(StaticCast<const Decl&>(node)) + mangled;
}
return mangled;
}
std::string BaseMangler::ManglePackage(const Decl& decl) const
{
std::string genericPackageName = ManglePackageNameForGeneric(decl);
return genericPackageName.empty() ? MangleFullPackageName(decl) : genericPackageName;
}
std::unique_ptr<ManglerContext> BaseMangler::PrepareContextForPackage(const Ptr<AST::Package> pkg)
{
std::string pkgName = ManglerContext::ReduceUnitTestPackageName(pkg->fullPackageName);
auto manglerCtx = std::make_unique<ManglerContext>();
manglerCtxTable[pkgName] = manglerCtx.get();
return manglerCtx;
}
Ptr<AST::Node> BaseMangler::FindOuterNodeOfLambda(
const std::vector<Ptr<AST::Node>>::const_iterator& iter, const ::std::vector<Ptr<AST::Node>>& prefix) const
{
auto prevItem = prev(iter);
auto cnt = prevItem - prefix.begin() + 1;
while (cnt--) {
auto prevPrefix = *prevItem;
prevItem = prev(prevItem);
auto vda = dynamic_cast<VarDeclAbstract*>(prevPrefix.get());
if (prevPrefix->astKind == AST::ASTKind::FUNC_DECL || prevPrefix->astKind == AST::ASTKind::PRIMARY_CTOR_DECL ||
prevPrefix->astKind == AST::ASTKind::LAMBDA_EXPR || (vda && vda->TestAttr(Attribute::GLOBAL)) ||
(vda && vda->outerDecl.get() &&
(vda->outerDecl->astKind == ASTKind::CLASS_DECL || vda->outerDecl->astKind == ASTKind::INTERFACE_DECL ||
vda->outerDecl->astKind == ASTKind::STRUCT_DECL ||
vda->outerDecl->astKind == ASTKind::ENUM_DECL))) {
return prevPrefix;
}
}
CJC_ASSERT(false && "no outer container of lambda found.");
return Ptr<AST::Node>();
}
std::string BaseMangler::GetMangledLocalFuncIndex(const AST::FuncDecl& decl) const
{
auto outerNode = GetOuterDecl(decl);
std::string pkgName = decl.fullPackageName;
pkgName = ManglerContext::ReduceUnitTestPackageName(pkgName);
auto mangleCtx = manglerCtxTable.at(pkgName);
std::optional<size_t> index = mangleCtx->GetIndexOfFunc(outerNode, &decl);
CJC_ASSERT(index.has_value());
if (index.value() > 0) {
return MANGLE_COUNT_PREFIX + MangleUtils::DecimalToManglingNumber(std::to_string(index.value() - 1));
} else {
return "";
}
}
std::string BaseMangler::MangleLambda(const LambdaExpr& lambda, const::std::vector<Ptr<AST::Node>>& prefix) const
{
auto outerNode = FindOuterNodeOfLambda(prefix.end(), prefix);
std::string pkgName = "";
if (auto decl = dynamic_cast<Decl*>(outerNode.get()); decl) {
pkgName = decl->fullPackageName;
} else {
for (size_t i = 0; i < prefix.size(); i++) {
if (auto prefixDecl = dynamic_cast<Decl*>(prefix[i].get()); prefixDecl) {
pkgName = prefixDecl->fullPackageName;
break;
}
}
}
pkgName = ManglerContext::ReduceUnitTestPackageName(pkgName);
CJC_ASSERT(!pkgName.empty() && "pkgName of lambda is empty.");
CJC_ASSERT(manglerCtxTable.find(pkgName) != manglerCtxTable.end() && "can not find pkgName in manglerCtxTable.");
auto mangleCtx = manglerCtxTable.at(pkgName);
CJC_NULLPTR_CHECK(mangleCtx.get());
std::optional<size_t> index = mangleCtx->GetIndexOfLambda(outerNode, &lambda);
std::string mangleStr = MANGLE_CANGJIE_PREFIX + MANGLE_NESTED_PREFIX;
std::vector<std::string> genericsTypeStack;
mangleStr += ManglePrefix(lambda, prefix, genericsTypeStack, true);
mangleStr +=
MANGLE_LAMBDA_PREFIX + MangleUtils::DecimalToManglingNumber(std::to_string(index.value())) + MANGLE_SUFFIX;
return Compression::CJMangledCompression(mangleStr);
}
void BaseMangler::CollectLocalDecls(ManglerContext& ctx, AST::Package& pkg) const
{
Walker(&pkg, [&ctx](const Ptr<Node> node) {
if (auto ed = DynamicCast<ExtendDecl>(node); ed) {
ctx.SaveExtend2CurFile(ed->curFile, ed);
}
if (auto vpd = DynamicCast<VarWithPatternDecl>(node); vpd && vpd->TestAttr(Attribute::GLOBAL)) {
ctx.SaveGlobalWildcardVar(vpd->curFile, vpd);
}
bool isFunc = node->astKind == ASTKind::FUNC_DECL;
bool isLambda = node->astKind == ASTKind::LAMBDA_EXPR;
bool isGlobal = Is<VarDeclAbstract>(node) && node->TestAttr(Attribute::GLOBAL);
auto vda = DynamicCast<VarDeclAbstract>(node);
bool isCompositeType = vda && vda->outerDecl &&
(vda->outerDecl->astKind == ASTKind::CLASS_DECL || vda->outerDecl->astKind == ASTKind::INTERFACE_DECL ||
vda->outerDecl->astKind == ASTKind::STRUCT_DECL || vda->outerDecl->astKind == ASTKind::ENUM_DECL);
bool needCollect = isFunc || isLambda || isGlobal || isCompositeType;
if (needCollect) {
ctx.SaveVar2CurDecl(node);
ctx.SaveLambda2CurDecl(node);
ctx.SaveLocalWildcardVar2Decl(node);
ctx.SaveFunc2CurDecl(node);
}
return VisitAction::WALK_CHILDREN;
}).Walk();
}
void BaseMangler::MangleExportId(Package& pkg)
{
std::string pkgName = ManglerContext::ReduceUnitTestPackageName(pkg.fullPackageName);
auto manglerCtx = std::make_unique<ManglerContext>();
manglerCtxTable[pkgName] = manglerCtx.get();
CollectLocalDecls(*manglerCtxTable.at(pkgName), pkg);
exportIdMode = true;
Walker(&pkg, [this](auto node) {
if (auto decl = DynamicCast<Decl*>(node);
decl && Ty::IsTyCorrect(decl->GetTy()) && decl->TestAttr(Attribute::GLOBAL)) {
decl->exportId = MangleExportId(*decl);
}
return VisitAction::WALK_CHILDREN;
}).Walk();
}
std::string BaseMangler::MangleExportId(Decl& decl) const
{
if (decl.TestAttr(Attribute::NO_MANGLE)) {
return decl.identifier;
}
return match(decl)(
[&, this](FuncDecl& fd) {
fd.exportId = Mangle(fd);
if (fd.TestAttr(Attribute::DEFAULT) && fd.outerDecl && fd.outerDecl->astKind == ASTKind::INTERFACE_DECL) {
MangleExportIdForGenericParamDecl(fd);
}
return fd.exportId;
},
[this](PropDecl& propDecl) {
auto mangleExport = [this](auto& it) { it->exportId = Mangle(*it); };
std::for_each(propDecl.getters.begin(), propDecl.getters.end(), mangleExport);
std::for_each(propDecl.setters.begin(), propDecl.setters.end(), mangleExport);
return Mangle(propDecl);
},
[](const PrimaryCtorDecl& ) { return std::string(); },
[&decl, this]() {
decl.exportId = Mangle(decl);
for (auto& it : decl.GetMemberDeclPtrs()) {
it->exportId = MangleExportId(*it);
}
if (decl.astKind == ASTKind::INTERFACE_DECL && decl.TestAttr(Attribute::GENERIC)) {
MangleExportIdForGenericParamDecl(decl);
}
return decl.exportId;
});
}
void BaseMangler::MangleExportIdForGenericParamDecl(const Decl& decl) const
{
if (auto generic = decl.GetGeneric()) {
for (auto& gpd : generic->typeParameters) {
CJC_NULLPTR_CHECK(gpd->outerDecl);
std::vector<std::string> genericsTypeStack;
gpd->exportId = gpd->outerDecl->exportId + MANGLE_WILDCARD_PREFIX + gpd->identifier +
MangleType(*gpd->GetTy(), genericsTypeStack, false, false);
}
}
}
Ptr<const Decl> BaseMangler::GetOuterDecl(const Decl& decl) const
{
auto outerDecl = decl.outerDecl;
if (!Is<FuncDecl>(&decl)) {
return outerDecl;
}
return GetParentDecl(StaticCast<const FuncDecl&>(decl));
}
std::string BaseMangler::MangleEnumType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack, bool declare,
bool isCollectGTy) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_ENUM);
auto enumTy = StaticCast<const EnumTy&>(ty);
return MangleUserDefinedType(enumTy, genericsTypeStack, declare, isCollectGTy);
}
std::string BaseMangler::MangleRawArrayType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack,
bool declare, bool isCollectGTy) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_ARRAY);
auto arrayTy = StaticCast<const ArrayTy&>(ty);
return MANGLE_TYPE_ARRAY_PREFIX + MangleUtils::DecimalToManglingNumber(std::to_string(arrayTy.dims)) +
MangleType(*arrayTy.typeArgs[0], genericsTypeStack, declare, isCollectGTy);
}
std::string BaseMangler::MangleVArrayType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack,
bool declare, bool isCollectGTy) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_VARRAY);
auto varrayTy = StaticCast<const VArrayTy&>(ty);
std::string mangled = MANGLE_VARRAY_PREFIX + MangleUtils::DecimalToManglingNumber(std::to_string(varrayTy.size));
for (const auto it : varrayTy.typeArgs) {
mangled += MangleType(*it, genericsTypeStack, declare, isCollectGTy);
}
return mangled;
}
std::string BaseMangler::MangleTupleType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack, bool declare,
bool isCollectGTy) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_TUPLE);
auto tupleTy = StaticCast<const TupleTy&>(ty);
std::string mangled = MANGLE_TUPLE_PREFIX +
MangleUtils::DecimalToManglingNumber(std::to_string(tupleTy.typeArgs.size()));
for (const auto it : tupleTy.typeArgs) {
mangled += MangleType(*it, genericsTypeStack, declare, isCollectGTy);
}
mangled += MANGLE_SUFFIX;
return mangled;
}
std::string BaseMangler::MangleFuncType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack, bool declare,
bool isCollectGTy) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_FUNC);
auto funcTy = StaticCast<const FuncTy&>(ty);
std::string mangled = funcTy.IsCFunc() ? MANGLE_CFUNC_PREFIX : MANGLE_GENERAL_FUNC_PREFIX;
std::string retTy = MangleType(*funcTy.retTy, genericsTypeStack, declare, isCollectGTy);
if (retTy.empty()) {
retTy = MANGLE_VOID_TY_SUFFIX;
}
std::string params = "";
for (auto it : funcTy.paramTys) {
params += MangleType(*it, genericsTypeStack, declare, isCollectGTy);
}
mangled += retTy + params + MANGLE_SUFFIX;
return mangled;
}
std::string BaseMangler::MangleGenericType(const AST::Ty& ty) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_GENERICS);
auto genericsTy = StaticCast<const GenericsTy&>(ty);
std::string mangled = MANGLE_GENERIC_TYPE_PREFIX + MangleUtils::MangleName(genericsTy.name);
return mangled;
}
std::string BaseMangler::MangleGenericType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack,
bool declare) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_GENERICS);
auto genericsTy = StaticCast<const GenericsTy&>(ty);
size_t index = 0;
if (declare) {
index = genericsTypeStack.size();
genericsTypeStack.emplace_back(genericsTy.name);
} else {
auto result = std::find_if(genericsTypeStack.rbegin(), genericsTypeStack.rend(),
[&genericsTy](const std::string& name) { return name == genericsTy.name; });
index = static_cast<size_t>(std::distance(result, genericsTypeStack.rend())) - MANGLE_CHAR_LEN;
CJC_ASSERT(result != genericsTypeStack.rend() && "Using undeclared generic type!");
}
auto number = MangleUtils::DecimalToManglingNumber(std::to_string(index));
return MANGLE_GENERIC_TYPE_PREFIX + number;
}
std::string BaseMangler::MangleFuncParams(const AST::FuncDecl& funcDecl, std::vector<std::string>& genericsTypeStack,
bool declare, bool isCollectGTy) const
{
if (!funcDecl.funcBody || funcDecl.funcBody->paramLists.empty() ||
funcDecl.funcBody->paramLists[0]->params.empty()) {
return MANGLE_VOID_TY_SUFFIX;
}
std::string mangled = "";
for (auto& param : funcDecl.funcBody->paramLists[0]->params) {
CJC_NULLPTR_CHECK(param->GetTy());
if (Ty::IsInitialTy(param->GetTy())) {
continue;
}
mangled += MangleType(*param->GetTy(), genericsTypeStack, declare, isCollectGTy);
}
return mangled;
}
std::string BaseMangler::MangleCPointerType(const AST::Ty& ty, std::vector<std::string>& genericsTypeStack,
bool declare, bool isCollectGTy) const
{
CJC_ASSERT(ty.kind == TypeKind::TYPE_POINTER);
auto pointerTy = StaticCast<const PointerTy&>(ty);
CJC_ASSERT(!pointerTy.typeArgs.empty() && pointerTy.typeArgs[0]);
return !pointerTy.typeArgs.empty() && pointerTy.typeArgs[0] ? MANGLE_POINTER_PREFIX +
MangleType(*pointerTy.typeArgs[0], genericsTypeStack, declare, isCollectGTy) : "";
}
std::string BaseMangler::ManglePackageNameForGeneric(const AST::Decl& decl) const
{
std::string genericPkg;
auto genericDecl = decl.genericDecl;
while (genericDecl != nullptr) {
genericPkg = MangleFullPackageName(*genericDecl);
genericDecl = genericDecl->genericDecl;
}
if (!genericPkg.empty()) {
return genericPkg;
}
auto outer = &decl;
while (outer != nullptr) {
if (outer->genericDecl != nullptr) {
return MangleFullPackageName(*outer->genericDecl);
}
outer = GetOuterDecl(*outer);
}
return genericPkg;
}
bool BaseMangler::IsLocalVariable(const AST::Decl& decl) const
{
auto varDecl = dynamic_cast<const AST::VarDecl*>(&decl);
if (varDecl == nullptr) {
return false;
}
auto isStaticMemberVar = [varDecl]() {
return varDecl->outerDecl && (varDecl->outerDecl->IsClassLikeDecl() ||
varDecl->outerDecl->IsStructOrClassDecl()) && varDecl->TestAttr(AST::Attribute::STATIC);
};
if (!varDecl->TestAttr(AST::Attribute::GLOBAL) && !isStaticMemberVar()) {
return true;
}
return false;
}
bool BaseMangler::IsLocalFunc(const AST::FuncDecl& funcDecl) const
{
return !funcDecl.TestAttr(AST::Attribute::GLOBAL) && funcDecl.outerDecl && !funcDecl.outerDecl->IsNominalDecl();
}
std::string BaseMangler::HashToBase62(const std::string& input)
{
uint32_t hashValue = Fnv1aHash(input);
return ToBase62(hashValue);
}
bool BaseMangler::IsHashable(const std::string& str)
{
auto fileName = FileNameWithoutExtension(str);
if (fileName.size() > 12) {
return true;
}
for (char c : fileName) {
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '.') || (c == '_') ||
(c == '-'))) {
return true;
}
}
return false;
}
std::string BaseMangler::FileNameWithoutExtension(const std::string& fileName)
{
std::string fileNameWithoutExtension = fileName;
size_t length = 3;
if (fileName.size() > length && fileName.rfind(".cj") == fileName.size() - length) {
fileNameWithoutExtension = fileName.substr(0, fileName.size() - length);
}
return fileNameWithoutExtension;
}
void ManglerContext::SaveGlobalWildcardVar(const Ptr<const AST::File> file, const Ptr<AST::VarWithPatternDecl> vpd)
{
if (vpd->irrefutablePattern->astKind == AST::ASTKind::WILDCARD_PATTERN ||
CheckAllElementsWildcard(vpd->irrefutablePattern.get())) {
file2GlobalWildcardVar[file].emplace_back(vpd);
}
}
bool ManglerContext::CheckAllElementsWildcard(const Ptr<AST::Pattern>& root)
{
if (root->astKind == AST::ASTKind::WILDCARD_PATTERN) {
return true;
}
bool areAllElementsWildcard = true;
if (auto tp = DynamicCast<TuplePattern>(root)) {
for (auto& pattern : tp->patterns) {
if (!pattern) {
continue;
}
areAllElementsWildcard = areAllElementsWildcard && CheckAllElementsWildcard(pattern.get());
}
} else if (auto ep = DynamicCast<EnumPattern>(root)) {
if (ep->patterns.empty()) {
areAllElementsWildcard = false;
}
for (auto& pattern : ep->patterns) {
if (!pattern) {
continue;
}
areAllElementsWildcard = areAllElementsWildcard && CheckAllElementsWildcard(pattern.get());
}
} else {
areAllElementsWildcard = false;
}
return areAllElementsWildcard;
}
namespace {
Ptr<Node> GetDeclKey(const Ptr<Node> node)
{
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
return lambda->funcBody.get();
} else if (auto function = DynamicCast<FuncDecl>(node)) {
return function->funcBody.get();
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
return pcd->funcBody.get();
} else if (auto vda = DynamicCast<VarDeclAbstract>(node)) {
return vda;
}
return nullptr;
}
}
void ManglerContext::SaveFunc2CurDecl(const Ptr<Node> node)
{
Ptr<Node> key = nullptr;
if (auto function = DynamicCast<FuncDecl>(node)) {
if (function->TestAttr(AST::Attribute::GENERIC_INSTANTIATED) && !function->TestAttr(AST::Attribute::GLOBAL)) {
if (function->outerDecl && !function->outerDecl->IsNominalDecl()) {
key = GetDeclKey(function->outerDecl);
}
if (key != nullptr) {
auto& mapOfName2Func = node2LocalFunc[key][function->identifier.Val()];
mapOfName2Func.emplace_back(function);
}
}
}
key = GetDeclKey(node);
if (key == nullptr) {
return;
}
Walker(key, [this, &key](const Ptr<Node>& node) {
if (auto fd = DynamicCast<FuncDecl>(node); fd && node != key) {
auto& mapOfName2Func = node2LocalFunc[key][fd->identifier.Val()];
mapOfName2Func.emplace_back(fd);
} else if (Is<FuncBody>(node) && node != key) {
return VisitAction::WALK_CHILDREN;
}
return VisitAction::WALK_CHILDREN;
}).Walk();
}
void ManglerContext::SaveLocalWildcardVar2Decl(const Ptr<AST::Node> node)
{
Ptr<Node> key = nullptr;
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
key = lambda->funcBody.get();
} else if (auto function = DynamicCast<FuncDecl>(node)) {
key = function->funcBody.get();
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
key = pcd->funcBody.get();
} else if (auto vda = DynamicCast<VarDeclAbstract>(node); vda && vda->TestAttr(Attribute::GLOBAL)) {
key = vda;
}
if (!key) {
return;
}
Walker(key, [this, &key](const Ptr<Node>& node) {
if (auto vda = DynamicCast<VarWithPatternDecl>(node); vda && node != key) {
node2LocalWildcardVar[key].emplace_back(vda);
} else if (Is<FuncBody>(node) && node != key) {
return VisitAction::SKIP_CHILDREN;
}
return VisitAction::WALK_CHILDREN;
}).Walk();
}
void ManglerContext::SaveVar2CurDecl(const Ptr<Node> node)
{
Ptr<Node> key = nullptr;
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
key = lambda->funcBody.get();
} else if (auto function = DynamicCast<FuncDecl>(node)) {
key = function->funcBody.get();
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
key = pcd->funcBody.get();
} else if (auto vda = DynamicCast<VarDeclAbstract>(node); vda && vda->TestAttr(Attribute::GLOBAL)) {
key = vda;
}
if (!key) {
return;
}
Walker(key, [this, &key](const Ptr<Node>& node) {
if (auto vda = DynamicCast<VarDeclAbstract>(node); vda && node != key) {
auto& mapOfName2Var = node2LocalVar[key][vda->identifier.Val()];
mapOfName2Var.emplace_back(vda);
} else if (Is<FuncBody>(node) && node != key) {
return VisitAction::SKIP_CHILDREN;
}
return VisitAction::WALK_CHILDREN;
}).Walk();
}
void ManglerContext::SaveLambda2CurDecl(const Ptr<Node> node)
{
std::vector<Ptr<Node>> keys;
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
keys.emplace_back(lambda->funcBody.get());
} else if (auto function = DynamicCast<FuncDecl>(node)) {
keys.emplace_back(function->funcBody.get());
keys.emplace_back(function->annotationsArray.get());
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
keys.emplace_back(pcd->funcBody.get());
keys.emplace_back(pcd->annotationsArray.get());
} else if (auto vda = DynamicCast<VarDeclAbstract>(node); vda &&
(vda->TestAttr(Attribute::GLOBAL) ||
(vda->outerDecl &&
(vda->outerDecl->astKind == ASTKind::CLASS_DECL ||
vda->outerDecl->astKind == ASTKind::INTERFACE_DECL ||
vda->outerDecl->astKind == ASTKind::STRUCT_DECL ||
vda->outerDecl->astKind == ASTKind::ENUM_DECL)))) {
keys.emplace_back(vda);
keys.emplace_back(vda->annotationsArray.get());
}
for (Ptr<Node> key : keys) {
if (!key) {
continue;
}
Walker(key, [this, &key](const Ptr<Node>& node) {
if (auto le = DynamicCast<LambdaExpr>(node); le && node != key) {
node2Lambda[key].emplace_back(le);
} else if (Is<FuncBody>(node) && node != key) {
return VisitAction::SKIP_CHILDREN;
}
return VisitAction::WALK_CHILDREN;
}).Walk();
}
}
void ManglerContext::SaveExtend2CurFile(const Ptr<const AST::File> file, const Ptr<AST::ExtendDecl> node)
{
file2ExtendDecl[file][node->extendedType->GetTy()->String()].emplace_back(node);
}
std::optional<size_t> ManglerContext::GetIndexOfGlobalWildcardVar(
const Ptr<const AST::File> file, const Ptr<const VarWithPatternDecl> target) const
{
if (!file || file->fileHash == 0) {
return {};
}
auto found = file2GlobalWildcardVar.find(file);
if (found != file2GlobalWildcardVar.end()) {
for (size_t i = 0; i < found->second.size(); ++i) {
if (found->second[i] == target) {
return i;
}
}
}
return {};
}
std::optional<size_t> ManglerContext::GetIndexOfExtend(
const Ptr<const AST::File> file, const Ptr<const AST::ExtendDecl> target) const
{
if (!file) {
return {};
}
auto fileMap = file2ExtendDecl.find(file);
CJC_ASSERT(fileMap != file2ExtendDecl.end());
auto elementsVector = fileMap->second.find(target->extendedType->GetTy()->String());
CJC_ASSERT(elementsVector != fileMap->second.end());
auto found = std::find(elementsVector->second.begin(), elementsVector->second.end(), target);
if (found != elementsVector->second.end()) {
return found - elementsVector->second.begin();
}
return {};
}
std::optional<size_t> ManglerContext::GetIndexOfLocalWildcardVar(
const Ptr<const AST::Node> node, const Ptr<const AST::VarWithPatternDecl> target) const
{
auto foundFunc = node2LocalWildcardVar.end();
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
foundFunc = node2LocalWildcardVar.find(lambda->funcBody.get());
} else if (auto function = DynamicCast<FuncDecl>(node)) {
foundFunc = node2LocalWildcardVar.find(function->funcBody.get());
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
foundFunc = node2LocalWildcardVar.find(pcd->funcBody.get());
} else if (auto vda = DynamicCast<VarDeclAbstract>(node); vda && vda->TestAttr(Attribute::GLOBAL)) {
foundFunc = node2LocalWildcardVar.find(vda);
}
if (foundFunc != node2LocalWildcardVar.end()) {
auto targetIt = std::find(foundFunc->second.begin(), foundFunc->second.end(), target);
if (targetIt != foundFunc->second.end()) {
return targetIt - foundFunc->second.begin();
}
return {};
}
return {};
}
std::optional<size_t> ManglerContext::GetIndexOfVar(
const Ptr<const Node> node, const Ptr<const VarDeclAbstract> target) const
{
auto foundFunc = node2LocalVar.end();
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
foundFunc = node2LocalVar.find(lambda->funcBody.get());
} else if (auto function = DynamicCast<FuncDecl>(node)) {
foundFunc = node2LocalVar.find(function->funcBody.get());
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
foundFunc = node2LocalVar.find(pcd->funcBody.get());
} else if (auto vda = DynamicCast<VarDeclAbstract>(node); vda && vda->TestAttr(Attribute::GLOBAL)) {
foundFunc = node2LocalVar.find(vda);
}
if (foundFunc != node2LocalVar.end()) {
auto foundId = foundFunc->second.find(target->identifier);
if (foundId == foundFunc->second.end()) {
return {};
}
auto targetIt = std::find(foundId->second.begin(), foundId->second.end(), target);
if (targetIt != foundId->second.end()) {
return targetIt - foundId->second.begin();
}
return {};
}
return {};
}
std::optional<size_t> ManglerContext::GetIndexOfFunc(
const Ptr<const Node> node, const Ptr<const FuncDecl> target) const
{
auto foundFunc = node2LocalFunc.end();
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
foundFunc = node2LocalFunc.find(lambda->funcBody.get());
} else if (auto function = DynamicCast<FuncDecl>(node)) {
foundFunc = node2LocalFunc.find(function->funcBody.get());
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
foundFunc = node2LocalFunc.find(pcd->funcBody.get());
} else if (auto vda = DynamicCast<VarDeclAbstract>(node)) {
foundFunc = node2LocalFunc.find(vda);
}
if (foundFunc != node2LocalFunc.end()) {
auto foundId = foundFunc->second.find(target->identifier);
if (foundId == foundFunc->second.end()) {
return {};
}
auto targetIt = std::find(foundId->second.begin(), foundId->second.end(), target);
if (targetIt != foundId->second.end()) {
return targetIt - foundId->second.begin();
}
return {};
}
return {};
}
std::optional<size_t> ManglerContext::GetIndexOfLambda(
const Ptr<const Node> node, const Ptr<const LambdaExpr> target) const
{
auto foundFunc = node2Lambda.end();
auto foundArrayLit = node2Lambda.end();
if (auto lambda = DynamicCast<LambdaExpr>(node)) {
foundFunc = node2Lambda.find(lambda->funcBody.get());
} else if (auto function = DynamicCast<FuncDecl>(node)) {
foundFunc = node2Lambda.find(function->funcBody.get());
foundArrayLit = node2Lambda.find(function->annotationsArray.get());
} else if (auto pcd = DynamicCast<PrimaryCtorDecl>(node)) {
foundFunc = node2Lambda.find(pcd->funcBody.get());
foundArrayLit = node2Lambda.find(pcd->annotationsArray.get());
} else if (auto vda = DynamicCast<VarDeclAbstract>(node); vda &&
(vda->TestAttr(Attribute::GLOBAL) ||
(vda->outerDecl &&
(vda->outerDecl->astKind == ASTKind::CLASS_DECL ||
vda->outerDecl->astKind == ASTKind::INTERFACE_DECL ||
vda->outerDecl->astKind == ASTKind::STRUCT_DECL ||
vda->outerDecl->astKind == ASTKind::ENUM_DECL)))) {
foundFunc = node2Lambda.find(vda);
foundArrayLit = node2Lambda.find(vda->annotationsArray.get());
}
auto getIndex = [this, &target](std::map<Ptr<const AST::Node>,
std::vector<Ptr<AST::LambdaExpr>>>::const_iterator it) -> std::optional<size_t> {
if (it != node2Lambda.end()) {
auto targetIt = std::find(it->second.begin(), it->second.end(), target);
if (targetIt != it->second.end()) {
return targetIt - it->second.begin();
}
}
return {};
};
std::optional<size_t> funcIdx = getIndex(foundFunc);
if (funcIdx.has_value()) {
return funcIdx;
}
std::optional<size_t> arrayIdx = getIndex(foundArrayLit);
CJC_ASSERT(arrayIdx.has_value() && "index of lambda has no value.");
size_t offset = foundFunc != node2Lambda.end() ? foundFunc->second.size() : 0;
return arrayIdx.value() + offset;
}