mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
2409 lines
80 KiB
C++
2409 lines
80 KiB
C++
//===--- OldDemangler.cpp - Old Swift Demangling --------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements Swift symbol demangling with the old scheme.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Demangling/Demangle.h"
|
|
#include "swift/Demangling/Demangler.h"
|
|
#include "swift/Demangling/ManglingMacros.h"
|
|
#include "swift/Demangling/ManglingUtils.h"
|
|
#include "swift/Demangling/Punycode.h"
|
|
#include "swift/Strings.h"
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <functional>
|
|
#include <optional>
|
|
#include <vector>
|
|
|
|
using namespace swift;
|
|
using namespace Demangle;
|
|
|
|
namespace {
|
|
struct FindPtr {
|
|
FindPtr(Node *v) : Target(v) {}
|
|
bool operator()(NodePointer sp) const {
|
|
return sp == Target;
|
|
}
|
|
private:
|
|
Node *Target;
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
static bool isStartOfIdentifier(char c) {
|
|
if (c >= '0' && c <= '9')
|
|
return true;
|
|
return c == 'o';
|
|
}
|
|
|
|
static bool isStartOfNominalType(char c) {
|
|
switch (c) {
|
|
case 'C':
|
|
case 'V':
|
|
case 'O':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool isStartOfEntity(char c) {
|
|
switch (c) {
|
|
case 'F':
|
|
case 'I':
|
|
case 'v':
|
|
case 'P':
|
|
case 's':
|
|
case 'Z':
|
|
return true;
|
|
default:
|
|
return isStartOfNominalType(c);
|
|
}
|
|
}
|
|
|
|
static Node::Kind nominalTypeMarkerToNodeKind(char c) {
|
|
if (c == 'C')
|
|
return Node::Kind::Class;
|
|
if (c == 'V')
|
|
return Node::Kind::Structure;
|
|
if (c == 'O')
|
|
return Node::Kind::Enum;
|
|
return Node::Kind::Identifier;
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// A convenient class for parsing characters out of a string.
|
|
class NameSource {
|
|
StringRef Text;
|
|
public:
|
|
NameSource(StringRef text) : Text(text) {}
|
|
|
|
/// Return whether there are at least len characters remaining.
|
|
bool hasAtLeast(size_t len) { return (len <= Text.size()); }
|
|
|
|
bool isEmpty() { return Text.empty(); }
|
|
explicit operator bool() { return !isEmpty(); }
|
|
|
|
/// Return the next character without claiming it. Asserts that
|
|
/// there is at least one remaining character.
|
|
char peek() {
|
|
if (isEmpty()) {
|
|
// Return an otherwise unused character to prevent crashes for malformed
|
|
// symbols.
|
|
return '.';
|
|
}
|
|
return Text.front();
|
|
}
|
|
|
|
/// Claim and return the next character. Asserts that there is at
|
|
/// least one remaining character.
|
|
char next() {
|
|
char c = peek();
|
|
if (!isEmpty())
|
|
advanceOffset(1);
|
|
return c;
|
|
}
|
|
|
|
/// Claim the next character if it exists and equals the given
|
|
/// character.
|
|
bool nextIf(char c) {
|
|
if (isEmpty() || peek() != c) return false;
|
|
advanceOffset(1);
|
|
return true;
|
|
}
|
|
|
|
/// Claim the next few characters if they exactly match the given string.
|
|
bool nextIf(StringRef str) {
|
|
if (!Text.starts_with(str)) return false;
|
|
advanceOffset(str.size());
|
|
return true;
|
|
}
|
|
|
|
/// Return the next len characters without claiming them. Asserts
|
|
/// that there are at least so many characters.
|
|
StringRef slice(size_t len) { return Text.substr(0, len); }
|
|
|
|
/// Return the current string ref without claiming any characters.
|
|
StringRef str() { return Text; }
|
|
|
|
/// Claim the next len characters.
|
|
void advanceOffset(size_t len) {
|
|
Text = Text.substr(len);
|
|
}
|
|
|
|
/// Claim and return all the rest of the characters.
|
|
StringRef getString() {
|
|
auto result = Text;
|
|
advanceOffset(Text.size());
|
|
return result;
|
|
}
|
|
|
|
bool readUntil(char c, std::string &result) {
|
|
std::optional<char> c2;
|
|
while (!isEmpty() && (c2 = peek()).value() != c) {
|
|
result.push_back(c2.value());
|
|
advanceOffset(1);
|
|
}
|
|
return c2.has_value() && c2.value() == c;
|
|
}
|
|
};
|
|
|
|
/// The main class for parsing a demangling tree out of a mangled string.
|
|
class OldDemangler {
|
|
std::vector<NodePointer> Substitutions;
|
|
NameSource Mangled;
|
|
NodeFactory &Factory;
|
|
|
|
static const unsigned MaxDepth = 1024;
|
|
|
|
public:
|
|
OldDemangler(llvm::StringRef mangled, NodeFactory &Factory)
|
|
: Mangled(mangled), Factory(Factory) {}
|
|
|
|
/// Try to demangle a child node of the given kind. If that fails,
|
|
/// return; otherwise add it to the parent.
|
|
#define DEMANGLE_CHILD_OR_RETURN(PARENT, CHILD_KIND, DEPTH) \
|
|
do { \
|
|
auto _node = demangle##CHILD_KIND(DEPTH); \
|
|
if (!_node) \
|
|
return nullptr; \
|
|
addChild(PARENT, _node); \
|
|
} while (false)
|
|
|
|
/// Try to demangle a child node of the given kind. If that fails,
|
|
/// return; otherwise add it to the parent.
|
|
#define DEMANGLE_CHILD_AS_NODE_OR_RETURN(PARENT, CHILD_KIND, DEPTH) \
|
|
do { \
|
|
auto _kind = demangle##CHILD_KIND(DEPTH); \
|
|
if (!_kind.has_value()) \
|
|
return nullptr; \
|
|
addChild(PARENT, \
|
|
Factory.createNode(Node::Kind::CHILD_KIND, unsigned(*_kind))); \
|
|
} while (false)
|
|
|
|
/// Attempt to demangle the source string. The root node will
|
|
/// always be a Global. Extra characters at the end will be
|
|
/// tolerated (and included as a Suffix node as a child of the
|
|
/// Global).
|
|
///
|
|
/// \return true if the mangling succeeded
|
|
NodePointer demangleTopLevel() {
|
|
if (!Mangled.nextIf("_T"))
|
|
return nullptr;
|
|
|
|
NodePointer topLevel = Factory.createNode(Node::Kind::Global);
|
|
|
|
// First demangle any specialization prefixes.
|
|
if (Mangled.nextIf("TS")) {
|
|
do {
|
|
DEMANGLE_CHILD_OR_RETURN(topLevel, SpecializedAttribute, 0);
|
|
|
|
// The Substitution header does not share state with the rest
|
|
// of the mangling.
|
|
Substitutions.clear();
|
|
} while (Mangled.nextIf("_TTS"));
|
|
|
|
// Then check that we have a global.
|
|
if (!Mangled.nextIf("_T"))
|
|
return nullptr;
|
|
|
|
} else if (Mangled.nextIf("To")) {
|
|
addChild(topLevel, Factory.createNode(Node::Kind::ObjCAttribute));
|
|
} else if (Mangled.nextIf("TO")) {
|
|
addChild(topLevel, Factory.createNode(Node::Kind::NonObjCAttribute));
|
|
} else if (Mangled.nextIf("TD")) {
|
|
addChild(topLevel, Factory.createNode(Node::Kind::DynamicAttribute));
|
|
} else if (Mangled.nextIf("Td")) {
|
|
addChild(topLevel, Factory.createNode(
|
|
Node::Kind::DirectMethodReferenceAttribute));
|
|
} else if (Mangled.nextIf("TV")) {
|
|
addChild(topLevel, Factory.createNode(Node::Kind::VTableAttribute));
|
|
}
|
|
|
|
DEMANGLE_CHILD_OR_RETURN(topLevel, Global, 0);
|
|
|
|
// Add a suffix node if there's anything left unmangled.
|
|
if (!Mangled.isEmpty()) {
|
|
addChild(topLevel, Factory.createNode(Node::Kind::Suffix,
|
|
Mangled.getString()));
|
|
}
|
|
|
|
return topLevel;
|
|
}
|
|
|
|
NodePointer demangleTypeName(unsigned depth) { return demangleType(depth); }
|
|
|
|
private:
|
|
enum class IsVariadic {
|
|
yes = true, no = false
|
|
};
|
|
|
|
void addChild(NodePointer Parent, NodePointer Child) {
|
|
Parent->addChild(Child, Factory);
|
|
}
|
|
|
|
std::optional<Directness> demangleDirectness(unsigned depth) {
|
|
if (Mangled.nextIf('d'))
|
|
return Directness::Direct;
|
|
if (Mangled.nextIf('i'))
|
|
return Directness::Indirect;
|
|
return std::nullopt;
|
|
}
|
|
|
|
bool demangleNatural(Node::IndexType &num, unsigned depth) {
|
|
if (!Mangled)
|
|
return false;
|
|
char c = Mangled.next();
|
|
if (c < '0' || c > '9')
|
|
return false;
|
|
num = (c - '0');
|
|
while (true) {
|
|
if (!Mangled) {
|
|
return true;
|
|
}
|
|
c = Mangled.peek();
|
|
if (c < '0' || c > '9') {
|
|
return true;
|
|
} else {
|
|
num = (10 * num) + (c - '0');
|
|
}
|
|
Mangled.next();
|
|
}
|
|
}
|
|
|
|
bool demangleBuiltinSize(Node::IndexType &num, unsigned depth) {
|
|
if (!demangleNatural(num, depth + 1))
|
|
return false;
|
|
if (Mangled.nextIf('_'))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
std::optional<ValueWitnessKind> demangleValueWitnessKind(unsigned depth) {
|
|
char Code[2];
|
|
if (!Mangled)
|
|
return std::nullopt;
|
|
Code[0] = Mangled.next();
|
|
if (!Mangled)
|
|
return std::nullopt;
|
|
Code[1] = Mangled.next();
|
|
|
|
StringRef CodeStr(Code, 2);
|
|
#define VALUE_WITNESS(MANGLING, NAME) \
|
|
if (CodeStr == #MANGLING) return ValueWitnessKind::NAME;
|
|
#include "swift/Demangling/ValueWitnessMangling.def"
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
NodePointer demangleGlobal(unsigned depth) {
|
|
if (depth > OldDemangler::MaxDepth || !Mangled)
|
|
return nullptr;
|
|
|
|
// Type metadata.
|
|
if (Mangled.nextIf('M')) {
|
|
if (Mangled.nextIf('P')) {
|
|
auto pattern =
|
|
Factory.createNode(Node::Kind::GenericTypeMetadataPattern);
|
|
DEMANGLE_CHILD_OR_RETURN(pattern, Type, depth + 1);
|
|
return pattern;
|
|
}
|
|
if (Mangled.nextIf('a')) {
|
|
auto accessor =
|
|
Factory.createNode(Node::Kind::TypeMetadataAccessFunction);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, Type, depth + 1);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('L')) {
|
|
auto cache = Factory.createNode(Node::Kind::TypeMetadataLazyCache);
|
|
DEMANGLE_CHILD_OR_RETURN(cache, Type, depth + 1);
|
|
return cache;
|
|
}
|
|
if (Mangled.nextIf('m')) {
|
|
auto metaclass = Factory.createNode(Node::Kind::Metaclass);
|
|
DEMANGLE_CHILD_OR_RETURN(metaclass, Type, depth + 1);
|
|
return metaclass;
|
|
}
|
|
if (Mangled.nextIf('n')) {
|
|
auto nominalType =
|
|
Factory.createNode(Node::Kind::NominalTypeDescriptor);
|
|
DEMANGLE_CHILD_OR_RETURN(nominalType, Type, depth + 1);
|
|
return nominalType;
|
|
}
|
|
if (Mangled.nextIf('f')) {
|
|
auto metadata = Factory.createNode(Node::Kind::FullTypeMetadata);
|
|
DEMANGLE_CHILD_OR_RETURN(metadata, Type, depth + 1);
|
|
return metadata;
|
|
}
|
|
if (Mangled.nextIf('p')) {
|
|
auto metadata = Factory.createNode(Node::Kind::ProtocolDescriptor);
|
|
DEMANGLE_CHILD_OR_RETURN(metadata, ProtocolName, depth + 1);
|
|
return metadata;
|
|
}
|
|
auto metadata = Factory.createNode(Node::Kind::TypeMetadata);
|
|
DEMANGLE_CHILD_OR_RETURN(metadata, Type, depth + 1);
|
|
return metadata;
|
|
}
|
|
|
|
// Partial application thunks.
|
|
if (Mangled.nextIf("PA")) {
|
|
Node::Kind kind = Node::Kind::PartialApplyForwarder;
|
|
if (Mangled.nextIf('o'))
|
|
kind = Node::Kind::PartialApplyObjCForwarder;
|
|
auto forwarder = Factory.createNode(kind);
|
|
if (Mangled.nextIf("__T"))
|
|
DEMANGLE_CHILD_OR_RETURN(forwarder, Global, depth + 1);
|
|
return forwarder;
|
|
}
|
|
|
|
// Top-level types, for various consumers.
|
|
if (Mangled.nextIf('t')) {
|
|
auto type = Factory.createNode(Node::Kind::TypeMangling);
|
|
DEMANGLE_CHILD_OR_RETURN(type, Type, depth + 1);
|
|
return type;
|
|
}
|
|
|
|
// Value witnesses.
|
|
if (Mangled.nextIf('w')) {
|
|
std::optional<ValueWitnessKind> w = demangleValueWitnessKind(depth + 1);
|
|
if (!w.has_value())
|
|
return nullptr;
|
|
auto witness =
|
|
Factory.createNode(Node::Kind::ValueWitness);
|
|
NodePointer Idx = Factory.createNode(Node::Kind::Index,
|
|
unsigned(w.value()));
|
|
witness->addChild(Idx, Factory);
|
|
DEMANGLE_CHILD_OR_RETURN(witness, Type, depth + 1);
|
|
return witness;
|
|
}
|
|
|
|
// Offsets, value witness tables, and protocol witnesses.
|
|
if (Mangled.nextIf('W')) {
|
|
if (Mangled.nextIf('V')) {
|
|
auto witnessTable = Factory.createNode(Node::Kind::ValueWitnessTable);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, Type, depth + 1);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('v')) {
|
|
auto fieldOffset = Factory.createNode(Node::Kind::FieldOffset);
|
|
DEMANGLE_CHILD_AS_NODE_OR_RETURN(fieldOffset, Directness, depth + 1);
|
|
DEMANGLE_CHILD_OR_RETURN(fieldOffset, Entity, depth + 1);
|
|
return fieldOffset;
|
|
}
|
|
if (Mangled.nextIf('P')) {
|
|
auto witnessTable =
|
|
Factory.createNode(Node::Kind::ProtocolWitnessTable);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance, depth + 1);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('G')) {
|
|
auto witnessTable =
|
|
Factory.createNode(Node::Kind::GenericProtocolWitnessTable);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance, depth + 1);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('I')) {
|
|
auto witnessTable = Factory.createNode(
|
|
Node::Kind::GenericProtocolWitnessTableInstantiationFunction);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance, depth + 1);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('l')) {
|
|
auto accessor =
|
|
Factory.createNode(Node::Kind::LazyProtocolWitnessTableAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, Type, depth + 1);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('L')) {
|
|
auto accessor =
|
|
Factory.createNode(Node::Kind::LazyProtocolWitnessTableCacheVariable);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, Type, depth + 1);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('a')) {
|
|
auto tableTemplate =
|
|
Factory.createNode(Node::Kind::ProtocolWitnessTableAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance, depth + 1);
|
|
return tableTemplate;
|
|
}
|
|
if (Mangled.nextIf('t')) {
|
|
auto accessor = Factory.createNode(
|
|
Node::Kind::AssociatedTypeMetadataAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName, depth + 1);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('T')) {
|
|
auto accessor = Factory.createNode(
|
|
Node::Kind::AssociatedTypeWitnessTableAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName, depth + 1);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolName, depth + 1);
|
|
return accessor;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Other thunks.
|
|
if (Mangled.nextIf('T')) {
|
|
if (Mangled.nextIf('R')) {
|
|
auto thunk = Factory.createNode(Node::Kind::ReabstractionThunkHelper);
|
|
if (!demangleReabstractSignature(thunk, depth + 1))
|
|
return nullptr;
|
|
return thunk;
|
|
}
|
|
if (Mangled.nextIf('r')) {
|
|
auto thunk = Factory.createNode(Node::Kind::ReabstractionThunk);
|
|
if (!demangleReabstractSignature(thunk, depth + 1))
|
|
return nullptr;
|
|
return thunk;
|
|
}
|
|
if (Mangled.nextIf('W')) {
|
|
NodePointer thunk = Factory.createNode(Node::Kind::ProtocolWitness);
|
|
DEMANGLE_CHILD_OR_RETURN(thunk, ProtocolConformance, depth + 1);
|
|
// The entity is mangled in its own generic context.
|
|
DEMANGLE_CHILD_OR_RETURN(thunk, Entity, depth + 1);
|
|
return thunk;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Everything else is just an entity.
|
|
return demangleEntity(depth + 1);
|
|
}
|
|
|
|
NodePointer demangleGenericSpecialization(NodePointer specialization,
|
|
unsigned depth) {
|
|
if (depth > OldDemangler::MaxDepth)
|
|
return nullptr;
|
|
|
|
while (!Mangled.nextIf('_')) {
|
|
// Otherwise, we have another parameter. Demangle the type.
|
|
NodePointer param = Factory.createNode(Node::Kind::GenericSpecializationParam);
|
|
DEMANGLE_CHILD_OR_RETURN(param, Type, depth + 1);
|
|
|
|
// Then parse any conformances until we find an underscore. Pop off the
|
|
// underscore since it serves as the end of our mangling list.
|
|
while (!Mangled.nextIf('_')) {
|
|
DEMANGLE_CHILD_OR_RETURN(param, ProtocolConformance, depth + 1);
|
|
}
|
|
|
|
// Add the parameter to our specialization list.
|
|
specialization->addChild(param, Factory);
|
|
}
|
|
|
|
return specialization;
|
|
}
|
|
|
|
/// TODO: This is an atrocity. Come up with a shorter name.
|
|
#define FUNCSIGSPEC_CREATE_PARAM_KIND(kind) \
|
|
Factory.createNode( \
|
|
Node::Kind::FunctionSignatureSpecializationParamKind, \
|
|
Node::IndexType(FunctionSigSpecializationParamKind::kind))
|
|
|
|
#define FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(payload) \
|
|
Factory.createNode(Node::Kind::FunctionSignatureSpecializationParamPayload, \
|
|
payload)
|
|
|
|
bool demangleFuncSigSpecializationConstantProp(NodePointer parent,
|
|
unsigned depth) {
|
|
// Then figure out what was actually constant propagated. First check if
|
|
// we have a function.
|
|
if (Mangled.nextIf("fr")) {
|
|
// Demangle the identifier
|
|
NodePointer name = demangleIdentifier(depth + 1);
|
|
if (!name || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFunction), Factory);
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()), Factory);
|
|
return true;
|
|
}
|
|
|
|
if (Mangled.nextIf('g')) {
|
|
NodePointer name = demangleIdentifier(depth + 1);
|
|
if (!name || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropGlobal), Factory);
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()), Factory);
|
|
return true;
|
|
}
|
|
|
|
if (Mangled.nextIf('i')) {
|
|
std::string Str;
|
|
if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropInteger), Factory);
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str), Factory);
|
|
return true;
|
|
}
|
|
|
|
if (Mangled.nextIf("fl")) {
|
|
std::string Str;
|
|
if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFloat), Factory);
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str), Factory);
|
|
return true;
|
|
}
|
|
|
|
if (Mangled.nextIf("s")) {
|
|
// Skip: 'e' encoding 'v' str. encoding is a 0 or 1 and str is a string of
|
|
// length less than or equal to 32. We do not specialize strings with a
|
|
// length greater than 32.
|
|
if (!Mangled.nextIf('e'))
|
|
return false;
|
|
char encoding = Mangled.peek();
|
|
if (encoding != '0' && encoding != '1')
|
|
return false;
|
|
std::string encodingStr;
|
|
if (encoding == '0')
|
|
encodingStr += "u8";
|
|
else
|
|
encodingStr += "u16";
|
|
Mangled.advanceOffset(1);
|
|
|
|
if (!Mangled.nextIf('v'))
|
|
return false;
|
|
NodePointer str = demangleIdentifier(depth + 1);
|
|
if (!str || !Mangled.nextIf('_'))
|
|
return false;
|
|
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropString), Factory);
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(encodingStr), Factory);
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(str->getText()), Factory);
|
|
return true;
|
|
}
|
|
|
|
// Unknown constant prop specialization
|
|
return false;
|
|
}
|
|
|
|
bool demangleFuncSigSpecializationClosureProp(NodePointer parent,
|
|
unsigned depth) {
|
|
// We don't actually demangle the function or types for now. But we do want
|
|
// to signal that we specialized a closure.
|
|
|
|
NodePointer name = demangleIdentifier(depth + 1);
|
|
if (!name) {
|
|
return false;
|
|
}
|
|
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ClosureProp), Factory);
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()), Factory);
|
|
|
|
// Then demangle types until we fail.
|
|
NodePointer type = nullptr;
|
|
while (Mangled.peek() != '_' && (type = demangleType(depth + 1))) {
|
|
parent->addChild(type, Factory);
|
|
}
|
|
|
|
// Eat last '_'
|
|
if (!Mangled.nextIf('_'))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
NodePointer
|
|
demangleFunctionSignatureSpecialization(NodePointer specialization,
|
|
unsigned depth) {
|
|
// Until we hit the last '_' in our specialization info...
|
|
while (!Mangled.nextIf('_')) {
|
|
// Create the parameter.
|
|
NodePointer param =
|
|
Factory.createNode(Node::Kind::FunctionSignatureSpecializationParam);
|
|
|
|
// First handle options.
|
|
if (Mangled.nextIf("n_")) {
|
|
// Leave the parameter empty.
|
|
} else if (Mangled.nextIf("cp")) {
|
|
if (!demangleFuncSigSpecializationConstantProp(param, depth + 1))
|
|
return nullptr;
|
|
} else if (Mangled.nextIf("cl")) {
|
|
if (!demangleFuncSigSpecializationClosureProp(param, depth + 1))
|
|
return nullptr;
|
|
} else if (Mangled.nextIf("i_")) {
|
|
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToValue);
|
|
if (!result)
|
|
return nullptr;
|
|
param->addChild(result, Factory);
|
|
} else if (Mangled.nextIf("k_")) {
|
|
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToStack);
|
|
if (!result)
|
|
return nullptr;
|
|
param->addChild(result, Factory);
|
|
} else if (Mangled.nextIf("r_")) {
|
|
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(InOutToOut);
|
|
if (!result)
|
|
return nullptr;
|
|
param->addChild(result, Factory);
|
|
} else {
|
|
// Otherwise handle option sets.
|
|
unsigned Value = 0;
|
|
if (Mangled.nextIf('d')) {
|
|
Value |=
|
|
unsigned(FunctionSigSpecializationParamKind::Dead);
|
|
}
|
|
|
|
if (Mangled.nextIf('g')) {
|
|
Value |=
|
|
unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed);
|
|
}
|
|
|
|
if (Mangled.nextIf('o')) {
|
|
Value |=
|
|
unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned);
|
|
}
|
|
|
|
if (Mangled.nextIf('s')) {
|
|
Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
|
|
}
|
|
|
|
if (!Mangled.nextIf('_'))
|
|
return nullptr;
|
|
|
|
if (!Value)
|
|
return nullptr;
|
|
|
|
auto result = Factory.createNode(
|
|
Node::Kind::FunctionSignatureSpecializationParamKind, Value);
|
|
if (!result)
|
|
return nullptr;
|
|
param->addChild(result, Factory);
|
|
}
|
|
|
|
specialization->addChild(param, Factory);
|
|
}
|
|
|
|
return specialization;
|
|
}
|
|
|
|
#undef FUNCSIGSPEC_CREATE_PARAM_KIND
|
|
#undef FUNCSIGSPEC_CREATE_PARAM_PAYLOAD
|
|
|
|
NodePointer demangleSpecializedAttribute(unsigned depth) {
|
|
bool isNotReAbstracted = false;
|
|
if (Mangled.nextIf("g") || (isNotReAbstracted = Mangled.nextIf("r"))) {
|
|
auto spec = Factory.createNode(isNotReAbstracted ?
|
|
Node::Kind::GenericSpecializationNotReAbstracted :
|
|
Node::Kind::GenericSpecialization);
|
|
|
|
// Create a node if the specialization is serialized.
|
|
if (Mangled.nextIf("q")) {
|
|
auto kind = Node::Kind::IsSerialized;
|
|
spec->addChild(Factory.createNode(kind), Factory);
|
|
}
|
|
|
|
// Create a node for the pass id.
|
|
spec->addChild(Factory.createNode(Node::Kind::SpecializationPassID,
|
|
unsigned(Mangled.next() - 48)), Factory);
|
|
|
|
// And then mangle the generic specialization.
|
|
return demangleGenericSpecialization(spec, depth + 1);
|
|
}
|
|
if (Mangled.nextIf("f")) {
|
|
auto spec =
|
|
Factory.createNode(Node::Kind::FunctionSignatureSpecialization);
|
|
|
|
// Create a node if the specialization is serialized.
|
|
if (Mangled.nextIf("q")) {
|
|
auto kind = Node::Kind::IsSerialized;
|
|
spec->addChild(Factory.createNode(kind), Factory);
|
|
}
|
|
|
|
// Add the pass id.
|
|
spec->addChild(Factory.createNode(Node::Kind::SpecializationPassID,
|
|
unsigned(Mangled.next() - 48)), Factory);
|
|
|
|
// Then perform the function signature specialization.
|
|
return demangleFunctionSignatureSpecialization(spec, depth + 1);
|
|
}
|
|
|
|
// We don't know how to handle this specialization.
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleDeclName(unsigned depth) {
|
|
// decl-name ::= local-decl-name
|
|
// local-decl-name ::= 'L' index identifier
|
|
if (Mangled.nextIf('L')) {
|
|
NodePointer discriminator = demangleIndexAsNode(depth + 1);
|
|
if (!discriminator) return nullptr;
|
|
|
|
NodePointer name = demangleIdentifier(depth + 1);
|
|
if (!name) return nullptr;
|
|
|
|
NodePointer localName = Factory.createNode(Node::Kind::LocalDeclName);
|
|
localName->addChild(discriminator, Factory);
|
|
localName->addChild(name, Factory);
|
|
return localName;
|
|
|
|
} else if (Mangled.nextIf('P')) {
|
|
NodePointer discriminator = demangleIdentifier(depth + 1);
|
|
if (!discriminator) return nullptr;
|
|
|
|
NodePointer name = demangleIdentifier(depth + 1);
|
|
if (!name) return nullptr;
|
|
|
|
auto privateName = Factory.createNode(Node::Kind::PrivateDeclName);
|
|
privateName->addChild(discriminator, Factory);
|
|
privateName->addChild(name, Factory);
|
|
return privateName;
|
|
}
|
|
|
|
// decl-name ::= identifier
|
|
return demangleIdentifier(depth + 1);
|
|
}
|
|
|
|
NodePointer
|
|
demangleIdentifier(unsigned depth,
|
|
std::optional<Node::Kind> kind = std::nullopt) {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
|
|
bool isPunycoded = Mangled.nextIf('X');
|
|
std::string decodeBuffer;
|
|
|
|
auto decode = [&](StringRef s) -> StringRef {
|
|
if (!isPunycoded)
|
|
return s;
|
|
if (!Punycode::decodePunycodeUTF8(s, decodeBuffer))
|
|
return {};
|
|
return decodeBuffer;
|
|
};
|
|
|
|
bool isOperator = false;
|
|
if (Mangled.nextIf('o')) {
|
|
isOperator = true;
|
|
// Operator identifiers aren't valid in the contexts that are
|
|
// building more specific identifiers.
|
|
if (kind.has_value()) return nullptr;
|
|
|
|
char op_mode = Mangled.next();
|
|
switch (op_mode) {
|
|
case 'p':
|
|
kind = Node::Kind::PrefixOperator;
|
|
break;
|
|
case 'P':
|
|
kind = Node::Kind::PostfixOperator;
|
|
break;
|
|
case 'i':
|
|
kind = Node::Kind::InfixOperator;
|
|
break;
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (!kind.has_value()) kind = Node::Kind::Identifier;
|
|
|
|
Node::IndexType length;
|
|
if (!demangleNatural(length, depth + 1))
|
|
return nullptr;
|
|
if (!Mangled.hasAtLeast(length))
|
|
return nullptr;
|
|
|
|
StringRef identifier = Mangled.slice(length);
|
|
Mangled.advanceOffset(length);
|
|
|
|
// Decode Unicode identifiers.
|
|
identifier = decode(identifier);
|
|
if (identifier.empty())
|
|
return nullptr;
|
|
|
|
// Decode operator names.
|
|
std::string opDecodeBuffer;
|
|
if (isOperator) {
|
|
// abcdefghijklmnopqrstuvwxyz
|
|
static const char op_char_table[] = "& @/= > <*!|+?%-~ ^ .";
|
|
|
|
opDecodeBuffer.reserve(identifier.size());
|
|
for (signed char c : identifier) {
|
|
if (c < 0) {
|
|
// Pass through Unicode characters.
|
|
opDecodeBuffer.push_back(c);
|
|
continue;
|
|
}
|
|
if (c < 'a' || c > 'z')
|
|
return nullptr;
|
|
char o = op_char_table[c - 'a'];
|
|
if (o == ' ')
|
|
return nullptr;
|
|
opDecodeBuffer.push_back(o);
|
|
}
|
|
identifier = opDecodeBuffer;
|
|
}
|
|
|
|
return Factory.createNode(*kind, identifier);
|
|
}
|
|
|
|
bool demangleIndex(Node::IndexType &natural, unsigned depth) {
|
|
if (Mangled.nextIf('_')) {
|
|
natural = 0;
|
|
return true;
|
|
}
|
|
if (demangleNatural(natural, depth + 1)) {
|
|
if (!Mangled.nextIf('_'))
|
|
return false;
|
|
++natural;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Demangle an <index> and package it as a node of some kind.
|
|
NodePointer demangleIndexAsNode(unsigned depth,
|
|
Node::Kind kind = Node::Kind::Number) {
|
|
Node::IndexType index;
|
|
if (!demangleIndex(index, depth))
|
|
return nullptr;
|
|
return Factory.createNode(kind, index);
|
|
}
|
|
|
|
NodePointer createSwiftType(Node::Kind typeKind, StringRef name) {
|
|
NodePointer type = Factory.createNode(typeKind);
|
|
type->addChild(Factory.createNode(Node::Kind::Module, STDLIB_NAME), Factory);
|
|
type->addChild(Factory.createNode(Node::Kind::Identifier, name), Factory);
|
|
return type;
|
|
}
|
|
|
|
/// Demangle a <substitution>, given that we've already consumed the 'S'.
|
|
NodePointer demangleSubstitutionIndex(unsigned depth) {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
if (Mangled.nextIf('o'))
|
|
return Factory.createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
|
|
if (Mangled.nextIf('C'))
|
|
return Factory.createNode(Node::Kind::Module,
|
|
MANGLING_MODULE_CLANG_IMPORTER);
|
|
if (Mangled.nextIf('a'))
|
|
return createSwiftType(Node::Kind::Structure, "Array");
|
|
if (Mangled.nextIf('b'))
|
|
return createSwiftType(Node::Kind::Structure, "Bool");
|
|
if (Mangled.nextIf('c'))
|
|
return createSwiftType(Node::Kind::Structure, "UnicodeScalar");
|
|
if (Mangled.nextIf('d'))
|
|
return createSwiftType(Node::Kind::Structure, "Double");
|
|
if (Mangled.nextIf('f'))
|
|
return createSwiftType(Node::Kind::Structure, "Float");
|
|
if (Mangled.nextIf('i'))
|
|
return createSwiftType(Node::Kind::Structure, "Int");
|
|
if (Mangled.nextIf('V'))
|
|
return createSwiftType(Node::Kind::Structure, "UnsafeRawPointer");
|
|
if (Mangled.nextIf('v'))
|
|
return createSwiftType(Node::Kind::Structure, "UnsafeMutableRawPointer");
|
|
if (Mangled.nextIf('P'))
|
|
return createSwiftType(Node::Kind::Structure, "UnsafePointer");
|
|
if (Mangled.nextIf('p'))
|
|
return createSwiftType(Node::Kind::Structure, "UnsafeMutablePointer");
|
|
if (Mangled.nextIf('q'))
|
|
return createSwiftType(Node::Kind::Enum, "Optional");
|
|
if (Mangled.nextIf('Q'))
|
|
return createSwiftType(Node::Kind::Enum, "ImplicitlyUnwrappedOptional");
|
|
if (Mangled.nextIf('R'))
|
|
return createSwiftType(Node::Kind::Structure, "UnsafeBufferPointer");
|
|
if (Mangled.nextIf('r'))
|
|
return createSwiftType(Node::Kind::Structure, "UnsafeMutableBufferPointer");
|
|
if (Mangled.nextIf('S'))
|
|
return createSwiftType(Node::Kind::Structure, "String");
|
|
if (Mangled.nextIf('u'))
|
|
return createSwiftType(Node::Kind::Structure, "UInt");
|
|
Node::IndexType index_sub;
|
|
if (!demangleIndex(index_sub, depth))
|
|
return nullptr;
|
|
if (index_sub >= Substitutions.size())
|
|
return nullptr;
|
|
return Substitutions[index_sub];
|
|
}
|
|
|
|
NodePointer demangleModule(unsigned depth) {
|
|
if (Mangled.nextIf('s')) {
|
|
return Factory.createNode(Node::Kind::Module, STDLIB_NAME);
|
|
}
|
|
if (Mangled.nextIf('S')) {
|
|
NodePointer module = demangleSubstitutionIndex(depth + 1);
|
|
if (!module)
|
|
return nullptr;
|
|
if (module->getKind() != Node::Kind::Module)
|
|
return nullptr;
|
|
return module;
|
|
}
|
|
|
|
NodePointer module = demangleIdentifier(depth + 1, Node::Kind::Module);
|
|
if (!module) return nullptr;
|
|
Substitutions.push_back(module);
|
|
return module;
|
|
}
|
|
|
|
NodePointer demangleDeclarationName(Node::Kind kind, unsigned depth) {
|
|
NodePointer context = demangleContext(depth + 1);
|
|
if (!context) return nullptr;
|
|
|
|
auto name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
|
|
auto decl = Factory.createNode(kind);
|
|
decl->addChild(context, Factory);
|
|
decl->addChild(name, Factory);
|
|
Substitutions.push_back(decl);
|
|
return decl;
|
|
}
|
|
|
|
NodePointer demangleProtocolName(unsigned depth) {
|
|
NodePointer proto = demangleProtocolNameImpl(depth);
|
|
if (!proto) return nullptr;
|
|
|
|
NodePointer type = Factory.createNode(Node::Kind::Type);
|
|
type->addChild(proto, Factory);
|
|
return type;
|
|
}
|
|
|
|
NodePointer demangleProtocolNameGivenContext(NodePointer context,
|
|
unsigned depth) {
|
|
NodePointer name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
|
|
auto proto = Factory.createNode(Node::Kind::Protocol);
|
|
proto->addChild(context, Factory);
|
|
proto->addChild(name, Factory);
|
|
Substitutions.push_back(proto);
|
|
return proto;
|
|
}
|
|
|
|
NodePointer demangleProtocolNameImpl(unsigned depth) {
|
|
if (depth > OldDemangler::MaxDepth)
|
|
return nullptr;
|
|
|
|
// There's an ambiguity in <protocol> between a substitution of
|
|
// the protocol and a substitution of the protocol's context, so
|
|
// we have to duplicate some of the logic from
|
|
// demangleDeclarationName.
|
|
if (Mangled.nextIf('S')) {
|
|
NodePointer sub = demangleSubstitutionIndex(depth + 1);
|
|
if (!sub) return nullptr;
|
|
if (sub->getKind() == Node::Kind::Protocol)
|
|
return sub;
|
|
|
|
if (sub->getKind() != Node::Kind::Module)
|
|
return nullptr;
|
|
|
|
return demangleProtocolNameGivenContext(sub, depth + 1);
|
|
}
|
|
|
|
if (Mangled.nextIf('s')) {
|
|
NodePointer stdlib = Factory.createNode(Node::Kind::Module, STDLIB_NAME);
|
|
|
|
return demangleProtocolNameGivenContext(stdlib, depth + 1);
|
|
}
|
|
|
|
return demangleDeclarationName(Node::Kind::Protocol, depth + 1);
|
|
}
|
|
|
|
NodePointer demangleNominalType(unsigned depth) {
|
|
if (Mangled.nextIf('S'))
|
|
return demangleSubstitutionIndex(depth + 1);
|
|
if (Mangled.nextIf('V'))
|
|
return demangleDeclarationName(Node::Kind::Structure, depth + 1);
|
|
if (Mangled.nextIf('O'))
|
|
return demangleDeclarationName(Node::Kind::Enum, depth + 1);
|
|
if (Mangled.nextIf('C'))
|
|
return demangleDeclarationName(Node::Kind::Class, depth + 1);
|
|
if (Mangled.nextIf('P'))
|
|
return demangleDeclarationName(Node::Kind::Protocol, depth + 1);
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleBoundGenericArgs(NodePointer nominalType,
|
|
unsigned depth) {
|
|
if (nominalType->getNumChildren() == 0)
|
|
return nullptr;
|
|
|
|
// Generic arguments for the outermost type come first.
|
|
NodePointer parentOrModule = nominalType->getChild(0);
|
|
|
|
if (parentOrModule->getKind() != Node::Kind::Module &&
|
|
parentOrModule->getKind() != Node::Kind::Function &&
|
|
parentOrModule->getKind() != Node::Kind::Extension) {
|
|
parentOrModule = demangleBoundGenericArgs(parentOrModule, depth + 1);
|
|
if (!parentOrModule)
|
|
return nullptr;
|
|
|
|
// Rebuild this type with the new parent type, which may have
|
|
// had its generic arguments applied.
|
|
NodePointer result = Factory.createNode(nominalType->getKind());
|
|
result->addChild(parentOrModule, Factory);
|
|
for (unsigned ndx = 1; ndx < nominalType->getNumChildren(); ++ndx)
|
|
result->addChild(nominalType->getChild(ndx), Factory);
|
|
|
|
nominalType = result;
|
|
}
|
|
|
|
NodePointer args = Factory.createNode(Node::Kind::TypeList);
|
|
while (!Mangled.nextIf('_')) {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
args->addChild(type, Factory);
|
|
if (Mangled.isEmpty())
|
|
return nullptr;
|
|
}
|
|
|
|
// If there were no arguments at this level there is nothing left
|
|
// to do.
|
|
if (args->getNumChildren() == 0)
|
|
return nominalType;
|
|
|
|
// Otherwise, build a bound generic type node from the unbound
|
|
// type and arguments.
|
|
NodePointer unboundType = Factory.createNode(Node::Kind::Type);
|
|
unboundType->addChild(nominalType, Factory);
|
|
|
|
Node::Kind kind;
|
|
switch (nominalType->getKind()) { // look through Type node
|
|
case Node::Kind::Class:
|
|
kind = Node::Kind::BoundGenericClass;
|
|
break;
|
|
case Node::Kind::Structure:
|
|
kind = Node::Kind::BoundGenericStructure;
|
|
break;
|
|
case Node::Kind::Enum:
|
|
kind = Node::Kind::BoundGenericEnum;
|
|
break;
|
|
default:
|
|
return nullptr;
|
|
}
|
|
NodePointer result = Factory.createNode(kind);
|
|
result->addChild(unboundType, Factory);
|
|
result->addChild(args, Factory);
|
|
return result;
|
|
}
|
|
|
|
NodePointer demangleBoundGenericType(unsigned depth) {
|
|
// bound-generic-type ::= 'G' nominal-type (args+ '_')+
|
|
//
|
|
// Each level of nominal type nesting has its own list of arguments.
|
|
|
|
NodePointer nominalType = demangleNominalType(depth + 1);
|
|
if (!nominalType)
|
|
return nullptr;
|
|
|
|
return demangleBoundGenericArgs(nominalType, depth + 1);
|
|
}
|
|
|
|
NodePointer demangleContext(unsigned depth) {
|
|
// context ::= module
|
|
// context ::= entity
|
|
// context ::= 'E' module context (extension defined in a different module)
|
|
// context ::= 'e' module context generic-signature (constrained extension)
|
|
if (!Mangled) return nullptr;
|
|
if (Mangled.nextIf('E')) {
|
|
NodePointer ext = Factory.createNode(Node::Kind::Extension);
|
|
NodePointer def_module = demangleModule(depth + 1);
|
|
if (!def_module) return nullptr;
|
|
NodePointer type = demangleContext(depth + 1);
|
|
if (!type) return nullptr;
|
|
ext->addChild(def_module, Factory);
|
|
ext->addChild(type, Factory);
|
|
return ext;
|
|
}
|
|
if (Mangled.nextIf('e')) {
|
|
NodePointer ext = Factory.createNode(Node::Kind::Extension);
|
|
NodePointer def_module = demangleModule(depth + 1);
|
|
if (!def_module) return nullptr;
|
|
NodePointer sig = demangleGenericSignature(depth + 1);
|
|
// The generic context is currently re-specified by the type mangling.
|
|
// If we ever remove 'self' from manglings, we should stop resetting the
|
|
// context here.
|
|
if (!sig) return nullptr;
|
|
NodePointer type = demangleContext(depth + 1);
|
|
if (!type) return nullptr;
|
|
|
|
ext->addChild(def_module, Factory);
|
|
ext->addChild(type, Factory);
|
|
ext->addChild(sig, Factory);
|
|
return ext;
|
|
}
|
|
if (Mangled.nextIf('S'))
|
|
return demangleSubstitutionIndex(depth + 1);
|
|
if (Mangled.nextIf('s'))
|
|
return Factory.createNode(Node::Kind::Module, STDLIB_NAME);
|
|
if (Mangled.nextIf('G'))
|
|
return demangleBoundGenericType(depth + 1);
|
|
if (isStartOfEntity(Mangled.peek()))
|
|
return demangleEntity(depth + 1);
|
|
return demangleModule(depth + 1);
|
|
}
|
|
|
|
NodePointer demangleProtocolList(unsigned depth) {
|
|
NodePointer proto_list = Factory.createNode(Node::Kind::ProtocolList);
|
|
NodePointer type_list = Factory.createNode(Node::Kind::TypeList);
|
|
proto_list->addChild(type_list, Factory);
|
|
while (!Mangled.nextIf('_')) {
|
|
NodePointer proto = demangleProtocolName(depth + 1);
|
|
if (!proto)
|
|
return nullptr;
|
|
type_list->addChild(proto, Factory);
|
|
}
|
|
return proto_list;
|
|
}
|
|
|
|
NodePointer demangleProtocolConformance(unsigned depth) {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer protocol = demangleProtocolName(depth + 1);
|
|
if (!protocol)
|
|
return nullptr;
|
|
NodePointer context = demangleContext(depth + 1);
|
|
if (!context)
|
|
return nullptr;
|
|
NodePointer proto_conformance =
|
|
Factory.createNode(Node::Kind::ProtocolConformance);
|
|
proto_conformance->addChild(type, Factory);
|
|
proto_conformance->addChild(protocol, Factory);
|
|
proto_conformance->addChild(context, Factory);
|
|
return proto_conformance;
|
|
}
|
|
|
|
// entity ::= entity-kind context entity-name
|
|
// entity ::= nominal-type
|
|
NodePointer demangleEntity(unsigned depth) {
|
|
if (depth > OldDemangler::MaxDepth)
|
|
return nullptr;
|
|
|
|
// static?
|
|
bool isStatic = Mangled.nextIf('Z');
|
|
|
|
// entity-kind
|
|
Node::Kind entityBasicKind;
|
|
if (Mangled.nextIf('F')) {
|
|
entityBasicKind = Node::Kind::Function;
|
|
} else if (Mangled.nextIf('v')) {
|
|
entityBasicKind = Node::Kind::Variable;
|
|
} else if (Mangled.nextIf('I')) {
|
|
entityBasicKind = Node::Kind::Initializer;
|
|
} else if (Mangled.nextIf('i')) {
|
|
entityBasicKind = Node::Kind::Subscript;
|
|
} else {
|
|
return demangleNominalType(depth + 1);
|
|
}
|
|
|
|
NodePointer context = demangleContext(depth + 1);
|
|
if (!context) return nullptr;
|
|
|
|
// entity-name
|
|
Node::Kind entityKind;
|
|
bool hasType = true;
|
|
// Wrap the enclosed entity in a variable or subscript node
|
|
bool wrapEntity = false;
|
|
NodePointer name = nullptr;
|
|
if (Mangled.nextIf('D')) {
|
|
entityKind = Node::Kind::Deallocator;
|
|
hasType = false;
|
|
} else if (Mangled.nextIf('Z')) {
|
|
entityKind = Node::Kind::IsolatedDeallocator;
|
|
hasType = false;
|
|
} else if (Mangled.nextIf('d')) {
|
|
entityKind = Node::Kind::Destructor;
|
|
hasType = false;
|
|
} else if (Mangled.nextIf('e')) {
|
|
entityKind = Node::Kind::IVarInitializer;
|
|
hasType = false;
|
|
} else if (Mangled.nextIf('E')) {
|
|
entityKind = Node::Kind::IVarDestroyer;
|
|
hasType = false;
|
|
} else if (Mangled.nextIf('C')) {
|
|
entityKind = Node::Kind::Allocator;
|
|
} else if (Mangled.nextIf('c')) {
|
|
entityKind = Node::Kind::Constructor;
|
|
} else if (Mangled.nextIf('a')) {
|
|
wrapEntity = true;
|
|
if (Mangled.nextIf('O')) {
|
|
entityKind = Node::Kind::OwningMutableAddressor;
|
|
} else if (Mangled.nextIf('o')) {
|
|
entityKind = Node::Kind::NativeOwningMutableAddressor;
|
|
} else if (Mangled.nextIf('p')) {
|
|
entityKind = Node::Kind::NativePinningMutableAddressor;
|
|
} else if (Mangled.nextIf('u')) {
|
|
entityKind = Node::Kind::UnsafeMutableAddressor;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('l')) {
|
|
wrapEntity = true;
|
|
if (Mangled.nextIf('O')) {
|
|
entityKind = Node::Kind::OwningAddressor;
|
|
} else if (Mangled.nextIf('o')) {
|
|
entityKind = Node::Kind::NativeOwningAddressor;
|
|
} else if (Mangled.nextIf('p')) {
|
|
entityKind = Node::Kind::NativePinningAddressor;
|
|
} else if (Mangled.nextIf('u')) {
|
|
entityKind = Node::Kind::UnsafeAddressor;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('g')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::Getter;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('G')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::GlobalGetter;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('s')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::Setter;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('m')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::MaterializeForSet;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('w')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::WillSet;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('W')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::DidSet;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('r')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::ReadAccessor;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('M')) {
|
|
wrapEntity = true;
|
|
entityKind = Node::Kind::ModifyAccessor;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('U')) {
|
|
entityKind = Node::Kind::ExplicitClosure;
|
|
name = demangleIndexAsNode(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('u')) {
|
|
entityKind = Node::Kind::ImplicitClosure;
|
|
name = demangleIndexAsNode(depth + 1);
|
|
if (!name) return nullptr;
|
|
} else if (entityBasicKind == Node::Kind::Initializer) {
|
|
// entity-name ::= 'A' index
|
|
if (Mangled.nextIf('A')) {
|
|
entityKind = Node::Kind::DefaultArgumentInitializer;
|
|
name = demangleIndexAsNode(depth + 1);
|
|
if (!name) return nullptr;
|
|
// entity-name ::= 'i'
|
|
} else if (Mangled.nextIf('i')) {
|
|
entityKind = Node::Kind::Initializer;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
hasType = false;
|
|
} else {
|
|
entityKind = entityBasicKind;
|
|
name = demangleDeclName(depth + 1);
|
|
if (!name) return nullptr;
|
|
}
|
|
|
|
NodePointer entity = Factory.createNode(entityKind);
|
|
if (wrapEntity) {
|
|
// Create a subscript or variable node and make it the accessor's child
|
|
NodePointer wrappedEntity;
|
|
bool isSubscript = false;
|
|
|
|
// Rewrite the subscript's name to match the new mangling scheme
|
|
switch (name->getKind()) {
|
|
case Node::Kind::Identifier:
|
|
if (name->getText() == "subscript") {
|
|
isSubscript = true;
|
|
// Subscripts have no 'subscript' identifier name
|
|
name = nullptr;
|
|
}
|
|
break;
|
|
case Node::Kind::PrivateDeclName: // identifier file-discriminator?
|
|
if (name->getNumChildren() > 1 &&
|
|
name->getChild(1)->getText() == "subscript") {
|
|
isSubscript = true;
|
|
|
|
auto discriminator = name->getChild(0);
|
|
|
|
// Create new PrivateDeclName with no 'subscript' identifier child
|
|
name = Factory.createNode(Node::Kind::PrivateDeclName);
|
|
name->addChild(discriminator, Factory);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Create wrapped entity node
|
|
if (isSubscript) {
|
|
wrappedEntity = Factory.createNode(Node::Kind::Subscript);
|
|
} else {
|
|
wrappedEntity = Factory.createNode(Node::Kind::Variable);
|
|
}
|
|
wrappedEntity->addChild(context, Factory);
|
|
|
|
// Variables mangle their name before their type
|
|
if (!isSubscript)
|
|
wrappedEntity->addChild(name, Factory);
|
|
|
|
if (hasType) {
|
|
auto type = demangleType(depth + 1);
|
|
if (!type) return nullptr;
|
|
wrappedEntity->addChild(type, Factory);
|
|
}
|
|
|
|
// Subscripts mangle their file-discriminator after the type
|
|
if (isSubscript && name)
|
|
wrappedEntity->addChild(name, Factory);
|
|
|
|
entity->addChild(wrappedEntity, Factory);
|
|
} else {
|
|
entity->addChild(context, Factory);
|
|
|
|
if (name) entity->addChild(name, Factory);
|
|
|
|
if (hasType) {
|
|
auto type = demangleType(depth + 1);
|
|
if (!type) return nullptr;
|
|
entity->addChild(type, Factory);
|
|
}
|
|
}
|
|
|
|
if (isStatic) {
|
|
auto staticNode = Factory.createNode(Node::Kind::Static);
|
|
staticNode->addChild(entity, Factory);
|
|
return staticNode;
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
NodePointer getDependentGenericParamType(unsigned depth, unsigned index) {
|
|
DemanglerPrinter PrintName;
|
|
PrintName << genericParameterName(depth, index);
|
|
|
|
auto paramTy = Factory.createNode(Node::Kind::DependentGenericParamType);
|
|
paramTy->addChild(Factory.createNode(Node::Kind::Index, depth), Factory);
|
|
paramTy->addChild(Factory.createNode(Node::Kind::Index, index), Factory);
|
|
|
|
return paramTy;
|
|
}
|
|
|
|
NodePointer demangleGenericParamIndex(unsigned depth) {
|
|
Node::IndexType paramDepth, index;
|
|
|
|
if (Mangled.nextIf('d')) {
|
|
if (!demangleIndex(paramDepth, depth + 1))
|
|
return nullptr;
|
|
paramDepth += 1;
|
|
if (!demangleIndex(index, depth + 1))
|
|
return nullptr;
|
|
} else if (Mangled.nextIf('x')) {
|
|
paramDepth = 0;
|
|
index = 0;
|
|
} else {
|
|
if (!demangleIndex(index, depth + 1))
|
|
return nullptr;
|
|
paramDepth = 0;
|
|
index += 1;
|
|
}
|
|
return getDependentGenericParamType(paramDepth, index);
|
|
}
|
|
|
|
NodePointer demangleDependentMemberTypeName(NodePointer base,
|
|
unsigned depth) {
|
|
assert(base->getKind() == Node::Kind::Type
|
|
&& "base should be a type");
|
|
NodePointer assocTy = nullptr;
|
|
|
|
if (Mangled.nextIf('S')) {
|
|
assocTy = demangleSubstitutionIndex(depth + 1);
|
|
if (!assocTy)
|
|
return nullptr;
|
|
if (assocTy->getKind() != Node::Kind::DependentAssociatedTypeRef)
|
|
return nullptr;
|
|
} else {
|
|
NodePointer protocol = nullptr;
|
|
if (Mangled.nextIf('P')) {
|
|
protocol = demangleProtocolName(depth + 1);
|
|
if (!protocol) return nullptr;
|
|
}
|
|
|
|
// TODO: If the protocol name was elided from the assoc type mangling,
|
|
// we could try to fish it out of the generic signature constraints on the
|
|
// base.
|
|
NodePointer ID = demangleIdentifier(depth + 1);
|
|
if (!ID) return nullptr;
|
|
assocTy = Factory.createNode(Node::Kind::DependentAssociatedTypeRef);
|
|
if (!assocTy) return nullptr;
|
|
assocTy->addChild(ID, Factory);
|
|
if (protocol)
|
|
assocTy->addChild(protocol, Factory);
|
|
|
|
Substitutions.push_back(assocTy);
|
|
}
|
|
|
|
NodePointer depTy = Factory.createNode(Node::Kind::DependentMemberType);
|
|
depTy->addChild(base, Factory);
|
|
depTy->addChild(assocTy, Factory);
|
|
return depTy;
|
|
}
|
|
|
|
NodePointer demangleAssociatedTypeSimple(unsigned depth) {
|
|
// Demangle the base type.
|
|
auto base = demangleGenericParamIndex(depth + 1);
|
|
if (!base)
|
|
return nullptr;
|
|
|
|
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
|
|
nodeType->addChild(base, Factory);
|
|
|
|
// Demangle the associated type name.
|
|
return demangleDependentMemberTypeName(nodeType, depth + 1);
|
|
}
|
|
|
|
NodePointer demangleAssociatedTypeCompound(unsigned depth) {
|
|
// Demangle the base type.
|
|
auto base = demangleGenericParamIndex(depth + 1);
|
|
if (!base)
|
|
return nullptr;
|
|
|
|
// Demangle the associated type chain.
|
|
while (!Mangled.nextIf('_')) {
|
|
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
|
|
nodeType->addChild(base, Factory);
|
|
|
|
base = demangleDependentMemberTypeName(nodeType, depth + 1);
|
|
if (!base)
|
|
return nullptr;
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
NodePointer demangleDependentType(unsigned depth) {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
|
|
// A dependent member type begins with a non-index, non-'d' character.
|
|
auto c = Mangled.peek();
|
|
if (c != 'd' && c != '_' && !Mangle::isDigit(c)) {
|
|
NodePointer baseType = demangleType(depth + 1);
|
|
if (!baseType) return nullptr;
|
|
return demangleDependentMemberTypeName(baseType, depth + 1);
|
|
}
|
|
|
|
// Otherwise, we have a generic parameter.
|
|
return demangleGenericParamIndex(depth + 1);
|
|
}
|
|
|
|
NodePointer demangleConstrainedTypeImpl(unsigned depth) {
|
|
// The constrained type can only be a generic parameter or an associated
|
|
// type thereof. The 'q' introducer is thus left off of generic params.
|
|
if (Mangled.nextIf('w')) {
|
|
return demangleAssociatedTypeSimple(depth + 1);
|
|
}
|
|
if (Mangled.nextIf('W')) {
|
|
return demangleAssociatedTypeCompound(depth + 1);
|
|
}
|
|
return demangleGenericParamIndex(depth + 1);
|
|
}
|
|
|
|
NodePointer demangleConstrainedType(unsigned depth) {
|
|
auto type = demangleConstrainedTypeImpl(depth);
|
|
if (!type)
|
|
return nullptr;
|
|
|
|
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
|
|
nodeType->addChild(type, Factory);
|
|
return nodeType;
|
|
}
|
|
|
|
NodePointer demangleGenericSignature(unsigned depth,
|
|
bool isPseudogeneric = false) {
|
|
auto sig =
|
|
Factory.createNode(isPseudogeneric
|
|
? Node::Kind::DependentPseudogenericSignature
|
|
: Node::Kind::DependentGenericSignature);
|
|
// First read in the parameter counts at each depth.
|
|
Node::IndexType count = ~(Node::IndexType)0;
|
|
|
|
auto addCount = [&]{
|
|
auto countNode =
|
|
Factory.createNode(Node::Kind::DependentGenericParamCount, count);
|
|
sig->addChild(countNode, Factory);
|
|
};
|
|
|
|
while (Mangled.peek() != 'R' && Mangled.peek() != 'r') {
|
|
if (Mangled.nextIf('z')) {
|
|
count = 0;
|
|
} else if (demangleIndex(count, depth + 1)) {
|
|
count += 1;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
addCount();
|
|
}
|
|
|
|
// No mangled parameters means we have exactly one.
|
|
if (count == ~(Node::IndexType)0) {
|
|
count = 1;
|
|
addCount();
|
|
}
|
|
|
|
// Next read in the generic requirements, if any.
|
|
if (Mangled.nextIf('r'))
|
|
return sig;
|
|
|
|
if (!Mangled.nextIf('R'))
|
|
return nullptr;
|
|
|
|
while (!Mangled.nextIf('r')) {
|
|
NodePointer reqt = demangleGenericRequirement(depth + 1);
|
|
if (!reqt) return nullptr;
|
|
sig->addChild(reqt, Factory);
|
|
}
|
|
|
|
return sig;
|
|
}
|
|
|
|
NodePointer demangleMetatypeRepresentation(unsigned depth) {
|
|
if (Mangled.nextIf('t'))
|
|
return Factory.createNode(Node::Kind::MetatypeRepresentation, "@thin");
|
|
|
|
if (Mangled.nextIf('T'))
|
|
return Factory.createNode(Node::Kind::MetatypeRepresentation, "@thick");
|
|
|
|
if (Mangled.nextIf('o'))
|
|
return Factory.createNode(Node::Kind::MetatypeRepresentation,
|
|
"@objc_metatype");
|
|
|
|
// Unknown metatype representation
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleGenericRequirement(unsigned depth) {
|
|
NodePointer constrainedType = demangleConstrainedType(depth + 1);
|
|
if (!constrainedType)
|
|
return nullptr;
|
|
if (Mangled.nextIf('z')) {
|
|
NodePointer second = demangleType(depth + 1);
|
|
if (!second) return nullptr;
|
|
auto reqt = Factory.createNode(
|
|
Node::Kind::DependentGenericSameTypeRequirement);
|
|
reqt->addChild(constrainedType, Factory);
|
|
reqt->addChild(second, Factory);
|
|
return reqt;
|
|
}
|
|
|
|
if (Mangled.nextIf('l')) {
|
|
StringRef name;
|
|
Node::Kind kind;
|
|
Node::IndexType size = SIZE_MAX;
|
|
Node::IndexType alignment = SIZE_MAX;
|
|
if (Mangled.nextIf('U')) {
|
|
kind = Node::Kind::Identifier;
|
|
name = "U";
|
|
} else if (Mangled.nextIf('R')) {
|
|
kind = Node::Kind::Identifier;
|
|
name = "R";
|
|
} else if (Mangled.nextIf('N')) {
|
|
kind = Node::Kind::Identifier;
|
|
name = "N";
|
|
} else if (Mangled.nextIf('T')) {
|
|
kind = Node::Kind::Identifier;
|
|
name = "T";
|
|
} else if (Mangled.nextIf('B')) {
|
|
kind = Node::Kind::Identifier;
|
|
name = "B";
|
|
} else if (Mangled.nextIf('E')) {
|
|
kind = Node::Kind::Identifier;
|
|
if (!demangleNatural(size, depth + 1))
|
|
return nullptr;
|
|
if (!Mangled.nextIf('_'))
|
|
return nullptr;
|
|
if (!demangleNatural(alignment, depth + 1))
|
|
return nullptr;
|
|
name = "E";
|
|
} else if (Mangled.nextIf('e')) {
|
|
kind = Node::Kind::Identifier;
|
|
if (!demangleNatural(size, depth + 1))
|
|
return nullptr;
|
|
name = "e";
|
|
} else if (Mangled.nextIf('M')) {
|
|
kind = Node::Kind::Identifier;
|
|
if (!demangleNatural(size, depth + 1))
|
|
return nullptr;
|
|
if (!Mangled.nextIf('_'))
|
|
return nullptr;
|
|
if (!demangleNatural(alignment, depth + 1))
|
|
return nullptr;
|
|
name = "M";
|
|
} else if (Mangled.nextIf('m')) {
|
|
kind = Node::Kind::Identifier;
|
|
if (!demangleNatural(size, depth + 1))
|
|
return nullptr;
|
|
name = "m";
|
|
} else if (Mangled.nextIf('S')) {
|
|
kind = Node::Kind::Identifier;
|
|
if (!demangleNatural(size, depth + 1))
|
|
return nullptr;
|
|
name = "S";
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer second = Factory.createNode(kind, name);
|
|
if (!second) return nullptr;
|
|
auto reqt = Factory.createNode(
|
|
Node::Kind::DependentGenericLayoutRequirement);
|
|
reqt->addChild(constrainedType, Factory);
|
|
reqt->addChild(second, Factory);
|
|
if (size != SIZE_MAX) {
|
|
reqt->addChild(Factory.createNode(Node::Kind::Number, size), Factory);
|
|
if (alignment != SIZE_MAX)
|
|
reqt->addChild(Factory.createNode(Node::Kind::Number, alignment), Factory);
|
|
}
|
|
return reqt;
|
|
}
|
|
|
|
// Base class constraints are introduced by a class type mangling, which
|
|
// will begin with either 'C' or 'S'.
|
|
if (!Mangled)
|
|
return nullptr;
|
|
NodePointer constraint = nullptr;
|
|
|
|
auto next = Mangled.peek();
|
|
|
|
if (next == 'C') {
|
|
constraint = demangleType(depth + 1);
|
|
if (!constraint) return nullptr;
|
|
} else if (next == 'S') {
|
|
// A substitution may be either the module name of a protocol or a full
|
|
// type name.
|
|
NodePointer typeName = nullptr;
|
|
Mangled.next();
|
|
NodePointer sub = demangleSubstitutionIndex(depth + 1);
|
|
if (!sub) return nullptr;
|
|
if (sub->getKind() == Node::Kind::Protocol
|
|
|| sub->getKind() == Node::Kind::Class) {
|
|
typeName = sub;
|
|
} else if (sub->getKind() == Node::Kind::Module) {
|
|
typeName = demangleProtocolNameGivenContext(sub, depth + 1);
|
|
if (!typeName)
|
|
return nullptr;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
constraint = Factory.createNode(Node::Kind::Type);
|
|
constraint->addChild(typeName, Factory);
|
|
} else {
|
|
constraint = demangleProtocolName(depth + 1);
|
|
if (!constraint)
|
|
return nullptr;
|
|
}
|
|
auto reqt = Factory.createNode(
|
|
Node::Kind::DependentGenericConformanceRequirement);
|
|
reqt->addChild(constrainedType, Factory);
|
|
reqt->addChild(constraint, Factory);
|
|
return reqt;
|
|
}
|
|
|
|
NodePointer demangleArchetypeType(unsigned depth) {
|
|
auto makeAssociatedType = [&](NodePointer root) -> NodePointer {
|
|
NodePointer name = demangleIdentifier(depth + 1);
|
|
if (!name)
|
|
return nullptr;
|
|
auto assocType = Factory.createNode(Node::Kind::AssociatedTypeRef);
|
|
assocType->addChild(root, Factory);
|
|
assocType->addChild(name, Factory);
|
|
Substitutions.push_back(assocType);
|
|
return assocType;
|
|
};
|
|
|
|
if (Mangled.nextIf('Q')) {
|
|
NodePointer root = demangleArchetypeType(depth + 1);
|
|
if (!root) return nullptr;
|
|
return makeAssociatedType(root);
|
|
}
|
|
if (Mangled.nextIf('S')) {
|
|
NodePointer sub = demangleSubstitutionIndex(depth + 1);
|
|
if (!sub) return nullptr;
|
|
return makeAssociatedType(sub);
|
|
}
|
|
if (Mangled.nextIf('s')) {
|
|
NodePointer stdlib = Factory.createNode(Node::Kind::Module, STDLIB_NAME);
|
|
return makeAssociatedType(stdlib);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleTuple(IsVariadic isV, unsigned depth) {
|
|
NodePointer tuple = Factory.createNode(Node::Kind::Tuple);
|
|
NodePointer elt = nullptr;
|
|
while (!Mangled.nextIf('_')) {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
elt = Factory.createNode(Node::Kind::TupleElement);
|
|
|
|
if (isStartOfIdentifier(Mangled.peek())) {
|
|
NodePointer label =
|
|
demangleIdentifier(depth + 1, Node::Kind::TupleElementName);
|
|
if (!label)
|
|
return nullptr;
|
|
elt->addChild(label, Factory);
|
|
}
|
|
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
elt->addChild(type, Factory);
|
|
|
|
tuple->addChild(elt, Factory);
|
|
}
|
|
if (isV == IsVariadic::yes && elt) {
|
|
elt->reverseChildren();
|
|
NodePointer marker = Factory.createNode(Node::Kind::VariadicMarker);
|
|
elt->addChild(marker, Factory);
|
|
elt->reverseChildren();
|
|
}
|
|
return tuple;
|
|
}
|
|
|
|
NodePointer postProcessReturnTypeNode (NodePointer out_args) {
|
|
NodePointer out_node = Factory.createNode(Node::Kind::ReturnType);
|
|
out_node->addChild(out_args, Factory);
|
|
return out_node;
|
|
}
|
|
|
|
NodePointer demangleType(unsigned depth) {
|
|
NodePointer type = demangleTypeImpl(depth);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
|
|
nodeType->addChild(type, Factory);
|
|
return nodeType;
|
|
}
|
|
|
|
NodePointer demangleFunctionType(Node::Kind kind, unsigned depth) {
|
|
bool throws = false, concurrent = false, async = false;
|
|
auto diffKind = MangledDifferentiabilityKind::NonDifferentiable;
|
|
NodePointer globalActorType = nullptr;
|
|
if (Mangled) {
|
|
throws = Mangled.nextIf('z');
|
|
concurrent = Mangled.nextIf('y');
|
|
async = Mangled.nextIf('Z');
|
|
if (Mangled.nextIf('D')) {
|
|
switch (auto kind = (MangledDifferentiabilityKind)Mangled.next()) {
|
|
case MangledDifferentiabilityKind::Forward:
|
|
case MangledDifferentiabilityKind::Reverse:
|
|
case MangledDifferentiabilityKind::Normal:
|
|
case MangledDifferentiabilityKind::Linear:
|
|
diffKind = kind;
|
|
break;
|
|
case MangledDifferentiabilityKind::NonDifferentiable:
|
|
assert(false && "Impossible case 'NonDifferentiable'");
|
|
}
|
|
}
|
|
if (Mangled.nextIf('Y')) {
|
|
globalActorType = demangleType(depth + 1);
|
|
if (!globalActorType)
|
|
return nullptr;
|
|
}
|
|
}
|
|
NodePointer in_args = demangleType(depth + 1);
|
|
if (!in_args)
|
|
return nullptr;
|
|
NodePointer out_args = demangleType(depth + 1);
|
|
if (!out_args)
|
|
return nullptr;
|
|
NodePointer block = Factory.createNode(kind);
|
|
|
|
if (throws) {
|
|
block->addChild(Factory.createNode(Node::Kind::ThrowsAnnotation), Factory);
|
|
}
|
|
if (async) {
|
|
block->addChild(Factory.createNode(Node::Kind::AsyncAnnotation), Factory);
|
|
}
|
|
if (concurrent) {
|
|
block->addChild(
|
|
Factory.createNode(Node::Kind::ConcurrentFunctionType), Factory);
|
|
}
|
|
if (diffKind != MangledDifferentiabilityKind::NonDifferentiable) {
|
|
block->addChild(
|
|
Factory.createNode(
|
|
Node::Kind::DifferentiableFunctionType, (char)diffKind), Factory);
|
|
}
|
|
if (globalActorType) {
|
|
auto globalActorNode =
|
|
Factory.createNode(Node::Kind::GlobalActorFunctionType);
|
|
globalActorNode->addChild(globalActorType, Factory);
|
|
block->addChild(globalActorNode, Factory);
|
|
}
|
|
// Is there any need to handle isolated(any) function types here?
|
|
|
|
NodePointer in_node = Factory.createNode(Node::Kind::ArgumentTuple);
|
|
block->addChild(in_node, Factory);
|
|
in_node->addChild(in_args, Factory);
|
|
block->addChild(postProcessReturnTypeNode(out_args), Factory);
|
|
return block;
|
|
}
|
|
|
|
NodePointer demangleTypeImpl(unsigned depth) {
|
|
if (depth > OldDemangler::MaxDepth || !Mangled)
|
|
return nullptr;
|
|
char c = Mangled.next();
|
|
if (c == 'B') {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
c = Mangled.next();
|
|
if (c == 'b')
|
|
return Factory.createNode(Node::Kind::BuiltinTypeName,
|
|
"Builtin.BridgeObject");
|
|
if (c == 'B')
|
|
return Factory.createNode(Node::Kind::BuiltinTypeName,
|
|
"Builtin.UnsafeValueBuffer");
|
|
if (c == 'f') {
|
|
Node::IndexType size;
|
|
if (demangleBuiltinSize(size, depth + 1)) {
|
|
return Factory.createNode(
|
|
Node::Kind::BuiltinTypeName,
|
|
std::move(DemanglerPrinter() << "Builtin.FPIEEE" << size).str());
|
|
}
|
|
}
|
|
if (c == 'i') {
|
|
Node::IndexType size;
|
|
if (demangleBuiltinSize(size, depth + 1)) {
|
|
return Factory.createNode(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Int" << size).str());
|
|
}
|
|
}
|
|
if (c == 'v') {
|
|
Node::IndexType elts;
|
|
if (demangleNatural(elts, depth + 1)) {
|
|
if (!Mangled.nextIf('B'))
|
|
return nullptr;
|
|
if (Mangled.nextIf('i')) {
|
|
Node::IndexType size;
|
|
if (!demangleBuiltinSize(size, depth + 1))
|
|
return nullptr;
|
|
return Factory.createNode(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xInt" << size)
|
|
.str());
|
|
}
|
|
if (Mangled.nextIf('f')) {
|
|
Node::IndexType size;
|
|
if (!demangleBuiltinSize(size, depth + 1))
|
|
return nullptr;
|
|
return Factory.createNode(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xFPIEEE"
|
|
<< size).str());
|
|
}
|
|
if (Mangled.nextIf('p'))
|
|
return Factory.createNode(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xRawPointer")
|
|
.str());
|
|
}
|
|
}
|
|
if (c == 'O')
|
|
return Factory.createNode(Node::Kind::BuiltinTypeName,
|
|
"Builtin.UnknownObject");
|
|
if (c == 'o')
|
|
return Factory.createNode(Node::Kind::BuiltinTypeName,
|
|
"Builtin.NativeObject");
|
|
if (c == 'p')
|
|
return Factory.createNode(Node::Kind::BuiltinTypeName,
|
|
"Builtin.RawPointer");
|
|
if (c == 't')
|
|
return Factory.createNode(Node::Kind::BuiltinTypeName,
|
|
"Builtin.SILToken");
|
|
if (c == 'w')
|
|
return Factory.createNode(Node::Kind::BuiltinTypeName,
|
|
"Builtin.Word");
|
|
return nullptr;
|
|
}
|
|
if (c == 'a')
|
|
return demangleDeclarationName(Node::Kind::TypeAlias, depth + 1);
|
|
|
|
if (c == 'b') {
|
|
return demangleFunctionType(Node::Kind::ObjCBlock, depth + 1);
|
|
}
|
|
if (c == 'c') {
|
|
return demangleFunctionType(Node::Kind::CFunctionPointer, depth + 1);
|
|
}
|
|
if (c == 'D') {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
|
|
NodePointer dynamicSelf = Factory.createNode(Node::Kind::DynamicSelf);
|
|
dynamicSelf->addChild(type, Factory);
|
|
return dynamicSelf;
|
|
}
|
|
if (c == 'E') {
|
|
if (!Mangled.nextIf('R'))
|
|
return nullptr;
|
|
if (!Mangled.nextIf('R'))
|
|
return nullptr;
|
|
return Factory.createNode(Node::Kind::ErrorType, std::string());
|
|
}
|
|
if (c == 'F') {
|
|
return demangleFunctionType(Node::Kind::FunctionType, depth + 1);
|
|
}
|
|
if (c == 'f') {
|
|
return demangleFunctionType(Node::Kind::UncurriedFunctionType, depth + 1);
|
|
}
|
|
if (c == 'G') {
|
|
return demangleBoundGenericType(depth + 1);
|
|
}
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('b')) {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer boxType = Factory.createNode(Node::Kind::SILBoxType);
|
|
boxType->addChild(type, Factory);
|
|
return boxType;
|
|
}
|
|
if (Mangled.nextIf('B')) {
|
|
NodePointer signature = nullptr;
|
|
if (Mangled.nextIf('G')) {
|
|
signature = demangleGenericSignature(depth, /*pseudogeneric*/ false);
|
|
if (!signature)
|
|
return nullptr;
|
|
}
|
|
NodePointer layout = Factory.createNode(Node::Kind::SILBoxLayout);
|
|
while (!Mangled.nextIf('_')) {
|
|
Node::Kind kind;
|
|
if (Mangled.nextIf('m'))
|
|
kind = Node::Kind::SILBoxMutableField;
|
|
else if (Mangled.nextIf('i'))
|
|
kind = Node::Kind::SILBoxImmutableField;
|
|
else
|
|
return nullptr;
|
|
|
|
auto type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
auto field = Factory.createNode(kind);
|
|
field->addChild(type, Factory);
|
|
layout->addChild(field, Factory);
|
|
}
|
|
NodePointer genericArgs = nullptr;
|
|
if (signature) {
|
|
genericArgs = Factory.createNode(Node::Kind::TypeList);
|
|
while (!Mangled.nextIf('_')) {
|
|
auto type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
genericArgs->addChild(type, Factory);
|
|
}
|
|
}
|
|
NodePointer boxType =
|
|
Factory.createNode(Node::Kind::SILBoxTypeWithLayout);
|
|
boxType->addChild(layout, Factory);
|
|
if (signature) {
|
|
boxType->addChild(signature, Factory);
|
|
assert(genericArgs);
|
|
boxType->addChild(genericArgs, Factory);
|
|
}
|
|
return boxType;
|
|
}
|
|
}
|
|
if (c == 'K') {
|
|
return demangleFunctionType(Node::Kind::AutoClosureType, depth + 1);
|
|
}
|
|
if (c == 'M') {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer metatype = Factory.createNode(Node::Kind::Metatype);
|
|
metatype->addChild(type, Factory);
|
|
return metatype;
|
|
}
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('M')) {
|
|
NodePointer metatypeRepr = demangleMetatypeRepresentation(depth + 1);
|
|
if (!metatypeRepr) return nullptr;
|
|
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer metatype = Factory.createNode(Node::Kind::Metatype);
|
|
metatype->addChild(metatypeRepr, Factory);
|
|
metatype->addChild(type, Factory);
|
|
return metatype;
|
|
}
|
|
}
|
|
if (c == 'P') {
|
|
if (Mangled.nextIf('M')) {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type) return nullptr;
|
|
auto metatype = Factory.createNode(Node::Kind::ExistentialMetatype);
|
|
metatype->addChild(type, Factory);
|
|
return metatype;
|
|
}
|
|
|
|
return demangleProtocolList(depth + 1);
|
|
}
|
|
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('P')) {
|
|
if (Mangled.nextIf('M')) {
|
|
NodePointer metatypeRepr = demangleMetatypeRepresentation(depth + 1);
|
|
if (!metatypeRepr) return nullptr;
|
|
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type) return nullptr;
|
|
|
|
auto metatype = Factory.createNode(Node::Kind::ExistentialMetatype);
|
|
metatype->addChild(metatypeRepr, Factory);
|
|
metatype->addChild(type, Factory);
|
|
return metatype;
|
|
}
|
|
|
|
return demangleProtocolList(depth + 1);
|
|
}
|
|
}
|
|
if (c == 'Q') {
|
|
if (Mangled.nextIf('u')) {
|
|
// Special mangling for opaque return type.
|
|
return Factory.createNode(Node::Kind::OpaqueReturnType);
|
|
}
|
|
if (Mangled.nextIf('U')) {
|
|
// Special mangling for opaque return type.
|
|
Node::IndexType ordinal;
|
|
if (!demangleIndex(ordinal, depth))
|
|
return nullptr;
|
|
auto result = Factory.createNode(Node::Kind::OpaqueReturnType);
|
|
result->addChild(
|
|
Factory.createNode(Node::Kind::OpaqueReturnTypeIndex, ordinal), Factory);
|
|
return result;
|
|
}
|
|
return demangleArchetypeType(depth + 1);
|
|
}
|
|
if (c == 'q') {
|
|
return demangleDependentType(depth + 1);
|
|
}
|
|
if (c == 'x') {
|
|
// Special mangling for the first generic param.
|
|
return getDependentGenericParamType(0, 0);
|
|
}
|
|
if (c == 'w') {
|
|
return demangleAssociatedTypeSimple(depth + 1);
|
|
}
|
|
if (c == 'W') {
|
|
return demangleAssociatedTypeCompound(depth + 1);
|
|
}
|
|
if (c == 'R') {
|
|
NodePointer inout = Factory.createNode(Node::Kind::InOut);
|
|
NodePointer type = demangleTypeImpl(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
inout->addChild(type, Factory);
|
|
return inout;
|
|
}
|
|
if (c == 'k') {
|
|
auto noDerivative = Factory.createNode(Node::Kind::NoDerivative);
|
|
auto type = demangleTypeImpl(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
noDerivative->addChild(type, Factory);
|
|
return noDerivative;
|
|
}
|
|
if (c == 'S') {
|
|
return demangleSubstitutionIndex(depth + 1);
|
|
}
|
|
if (c == 'T') {
|
|
return demangleTuple(IsVariadic::no, depth + 1);
|
|
}
|
|
if (c == 't') {
|
|
return demangleTuple(IsVariadic::yes, depth + 1);
|
|
}
|
|
if (c == 'u') {
|
|
NodePointer sig = demangleGenericSignature(depth + 1);
|
|
if (!sig) return nullptr;
|
|
NodePointer sub = demangleType(depth + 1);
|
|
if (!sub) return nullptr;
|
|
NodePointer dependentGenericType
|
|
= Factory.createNode(Node::Kind::DependentGenericType);
|
|
dependentGenericType->addChild(sig, Factory);
|
|
dependentGenericType->addChild(sub, Factory);
|
|
return dependentGenericType;
|
|
}
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('f')) {
|
|
return demangleFunctionType(Node::Kind::ThinFunctionType, depth + 1);
|
|
}
|
|
if (Mangled.nextIf('o')) {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer unowned = Factory.createNode(Node::Kind::Unowned);
|
|
unowned->addChild(type, Factory);
|
|
return unowned;
|
|
}
|
|
if (Mangled.nextIf('u')) {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer unowned = Factory.createNode(Node::Kind::Unmanaged);
|
|
unowned->addChild(type, Factory);
|
|
return unowned;
|
|
}
|
|
if (Mangled.nextIf('w')) {
|
|
NodePointer type = demangleType(depth + 1);
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer weak = Factory.createNode(Node::Kind::Weak);
|
|
weak->addChild(type, Factory);
|
|
return weak;
|
|
}
|
|
|
|
// type ::= 'XF' impl-function-type
|
|
if (Mangled.nextIf('F')) {
|
|
return demangleImplFunctionType(depth + 1);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
if (isStartOfNominalType(c))
|
|
return demangleDeclarationName(nominalTypeMarkerToNodeKind(c), depth + 1);
|
|
return nullptr;
|
|
}
|
|
|
|
bool demangleReabstractSignature(NodePointer signature, unsigned depth) {
|
|
if (Mangled.nextIf('G')) {
|
|
NodePointer generics = demangleGenericSignature(depth + 1);
|
|
if (!generics) return false;
|
|
signature->addChild(generics, Factory);
|
|
}
|
|
|
|
NodePointer srcType = demangleType(depth + 1);
|
|
if (!srcType) return false;
|
|
signature->addChild(srcType, Factory);
|
|
|
|
NodePointer destType = demangleType(depth + 1);
|
|
if (!destType) return false;
|
|
signature->addChild(destType, Factory);
|
|
|
|
return true;
|
|
}
|
|
|
|
// impl-function-type ::= impl-callee-convention impl-function-attribute*
|
|
// generics? '_' impl-parameter* '_' impl-result* '_'
|
|
// impl-function-attribute ::= 'Cb' // compatible with C block invocation function
|
|
// impl-function-attribute ::= 'Cc' // compatible with C global function
|
|
// impl-function-attribute ::= 'Cm' // compatible with Swift method
|
|
// impl-function-attribute ::= 'CO' // compatible with ObjC method
|
|
// impl-function-attribute ::= 'Cw' // compatible with protocol witness
|
|
// impl-function-attribute ::= 'G' // generic
|
|
NodePointer demangleImplFunctionType(unsigned depth) {
|
|
NodePointer type = Factory.createNode(Node::Kind::ImplFunctionType);
|
|
|
|
if (!demangleImplCalleeConvention(type, depth + 1))
|
|
return nullptr;
|
|
|
|
if (Mangled.nextIf('C')) {
|
|
if (Mangled.nextIf('b'))
|
|
addImplFunctionConvention(type, "block");
|
|
else if (Mangled.nextIf('c'))
|
|
addImplFunctionConvention(type, "c");
|
|
else if (Mangled.nextIf('m'))
|
|
addImplFunctionConvention(type, "method");
|
|
else if (Mangled.nextIf('O'))
|
|
addImplFunctionConvention(type, "objc_method");
|
|
else if (Mangled.nextIf('w'))
|
|
addImplFunctionConvention(type, "witness_method");
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (Mangled.nextIf('h'))
|
|
addImplFunctionAttribute(type, "@Sendable");
|
|
|
|
if (Mangled.nextIf('H'))
|
|
addImplFunctionAttribute(type, "@async");
|
|
|
|
// Enter a new generic context if this type is generic.
|
|
// FIXME: replace with std::optional, when we have it.
|
|
bool isPseudogeneric = false;
|
|
if (Mangled.nextIf('G') ||
|
|
(isPseudogeneric = Mangled.nextIf('g'))) {
|
|
NodePointer generics =
|
|
demangleGenericSignature(depth + 1, isPseudogeneric);
|
|
if (!generics)
|
|
return nullptr;
|
|
type->addChild(generics, Factory);
|
|
}
|
|
|
|
// Expect the attribute terminator.
|
|
if (!Mangled.nextIf('_'))
|
|
return nullptr;
|
|
|
|
// Demangle the parameters.
|
|
if (!demangleImplParameters(type, depth + 1))
|
|
return nullptr;
|
|
|
|
// Demangle the result type.
|
|
if (!demangleImplResults(type, depth + 1))
|
|
return nullptr;
|
|
|
|
return type;
|
|
}
|
|
|
|
enum class ImplConventionContext { Callee, Parameter, Result };
|
|
|
|
/// impl-convention ::= 'a' // direct, autoreleased
|
|
/// impl-convention ::= 'd' // direct, no ownership transfer
|
|
/// impl-convention ::= 'D' // direct, no ownership transfer,
|
|
/// // dependent on self
|
|
/// impl-convention ::= 'g' // direct, guaranteed
|
|
/// impl-convention ::= 'e' // direct, deallocating
|
|
/// impl-convention ::= 'i' // indirect, ownership transfer
|
|
/// impl-convention ::= 'l' // indirect, inout
|
|
/// impl-convention ::= 'o' // direct, ownership transfer
|
|
///
|
|
/// Returns an empty string otherwise.
|
|
StringRef demangleImplConvention(ImplConventionContext ctxt, unsigned depth) {
|
|
#define CASE(CHAR, FOR_CALLEE, FOR_PARAMETER, FOR_RESULT) \
|
|
if (Mangled.nextIf(CHAR)) { \
|
|
switch (ctxt) { \
|
|
case ImplConventionContext::Callee: return (FOR_CALLEE); \
|
|
case ImplConventionContext::Parameter: return (FOR_PARAMETER); \
|
|
case ImplConventionContext::Result: return (FOR_RESULT); \
|
|
} \
|
|
return StringRef(); \
|
|
}
|
|
auto Nothing = StringRef();
|
|
CASE('a', Nothing, Nothing, "@autoreleased")
|
|
CASE('d', "@callee_unowned", "@unowned", "@unowned")
|
|
CASE('D', Nothing, Nothing, "@unowned_inner_pointer")
|
|
CASE('g', "@callee_guaranteed", "@guaranteed", Nothing)
|
|
CASE('e', Nothing, "@deallocating", Nothing)
|
|
CASE('i', Nothing, "@in", "@out")
|
|
CASE('l', Nothing, "@inout", Nothing)
|
|
CASE('o', "@callee_owned", "@owned", "@owned")
|
|
return Nothing;
|
|
#undef CASE
|
|
}
|
|
|
|
// impl-callee-convention ::= 't'
|
|
// impl-callee-convention ::= impl-convention
|
|
bool demangleImplCalleeConvention(NodePointer type, unsigned depth) {
|
|
StringRef attr;
|
|
if (Mangled.nextIf('t')) {
|
|
attr = "@convention(thin)";
|
|
} else {
|
|
attr = demangleImplConvention(ImplConventionContext::Callee, depth + 1);
|
|
}
|
|
if (attr.empty()) {
|
|
return false;
|
|
}
|
|
type->addChild(Factory.createNode(Node::Kind::ImplConvention, attr), Factory);
|
|
return true;
|
|
}
|
|
|
|
void addImplFunctionAttribute(NodePointer parent, StringRef attr,
|
|
Node::Kind kind = Node::Kind::ImplFunctionAttribute) {
|
|
parent->addChild(Factory.createNode(kind, attr), Factory);
|
|
}
|
|
|
|
void addImplFunctionConvention(NodePointer parent, StringRef attr) {
|
|
auto attrNode = Factory.createNode(Node::Kind::ImplFunctionConvention);
|
|
attrNode->addChild(
|
|
Factory.createNode(Node::Kind::ImplFunctionConventionName, attr),
|
|
Factory);
|
|
parent->addChild(attrNode, Factory);
|
|
}
|
|
|
|
// impl-parameter ::= impl-convention type
|
|
bool demangleImplParameters(NodePointer parent, unsigned depth) {
|
|
while (!Mangled.nextIf('_')) {
|
|
auto input =
|
|
demangleImplParameterOrResult(Node::Kind::ImplParameter, depth + 1);
|
|
if (!input) return false;
|
|
parent->addChild(input, Factory);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// impl-result ::= impl-convention type
|
|
bool demangleImplResults(NodePointer parent, unsigned depth) {
|
|
while (!Mangled.nextIf('_')) {
|
|
auto res =
|
|
demangleImplParameterOrResult(Node::Kind::ImplResult, depth + 1);
|
|
if (!res) return false;
|
|
parent->addChild(res, Factory);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
NodePointer demangleImplParameterOrResult(Node::Kind kind, unsigned depth) {
|
|
if (Mangled.nextIf('z')) {
|
|
// Only valid for a result.
|
|
if (kind != Node::Kind::ImplResult)
|
|
return nullptr;
|
|
kind = Node::Kind::ImplErrorResult;
|
|
}
|
|
|
|
ImplConventionContext ConvCtx;
|
|
if (kind == Node::Kind::ImplParameter) {
|
|
ConvCtx = ImplConventionContext::Parameter;
|
|
} else if (kind == Node::Kind::ImplResult
|
|
|| kind == Node::Kind::ImplErrorResult) {
|
|
ConvCtx = ImplConventionContext::Result;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
auto convention = demangleImplConvention(ConvCtx, depth + 1);
|
|
if (convention.empty()) return nullptr;
|
|
auto type = demangleType(depth + 1);
|
|
if (!type) return nullptr;
|
|
|
|
NodePointer node = Factory.createNode(kind);
|
|
node->addChild(Factory.createNode(Node::Kind::ImplConvention, convention),
|
|
Factory);
|
|
node->addChild(type, Factory);
|
|
|
|
return node;
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
NodePointer
|
|
swift::Demangle::demangleOldSymbolAsNode(StringRef MangledName,
|
|
NodeFactory &Factory) {
|
|
OldDemangler demangler(MangledName, Factory);
|
|
return demangler.demangleTopLevel();
|
|
}
|
|
|