Index: source/Core/CxaDemangle.inc =================================================================== --- source/Core/CxaDemangle.inc +++ source/Core/CxaDemangle.inc @@ -1,34 +1,3 @@ -//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - - -// FreeBSD9-STABLE requires this to know about size_t in cxxabi.h -#include -#if defined(_MSC_VER) -#include "lldb/Host/windows/windows.h" -#include -#elif defined (__FreeBSD__) -#define LLDB_USE_BUILTIN_DEMANGLER -#else -#include -#endif - -#ifdef LLDB_USE_BUILTIN_DEMANGLER - -// Provide a fast-path demangler implemented in FastDemangle.cpp until it can -// replace the existing C++ demangler with a complete implementation -namespace lldb_private -{ - extern char * FastDemangle (const char * mangled_name, - long mangled_name_length); -} - //---------------------------------------------------------------------- // Inlined copy of: // http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp @@ -4977,409 +4946,3 @@ } } -#endif - - -#include "llvm/ADT/DenseMap.h" - -#include "lldb/Core/ConstString.h" -#include "lldb/Core/Mangled.h" -#include "lldb/Core/RegularExpression.h" -#include "lldb/Core/Stream.h" -#include "lldb/Core/Timer.h" -#include "lldb/Target/CPPLanguageRuntime.h" -#include -#include -#include - - -using namespace lldb_private; - -static inline bool -cstring_is_mangled (const char *s) -{ - if (s) -#if defined(_MSC_VER) - return (s[0] == '?'); -#else - return (s[0] == '_' && s[1] == 'Z'); -#endif - return false; -} - -static const ConstString & -get_demangled_name_without_arguments (const Mangled *obj) -{ - // This pair is - static std::pair g_most_recent_mangled_to_name_sans_args; - - // Need to have the mangled & demangled names we're currently examining as statics - // so we can return a const ref to them at the end of the func if we don't have - // anything better. - static ConstString g_last_mangled; - static ConstString g_last_demangled; - - ConstString mangled = obj->GetMangledName (); - ConstString demangled = obj->GetDemangledName (); - - if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled) - { - return g_most_recent_mangled_to_name_sans_args.second; - } - - g_last_demangled = demangled; - g_last_mangled = mangled; - - const char *mangled_name_cstr = mangled.GetCString(); - - if (demangled && mangled_name_cstr && mangled_name_cstr[0]) - { - if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' && - (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure, typeinfo structure, and typeinfo mangled_name - mangled_name_cstr[2] != 'G' && // avoid guard variables - mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back) - { - CPPLanguageRuntime::MethodName cxx_method (demangled); - if (!cxx_method.GetBasename().empty() && !cxx_method.GetContext().empty()) - { - std::string shortname = cxx_method.GetContext().str(); - shortname += "::"; - shortname += cxx_method.GetBasename().str(); - ConstString result(shortname.c_str()); - g_most_recent_mangled_to_name_sans_args.first = mangled; - g_most_recent_mangled_to_name_sans_args.second = result; - return g_most_recent_mangled_to_name_sans_args.second; - } - } - } - - if (demangled) - return g_last_demangled; - return g_last_mangled; -} - -#pragma mark Mangled -//---------------------------------------------------------------------- -// Default constructor -//---------------------------------------------------------------------- -Mangled::Mangled () : - m_mangled(), - m_demangled() -{ -} - -//---------------------------------------------------------------------- -// Constructor with an optional string and a boolean indicating if it is -// the mangled version. -//---------------------------------------------------------------------- -Mangled::Mangled (const ConstString &s, bool mangled) : - m_mangled(), - m_demangled() -{ - if (s) - SetValue(s, mangled); -} - -Mangled::Mangled (const ConstString &s) : - m_mangled(), - m_demangled() -{ - if (s) - SetValue(s); -} - -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -Mangled::~Mangled () -{ -} - -//---------------------------------------------------------------------- -// Convert to pointer operator. This allows code to check any Mangled -// objects to see if they contain anything valid using code such as: -// -// Mangled mangled(...); -// if (mangled) -// { ... -//---------------------------------------------------------------------- -Mangled::operator void* () const -{ - return (m_mangled) ? const_cast(this) : NULL; -} - -//---------------------------------------------------------------------- -// Logical NOT operator. This allows code to check any Mangled -// objects to see if they are invalid using code such as: -// -// Mangled mangled(...); -// if (!file_spec) -// { ... -//---------------------------------------------------------------------- -bool -Mangled::operator! () const -{ - return !m_mangled; -} - -//---------------------------------------------------------------------- -// Clear the mangled and demangled values. -//---------------------------------------------------------------------- -void -Mangled::Clear () -{ - m_mangled.Clear(); - m_demangled.Clear(); -} - - -//---------------------------------------------------------------------- -// Compare the the string values. -//---------------------------------------------------------------------- -int -Mangled::Compare (const Mangled& a, const Mangled& b) -{ - return ConstString::Compare(a.GetName(ePreferMangled), a.GetName(ePreferMangled)); -} - - - -//---------------------------------------------------------------------- -// Set the string value in this objects. If "mangled" is true, then -// the mangled named is set with the new value in "s", else the -// demangled name is set. -//---------------------------------------------------------------------- -void -Mangled::SetValue (const ConstString &s, bool mangled) -{ - if (s) - { - if (mangled) - { - m_demangled.Clear(); - m_mangled = s; - } - else - { - m_demangled = s; - m_mangled.Clear(); - } - } - else - { - m_demangled.Clear(); - m_mangled.Clear(); - } -} - -void -Mangled::SetValue (const ConstString &name) -{ - if (name) - { - if (cstring_is_mangled(name.GetCString())) - { - m_demangled.Clear(); - m_mangled = name; - } - else - { - m_demangled = name; - m_mangled.Clear(); - } - } - else - { - m_demangled.Clear(); - m_mangled.Clear(); - } -} - -//---------------------------------------------------------------------- -// Generate the demangled name on demand using this accessor. Code in -// this class will need to use this accessor if it wishes to decode -// the demangled name. The result is cached and will be kept until a -// new string value is supplied to this object, or until the end of the -// object's lifetime. -//---------------------------------------------------------------------- -const ConstString& -Mangled::GetDemangledName () const -{ - // Check to make sure we have a valid mangled name and that we - // haven't already decoded our mangled name. - if (m_mangled && !m_demangled) - { - // We need to generate and cache the demangled name. - Timer scoped_timer (__PRETTY_FUNCTION__, - "Mangled::GetDemangledName (m_mangled = %s)", - m_mangled.GetCString()); - - // Don't bother running anything that isn't mangled - const char *mangled_cstr = m_mangled.GetCString(); - if (cstring_is_mangled(mangled_cstr)) - { - if (!m_mangled.GetMangledCounterpart(m_demangled)) - { - // We didn't already mangle this name, demangle it and if all goes well - // add it to our map. -#ifdef LLDB_USE_BUILTIN_DEMANGLER - // Try to use the fast-path demangler first for the - // performance win, falling back to the full demangler only - // when necessary - char *demangled_name = FastDemangle (mangled_cstr, - m_mangled.GetLength()); - if (!demangled_name) - demangled_name = __cxa_demangle (mangled_cstr, NULL, NULL, NULL); -#elif defined(_MSC_VER) - char *demangled_name = (char *)::malloc(1024); - ::ZeroMemory(demangled_name, 1024); - DWORD result = ::UnDecorateSymbolName(mangled_cstr, demangled_name, 1023, - UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected keywords - UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc keywords - UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications - UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers - UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords - ); - if (result == 0) - { - free (demangled_name); - demangled_name = nullptr; - } -#else - char *demangled_name = abi::__cxa_demangle (mangled_cstr, NULL, NULL, NULL); -#endif - - if (demangled_name) - { - m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled); - free (demangled_name); - } - } - } - if (!m_demangled) - { - // Set the demangled string to the empty string to indicate we - // tried to parse it once and failed. - m_demangled.SetCString(""); - } - } - - return m_demangled; -} - - -bool -Mangled::NameMatches (const RegularExpression& regex) const -{ - if (m_mangled && regex.Execute (m_mangled.AsCString())) - return true; - - if (GetDemangledName() && regex.Execute (m_demangled.AsCString())) - return true; - return false; -} - -//---------------------------------------------------------------------- -// Get the demangled name if there is one, else return the mangled name. -//---------------------------------------------------------------------- -const ConstString& -Mangled::GetName (Mangled::NamePreference preference) const -{ - if (preference == ePreferDemangledWithoutArguments) - { - // Call the accessor to make sure we get a demangled name in case - // it hasn't been demangled yet... - GetDemangledName(); - - return get_demangled_name_without_arguments (this); - } - if (preference == ePreferDemangled) - { - // Call the accessor to make sure we get a demangled name in case - // it hasn't been demangled yet... - if (GetDemangledName()) - return m_demangled; - return m_mangled; - } - else - { - if (m_mangled) - return m_mangled; - return GetDemangledName(); - } -} - -//---------------------------------------------------------------------- -// Dump a Mangled object to stream "s". We don't force our -// demangled name to be computed currently (we don't use the accessor). -//---------------------------------------------------------------------- -void -Mangled::Dump (Stream *s) const -{ - if (m_mangled) - { - *s << ", mangled = " << m_mangled; - } - if (m_demangled) - { - const char * demangled = m_demangled.AsCString(); - s->Printf(", demangled = %s", demangled[0] ? demangled : ""); - } -} - -//---------------------------------------------------------------------- -// Dumps a debug version of this string with extra object and state -// information to stream "s". -//---------------------------------------------------------------------- -void -Mangled::DumpDebug (Stream *s) const -{ - s->Printf("%*p: Mangled mangled = ", static_cast(sizeof(void*) * 2), - static_cast(this)); - m_mangled.DumpDebug(s); - s->Printf(", demangled = "); - m_demangled.DumpDebug(s); -} - -//---------------------------------------------------------------------- -// Return the size in byte that this object takes in memory. The size -// includes the size of the objects it owns, and not the strings that -// it references because they are shared strings. -//---------------------------------------------------------------------- -size_t -Mangled::MemorySize () const -{ - return m_mangled.MemorySize() + m_demangled.MemorySize(); -} - -lldb::LanguageType -Mangled::GetLanguage () -{ - ConstString mangled = GetMangledName(); - if (mangled) - { - if (GetDemangledName()) - { - if (cstring_is_mangled(mangled.GetCString())) - return lldb::eLanguageTypeC_plus_plus; - } - } - return lldb::eLanguageTypeUnknown; -} - -//---------------------------------------------------------------------- -// Dump OBJ to the supplied stream S. -//---------------------------------------------------------------------- -Stream& -operator << (Stream& s, const Mangled& obj) -{ - if (obj.GetMangledName()) - s << "mangled = '" << obj.GetMangledName() << "'"; - - const ConstString& demangled = obj.GetDemangledName(); - if (demangled) - s << ", demangled = '" << demangled << '\''; - else - s << ", demangled = "; - return s; -} Index: source/Core/Mangled.cpp =================================================================== --- source/Core/Mangled.cpp +++ source/Core/Mangled.cpp @@ -29,4954 +29,8 @@ long mangled_name_length); } -//---------------------------------------------------------------------- -// Inlined copy of: -// http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp -// revision 199944. -// -// Changes include: -// - remove the "__cxxabiv1" namespace -// - stripped GCC attributes() -// - removed extern "C" from the cxa_demangle function -// - Changed the scope of the unnamed namespace to include cxa_demangle -// function. -// - Added "#undef _LIBCPP_EXTERN_TEMPLATE" to avoid warning -//---------------------------------------------------------------------- - -#undef _LIBCPP_EXTERN_TEMPLATE // Avoid warning below - -//===-------------------------- cxa_demangle.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#define _LIBCPP_EXTERN_TEMPLATE(...) -#define _LIBCPP_NO_EXCEPTIONS - -#include -#include -#include -#include -#include -#include -#include - - -namespace -{ - -enum -{ - unknown_error = -4, - invalid_args = -3, - invalid_mangled_name, - memory_alloc_failure, - success -}; - -template - const char* parse_type(const char* first, const char* last, C& db); -template - const char* parse_encoding(const char* first, const char* last, C& db); -template - const char* parse_name(const char* first, const char* last, C& db); -template - const char* parse_expression(const char* first, const char* last, C& db); -template - const char* parse_template_args(const char* first, const char* last, C& db); -template - const char* parse_operator_name(const char* first, const char* last, C& db); -template - const char* parse_unqualified_name(const char* first, const char* last, C& db); -template - const char* parse_decltype(const char* first, const char* last, C& db); - -template -void -print_stack(const C& db) -{ - printf("---------\n"); - printf("names:\n"); - for (auto& s : db.names) - printf("{%s#%s}\n", s.first.c_str(), s.second.c_str()); - int i = -1; - printf("subs:\n"); - for (auto& v : db.subs) - { - if (i >= 0) - printf("S%i_ = {", i); - else - printf("S_ = {"); - for (auto& s : v) - printf("{%s#%s}", s.first.c_str(), s.second.c_str()); - printf("}\n"); - ++i; - } - printf("template_param:\n"); - for (auto& t : db.template_param) - { - printf("--\n"); - i = -1; - for (auto& v : t) - { - if (i >= 0) - printf("T%i_ = {", i); - else - printf("T_ = {"); - for (auto& s : v) - printf("{%s#%s}", s.first.c_str(), s.second.c_str()); - printf("}\n"); - ++i; - } - } - printf("---------\n\n"); -} - -template -void -print_state(const char* msg, const char* first, const char* last, const C& db) -{ - printf("%s: ", msg); - for (; first != last; ++first) - printf("%c", *first); - printf("\n"); - print_stack(db); -} - -// ::= [n] - -const char* -parse_number(const char* first, const char* last) -{ - if (first != last) - { - const char* t = first; - if (*t == 'n') - ++t; - if (t != last) - { - if (*t == '0') - { - first = t+1; - } - else if ('1' <= *t && *t <= '9') - { - first = t+1; - while (first != last && std::isdigit(*first)) - ++first; - } - } - } - return first; -} - -template -struct float_data; - -template <> -struct float_data -{ - static const size_t mangled_size = 8; - static const size_t max_demangled_size = 24; - static constexpr const char* spec = "%af"; -}; - -constexpr const char* float_data::spec; - -template <> -struct float_data -{ - static const size_t mangled_size = 16; - static const size_t max_demangled_size = 32; - static constexpr const char* spec = "%a"; -}; - -constexpr const char* float_data::spec; - -template <> -struct float_data -{ - static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms - static const size_t max_demangled_size = 40; - static constexpr const char* spec = "%LaL"; -}; - -constexpr const char* float_data::spec; - -template -const char* -parse_floating_number(const char* first, const char* last, C& db) -{ - const size_t N = float_data::mangled_size; - if (static_cast(last - first) > N) - { - last = first + N; - union - { - Float value; - char buf[sizeof(Float)]; - }; - const char* t = first; - char* e = buf; - for (; t != last; ++t, ++e) - { - if (!isxdigit(*t)) - return first; - unsigned d1 = isdigit(*t) ? static_cast(*t - '0') : - static_cast(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast(*t - '0') : - static_cast(*t - 'a' + 10); - *e = static_cast((d1 << 4) + d0); - } - if (*t == 'E') - { -#if __LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[float_data::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), float_data::spec, value); - if (static_cast(n) >= sizeof(num)) - return first; - db.names.push_back(typename C::String(num, static_cast(n))); - first = t+1; - } - } - return first; -} - -// ::= - -template -const char* -parse_source_name(const char* first, const char* last, C& db) -{ - if (first != last) - { - char c = *first; - if (isdigit(c) && first+1 != last) - { - const char* t = first+1; - size_t n = static_cast(c - '0'); - for (c = *t; isdigit(c); c = *t) - { - n = n * 10 + static_cast(c - '0'); - if (++t == last) - return first; - } - if (static_cast(last - t) >= n) - { - typename C::String r(t, n); - if (r.substr(0, 10) == "_GLOBAL__N") - db.names.push_back("(anonymous namespace)"); - else - db.names.push_back(std::move(r)); - first = t + n; - } - } - } - return first; -} - -// ::= S _ -// ::= S_ -// ::= Sa # ::std::allocator -// ::= Sb # ::std::basic_string -// ::= Ss # ::std::basic_string < char, -// ::std::char_traits, -// ::std::allocator > -// ::= Si # ::std::basic_istream > -// ::= So # ::std::basic_ostream > -// ::= Sd # ::std::basic_iostream > - -template -const char* -parse_substitution(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - if (*first == 'S') - { - switch (first[1]) - { - case 'a': - db.names.push_back("std::allocator"); - first += 2; - break; - case 'b': - db.names.push_back("std::basic_string"); - first += 2; - break; - case 's': - db.names.push_back("std::string"); - first += 2; - break; - case 'i': - db.names.push_back("std::istream"); - first += 2; - break; - case 'o': - db.names.push_back("std::ostream"); - first += 2; - break; - case 'd': - db.names.push_back("std::iostream"); - first += 2; - break; - case '_': - if (!db.subs.empty()) - { - for (const auto& n : db.subs.front()) - db.names.push_back(n); - first += 2; - } - break; - default: - if (std::isdigit(first[1]) || std::isupper(first[1])) - { - size_t sub = 0; - const char* t = first+1; - if (std::isdigit(*t)) - sub = static_cast(*t - '0'); - else - sub = static_cast(*t - 'A') + 10; - for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) - { - sub *= 36; - if (std::isdigit(*t)) - sub += static_cast(*t - '0'); - else - sub += static_cast(*t - 'A') + 10; - } - if (t == last || *t != '_') - return first; - ++sub; - if (sub < db.subs.size()) - { - for (const auto& n : db.subs[sub]) - db.names.push_back(n); - first = t+1; - } - } - break; - } - } - } - return first; -} - -// ::= v # void -// ::= w # wchar_t -// ::= b # bool -// ::= c # char -// ::= a # signed char -// ::= h # unsigned char -// ::= s # short -// ::= t # unsigned short -// ::= i # int -// ::= j # unsigned int -// ::= l # long -// ::= m # unsigned long -// ::= x # long long, __int64 -// ::= y # unsigned long long, __int64 -// ::= n # __int128 -// ::= o # unsigned __int128 -// ::= f # float -// ::= d # double -// ::= e # long double, __float80 -// ::= g # __float128 -// ::= z # ellipsis -// ::= Dd # IEEE 754r decimal floating point (64 bits) -// ::= De # IEEE 754r decimal floating point (128 bits) -// ::= Df # IEEE 754r decimal floating point (32 bits) -// ::= Dh # IEEE 754r half-precision floating point (16 bits) -// ::= Di # char32_t -// ::= Ds # char16_t -// ::= Da # auto (in dependent new-expressions) -// ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) -// ::= u # vendor extended type - -template -const char* -parse_builtin_type(const char* first, const char* last, C& db) -{ - if (first != last) - { - switch (*first) - { - case 'v': - db.names.push_back("void"); - ++first; - break; - case 'w': - db.names.push_back("wchar_t"); - ++first; - break; - case 'b': - db.names.push_back("bool"); - ++first; - break; - case 'c': - db.names.push_back("char"); - ++first; - break; - case 'a': - db.names.push_back("signed char"); - ++first; - break; - case 'h': - db.names.push_back("unsigned char"); - ++first; - break; - case 's': - db.names.push_back("short"); - ++first; - break; - case 't': - db.names.push_back("unsigned short"); - ++first; - break; - case 'i': - db.names.push_back("int"); - ++first; - break; - case 'j': - db.names.push_back("unsigned int"); - ++first; - break; - case 'l': - db.names.push_back("long"); - ++first; - break; - case 'm': - db.names.push_back("unsigned long"); - ++first; - break; - case 'x': - db.names.push_back("long long"); - ++first; - break; - case 'y': - db.names.push_back("unsigned long long"); - ++first; - break; - case 'n': - db.names.push_back("__int128"); - ++first; - break; - case 'o': - db.names.push_back("unsigned __int128"); - ++first; - break; - case 'f': - db.names.push_back("float"); - ++first; - break; - case 'd': - db.names.push_back("double"); - ++first; - break; - case 'e': - db.names.push_back("long double"); - ++first; - break; - case 'g': - db.names.push_back("__float128"); - ++first; - break; - case 'z': - db.names.push_back("..."); - ++first; - break; - case 'u': - { - const char*t = parse_source_name(first+1, last, db); - if (t != first+1) - first = t; - } - break; - case 'D': - if (first+1 != last) - { - switch (first[1]) - { - case 'd': - db.names.push_back("decimal64"); - first += 2; - break; - case 'e': - db.names.push_back("decimal128"); - first += 2; - break; - case 'f': - db.names.push_back("decimal32"); - first += 2; - break; - case 'h': - db.names.push_back("decimal16"); - first += 2; - break; - case 'i': - db.names.push_back("char32_t"); - first += 2; - break; - case 's': - db.names.push_back("char16_t"); - first += 2; - break; - case 'a': - db.names.push_back("auto"); - first += 2; - break; - case 'n': - db.names.push_back("std::nullptr_t"); - first += 2; - break; - } - } - break; - } - } - return first; -} - -// ::= [r] [V] [K] - -const char* -parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) -{ - cv = 0; - if (first != last) - { - if (*first == 'r') - { - cv |= 4; - ++first; - } - if (*first == 'V') - { - cv |= 2; - ++first; - } - if (*first == 'K') - { - cv |= 1; - ++first; - } - } - return first; -} - -// ::= T_ # first template parameter -// ::= T _ - -template -const char* -parse_template_param(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - if (*first == 'T') - { - if (first[1] == '_') - { - if (db.template_param.empty()) - return first; - if (!db.template_param.back().empty()) - { - for (auto& t : db.template_param.back().front()) - db.names.push_back(t); - first += 2; - } - else - { - db.names.push_back("T_"); - first += 2; - db.fix_forward_references = true; - } - } - else if (isdigit(first[1])) - { - const char* t = first+1; - size_t sub = static_cast(*t - '0'); - for (++t; t != last && isdigit(*t); ++t) - { - sub *= 10; - sub += static_cast(*t - '0'); - } - if (t == last || *t != '_' || db.template_param.empty()) - return first; - ++sub; - if (sub < db.template_param.back().size()) - { - for (auto& temp : db.template_param.back()[sub]) - db.names.push_back(temp); - first = t+1; - } - else - { - db.names.push_back(typename C::String(first, t+1)); - first = t+1; - db.fix_forward_references = true; - } - } - } - } - return first; -} - -// cc # const_cast (expression) - -template -const char* -parse_const_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// dc # dynamic_cast (expression) - -template -const char* -parse_dynamic_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// rc # reinterpret_cast (expression) - -template -const char* -parse_reinterpret_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// sc # static_cast (expression) - -template -const char* -parse_static_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// sp # pack expansion - -template -const char* -parse_pack_expansion(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'p') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - first = t; - } - return first; -} - -// st # sizeof (a type) - -template -const char* -parse_sizeof_type_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// sz # sizeof (a expression) - -template -const char* -parse_sizeof_expr_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'z') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// sZ # size of a parameter pack - -template -const char* -parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') - { - size_t k0 = db.names.size(); - const char* t = parse_template_param(first+2, last, db); - size_t k1 = db.names.size(); - if (t != first+2) - { - typename C::String tmp("sizeof...("); - size_t k = k0; - if (k != k1) - { - tmp += db.names[k].move_full(); - for (++k; k != k1; ++k) - tmp += ", " + db.names[k].move_full(); - } - tmp += ")"; - for (; k1 != k0; --k1) - db.names.pop_back(); - db.names.push_back(std::move(tmp)); - first = t; - } - } - return first; -} - -// ::= fp _ # L == 0, first parameter -// ::= fp _ # L == 0, second and later parameters -// ::= fL p _ # L > 0, first parameter -// ::= fL p _ # L > 0, second and later parameters - -template -const char* -parse_function_param(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && *first == 'f') - { - if (first[1] == 'p') - { - unsigned cv; - const char* t = parse_cv_qualifiers(first+2, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.names.push_back("fp" + typename C::String(t, t1)); - first = t1+1; - } - } - else if (first[1] == 'L') - { - unsigned cv; - const char* t0 = parse_number(first+2, last); - if (t0 != last && *t0 == 'p') - { - ++t0; - const char* t = parse_cv_qualifiers(t0, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.names.push_back("fp" + typename C::String(t, t1)); - first = t1+1; - } - } - } - } - return first; -} - -// sZ # size of a function parameter pack - -template -const char* -parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') - { - const char* t = parse_function_param(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// te # typeid (expression) -// ti # typeid (type) - -template -const char* -parse_typeid_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) - { - const char* t; - if (first[1] == 'e') - t = parse_expression(first+2, last, db); - else - t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "typeid(" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// tw # throw expression - -template -const char* -parse_throw_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 't' && first[1] == 'w') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "throw " + db.names.back().move_full(); - first = t; - } - } - return first; -} - -// ds # expr.*expr - -template -const char* -parse_dot_star_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 's') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += ".*" + expr; - first = t1; - } - } - } - return first; -} - -// ::= [ ] - -template -const char* -parse_simple_id(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t = parse_source_name(first, last, db); - if (t != first) - { - const char* t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - } - first = t1; - } - else - first = t; - } - return first; -} - -// ::= -// ::= -// ::= - -template -const char* -parse_unresolved_type(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t = first; - switch (*first) - { - case 'T': - { - size_t k0 = db.names.size(); - t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); - if (t != first && k1 == k0 + 1) - { - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - else - { - for (; k1 != k0; --k1) - db.names.pop_back(); - } - break; - } - case 'D': - t = parse_decltype(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - break; - case 'S': - t = parse_substitution(first, last, db); - if (t != first) - first = t; - else - { - if (last - first > 2 && first[1] == 't') - { - t = parse_unqualified_name(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "std::"); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - } - break; - } - } - return first; -} - -// ::= # e.g., ~T or ~decltype(f()) -// ::= # e.g., ~A<2*N> - -template -const char* -parse_destructor_name(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t = parse_unresolved_type(first, last, db); - if (t == first) - t = parse_simple_id(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "~"); - first = t; - } - } - return first; -} - -// ::= # unresolved name -// extension ::= # unresolved operator-function-id -// extension ::= # unresolved operator template-id -// ::= on # unresolved operator-function-id -// ::= on # unresolved operator template-id -// ::= dn # destructor or pseudo-destructor; -// # e.g. ~X or ~X - -template -const char* -parse_base_unresolved_name(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') - { - if (first[0] == 'o') - { - const char* t = parse_operator_name(first+2, last, db); - if (t != first+2) - { - first = parse_template_args(t, last, db); - if (first != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - } - } - } - else - { - const char* t = parse_destructor_name(first+2, last, db); - if (t != first+2) - first = t; - } - } - else - { - const char* t = parse_simple_id(first, last, db); - if (t == first) - { - t = parse_operator_name(first, last, db); - if (t != first) - { - first = parse_template_args(t, last, db); - if (first != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - } - } - } - else - first = t; - } - } - return first; -} - -// ::= - -template -const char* -parse_unresolved_qualifier_level(const char* first, const char* last, C& db) -{ - return parse_simple_id(first, last, db); -} - -// -// extension ::= srN [] * E -// ::= [gs] # x or (with "gs") ::x -// ::= [gs] sr + E -// # A::x, N::y, A::z; "gs" means leading "::" -// ::= sr # T::x / decltype(p)::x -// extension ::= sr -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN + E - -template -const char* -parse_unresolved_name(const char* first, const char* last, C& db) -{ - if (last - first > 2) - { - const char* t = first; - bool global = false; - if (t[0] == 'g' && t[1] == 's') - { - global = true; - t += 2; - } - const char* t2 = parse_base_unresolved_name(t, last, db); - if (t2 != t) - { - if (global) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "::"); - } - first = t2; - } - else if (last - t > 2 && t[0] == 's' && t[1] == 'r') - { - if (t[2] == 'N') - { - t += 3; - const char* t1 = parse_unresolved_type(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - t = t1; - if (t == last) - { - db.names.pop_back(); - return first; - } - } - while (*t != 'E') - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - t = t1; - } - ++t; - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - first = t1; - } - else - { - t += 2; - const char* t1 = parse_unresolved_type(t, last, db); - if (t1 != t) - { - t = t1; - t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - t = t1; - } - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - first = t1; - } - else - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - if (global) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "::"); - } - while (*t != 'E') - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - t = t1; - } - ++t; - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - first = t1; - } - } - } - } - return first; -} - -// dt # expr.name - -template -const char* -parse_dot_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 't') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_unresolved_name(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "." + name; - first = t1; - } - } - } - return first; -} - -// cl + E # call - -template -const char* -parse_call_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (t == last) - return first; - if (db.names.empty()) - return first; - db.names.back().first += db.names.back().second; - db.names.back().second = typename C::String(); - db.names.back().first.append("("); - bool first_expr = true; - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_expr) - { - db.names.back().first.append(", "); - first_expr = false; - } - db.names.back().first.append(tmp); - } - t = t1; - } - ++t; - if (db.names.empty()) - return first; - db.names.back().first.append(")"); - first = t; - } - } - return first; -} - -// [gs] nw * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * E # parenthesized initialization - -template -const char* -parse_new_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 4) - { - const char* t = first; - bool parsed_gs = false; - if (t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) - { - bool is_array = t[1] == 'a'; - t += 2; - if (t == last) - return first; - bool has_expr_list = false; - bool first_expr = true; - while (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - has_expr_list = true; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } - t = t1; - } - ++t; - const char* t1 = parse_type(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - bool has_init = false; - if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') - { - t += 2; - has_init = true; - first_expr = true; - while (*t != 'E') - { - t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } - t = t1; - } - } - if (*t != 'E') - return first; - typename C::String init_list; - if (has_init) - { - if (db.names.empty()) - return first; - init_list = db.names.back().move_full(); - db.names.pop_back(); - } - if (db.names.empty()) - return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - typename C::String expr_list; - if (has_expr_list) - { - if (db.names.empty()) - return first; - expr_list = db.names.back().move_full(); - db.names.pop_back(); - } - typename C::String r; - if (parsed_gs) - r = "::"; - if (is_array) - r += "[] "; - else - r += " "; - if (has_expr_list) - r += "(" + expr_list + ") "; - r += type; - if (has_init) - r += " (" + init_list + ")"; - db.names.push_back(std::move(r)); - first = t+1; - } - } - return first; -} - -// cv # conversion with one argument -// cv _ * E # conversion with a different number of arguments - -template -const char* -parse_conversion_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') - { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; - const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; - if (t != first+2 && t != last) - { - if (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t) - return first; - t = t1; - } - else - { - ++t; - if (t == last) - return first; - if (*t == 'E') - db.names.emplace_back(); - else - { - bool first_expr = true; - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } - t = t1; - } - } - ++t; - } - if (db.names.size() < 2) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; - first = t; - } - } - return first; -} - -// pt # expr->name - -template -const char* -parse_arrow_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'p' && first[1] == 't') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "->"; - db.names.back().first += tmp; - first = t1; - } - } - } - return first; -} - -// ::= R # & ref-qualifier -// ::= O # && ref-qualifier - -// ::= F [Y] [] E - -template -const char* -parse_function_type(const char* first, const char* last, C& db) -{ - if (first != last && *first == 'F') - { - const char* t = first+1; - if (t != last) - { - bool externC = false; - if (*t == 'Y') - { - externC = true; - if (++t == last) - return first; - } - const char* t1 = parse_type(t, last, db); - if (t1 != t) - { - t = t1; - typename C::String sig("("); - int ref_qual = 0; - while (true) - { - if (t == last) - { - db.names.pop_back(); - return first; - } - if (*t == 'E') - { - ++t; - break; - } - if (*t == 'v') - { - ++t; - continue; - } - if (*t == 'R' && t+1 != last && t[1] == 'E') - { - ref_qual = 1; - ++t; - continue; - } - if (*t == 'O' && t+1 != last && t[1] == 'E') - { - ref_qual = 2; - ++t; - continue; - } - size_t k0 = db.names.size(); - t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); - if (t1 == t || t1 == last) - return first; - for (size_t k = k0; k < k1; ++k) - { - if (sig.size() > 1) - sig += ", "; - sig += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) - db.names.pop_back(); - t = t1; - } - sig += ")"; - switch (ref_qual) - { - case 1: - sig += " &"; - break; - case 2: - sig += " &&"; - break; - } - if (db.names.empty()) - return first; - db.names.back().first += " "; - db.names.back().second.insert(0, sig); - first = t; - } - } - } - return first; -} - -// ::= M - -template -const char* -parse_pointer_to_member_type(const char* first, const char* last, C& db) -{ - if (first != last && *first == 'M') - { - const char* t = parse_type(first+1, last, db); - if (t != first+1) - { - const char* t2 = parse_type(t, last, db); - if (t2 != t) - { - if (db.names.size() < 2) - return first; - auto func = std::move(db.names.back()); - db.names.pop_back(); - auto class_type = std::move(db.names.back()); - if (func.second.front() == '(') - { - db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; - db.names.back().second = ")" + std::move(func.second); - } - else - { - db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; - db.names.back().second = std::move(func.second); - } - first = t2; - } - } - } - return first; -} - -// ::= A _ -// ::= A [] _ - -template -const char* -parse_array_type(const char* first, const char* last, C& db) -{ - if (first != last && *first == 'A' && first+1 != last) - { - if (first[1] == '_') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " []"); - first = t; - } - } - else if ('1' <= first[1] && first[1] <= '9') - { - const char* t = parse_number(first+1, last); - if (t != last && *t == '_') - { - const char* t2 = parse_type(t+1, last, db); - if (t2 != t+1) - { - if (db.names.empty()) - return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); - first = t2; - } - } - } - else - { - const char* t = parse_expression(first+1, last, db); - if (t != first+1 && t != last && *t == '_') - { - const char* t2 = parse_type(++t, last, db); - if (t2 != t) - { - if (db.names.size() < 2) - return first; - auto type = std::move(db.names.back()); - db.names.pop_back(); - auto expr = std::move(db.names.back()); - db.names.back().first = std::move(type.first); - if (type.second.substr(0, 2) == " [") - type.second.erase(0, 1); - db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); - first = t2; - } - } - } - } - return first; -} - -// ::= Dt E # decltype of an id-expression or class member access (C++0x) -// ::= DT E # decltype of an expression (C++0x) - -template -const char* -parse_decltype(const char* first, const char* last, C& db) -{ - if (last - first >= 4 && first[0] == 'D') - { - switch (first[1]) - { - case 't': - case 'T': - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2 && t != last && *t == 'E') - { - if (db.names.empty()) - return first; - db.names.back() = "decltype(" + db.names.back().move_full() + ")"; - first = t+1; - } - } - break; - } - } - return first; -} - -// extension: -// ::= Dv _ -// -// ::= Dv [] _ -// ::= -// ::= p # AltiVec vector pixel - -template -const char* -parse_vector_type(const char* first, const char* last, C& db) -{ - if (last - first > 3 && first[0] == 'D' && first[1] == 'v') - { - if ('1' <= first[2] && first[2] <= '9') - { - const char* t = parse_number(first+2, last); - if (t == last || *t != '_') - return first; - const char* num = first + 2; - size_t sz = static_cast(t - num); - if (++t != last) - { - if (*t != 'p') - { - const char* t1 = parse_type(t, last, db); - if (t1 != t) - { - if (db.names.empty()) - return first; - db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; - first = t1; - } - } - else - { - ++t; - db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); - first = t; - } - } - } - else - { - typename C::String num; - const char* t1 = first+2; - if (*t1 != '_') - { - const char* t = parse_expression(t1, last, db); - if (t != t1) - { - if (db.names.empty()) - return first; - num = db.names.back().move_full(); - db.names.pop_back(); - t1 = t; - } - } - if (t1 != last && *t1 == '_' && ++t1 != last) - { - const char* t = parse_type(t1, last, db); - if (t != t1) - { - if (db.names.empty()) - return first; - db.names.back().first += " vector[" + num + "]"; - first = t; - } - } - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= P # pointer-to -// ::= R # reference-to -// ::= O # rvalue reference-to (C++0x) -// ::= C # complex pair (C 2000) -// ::= G # imaginary (C 2000) -// ::= Dp # pack expansion (C++0x) -// ::= U # vendor extended type qualifier -// extension := U # objc-type -// extension := # starts with Dv - -// ::= objcproto # k0 = 9 + + k1 -// := # PU<11+>objcproto 11objc_object 11objc_object -> id - -template -const char* -parse_type(const char* first, const char* last, C& db) -{ - if (first != last) - { - switch (*first) - { - case 'r': - case 'V': - case 'K': - { - unsigned cv = 0; - const char* t = parse_cv_qualifiers(first, last, cv); - if (t != first) - { - bool is_function = *t == 'F'; - size_t k0 = db.names.size(); - const char* t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); - if (t1 != t) - { - if (is_function) - db.subs.pop_back(); - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (is_function) - { - size_t p = db.names[k].second.size(); - if (db.names[k].second[p-2] == '&') - p -= 3; - else if (db.names[k].second.back() == '&') - p -= 2; - if (cv & 1) - { - db.names[k].second.insert(p, " const"); - p += 6; - } - if (cv & 2) - { - db.names[k].second.insert(p, " volatile"); - p += 9; - } - if (cv & 4) - db.names[k].second.insert(p, " restrict"); - } - else - { - if (cv & 1) - db.names[k].first.append(" const"); - if (cv & 2) - db.names[k].first.append(" volatile"); - if (cv & 4) - db.names[k].first.append(" restrict"); - } - db.subs.back().push_back(db.names[k]); - } - first = t1; - } - } - } - break; - default: - { - const char* t = parse_builtin_type(first, last, db); - if (t != first) - { - first = t; - } - else - { - switch (*first) - { - case 'A': - t = parse_array_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'C': - t = parse_type(first+1, last, db); - if (t != first+1) - { - if (db.names.empty()) - return first; - db.names.back().first.append(" complex"); - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'F': - t = parse_function_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'G': - t = parse_type(first+1, last, db); - if (t != first+1) - { - if (db.names.empty()) - return first; - db.names.back().first.append(" imaginary"); - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'M': - t = parse_pointer_to_member_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'O': - { - size_t k0 = db.names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); - if (t != first+1) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&&"); - db.subs.back().push_back(db.names[k]); - } - first = t; - } - break; - } - case 'P': - { - size_t k0 = db.names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); - if (t != first+1) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") - { - db.names[k].first.append("*"); - } - else - { - db.names[k].first.replace(0, 11, "id"); - } - db.subs.back().push_back(db.names[k]); - } - first = t; - } - break; - } - case 'R': - { - size_t k0 = db.names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); - if (t != first+1) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&"); - db.subs.back().push_back(db.names[k]); - } - first = t; - } - break; - } - case 'T': - { - size_t k0 = db.names.size(); - t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); - if (t != first) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); - if (db.try_to_parse_template_args && k1 == k0+1) - { - const char* t1 = parse_template_args(t, last, db); - if (t1 != t) - { - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - t = t1; - } - } - first = t; - } - break; - } - case 'U': - if (first+1 != last) - { - t = parse_source_name(first+1, last, db); - if (t != first+1) - { - const char* t2 = parse_type(t, last, db); - if (t2 != t) - { - if (db.names.size() < 2) - return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.back().first.substr(0, 9) != "objcproto") - { - db.names.back() = type + " " + db.names.back().move_full(); - } - else - { - auto proto = db.names.back().move_full(); - db.names.pop_back(); - t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); - if (t != proto.data() + 9) - { - db.names.back() = type + "<" + db.names.back().move_full() + ">"; - } - else - { - db.names.push_back(type + " " + proto); - } - } - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t2; - } - } - } - break; - case 'S': - if (first+1 != last && first[1] == 't') - { - t = parse_name(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - else - { - t = parse_substitution(first, last, db); - if (t != first) - { - first = t; - // Parsed a substitution. If the substitution is a - // it might be followed by . - t = parse_template_args(first, last, db); - if (t != first) - { - if (db.names.size() < 2) - return first; - auto template_args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += template_args; - // Need to create substitution for - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - } - break; - case 'D': - if (first+1 != last) - { - switch (first[1]) - { - case 'p': - { - size_t k0 = db.names.size(); - t = parse_type(first+2, last, db); - size_t k1 = db.names.size(); - if (t != first+2) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); - first = t; - return first; - } - break; - } - case 't': - case 'T': - t = parse_decltype(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - return first; - } - break; - case 'v': - t = parse_vector_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - return first; - } - break; - } - } - // drop through - default: - // must check for builtin-types before class-enum-types to avoid - // ambiguities with operator-names - t = parse_builtin_type(first, last, db); - if (t != first) - { - first = t; - } - else - { - t = parse_name(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - break; - } - } - break; - } - } - } - return first; -} - -// -// ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= -// ::= li # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= v # vendor extended operator - -template -const char* -parse_operator_name(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - switch (first[0]) - { - case 'a': - switch (first[1]) - { - case 'a': - db.names.push_back("operator&&"); - first += 2; - break; - case 'd': - case 'n': - db.names.push_back("operator&"); - first += 2; - break; - case 'N': - db.names.push_back("operator&="); - first += 2; - break; - case 'S': - db.names.push_back("operator="); - first += 2; - break; - } - break; - case 'c': - switch (first[1]) - { - case 'l': - db.names.push_back("operator()"); - first += 2; - break; - case 'm': - db.names.push_back("operator,"); - first += 2; - break; - case 'o': - db.names.push_back("operator~"); - first += 2; - break; - case 'v': - { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; - const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "operator "); - db.parsed_ctor_dtor_cv = true; - first = t; - } - } - break; - } - break; - case 'd': - switch (first[1]) - { - case 'a': - db.names.push_back("operator delete[]"); - first += 2; - break; - case 'e': - db.names.push_back("operator*"); - first += 2; - break; - case 'l': - db.names.push_back("operator delete"); - first += 2; - break; - case 'v': - db.names.push_back("operator/"); - first += 2; - break; - case 'V': - db.names.push_back("operator/="); - first += 2; - break; - } - break; - case 'e': - switch (first[1]) - { - case 'o': - db.names.push_back("operator^"); - first += 2; - break; - case 'O': - db.names.push_back("operator^="); - first += 2; - break; - case 'q': - db.names.push_back("operator=="); - first += 2; - break; - } - break; - case 'g': - switch (first[1]) - { - case 'e': - db.names.push_back("operator>="); - first += 2; - break; - case 't': - db.names.push_back("operator>"); - first += 2; - break; - } - break; - case 'i': - if (first[1] == 'x') - { - db.names.push_back("operator[]"); - first += 2; - } - break; - case 'l': - switch (first[1]) - { - case 'e': - db.names.push_back("operator<="); - first += 2; - break; - case 'i': - { - const char* t = parse_source_name(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "operator\"\" "); - first = t; - } - } - break; - case 's': - db.names.push_back("operator<<"); - first += 2; - break; - case 'S': - db.names.push_back("operator<<="); - first += 2; - break; - case 't': - db.names.push_back("operator<"); - first += 2; - break; - } - break; - case 'm': - switch (first[1]) - { - case 'i': - db.names.push_back("operator-"); - first += 2; - break; - case 'I': - db.names.push_back("operator-="); - first += 2; - break; - case 'l': - db.names.push_back("operator*"); - first += 2; - break; - case 'L': - db.names.push_back("operator*="); - first += 2; - break; - case 'm': - db.names.push_back("operator--"); - first += 2; - break; - } - break; - case 'n': - switch (first[1]) - { - case 'a': - db.names.push_back("operator new[]"); - first += 2; - break; - case 'e': - db.names.push_back("operator!="); - first += 2; - break; - case 'g': - db.names.push_back("operator-"); - first += 2; - break; - case 't': - db.names.push_back("operator!"); - first += 2; - break; - case 'w': - db.names.push_back("operator new"); - first += 2; - break; - } - break; - case 'o': - switch (first[1]) - { - case 'o': - db.names.push_back("operator||"); - first += 2; - break; - case 'r': - db.names.push_back("operator|"); - first += 2; - break; - case 'R': - db.names.push_back("operator|="); - first += 2; - break; - } - break; - case 'p': - switch (first[1]) - { - case 'm': - db.names.push_back("operator->*"); - first += 2; - break; - case 'l': - db.names.push_back("operator+"); - first += 2; - break; - case 'L': - db.names.push_back("operator+="); - first += 2; - break; - case 'p': - db.names.push_back("operator++"); - first += 2; - break; - case 's': - db.names.push_back("operator+"); - first += 2; - break; - case 't': - db.names.push_back("operator->"); - first += 2; - break; - } - break; - case 'q': - if (first[1] == 'u') - { - db.names.push_back("operator?"); - first += 2; - } - break; - case 'r': - switch (first[1]) - { - case 'm': - db.names.push_back("operator%"); - first += 2; - break; - case 'M': - db.names.push_back("operator%="); - first += 2; - break; - case 's': - db.names.push_back("operator>>"); - first += 2; - break; - case 'S': - db.names.push_back("operator>>="); - first += 2; - break; - } - break; - case 'v': - if (std::isdigit(first[1])) - { - const char* t = parse_source_name(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "operator "); - first = t; - } - } - break; - } - } - return first; -} - -template -const char* -parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) -{ - const char* t = parse_number(first, last); - if (t != first && t != last && *t == 'E') - { - if (lit.size() > 3) - db.names.push_back("(" + lit + ")"); - else - db.names.emplace_back(); - if (*first == 'n') - { - db.names.back().first += '-'; - ++first; - } - db.names.back().first.append(first, t); - if (lit.size() <= 3) - db.names.back().first += lit; - first = t+1; - } - return first; -} - -// ::= L E # integer literal -// ::= L E # floating literal -// ::= L E # string literal -// ::= L E # nullptr literal (i.e., "LDnE") -// ::= L _ E # complex floating point literal (C 2000) -// ::= L E # external name - -template -const char* -parse_expr_primary(const char* first, const char* last, C& db) -{ - if (last - first >= 4 && *first == 'L') - { - switch (first[1]) - { - case 'w': - { - const char* t = parse_integer_literal(first+2, last, "wchar_t", db); - if (t != first+2) - first = t; - } - break; - case 'b': - if (first[3] == 'E') - { - switch (first[2]) - { - case '0': - db.names.push_back("false"); - first += 4; - break; - case '1': - db.names.push_back("true"); - first += 4; - break; - } - } - break; - case 'c': - { - const char* t = parse_integer_literal(first+2, last, "char", db); - if (t != first+2) - first = t; - } - break; - case 'a': - { - const char* t = parse_integer_literal(first+2, last, "signed char", db); - if (t != first+2) - first = t; - } - break; - case 'h': - { - const char* t = parse_integer_literal(first+2, last, "unsigned char", db); - if (t != first+2) - first = t; - } - break; - case 's': - { - const char* t = parse_integer_literal(first+2, last, "short", db); - if (t != first+2) - first = t; - } - break; - case 't': - { - const char* t = parse_integer_literal(first+2, last, "unsigned short", db); - if (t != first+2) - first = t; - } - break; - case 'i': - { - const char* t = parse_integer_literal(first+2, last, "", db); - if (t != first+2) - first = t; - } - break; - case 'j': - { - const char* t = parse_integer_literal(first+2, last, "u", db); - if (t != first+2) - first = t; - } - break; - case 'l': - { - const char* t = parse_integer_literal(first+2, last, "l", db); - if (t != first+2) - first = t; - } - break; - case 'm': - { - const char* t = parse_integer_literal(first+2, last, "ul", db); - if (t != first+2) - first = t; - } - break; - case 'x': - { - const char* t = parse_integer_literal(first+2, last, "ll", db); - if (t != first+2) - first = t; - } - break; - case 'y': - { - const char* t = parse_integer_literal(first+2, last, "ull", db); - if (t != first+2) - first = t; - } - break; - case 'n': - { - const char* t = parse_integer_literal(first+2, last, "__int128", db); - if (t != first+2) - first = t; - } - break; - case 'o': - { - const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db); - if (t != first+2) - first = t; - } - break; - case 'f': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'd': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'e': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case '_': - if (first[2] == 'Z') - { - const char* t = parse_encoding(first+3, last, db); - if (t != first+3 && t != last && *t == 'E') - first = t+1; - } - break; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - break; - default: - { - // might be named type - const char* t = parse_type(first+1, last, db); - if (t != first+1 && t != last) - { - if (*t != 'E') - { - const char* n = t; - for (; n != last && isdigit(*n); ++n) - ; - if (n != t && n != last && *n == 'E') - { - if (db.names.empty()) - return first; - db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); - first = n+1; - break; - } - } - else - { - first = t+1; - break; - } - } - } - } - } - return first; -} - -template -String -base_name(String& s) -{ - if (s.empty()) - return s; - if (s == "std::string") - { - s = "std::basic_string, std::allocator >"; - return "basic_string"; - } - if (s == "std::istream") - { - s = "std::basic_istream >"; - return "basic_istream"; - } - if (s == "std::ostream") - { - s = "std::basic_ostream >"; - return "basic_ostream"; - } - if (s == "std::iostream") - { - s = "std::basic_iostream >"; - return "basic_iostream"; - } - const char* const pf = s.data(); - const char* pe = pf + s.size(); - if (pe[-1] == '>') - { - unsigned c = 1; - while (true) - { - if (--pe == pf) - return String(); - if (pe[-1] == '<') - { - if (--c == 0) - { - --pe; - break; - } - } - else if (pe[-1] == '>') - ++c; - } - } - const char* p0 = pe - 1; - for (; p0 != pf; --p0) - { - if (*p0 == ':') - { - ++p0; - break; - } - } - return String(p0, pe); -} - -// ::= C1 # complete object constructor -// ::= C2 # base object constructor -// ::= C3 # complete object allocating constructor -// extension ::= C5 # ? -// ::= D0 # deleting destructor -// ::= D1 # complete object destructor -// ::= D2 # base object destructor -// extension ::= D5 # ? - -template -const char* -parse_ctor_dtor_name(const char* first, const char* last, C& db) -{ - if (last-first >= 2 && !db.names.empty()) - { - switch (first[0]) - { - case 'C': - switch (first[1]) - { - case '1': - case '2': - case '3': - case '5': - if (db.names.empty()) - return first; - db.names.push_back(base_name(db.names.back().first)); - first += 2; - db.parsed_ctor_dtor_cv = true; - break; - } - break; - case 'D': - switch (first[1]) - { - case '0': - case '1': - case '2': - case '5': - if (db.names.empty()) - return first; - db.names.push_back("~" + base_name(db.names.back().first)); - first += 2; - db.parsed_ctor_dtor_cv = true; - break; - } - break; - } - } - return first; -} - -// ::= Ut [ ] _ -// ::= -// -// ::= Ul E [ ] _ -// -// ::= + # Parameter types or "v" if the lambda has no parameters - -template -const char* -parse_unnamed_type_name(const char* first, const char* last, C& db) -{ - if (last - first > 2 && first[0] == 'U') - { - char type = first[1]; - switch (type) - { - case 't': - { - db.names.push_back(typename C::String("'unnamed")); - const char* t0 = first+2; - if (t0 == last) - { - db.names.pop_back(); - return first; - } - if (std::isdigit(*t0)) - { - const char* t1 = t0 + 1; - while (t1 != last && std::isdigit(*t1)) - ++t1; - db.names.back().first.append(t0, t1); - t0 = t1; - } - db.names.back().first.push_back('\''); - if (t0 == last || *t0 != '_') - { - db.names.pop_back(); - return first; - } - first = t0 + 1; - } - break; - case 'l': - { - db.names.push_back(typename C::String("'lambda'(")); - const char* t0 = first+2; - if (first[2] == 'v') - { - db.names.back().first += ')'; - ++t0; - } - else - { - const char* t1 = parse_type(t0, last, db); - if (t1 == t0) - { - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first.append(tmp); - t0 = t1; - while (true) - { - t1 = parse_type(t0, last, db); - if (t1 == t0) - break; - if (db.names.size() < 2) - return first; - tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - } - t0 = t1; - } - db.names.back().first.append(")"); - } - if (t0 == last || *t0 != 'E') - { - db.names.pop_back(); - return first; - } - ++t0; - if (t0 == last) - { - db.names.pop_back(); - return first; - } - if (std::isdigit(*t0)) - { - const char* t1 = t0 + 1; - while (t1 != last && std::isdigit(*t1)) - ++t1; - db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1); - t0 = t1; - } - if (t0 == last || *t0 != '_') - { - db.names.pop_back(); - return first; - } - first = t0 + 1; - } - break; - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= - -template -const char* -parse_unqualified_name(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t; - switch (*first) - { - case 'C': - case 'D': - t = parse_ctor_dtor_name(first, last, db); - if (t != first) - first = t; - break; - case 'U': - t = parse_unnamed_type_name(first, last, db); - if (t != first) - first = t; - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - t = parse_source_name(first, last, db); - if (t != first) - first = t; - break; - default: - t = parse_operator_name(first, last, db); - if (t != first) - first = t; - break; - }; - } - return first; -} - -// ::= -// ::= St # ::std:: -// extension ::= StL - -template -const char* -parse_unscoped_name(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - const char* t0 = first; - bool St = false; - if (first[0] == 'S' && first[1] == 't') - { - t0 += 2; - St = true; - if (t0 != last && *t0 == 'L') - ++t0; - } - const char* t1 = parse_unqualified_name(t0, last, db); - if (t1 != t0) - { - if (St) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "std::"); - } - first = t1; - } - } - return first; -} - -// at # alignof (a type) - -template -const char* -parse_alignof_type(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// az # alignof (a expression) - -template -const char* -parse_alignof_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -template -const char* -parse_noexcept_expression(const char* first, const char* last, C& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.names.empty()) - return first; - db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; - first = t1; - } - return first; -} - -template -const char* -parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.names.empty()) - return first; - db.names.back().first = op + "(" + db.names.back().move_full() + ")"; - first = t1; - } - return first; -} - -template -const char* -parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.names.size() < 2) - return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - auto& nm = db.names.back().first; - nm.clear(); - if (op == ">") - nm += '('; - nm += "(" + op1 + ") " + op + " (" + op2 + ")"; - if (op == ">") - nm += ')'; - first = t2; - } - else - db.names.pop_back(); - } - return first; -} - -// ::= -// ::= -// ::= -// ::= cl + E # call -// ::= cv # conversion with one argument -// ::= cv _ * E # conversion with a different number of arguments -// ::= [gs] nw * _ E # new (expr-list) type -// ::= [gs] nw * _ # new (expr-list) type (init) -// ::= [gs] na * _ E # new[] (expr-list) type -// ::= [gs] na * _ # new[] (expr-list) type (init) -// ::= [gs] dl # delete expression -// ::= [gs] da # delete[] expression -// ::= pp_ # prefix ++ -// ::= mm_ # prefix -- -// ::= ti # typeid (type) -// ::= te # typeid (expression) -// ::= dc # dynamic_cast (expression) -// ::= sc # static_cast (expression) -// ::= cc # const_cast (expression) -// ::= rc # reinterpret_cast (expression) -// ::= st # sizeof (a type) -// ::= sz # sizeof (an expression) -// ::= at # alignof (a type) -// ::= az # alignof (an expression) -// ::= nx # noexcept (expression) -// ::= -// ::= -// ::= dt # expr.name -// ::= pt # expr->name -// ::= ds # expr.*expr -// ::= sZ # size of a parameter pack -// ::= sZ # size of a function parameter pack -// ::= sp # pack expansion -// ::= tw # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= - -template -const char* -parse_expression(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - const char* t = first; - bool parsed_gs = false; - if (last - first >= 4 && t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - switch (*t) - { - case 'L': - first = parse_expr_primary(first, last, db); - break; - case 'T': - first = parse_template_param(first, last, db); - break; - case 'f': - first = parse_function_param(first, last, db); - break; - case 'a': - switch (t[1]) - { - case 'a': - t = parse_binary_expression(first+2, last, "&&", db); - if (t != first+2) - first = t; - break; - case 'd': - t = parse_prefix_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'n': - t = parse_binary_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'N': - t = parse_binary_expression(first+2, last, "&=", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "=", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_alignof_type(first, last, db); - break; - case 'z': - first = parse_alignof_expr(first, last, db); - break; - } - break; - case 'c': - switch (t[1]) - { - case 'c': - first = parse_const_cast_expr(first, last, db); - break; - case 'l': - first = parse_call_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, ",", db); - if (t != first+2) - first = t; - break; - case 'o': - t = parse_prefix_expression(first+2, last, "~", db); - if (t != first+2) - first = t; - break; - case 'v': - first = parse_conversion_expr(first, last, db); - break; - } - break; - case 'd': - switch (t[1]) - { - case 'a': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.names.empty()) - return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete[] " + db.names.back().move_full(); - first = t1; - } - } - break; - case 'c': - first = parse_dynamic_cast_expr(first, last, db); - break; - case 'e': - t = parse_prefix_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'l': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.names.empty()) - return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete " + db.names.back().move_full(); - first = t1; - } - } - break; - case 'n': - return parse_unresolved_name(first, last, db); - case 's': - first = parse_dot_star_expr(first, last, db); - break; - case 't': - first = parse_dot_expr(first, last, db); - break; - case 'v': - t = parse_binary_expression(first+2, last, "/", db); - if (t != first+2) - first = t; - break; - case 'V': - t = parse_binary_expression(first+2, last, "/=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'e': - switch (t[1]) - { - case 'o': - t = parse_binary_expression(first+2, last, "^", db); - if (t != first+2) - first = t; - break; - case 'O': - t = parse_binary_expression(first+2, last, "^=", db); - if (t != first+2) - first = t; - break; - case 'q': - t = parse_binary_expression(first+2, last, "==", db); - if (t != first+2) - first = t; - break; - } - break; - case 'g': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, ">=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, ">", db); - if (t != first+2) - first = t; - break; - } - break; - case 'i': - if (t[1] == 'x') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.names.size() < 2) - return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ")[" + op2 + "]"; - first = t2; - } - else - db.names.pop_back(); - } - } - break; - case 'l': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, "<=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, "<<", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "<<=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, "<", db); - if (t != first+2) - first = t; - break; - } - break; - case 'm': - switch (t[1]) - { - case 'i': - t = parse_binary_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 'I': - t = parse_binary_expression(first+2, last, "-=", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "*=", db); - if (t != first+2) - first = t; - break; - case 'm': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "--", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "(" + db.names.back().move_full() + ")--"; - first = t1; - } - } - break; - } - break; - case 'n': - switch (t[1]) - { - case 'a': - case 'w': - first = parse_new_expr(first, last, db); - break; - case 'e': - t = parse_binary_expression(first+2, last, "!=", db); - if (t != first+2) - first = t; - break; - case 'g': - t = parse_prefix_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_prefix_expression(first+2, last, "!", db); - if (t != first+2) - first = t; - break; - case 'x': - t = parse_noexcept_expression(first+2, last, db); - if (t != first+2) - first = t; - break; - } - break; - case 'o': - switch (t[1]) - { - case 'n': - return parse_unresolved_name(first, last, db); - case 'o': - t = parse_binary_expression(first+2, last, "||", db); - if (t != first+2) - first = t; - break; - case 'r': - t = parse_binary_expression(first+2, last, "|", db); - if (t != first+2) - first = t; - break; - case 'R': - t = parse_binary_expression(first+2, last, "|=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'p': - switch (t[1]) - { - case 'm': - t = parse_binary_expression(first+2, last, "->*", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "+=", db); - if (t != first+2) - first = t; - break; - case 'p': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "++", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "(" + db.names.back().move_full() + ")++"; - first = t1; - } - } - break; - case 's': - t = parse_prefix_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_arrow_expr(first, last, db); - break; - } - break; - case 'q': - if (t[1] == 'u') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - const char* t3 = parse_expression(t2, last, db); - if (t3 != t2) - { - if (db.names.size() < 3) - return first; - auto op3 = db.names.back().move_full(); - db.names.pop_back(); - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")"; - first = t3; - } - else - { - db.names.pop_back(); - db.names.pop_back(); - } - } - else - db.names.pop_back(); - } - } - break; - case 'r': - switch (t[1]) - { - case 'c': - first = parse_reinterpret_cast_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, "%", db); - if (t != first+2) - first = t; - break; - case 'M': - t = parse_binary_expression(first+2, last, "%=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, ">>", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, ">>=", db); - if (t != first+2) - first = t; - break; - } - break; - case 's': - switch (t[1]) - { - case 'c': - first = parse_static_cast_expr(first, last, db); - break; - case 'p': - first = parse_pack_expansion(first, last, db); - break; - case 'r': - return parse_unresolved_name(first, last, db); - case 't': - first = parse_sizeof_type_expr(first, last, db); - break; - case 'z': - first = parse_sizeof_expr_expr(first, last, db); - break; - case 'Z': - if (last - t >= 3) - { - switch (t[2]) - { - case 'T': - first = parse_sizeof_param_pack_expr(first, last, db); - break; - case 'f': - first = parse_sizeof_function_param_pack_expr(first, last, db); - break; - } - } - break; - } - break; - case 't': - switch (t[1]) - { - case 'e': - case 'i': - first = parse_typeid_expr(first, last, db); - break; - case 'r': - db.names.push_back("throw"); - first += 2; - break; - case 'w': - first = parse_throw_expr(first, last, db); - break; - } - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return parse_unresolved_name(first, last, db); - } - } - return first; -} - -// ::= # type or template -// ::= X E # expression -// ::= # simple expressions -// ::= J * E # argument pack -// ::= LZ E # extension - -template -const char* -parse_template_arg(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t; - switch (*first) - { - case 'X': - t = parse_expression(first+1, last, db); - if (t != first+1) - { - if (t != last && *t == 'E') - first = t+1; - } - break; - case 'J': - t = first+1; - if (t == last) - return first; - while (*t != 'E') - { - const char* t1 = parse_template_arg(t, last, db); - if (t1 == t) - return first; - t = t1; - } - first = t+1; - break; - case 'L': - // or LZ E - if (first+1 != last && first[1] == 'Z') - { - t = parse_encoding(first+2, last, db); - if (t != first+2 && t != last && *t == 'E') - first = t+1; - } - else - first = parse_expr_primary(first, last, db); - break; - default: - // - first = parse_type(first, last, db); - break; - } - } - return first; -} - -// ::= I * E -// extension, the abi says + - -template -const char* -parse_template_args(const char* first, const char* last, C& db) -{ - if (last - first >= 2 && *first == 'I') - { - if (db.tag_templates) - db.template_param.back().clear(); - const char* t = first+1; - typename C::String args("<"); - while (*t != 'E') - { - if (db.tag_templates) - db.template_param.emplace_back(db.names.get_allocator()); - size_t k0 = db.names.size(); - const char* t1 = parse_template_arg(t, last, db); - size_t k1 = db.names.size(); - if (db.tag_templates) - db.template_param.pop_back(); - if (t1 == t || t1 == last) - return first; - if (db.tag_templates) - { - db.template_param.back().emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - db.template_param.back().back().push_back(db.names[k]); - } - for (size_t k = k0; k < k1; ++k) - { - if (args.size() > 1) - args += ", "; - args += db.names[k].move_full(); - } - for (; k1 != k0; --k1) - db.names.pop_back(); - t = t1; - } - first = t + 1; - if (args.back() != '>') - args += ">"; - else - args += " >"; - db.names.push_back(std::move(args)); - - } - return first; -} +#include "CxaDemangle.inc" -// ::= N [] [] E -// ::= N [] [] E -// -// ::= -// ::= -// ::= -// ::= -// ::= # empty -// ::= -// ::= -// extension ::= L -// -// ::=