From: Rafael Espindola Date: Wed, 7 Sep 2016 16:14:00 +0000 (+0000) Subject: Use llvm's demangler. X-Git-Tag: llvmorg-4.0.0-rc1~10450 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9aa7d66aabe554ad9c34a938ce776f45ae3f3db9;p=platform%2Fupstream%2Fllvm.git Use llvm's demangler. LLVM now has a copy of libcxxabi demangler, so lldb doesn't need to keep one too. llvm-svn: 280821 --- diff --git a/lldb/cmake/LLDBDependencies.cmake b/lldb/cmake/LLDBDependencies.cmake index 8ce4ceb..adc84a5 100644 --- a/lldb/cmake/LLDBDependencies.cmake +++ b/lldb/cmake/LLDBDependencies.cmake @@ -192,6 +192,7 @@ set(LLVM_LINK_COMPONENTS bitreader bitwriter codegen + demangle ipo selectiondag bitreader diff --git a/lldb/include/lldb/Core/CxaDemangle.h b/lldb/include/lldb/Core/CxaDemangle.h deleted file mode 100644 index 0ebb794..0000000 --- a/lldb/include/lldb/Core/CxaDemangle.h +++ /dev/null @@ -1,19 +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/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt index b975fb8..4585117 100644 --- a/lldb/source/Core/CMakeLists.txt +++ b/lldb/source/Core/CMakeLists.txt @@ -12,7 +12,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 5c1c268..0000000 --- a/lldb/source/Core/CxaDemangle.cpp +++ /dev/null @@ -1,4402 +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 -// - Implemented missing rebind, construct, destroy in malloc_alloc -// - Replaced noexcept, constexpr, alignas with their LLVM_* equivalents -// - Included PosixApi.h for snprintf implementation for MSVC -// - Removed constexpr member initialization for MSVC -// - Changed argument to alignas() to a literal for MSVC -// - Include for fprintf, stderr like entities. -//---------------------------------------------------------------------- - -#include "llvm/Support/Compiler.h" // LLVM_{NOEXCEPT, CONSTEXPR, ALIGNAS} - -#include "lldb/Host/PosixApi.h" -#include "lldb/lldb-private.h" -#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 -#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 const char *spec; -}; - -const char *float_data::spec = "%af"; - -template <> struct float_data { - static const size_t mangled_size = 16; - static const size_t max_demangled_size = 32; - static const char *spec; -}; - -const char *float_data::spec = "%a"; - -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 const char *spec; -}; - -const char *float_data::spec = "%LaL"; - -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; - } - } - LLVM_FALLTHROUGH; - 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 -// -// ::=