diff --git a/lldb/include/lldb/Core/CxaDemangle.h b/lldb/include/lldb/Core/CxaDemangle.h deleted file mode 100644 index 0cd54fb36a32..000000000000 --- a/lldb/include/lldb/Core/CxaDemangle.h +++ /dev/null @@ -1,21 +0,0 @@ -//===-- CxaDemangle.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_CxaDemangle_h_ -#define liblldb_CxaDemangle_h_ - -namespace lldb_private -{ - - char* - __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status); - -} - -#endif diff --git a/lldb/include/lldb/Core/FastDemangle.h b/lldb/include/lldb/Core/FastDemangle.h deleted file mode 100644 index cd6128c73038..000000000000 --- a/lldb/include/lldb/Core/FastDemangle.h +++ /dev/null @@ -1,24 +0,0 @@ -//===-- FastDemangle.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_FastDemangle_h_ -#define liblldb_FastDemangle_h_ - -namespace lldb_private -{ - - char * - FastDemangle(const char *mangled_name); - - char * - FastDemangle(const char *mangled_name, long mangled_name_length); - -} - -#endif diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt index d96de9d94924..8a62fc35842e 100644 --- a/lldb/source/Core/CMakeLists.txt +++ b/lldb/source/Core/CMakeLists.txt @@ -14,7 +14,6 @@ add_lldb_library(lldbCore ConnectionMachPort.cpp ConnectionSharedMemory.cpp ConstString.cpp - CxaDemangle.cpp DataBufferHeap.cpp DataBufferMemoryMap.cpp DataEncoder.cpp diff --git a/lldb/source/Core/CxaDemangle.cpp b/lldb/source/Core/CxaDemangle.cpp deleted file mode 100644 index 5c05db979276..000000000000 --- a/lldb/source/Core/CxaDemangle.cpp +++ /dev/null @@ -1,4979 +0,0 @@ -//---------------------------------------------------------------------- -// Inlined copy of: -// http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp -// revision 238263. -// -// Changes include: -// - Renamed the "__cxxabiv1" namespace to "lldb_private" -// - Stripped GCC attributes() -// - Removed extern "C" from the 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 lldb_private -{ - -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, - bool* ends_with_template_args = 0); -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) -{ - fprintf(stderr, "---------\n"); - fprintf(stderr, "names:\n"); - for (auto& s : db.names) - fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str()); - int i = -1; - fprintf(stderr, "subs:\n"); - for (auto& v : db.subs) - { - if (i >= 0) - fprintf(stderr, "S%i_ = {", i); - else - fprintf(stderr, "S_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; - } - fprintf(stderr, "template_param:\n"); - for (auto& t : db.template_param) - { - fprintf(stderr, "--\n"); - i = -1; - for (auto& v : t) - { - if (i >= 0) - fprintf(stderr, "T%i_ = {", i); - else - fprintf(stderr, "T_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; - } - } - fprintf(stderr, "---------\n\n"); -} - -template -void -print_state(const char* msg, const char* first, const char* last, const C& db) -{ - fprintf(stderr, "%s: ", msg); - for (; first != last; ++first) - fprintf(stderr, "%c", *first); - fprintf(stderr, "\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 -{ -#if defined(__arm__) - static const size_t mangled_size = 16; -#else - static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms -#endif - 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 __BYTE_ORDER__ == __ORDER_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) -// ::= Dc # decltype(auto) -// ::= 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 'c': - db.names.push_back("decltype(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) - { - if (*t == 'Y') - { - /* extern "C" */ - 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.empty() && 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.empty() && - 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.empty() && - 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.empty() && - 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; -} - -// ::= N [] [] E -// ::= N [] [] E -// -// ::= -// ::= -// ::= -// ::= -// ::= # empty -// ::= -// ::= -// extension ::= L -// -// ::=