Files
revng-revng/lib/Model/Identifier.cpp
2024-06-27 11:05:49 +02:00

319 lines
6.4 KiB
C++

/// \file Identifier.cpp
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "revng/Model/Identifier.h"
using namespace model;
const Identifier Identifier::Empty = Identifier("");
const std::set<llvm::StringRef> ReservedKeywords = {
// reserved keywords for primitive types
"void",
"pointer_or_number8_t",
"pointer_or_number16_t",
"pointer_or_number32_t",
"pointer_or_number64_t",
"pointer_or_number128_t",
"number8_t",
"number16_t",
"number32_t",
"number64_t",
"number128_t",
"generic8_t",
"generic16_t",
"generic32_t",
"generic64_t",
"generic80_t",
"generic96_t",
"generic128_t",
"int8_t",
"int16_t",
"int32_t",
"int64_t",
"int128_t",
"int_fast8_t",
"int_fast16_t",
"int_fast32_t",
"int_fast64_t",
"int_fast128_t",
"int_least8_t",
"int_least16_t",
"int_least32_t",
"int_least64_t",
"int_least128_t",
"intmax_t",
"intptr_t",
"uint8_t",
"uint16_t",
"uint32_t",
"uint64_t",
"uint128_t",
"uint_fast8_t",
"uint_fast16_t",
"uint_fast32_t",
"uint_fast64_t",
"uint_fast128_t",
"uint_least8_t",
"uint_least16_t",
"uint_least32_t",
"uint_least64_t",
"uint_least128_t",
"uintmax_t",
"uintptr_t",
"float16_t",
"float32_t",
"float64_t",
"float80_t",
"float96_t",
"float128_t",
// Integer macros from stdint.h, reserved to prevent clashes.
"INT8_WIDTH",
"INT16_WIDTH",
"INT32_WIDTH",
"INT64_WIDTH",
"INT_FAST8_WIDTH",
"INT_FAST16_WIDTH",
"INT_FAST32_WIDTH",
"INT_FAST64_WIDTH",
"INT_LEAST8_WIDTH",
"INT_LEAST16_WIDTH",
"INT_LEAST32_WIDTH",
"INT_LEAST64_WIDTH",
"INTPTR_WIDTH",
"INTMAX_WIDTH",
"INT8_MIN",
"INT16_MIN",
"INT32_MIN",
"INT64_MIN",
"INT_FAST8_MIN",
"INT_FAST16_MIN",
"INT_FAST32_MIN",
"INT_FAST64_MIN",
"INT_LEAST8_MIN",
"INT_LEAST16_MIN",
"INT_LEAST32_MIN",
"INT_LEAST64_MIN",
"INTPTR_MIN",
"INTMAX_MIN",
"INT8_MAX",
"INT16_MAX",
"INT32_MAX",
"INT64_MAX",
"INT_FAST8_MAX",
"INT_FAST16_MAX",
"INT_FAST32_MAX",
"INT_FAST64_MAX",
"INT_LEAST8_MAX",
"INT_LEAST16_MAX",
"INT_LEAST32_MAX",
"INT_LEAST64_MAX",
"INTPTR_MAX",
"INTMAX_MAX",
"UINT8_WIDTH",
"UINT16_WIDTH",
"UINT32_WIDTH",
"UINT64_WIDTH",
"UINT_FAST8_WIDTH",
"UINT_FAST16_WIDTH",
"UINT_FAST32_WIDTH",
"UINT_FAST64_WIDTH",
"UINT_LEAST8_WIDTH",
"UINT_LEAST16_WIDTH",
"UINT_LEAST32_WIDTH",
"UINT_LEAST64_WIDTH",
"UINTPTR_WIDTH",
"UINTMAX_WIDTH",
"UINT8_MAX",
"UINT16_MAX",
"UINT32_MAX",
"UINT64_MAX",
"UINT_FAST8_MAX",
"UINT_FAST16_MAX",
"UINT_FAST32_MAX",
"UINT_FAST64_MAX",
"UINT_LEAST8_MAX",
"UINT_LEAST16_MAX",
"UINT_LEAST32_MAX",
"UINT_LEAST64_MAX",
"UINTPTR_MAX",
"UINTMAX_MAX",
"INT8_C",
"INT16_C",
"INT32_C",
"INT64_C",
"INTMAX_C",
"UINT8_C",
"UINT16_C",
"UINT32_C",
"UINT64_C",
"UINTMAX_C",
// C reserved keywords
"auto",
"break",
"case",
"char",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extern",
"float",
"for",
"goto",
"if",
"inline", // Since C99
"int",
"long",
"register",
"restrict", // Since C99
"return",
"short",
"signed",
"sizeof",
"static",
"struct",
"switch",
"typedef",
"union",
"unsigned",
"volatile",
"while",
"_Alignas", // Since C11
"_Alignof", // Since C11
"_Atomic", // Since C11
"_Bool", // Since C99
"_Complex", // Since C99
"_Decimal128", // Since C23
"_Decimal32", // Since C23
"_Decimal64", // Since C23
"_Generic", // Since C11
"_Imaginary", // Since C99
"_Noreturn", // Since C11
"_Static_assert", // Since C11
"_Thread_local", // Since C11
// Convenience macros
"alignas",
"alignof",
"bool",
"complex",
"imaginary",
"noreturn",
"static_assert",
"thread_local",
// Convenience macros for atomic types
"atomic_bool",
"atomic_char",
"atomic_schar",
"atomic_uchar",
"atomic_short",
"atomic_ushort",
"atomic_int",
"atomic_uint",
"atomic_long",
"atomic_ulong",
"atomic_llong",
"atomic_ullong",
"atomic_char16_t",
"atomic_char32_t",
"atomic_wchar_t",
"atomic_int_least8_t",
"atomic_uint_least8_t",
"atomic_int_least16_t",
"atomic_uint_least16_t",
"atomic_int_least32_t",
"atomic_uint_least32_t",
"atomic_int_least64_t",
"atomic_uint_least64_t",
"atomic_int_fast8_t",
"atomic_uint_fast8_t",
"atomic_int_fast16_t",
"atomic_uint_fast16_t",
"atomic_int_fast32_t",
"atomic_uint_fast32_t",
"atomic_int_fast64_t",
"atomic_uint_fast64_t",
"atomic_intptr_t",
"atomic_uintptr_t",
"atomic_size_t",
"atomic_ptrdiff_t",
"atomic_intmax_t",
"atomic_uintmax_t",
// C Extensions
"_Pragma",
"asm",
};
static bool isNotUnderscore(const char C) {
return C != '_';
};
static bool allAlphaNumOrUnderscore(const Identifier &Range) {
const auto &FilterRange = llvm::make_filter_range(Range, isNotUnderscore);
for (const auto &Entry : FilterRange)
if (not std::isalnum(Entry))
return false;
return true;
};
bool Identifier::verify(VerifyHelper &VH) const {
return VH.maybeFail(not(not empty() and std::isdigit(str()[0]))
and not startswith("_")
and allAlphaNumOrUnderscore(str())
and not ReservedKeywords.contains(str()),
llvm::Twine(*this) + " is not a valid identifier");
}
bool Identifier::verify(bool Assert) const {
VerifyHelper VH(Assert);
return verify(VH);
}
bool Identifier::verify() const {
return verify(false);
}
constexpr static llvm::StringRef PrefixForReservedNames = "unreserved_";
Identifier Identifier::fromString(llvm::StringRef Name) {
revng_assert(not Name.empty());
Identifier Result;
// For reserved C keywords prepend a non-reserved prefix and we're done.
if (ReservedKeywords.contains(Name)) {
Result += PrefixForReservedNames;
Result += Name;
return Result;
}
const auto BecomesUnderscore = [](const char C) {
return not std::isalnum(C) or C == '_';
};
// For invalid C identifiers prepend the our reserved prefix.
if (std::isdigit(Name[0]) or BecomesUnderscore(Name[0])) {
Result += PrefixForReservedNames;
}
// Append the rest of the name
Result += Name;
return sanitize(Result);
}
Identifier Identifier::sanitize(llvm::StringRef Name) {
Identifier Result(Name);
// Convert all non-alphanumeric chars to underscores
for (char &C : Result)
if (not std::isalnum(C))
C = '_';
return Result;
}