text: //===--- Demangle.cpp - Swift Name Demangling -----------------------------===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See http://swift.org/LICENSE.txt for license information
  // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  //  This file implements declaration name demangling in Swift.
  //
  //===----------------------------------------------------------------------===//
  
  #include "swift/Basic/Demangle.h"
  #include "swift/Basic/Fallthrough.h"
  #include "swift/Strings.h"
  #include "swift/Basic/LLVM.h"
  #include "swift/Basic/Punycode.h"
  #include "swift/Basic/UUID.h"
  #include "llvm/ADT/StringRef.h"
  #include <functional>
  #include <vector>
  #include <cstdio>
  #include <cstdlib>
  
  using namespace swift;
  using namespace Demangle;
  
  [[noreturn]]
  static void unreachable(const char *Message) {
    fprintf(stderr, "fatal error: %s\n", Message);
    std::abort();
  }
  
  DemanglerPrinter &DemanglerPrinter::operator<<(unsigned long long n) & {
    char buffer[32];
    snprintf(buffer, sizeof(buffer), "%llu", n);
    Stream.append(buffer);
    return *this;
  }
  DemanglerPrinter &DemanglerPrinter::operator<<(long long n) & {
    char buffer[32];
    snprintf(buffer, sizeof(buffer), "%lld",n);
    Stream.append(buffer);
    return *this;
  }
  
  namespace {
  struct QuotedString {
    std::string Value;
  
    explicit QuotedString(std::string Value) : Value(Value) {}
  };
  } // end anonymous namespace.
  
  static DemanglerPrinter &operator<<(DemanglerPrinter &printer,
                                      const QuotedString &QS) {
    printer << '"';
    for (auto C : QS.Value) {
      switch (C) {
      case '\\': printer << "\\\\"; break;
      case '\t': printer << "\\t"; break;
      case '\n': printer << "\\n"; break;
      case '\r': printer << "\\r"; break;
      case '"': printer << "\\\""; break;
      case '\'': printer << '\''; break; // no need to escape these
      case '\0': printer << "\\0"; break;
      default:
        auto c = static_cast<char>(C);
        // Other ASCII control characters should get escaped.
        if (c < 0x20 || c == 0x7F) {
          static const char Hexdigit[] = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F'
          };
          printer << "\\x" << Hexdigit[c >> 4] << Hexdigit[c & 0xF];
        } else {
          printer << c;
        }
        break;
      }
    }
    printer << '"';
    return printer;
  }
  
  Node::~Node() {
    switch (NodePayloadKind) {
    case PayloadKind::None: return;
    case PayloadKind::Index: return;
    case PayloadKind::Text: TextPayload.~basic_string(); return;
    }
    unreachable("bad payload kind");
  }
  
  namespace {
    struct FindPtr {
      FindPtr(Node *v) : Target(v) {}
      bool operator()(NodePointer sp) const {
        return sp.get() == 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;
  }
  
  static std::string archetypeName(Node::IndexType index,
                                   Node::IndexType depth) {
    DemanglerPrinter name;
    do {
      name << (char)('A' + (index % 26));
      index /= 26;
    } while (index);
    if (depth != 0)
      name << depth;
    return std::move(name).str();
  }
  
  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() { return Text.front(); }
  
    /// Claim and return the next character.  Asserts that there is at
    /// least one remaining character.
    char next() {
      char c = peek();
      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.startswith(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) {
      llvm::Optional<char> c2;
      while (!isEmpty() && (c2 = peek()).getValue() != c) {
        result.push_back(c2.getValue());
        advanceOffset(1);
      }
      return c2.hasValue() && c2.getValue() == c;
    }
  };
  
  static StringRef toString(Directness d) {
    switch (d) {
    case Directness::Direct:
      return "direct";
    case Directness::Indirect:
      return "indirect";
    }
    unreachable("bad directness");
  }
  
  static StringRef toString(ValueWitnessKind k) {
    switch (k) {
    case ValueWitnessKind::AllocateBuffer:
      return "allocateBuffer";
    case ValueWitnessKind::AssignWithCopy:
      return "assignWithCopy";
    case ValueWitnessKind::AssignWithTake:
      return "assignWithTake";
    case ValueWitnessKind::DeallocateBuffer:
      return "deallocateBuffer";
    case ValueWitnessKind::Destroy:
      return "destroy";
    case ValueWitnessKind::DestroyBuffer:
      return "destroyBuffer";
    case ValueWitnessKind::InitializeBufferWithCopyOfBuffer:
      return "initializeBufferWithCopyOfBuffer";
    case ValueWitnessKind::InitializeBufferWithCopy:
      return "initializeBufferWithCopy";
    case ValueWitnessKind::InitializeWithCopy:
        return "initializeWithCopy";
    case ValueWitnessKind::InitializeBufferWithTake:
      return "initializeBufferWithTake";
    case ValueWitnessKind::InitializeWithTake:
      return "initializeWithTake";
    case ValueWitnessKind::ProjectBuffer:
      return "projectBuffer";
    case ValueWitnessKind::InitializeBufferWithTakeOfBuffer:
      return "initializeBufferWithTakeOfBuffer";
    case ValueWitnessKind::DestroyArray:
      return "destroyArray";
    case ValueWitnessKind::InitializeArrayWithCopy:
      return "initializeArrayWithCopy";
    case ValueWitnessKind::InitializeArrayWithTakeFrontToBack:
      return "initializeArrayWithTakeFrontToBack";
    case ValueWitnessKind::InitializeArrayWithTakeBackToFront:
      return "initializeArrayWithTakeBackToFront";
    case ValueWitnessKind::StoreExtraInhabitant:
      return "storeExtraInhabitant";
    case ValueWitnessKind::GetExtraInhabitantIndex:
      return "getExtraInhabitantIndex";
    case ValueWitnessKind::GetEnumTag:
      return "getEnumTag";
    case ValueWitnessKind::DestructiveProjectEnumData:
      return "destructiveProjectEnumData";
    }
    unreachable("bad value witness kind");
  }
  
  /// The main class for parsing a demangling tree out of a mangled string.
  class Demangler {
    std::vector<NodePointer> Substitutions;
    NameSource Mangled;
  public:  
    Demangler(llvm::StringRef mangled) : Mangled(mangled) {}
  
  /// 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) do { \
      auto _node = demangle##CHILD_KIND();                  \
      if (!_node) return nullptr;                           \
      (PARENT)->addChild(std::move(_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) do {  \
      auto _kind = demangle##CHILD_KIND();                           \
      if (!_kind.hasValue()) return nullptr;                         \
      (PARENT)->addChild(NodeFactory::create(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 = NodeFactory::create(Node::Kind::Global);
  
      // First demangle any specialization prefixes.
      if (Mangled.nextIf("TS")) {
        do {
          DEMANGLE_CHILD_OR_RETURN(topLevel, SpecializedAttribute);
  
          // 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")) {
        topLevel->addChild(NodeFactory::create(Node::Kind::ObjCAttribute));
      } else if (Mangled.nextIf("TO")) {
        topLevel->addChild(NodeFactory::create(Node::Kind::NonObjCAttribute));
      } else if (Mangled.nextIf("TD")) {
        topLevel->addChild(NodeFactory::create(Node::Kind::DynamicAttribute));
      } else if (Mangled.nextIf("Td")) {
        topLevel->addChild(NodeFactory::create(
                                     Node::Kind::DirectMethodReferenceAttribute));
      } else if (Mangled.nextIf("TV")) {
        topLevel->addChild(NodeFactory::create(Node::Kind::VTableAttribute));
      }
  
      DEMANGLE_CHILD_OR_RETURN(topLevel, Global);
  
      // Add a suffix node if there's anything left unmangled.
      if (!Mangled.isEmpty()) {
        topLevel->addChild(NodeFactory::create(Node::Kind::Suffix,
                                               Mangled.getString()));
      }
  
      return topLevel;
    }
  
    NodePointer demangleTypeName() {
      return demangleType();
    }
    
  private:
    enum class IsVariadic {
      yes = true, no = false
    };
  
    Optional<Directness> demangleDirectness() {
      if (Mangled.nextIf('d'))
        return Directness::Direct;
      if (Mangled.nextIf('i'))
        return Directness::Indirect;
      return None;
    }
  
    bool demangleNatural(Node::IndexType &num) {
      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) {
      if (!demangleNatural(num))
        return false;
      if (Mangled.nextIf('_'))
        return true;
      return false;
    }
  
    Optional<ValueWitnessKind> demangleValueWitnessKind() {
      if (!Mangled)
        return None;
      char c1 = Mangled.next();
      if (!Mangled)
        return None;
      char c2 = Mangled.next();
      if (c1 == 'a' && c2 == 'l')
        return ValueWitnessKind::AllocateBuffer;
      if (c1 == 'c' && c2 == 'a')
        return ValueWitnessKind::AssignWithCopy;
      if (c1 == 't' && c2 == 'a')
        return ValueWitnessKind::AssignWithTake;
      if (c1 == 'd' && c2 == 'e')
        return ValueWitnessKind::DeallocateBuffer;
      if (c1 == 'x' && c2 == 'x')
        return ValueWitnessKind::Destroy;
      if (c1 == 'X' && c2 == 'X')
        return ValueWitnessKind::DestroyBuffer;
      if (c1 == 'C' && c2 == 'P')
        return ValueWitnessKind::InitializeBufferWithCopyOfBuffer;
      if (c1 == 'C' && c2 == 'p')
        return ValueWitnessKind::InitializeBufferWithCopy;
      if (c1 == 'c' && c2 == 'p')
        return ValueWitnessKind::InitializeWithCopy;
      if (c1 == 'C' && c2 == 'c')
        return ValueWitnessKind::InitializeArrayWithCopy;
      if (c1 == 'T' && c2 == 'K')
        return ValueWitnessKind::InitializeBufferWithTakeOfBuffer;
      if (c1 == 'T' && c2 == 'k')
        return ValueWitnessKind::InitializeBufferWithTake;
      if (c1 == 't' && c2 == 'k')
        return ValueWitnessKind::InitializeWithTake;
      if (c1 == 'T' && c2 == 't')
        return ValueWitnessKind::InitializeArrayWithTakeFrontToBack;
      if (c1 == 't' && c2 == 'T')
        return ValueWitnessKind::InitializeArrayWithTakeBackToFront;
      if (c1 == 'p' && c2 == 'r')
        return ValueWitnessKind::ProjectBuffer;
      if (c1 == 'X' && c2 == 'x')
        return ValueWitnessKind::DestroyArray;
      if (c1 == 'x' && c2 == 's')
        return ValueWitnessKind::StoreExtraInhabitant;
      if (c1 == 'x' && c2 == 'g')
        return ValueWitnessKind::GetExtraInhabitantIndex;
      if (c1 == 'u' && c2 == 'g')
        return ValueWitnessKind::GetEnumTag;
      if (c1 == 'u' && c2 == 'p')
        return ValueWitnessKind::DestructiveProjectEnumData;
      return None;
    }
  
    NodePointer demangleGlobal() {
      if (!Mangled)
        return nullptr;
  
      // Type metadata.
      if (Mangled.nextIf('M')) {
        if (Mangled.nextIf('P')) {
          auto pattern =
              NodeFactory::create(Node::Kind::GenericTypeMetadataPattern);
          DEMANGLE_CHILD_OR_RETURN(pattern, Type);
          return pattern;
        }
        if (Mangled.nextIf('a')) {
          auto accessor =
            NodeFactory::create(Node::Kind::TypeMetadataAccessFunction);
          DEMANGLE_CHILD_OR_RETURN(accessor, Type);
          return accessor;
        }
        if (Mangled.nextIf('L')) {
          auto cache = NodeFactory::create(Node::Kind::TypeMetadataLazyCache);
          DEMANGLE_CHILD_OR_RETURN(cache, Type);
          return cache;
        }
        if (Mangled.nextIf('m')) {
          auto metaclass = NodeFactory::create(Node::Kind::Metaclass);
          DEMANGLE_CHILD_OR_RETURN(metaclass, Type);
          return metaclass;
        }
        if (Mangled.nextIf('n')) {
          auto nominalType =
              NodeFactory::create(Node::Kind::NominalTypeDescriptor);
          DEMANGLE_CHILD_OR_RETURN(nominalType, Type);
          return nominalType;
        }
        if (Mangled.nextIf('f')) {
          auto metadata = NodeFactory::create(Node::Kind::FullTypeMetadata);
          DEMANGLE_CHILD_OR_RETURN(metadata, Type);
          return metadata;
        }
        if (Mangled.nextIf('p')) {
          auto metadata = NodeFactory::create(Node::Kind::ProtocolDescriptor);
          DEMANGLE_CHILD_OR_RETURN(metadata, ProtocolName);
          return metadata;
        }
        auto metadata = NodeFactory::create(Node::Kind::TypeMetadata);
        DEMANGLE_CHILD_OR_RETURN(metadata, Type);
        return metadata;
      }
  
      // Partial application thunks.
      if (Mangled.nextIf('P')) {
        if (!Mangled.nextIf('A')) return nullptr;
        Node::Kind kind = Node::Kind::PartialApplyForwarder;
        if (Mangled.nextIf('o'))
          kind = Node::Kind::PartialApplyObjCForwarder;
        auto forwarder = NodeFactory::create(kind);
        if (Mangled.nextIf("__T"))
          DEMANGLE_CHILD_OR_RETURN(forwarder, Global);
        return forwarder;
      }
  
      // Top-level types, for various consumers.
      if (Mangled.nextIf('t')) {
        auto type = NodeFactory::create(Node::Kind::TypeMangling);
        DEMANGLE_CHILD_OR_RETURN(type, Type);
        return type;
      }
  
      // Value witnesses.
      if (Mangled.nextIf('w')) {
        Optional<ValueWitnessKind> w = demangleValueWitnessKind();
        if (!w.hasValue())
          return nullptr;
        auto witness =
          NodeFactory::create(Node::Kind::ValueWitness, unsigned(w.getValue()));
        DEMANGLE_CHILD_OR_RETURN(witness, Type);
        return witness;
      }
  
      // Offsets, value witness tables, and protocol witnesses.
      if (Mangled.nextIf('W')) {
        if (Mangled.nextIf('V')) {
          auto witnessTable = NodeFactory::create(Node::Kind::ValueWitnessTable);
          DEMANGLE_CHILD_OR_RETURN(witnessTable, Type);
          return witnessTable;
        }
        if (Mangled.nextIf('o')) {
          auto witnessTableOffset =
              NodeFactory::create(Node::Kind::WitnessTableOffset);
          DEMANGLE_CHILD_OR_RETURN(witnessTableOffset, Entity);
          return witnessTableOffset;
        }
        if (Mangled.nextIf('v')) {
          auto fieldOffset = NodeFactory::create(Node::Kind::FieldOffset);
          DEMANGLE_CHILD_AS_NODE_OR_RETURN(fieldOffset, Directness);
          DEMANGLE_CHILD_OR_RETURN(fieldOffset, Entity);
          return fieldOffset;
        }
        if (Mangled.nextIf('P')) {
          auto witnessTable =
              NodeFactory::create(Node::Kind::ProtocolWitnessTable);
          DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
          return witnessTable;
        }
        if (Mangled.nextIf('G')) {
          auto witnessTable =
              NodeFactory::create(Node::Kind::GenericProtocolWitnessTable);
          DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
          return witnessTable;
        }
        if (Mangled.nextIf('I')) {
          auto witnessTable = NodeFactory::create(
              Node::Kind::GenericProtocolWitnessTableInstantiationFunction);
          DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
          return witnessTable;
        }
        if (Mangled.nextIf('l')) {
          auto accessor =
            NodeFactory::create(Node::Kind::LazyProtocolWitnessTableAccessor);
          DEMANGLE_CHILD_OR_RETURN(accessor, Type);
          DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
          return accessor;
        }
        if (Mangled.nextIf('L')) {
          auto accessor =
            NodeFactory::create(Node::Kind::LazyProtocolWitnessTableCacheVariable);
          DEMANGLE_CHILD_OR_RETURN(accessor, Type);
          DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
          return accessor;
        }
        if (Mangled.nextIf('a')) {
          auto tableTemplate =
            NodeFactory::create(Node::Kind::ProtocolWitnessTableAccessor);
          DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance);
          return tableTemplate;
        }
        if (Mangled.nextIf('t')) {
          auto accessor = NodeFactory::create(
              Node::Kind::AssociatedTypeMetadataAccessor);
          DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
          DEMANGLE_CHILD_OR_RETURN(accessor, DeclName);
          return accessor;
        }
        if (Mangled.nextIf('T')) {
          auto accessor = NodeFactory::create(
              Node::Kind::AssociatedTypeWitnessTableAccessor);
          DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
          DEMANGLE_CHILD_OR_RETURN(accessor, DeclName);
          DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolName);
          return accessor;
        }
        return nullptr;
      }
  
      // Other thunks.
      if (Mangled.nextIf('T')) {
        if (Mangled.nextIf('R')) {
          auto thunk = NodeFactory::create(Node::Kind::ReabstractionThunkHelper);
          if (!demangleReabstractSignature(thunk))
            return nullptr;
          return thunk;
        }
        if (Mangled.nextIf('r')) {
          auto thunk = NodeFactory::create(Node::Kind::ReabstractionThunk);
          if (!demangleReabstractSignature(thunk))
            return nullptr;
          return thunk;
        }
        if (Mangled.nextIf('W')) {
          NodePointer thunk = NodeFactory::create(Node::Kind::ProtocolWitness);
          DEMANGLE_CHILD_OR_RETURN(thunk, ProtocolConformance);
          // The entity is mangled in its own generic context.
          DEMANGLE_CHILD_OR_RETURN(thunk, Entity);
          return thunk;
        }
        return nullptr;
      }
  
      // Everything else is just an entity.
      return demangleEntity();
    }
  
    NodePointer demangleGenericSpecialization(NodePointer specialization) {
      while (!Mangled.nextIf('_')) {
        // Otherwise, we have another parameter. Demangle the type.
        NodePointer param = NodeFactory::create(Node::Kind::GenericSpecializationParam);
        DEMANGLE_CHILD_OR_RETURN(param, Type);
  
        // 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);
        }
  
        // Add the parameter to our specialization list.
        specialization->addChild(param);
      }
  
      return specialization;
    }
  
  /// TODO: This is an atrocity. Come up with a shorter name.
  #define FUNCSIGSPEC_CREATE_PARAM_KIND(kind)                                    \
    NodeFactory::create(Node::Kind::FunctionSignatureSpecializationParamKind,    \
                        unsigned(FunctionSigSpecializationParamKind::kind))
  #define FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(payload)                              \
    NodeFactory::create(Node::Kind::FunctionSignatureSpecializationParamPayload, \
                        payload)
  
    bool demangleFuncSigSpecializationConstantProp(NodePointer parent) {
      // 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();
        if (!name || !Mangled.nextIf('_'))
          return false;
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFunction));
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()));
        return true;
      }
  
      if (Mangled.nextIf('g')) {
        NodePointer name = demangleIdentifier();
        if (!name || !Mangled.nextIf('_'))
          return false;
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropGlobal));
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()));
        return true;
      }
  
      if (Mangled.nextIf('i')) {
        std::string Str;
        if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
          return false;
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropInteger));
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str));
        return true;
      }
  
      if (Mangled.nextIf("fl")) {
        std::string Str;
        if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
          return false;
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFloat));
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str));
        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();
        if (!str || !Mangled.nextIf('_'))
          return false;
  
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropString));
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(encodingStr));
        parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(str->getText()));
        return true;
      }
  
      unreachable("Unknown constant prop specialization");
    }
  
    bool demangleFuncSigSpecializationClosureProp(NodePointer parent) {
      // 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();
      if (!name) {
        return false;
      }
  
      parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ClosureProp));
      parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()));
  
      // Then demangle types until we fail.
      NodePointer type;
      while (Mangled.peek() != '_' && (type = demangleType())) {
        parent->addChild(type);
      }
  
      // Eat last '_'
      if (!Mangled.nextIf('_'))
        return false;
  
      return true;
    }
  
    NodePointer
    demangleFunctionSignatureSpecialization(NodePointer specialization) {
      unsigned paramCount = 0;
  
      // Until we hit the last '_' in our specialization info...
      while (!Mangled.nextIf('_')) {
        // Create the parameter.
        NodePointer param =
          NodeFactory::create(Node::Kind::FunctionSignatureSpecializationParam,
                              paramCount);
  
        // First handle options.
        if (Mangled.nextIf("n_")) {
          // Leave the parameter empty.
        } else if (Mangled.nextIf("cp")) {
          if (!demangleFuncSigSpecializationConstantProp(param))
            return nullptr;
        } else if (Mangled.nextIf("cl")) {
          if (!demangleFuncSigSpecializationClosureProp(param))
            return nullptr;
        } else if (Mangled.nextIf("i_")) {
          auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToValue);
          if (!result)
            return nullptr;
          param->addChild(result);
        } else if (Mangled.nextIf("k_")) {
          auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToStack);
          if (!result)
            return nullptr;
          param->addChild(result);
        } 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('s')) {
            Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
          }
  
          if (!Mangled.nextIf('_'))
            return nullptr;
  
          if (!Value)
            return nullptr;
  
          auto result = NodeFactory::create(
              Node::Kind::FunctionSignatureSpecializationParamKind, Value);
          if (!result)
            return nullptr;
          param->addChild(result);
        }
  
        specialization->addChild(param);
        paramCount++;
      }
  
      return specialization;
    }
  
  #undef FUNCSIGSPEC_CREATE_PARAM_KIND
  #undef FUNCSIGSPEC_CREATE_PARAM_PAYLOAD
  
    NodePointer demangleSpecializedAttribute() {
      bool isNotReAbstracted = false;
      if (Mangled.nextIf("g") || (isNotReAbstracted = Mangled.nextIf("r"))) {
        auto spec = NodeFactory::create(isNotReAbstracted ?
                                Node::Kind::GenericSpecializationNotReAbstracted :
                                Node::Kind::GenericSpecialization);
  
        // Create a node if the specialization is externally inlineable.
        if (Mangled.nextIf("q")) {
          auto kind = Node::Kind::SpecializationIsFragile;
          spec->addChild(NodeFactory::create(kind));
        }
  
        // Create a node for the pass id.
        spec->addChild(NodeFactory::create(Node::Kind::SpecializationPassID,
                                           unsigned(Mangled.next() - 48)));
  
        // And then mangle the generic specialization.
        return demangleGenericSpecialization(spec);
      }
      if (Mangled.nextIf("f")) {
        auto spec =
            NodeFactory::create(Node::Kind::FunctionSignatureSpecialization);
  
        // Create a node if the specialization is externally inlineable.
        if (Mangled.nextIf("q")) {
          auto kind = Node::Kind::SpecializationIsFragile;
          spec->addChild(NodeFactory::create(kind));
        }
  
        // Add the pass id.
        spec->addChild(NodeFactory::create(Node::Kind::SpecializationPassID,
                                           unsigned(Mangled.next() - 48)));
  
        // Then perform the function signature specialization.
        return demangleFunctionSignatureSpecialization(spec);
      }
  
      // We don't know how to handle this specialization.
      return nullptr;
    }
    
    NodePointer demangleDeclName() {
      // decl-name ::= local-decl-name
      // local-decl-name ::= 'L' index identifier
      if (Mangled.nextIf('L')) {
        NodePointer discriminator = demangleIndexAsNode();
        if (!discriminator) return nullptr;
  
        NodePointer name = demangleIdentifier();
        if (!name) return nullptr;
  
        NodePointer localName = NodeFactory::create(Node::Kind::LocalDeclName);
        localName->addChild(std::move(discriminator));
        localName->addChild(std::move(name));
        return localName;
  
      } else if (Mangled.nextIf('P')) {
        NodePointer discriminator = demangleIdentifier();
        if (!discriminator) return nullptr;
  
        NodePointer name = demangleIdentifier();
        if (!name) return nullptr;
  
        auto privateName = NodeFactory::create(Node::Kind::PrivateDeclName);
        privateName->addChildren(std::move(discriminator), std::move(name));
        return privateName;
      }
  
      // decl-name ::= identifier
      return demangleIdentifier();
    }
  
    NodePointer demangleIdentifier(Optional<Node::Kind> kind = None) {
      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.hasValue()) 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.hasValue()) kind = Node::Kind::Identifier;
  
      Node::IndexType length;
      if (!demangleNatural(length))
        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 NodeFactory::create(*kind, identifier);
    }
  
    bool demangleIndex(Node::IndexType &natural) {
      if (Mangled.nextIf('_')) {
        natural = 0;
        return true;
      }
      if (demangleNatural(natural)) {
        if (!Mangled.nextIf('_'))
          return false;
        natural++;
        return true;
      }
      return false;
    }
  
    /// Demangle an <index> and package it as a node of some kind.
    NodePointer demangleIndexAsNode(Node::Kind kind = Node::Kind::Number) {
      Node::IndexType index;
      if (!demangleIndex(index))
        return nullptr;
      return NodeFactory::create(kind, index);
    }
  
    NodePointer createSwiftType(Node::Kind typeKind, StringRef name) {
      NodePointer type = NodeFactory::create(typeKind);
      type->addChild(NodeFactory::create(Node::Kind::Module, STDLIB_NAME));
      type->addChild(NodeFactory::create(Node::Kind::Identifier, name));
      return type;
    }
  
    /// Demangle a <substitution>, given that we've already consumed the 'S'.
    NodePointer demangleSubstitutionIndex() {
      if (!Mangled)
        return nullptr;
      if (Mangled.nextIf('o'))
        return NodeFactory::create(Node::Kind::Module, MANGLING_MODULE_OBJC);
      if (Mangled.nextIf('C'))
        return NodeFactory::create(Node::Kind::Module, MANGLING_MODULE_C);
      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))
        return nullptr;
      if (index_sub >= Substitutions.size())
        return nullptr;
      return Substitutions[index_sub];
    }
  
    NodePointer demangleModule() {
      if (Mangled.nextIf('s')) {
        return NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
      }
      if (Mangled.nextIf('S')) {
        NodePointer module = demangleSubstitutionIndex();
        if (!module)
          return nullptr;
        if (module->getKind() != Node::Kind::Module)
          return nullptr;
        return module;
      }
  
      NodePointer module = demangleIdentifier(Node::Kind::Module);
      if (!module) return nullptr;
      Substitutions.push_back(module);
      return module;
    }
  
    NodePointer demangleDeclarationName(Node::Kind kind) {
      NodePointer context = demangleContext();
      if (!context) return nullptr;
  
      auto name = demangleDeclName();
      if (!name) return nullptr;
  
      auto decl = NodeFactory::create(kind);
      decl->addChild(context);
      decl->addChild(name);
      Substitutions.push_back(decl);
      return decl;
    }
  
    NodePointer demangleProtocolName() {
      NodePointer proto = demangleProtocolNameImpl();
      if (!proto) return nullptr;
  
      NodePointer type = NodeFactory::create(Node::Kind::Type);
      type->addChild(proto);
      return type;
    }
  
    NodePointer demangleProtocolNameGivenContext(NodePointer context) {
      NodePointer name = demangleDeclName();
      if (!name) return nullptr;
  
      auto proto = NodeFactory::create(Node::Kind::Protocol);
      proto->addChild(std::move(context));
      proto->addChild(std::move(name));
      Substitutions.push_back(proto);
      return proto;
    }
  
    NodePointer demangleProtocolNameImpl() {
      // 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();
        if (!sub) return nullptr;
        if (sub->getKind() == Node::Kind::Protocol)
          return sub;
  
        if (sub->getKind() != Node::Kind::Module)
          return nullptr;
  
        return demangleProtocolNameGivenContext(sub);
      }
  
      if (Mangled.nextIf('s')) {
        NodePointer stdlib = NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
  
        return demangleProtocolNameGivenContext(stdlib);
      }
  
      return demangleDeclarationName(Node::Kind::Protocol);
    }
  
    NodePointer demangleNominalType() {
      if (Mangled.nextIf('S'))
        return demangleSubstitutionIndex();
      if (Mangled.nextIf('V'))
        return demangleDeclarationName(Node::Kind::Structure);
      if (Mangled.nextIf('O'))
        return demangleDeclarationName(Node::Kind::Enum);
      if (Mangled.nextIf('C'))
        return demangleDeclarationName(Node::Kind::Class);
      if (Mangled.nextIf('P'))
        return demangleDeclarationName(Node::Kind::Protocol);
      return nullptr;
    }
  
    NodePointer demangleBoundGenericArgs(NodePointer nominalType) {
      // 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);
  
        // Rebuild this type with the new parent type, which may have
        // had its generic arguments applied.
        NodePointer result = NodeFactory::create(nominalType->getKind());
        result->addChild(parentOrModule);
        result->addChild(nominalType->getChild(1));
  
        nominalType = result;
      }
  
      NodePointer args = NodeFactory::create(Node::Kind::TypeList);
      while (!Mangled.nextIf('_')) {
        NodePointer type = demangleType();
        if (!type)
          return nullptr;
        args->addChild(type);
        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 = NodeFactory::create(Node::Kind::Type);
      unboundType->addChild(nominalType);
  
      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 = NodeFactory::create(kind);
      result->addChild(unboundType);
      result->addChild(args);
      return result;
    }
  
    NodePointer demangleBoundGenericType() {
      // bound-generic-type ::= 'G' nominal-type (args+ '_')+
      //
      // Each level of nominal type nesting has its own list of arguments.
  
      NodePointer nominalType = demangleNominalType();
      if (!nominalType)
        return nullptr;
  
      return demangleBoundGenericArgs(nominalType);
    }
  
    NodePointer demangleContext() {
      // 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 = NodeFactory::create(Node::Kind::Extension);
        NodePointer def_module = demangleModule();
        if (!def_module) return nullptr;
        NodePointer type = demangleContext();
        if (!type) return nullptr;
        ext->addChild(def_module);
        ext->addChild(type);
        return ext;
      }
      if (Mangled.nextIf('e')) {
        NodePointer ext = NodeFactory::create(Node::Kind::Extension);
        NodePointer def_module = demangleModule();
        if (!def_module) return nullptr;
        NodePointer sig = demangleGenericSignature();
        // 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();
        if (!type) return nullptr;
  
        ext->addChild(def_module);
        ext->addChild(type);
        ext->addChild(sig);
        return ext;
      }
      if (Mangled.nextIf('S'))
        return demangleSubstitutionIndex();
      if (Mangled.nextIf('s'))
        return NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
      if (Mangled.nextIf('G'))
        return demangleBoundGenericType();
      if (isStartOfEntity(Mangled.peek()))
        return demangleEntity();
      return demangleModule();
    }
    
    NodePointer demangleProtocolList() {
      NodePointer proto_list = NodeFactory::create(Node::Kind::ProtocolList);
      NodePointer type_list = NodeFactory::create(Node::Kind::TypeList);
      proto_list->addChild(type_list);
      while (!Mangled.nextIf('_')) {
        NodePointer proto = demangleProtocolName();
        if (!proto)
          return nullptr;
        type_list->addChild(std::move(proto));
      }
      return proto_list;
    }
  
    NodePointer demangleProtocolConformance() {
      NodePointer type = demangleType();
      if (!type)
        return nullptr;
      NodePointer protocol = demangleProtocolName();
      if (!protocol)
        return nullptr;
      NodePointer context = demangleContext();
      if (!context)
        return nullptr;
      NodePointer proto_conformance =
          NodeFactory::create(Node::Kind::ProtocolConformance);
      proto_conformance->addChild(type);
      proto_conformance->addChild(protocol);
      proto_conformance->addChild(context);
      return proto_conformance;
    }
  
    // entity ::= entity-kind context entity-name
    // entity ::= nominal-type
    NodePointer demangleEntity() {
      // 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();
      }
  
      NodePointer context = demangleContext();
      if (!context) return nullptr;
  
      // entity-name
      Node::Kind entityKind;
      bool hasType = true;
      NodePointer name;
      if (Mangled.nextIf('D')) {
        entityKind = Node::Kind::Deallocator;
        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')) {
        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();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('l')) {
        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();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('g')) {
        entityKind = Node::Kind::Getter;
        name = demangleDeclName();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('G')) {
        entityKind = Node::Kind::GlobalGetter;
        name = demangleDeclName();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('s')) {
        entityKind = Node::Kind::Setter;
        name = demangleDeclName();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('m')) {
        entityKind = Node::Kind::MaterializeForSet;
        name = demangleDeclName();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('w')) {
        entityKind = Node::Kind::WillSet;
        name = demangleDeclName();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('W')) {
        entityKind = Node::Kind::DidSet;
        name = demangleDeclName();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('U')) {
        entityKind = Node::Kind::ExplicitClosure;
        name = demangleIndexAsNode();
        if (!name) return nullptr;
      } else if (Mangled.nextIf('u')) {
        entityKind = Node::Kind::ImplicitClosure;
        name = demangleIndexAsNode();
        if (!name) return nullptr;
      } else if (entityBasicKind == Node::Kind::Initializer) {
        // entity-name ::= 'A' index
        if (Mangled.nextIf('A')) {
          entityKind = Node::Kind::DefaultArgumentInitializer;
          name = demangleIndexAsNode();
          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();
        if (!name) return nullptr;
      }
  
      NodePointer entity = NodeFactory::create(entityKind);
      entity->addChild(context);
  
      if (name) entity->addChild(name);
  
      if (hasType) {
        auto type = demangleType();
        if (!type) return nullptr;
        entity->addChild(type);
      }
      
      if (isStatic) {
        auto staticNode = NodeFactory::create(Node::Kind::Static);
        staticNode->addChild(entity);
        return staticNode;
      }
  
      return entity;
    }
  
    NodePointer demangleArchetypeRef(Node::IndexType depth, Node::IndexType i) {
      // FIXME: Name won't match demangled context generic signatures correctly.
      auto ref = NodeFactory::create(Node::Kind::ArchetypeRef,
                                     archetypeName(i, depth));
      ref->addChild(NodeFactory::create(Node::Kind::Index, depth));
      ref->addChild(NodeFactory::create(Node::Kind::Index, i));
      return ref;
    }
  
    NodePointer getDependentGenericParamType(unsigned depth, unsigned index) {
      DemanglerPrinter PrintName;
      PrintName << archetypeName(index, depth);
  
      auto paramTy = NodeFactory::create(Node::Kind::DependentGenericParamType,
                                         std::move(PrintName).str());
      paramTy->addChild(NodeFactory::create(Node::Kind::Index, depth));
      paramTy->addChild(NodeFactory::create(Node::Kind::Index, index));
  
      return paramTy;
    }
  
    NodePointer demangleGenericParamIndex() {
      Node::IndexType depth, index;
  
      if (Mangled.nextIf('d')) {
        if (!demangleIndex(depth))
          return nullptr;
        depth += 1;
        if (!demangleIndex(index))
          return nullptr;
      } else if (Mangled.nextIf('x')) {
        depth = 0;
        index = 0;
      } else {
        if (!demangleIndex(index))
          return nullptr;
        depth = 0;
        index += 1;
      }
      return getDependentGenericParamType(depth, index);
    }
  
    NodePointer demangleDependentMemberTypeName(NodePointer base) {
      assert(base->getKind() == Node::Kind::Type
             && "base should be a type");
      NodePointer assocTy;
  
      if (Mangled.nextIf('S')) {
        assocTy = demangleSubstitutionIndex();
        if (assocTy->getKind() != Node::Kind::DependentAssociatedTypeRef)
          return nullptr;
      } else {
        NodePointer protocol = nullptr;
        if (Mangled.nextIf('P')) {
          protocol = demangleProtocolName();
          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.
        assocTy = demangleIdentifier(Node::Kind::DependentAssociatedTypeRef);
        if (!assocTy) return nullptr;
        if (protocol)
          assocTy->addChild(protocol);
  
        Substitutions.push_back(assocTy);
      }
  
      NodePointer depTy = NodeFactory::create(Node::Kind::DependentMemberType);
      depTy->addChild(base);
      depTy->addChild(assocTy);
      return depTy;
    }
  
    NodePointer demangleAssociatedTypeSimple() {
      // Demangle the base type.
      auto base = demangleGenericParamIndex();
      if (!base)
        return nullptr;
  
      NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
      nodeType->addChild(base);
  
      // Demangle the associated type name.
      return demangleDependentMemberTypeName(nodeType);
    }
    
    NodePointer demangleAssociatedTypeCompound() {
      // Demangle the base type.
      auto base = demangleGenericParamIndex();
      if (!base)
        return nullptr;
  
      // Demangle the associated type chain.
      while (!Mangled.nextIf('_')) {
        NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
        nodeType->addChild(base);
        
        base = demangleDependentMemberTypeName(nodeType);
        if (!base)
          return nullptr;
      }
  
      return base;
    }
    
    NodePointer demangleDependentType() {
      if (!Mangled)
        return nullptr;
  
      // A dependent member type begins with a non-index, non-'d' character.
      auto c = Mangled.peek();
      if (c != 'd' && c != '_' && !isDigit(c)) {
        NodePointer baseType = demangleType();
        if (!baseType) return nullptr;
        return demangleDependentMemberTypeName(baseType);
      }
      
      // Otherwise, we have a generic parameter.
      return demangleGenericParamIndex();
    }
  
    NodePointer demangleConstrainedTypeImpl() {
      // 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();
      }
      if (Mangled.nextIf('W')) {
        return demangleAssociatedTypeCompound();
      }
      return demangleGenericParamIndex();
    }
  
    NodePointer demangleConstrainedType() {
      auto type = demangleConstrainedTypeImpl();
      if (!type)
        return nullptr;
  
      NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
      nodeType->addChild(type);
      return nodeType;
    }
  
    NodePointer demangleGenericSignature(bool isPseudogeneric = false) {
      auto sig =
        NodeFactory::create(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 =
          NodeFactory::create(Node::Kind::DependentGenericParamCount, count);
        sig->addChild(countNode);
      };
      
      while (Mangled.peek() != 'R' && Mangled.peek() != 'r') {
        if (Mangled.nextIf('z')) {
          count = 0;
        } else if (demangleIndex(count)) {
          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();
        if (!reqt) return nullptr;
        sig->addChild(reqt);
      }
      
      return sig;
    }
  
    NodePointer demangleMetatypeRepresentation() {
      if (Mangled.nextIf('t'))
        return NodeFactory::create(Node::Kind::MetatypeRepresentation, "@thin");
  
      if (Mangled.nextIf('T'))
        return NodeFactory::create(Node::Kind::MetatypeRepresentation, "@thick");
  
      if (Mangled.nextIf('o'))
        return NodeFactory::create(Node::Kind::MetatypeRepresentation,
                                   "@objc_metatype");
  
      unreachable("Unhandled metatype representation");
    }
    
    NodePointer demangleGenericRequirement() {
      NodePointer constrainedType = demangleConstrainedType();
      if (!constrainedType)
        return nullptr;
      if (Mangled.nextIf('z')) {
        NodePointer second = demangleType();
        if (!second) return nullptr;
        auto reqt = NodeFactory::create(
            Node::Kind::DependentGenericSameTypeRequirement);
        reqt->addChild(constrainedType);
        reqt->addChild(second);
        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;
  
      auto next = Mangled.peek();
  
      if (next == 'C') {
        constraint = demangleType();
        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;
        Mangled.next();
        NodePointer sub = demangleSubstitutionIndex();
        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);
          if (!typeName)
            return nullptr;
        } else {
          return nullptr;
        }
        constraint = NodeFactory::create(Node::Kind::Type);
        constraint->addChild(typeName);
      } else {
        constraint = demangleProtocolName();
        if (!constraint)
          return nullptr;
      }
      auto reqt = NodeFactory::create(
                            Node::Kind::DependentGenericConformanceRequirement);
      reqt->addChild(constrainedType);
      reqt->addChild(constraint);
      return reqt;
    }
    
    NodePointer demangleArchetypeType() {
      auto makeSelfType = [&](NodePointer proto) -> NodePointer {
        auto selfType = NodeFactory::create(Node::Kind::SelfTypeRef);
        selfType->addChild(proto);
        Substitutions.push_back(selfType);
        return selfType;
      };
      
      auto makeAssociatedType = [&](NodePointer root) -> NodePointer {
        NodePointer name = demangleIdentifier();
        if (!name) return nullptr;
        auto assocType = NodeFactory::create(Node::Kind::AssociatedTypeRef);
        assocType->addChild(root);
        assocType->addChild(name);
        Substitutions.push_back(assocType);
        return assocType;
      };
      
      if (Mangled.nextIf('P')) {
        NodePointer proto = demangleProtocolName();
        if (!proto) return nullptr;
        return makeSelfType(proto);
      }
      
      if (Mangled.nextIf('Q')) {
        NodePointer root = demangleArchetypeType();
        if (!root) return nullptr;
        return makeAssociatedType(root);
      }
      if (Mangled.nextIf('S')) {
        NodePointer sub = demangleSubstitutionIndex();
        if (!sub) return nullptr;
        if (sub->getKind() == Node::Kind::Protocol)
          return makeSelfType(sub);
        else
          return makeAssociatedType(sub);
      }
      if (Mangled.nextIf('s')) {
        NodePointer stdlib = NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
        return makeAssociatedType(stdlib);
      }
      if (Mangled.nextIf('d')) {
        Node::IndexType depth, index;
        if (!demangleIndex(depth))
          return nullptr;
        if (!demangleIndex(index))
          return nullptr;
        return demangleArchetypeRef(depth + 1, index);
      }
      if (Mangled.nextIf('q')) {
        NodePointer index = demangleIndexAsNode();
        if (!index)
          return nullptr;
        NodePointer decl_ctx = NodeFactory::create(Node::Kind::DeclContext);
        NodePointer ctx = demangleContext();
        if (!ctx)
          return nullptr;
        decl_ctx->addChild(ctx);
        auto qual_atype = NodeFactory::create(Node::Kind::QualifiedArchetype);
        qual_atype->addChild(index);
        qual_atype->addChild(decl_ctx);
        return qual_atype;
      }
      Node::IndexType index;
      if (!demangleIndex(index))
        return nullptr;
      return demangleArchetypeRef(0, index);
    }
  
    NodePointer demangleTuple(IsVariadic isV) {
      NodePointer tuple = NodeFactory::create(
          isV == IsVariadic::yes ? Node::Kind::VariadicTuple
                                 : Node::Kind::NonVariadicTuple);
      while (!Mangled.nextIf('_')) {
        if (!Mangled)
          return nullptr;
        NodePointer elt = NodeFactory::create(Node::Kind::TupleElement);
  
        if (isStartOfIdentifier(Mangled.peek())) {
          NodePointer label = demangleIdentifier(Node::Kind::TupleElementName);
          if (!label)
            return nullptr;
          elt->addChild(label);
        }
  
        NodePointer type = demangleType();
        if (!type)
          return nullptr;
        elt->addChild(type);
  
        tuple->addChild(elt);
      }
      return tuple;
    }
    
    NodePointer postProcessReturnTypeNode (NodePointer out_args) {
      NodePointer out_node = NodeFactory::create(Node::Kind::ReturnType);
      out_node->addChild(out_args);
      return out_node;
    }
  
    NodePointer demangleType() {
      NodePointer type = demangleTypeImpl();
      if (!type)
        return nullptr;
      NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
      nodeType->addChild(type);
      return nodeType;
    }
    
    NodePointer demangleFunctionType(Node::Kind kind) {
      bool throws = false;
      if (Mangled &&
          Mangled.nextIf('z')) {
        throws = true;
      }
      NodePointer in_args = demangleType();
      if (!in_args)
        return nullptr;
      NodePointer out_args = demangleType();
      if (!out_args)
        return nullptr;
      NodePointer block = NodeFactory::create(kind);
      
      if (throws) {
        block->addChild(NodeFactory::create(Node::Kind::ThrowsAnnotation));
      }
      
      NodePointer in_node = NodeFactory::create(Node::Kind::ArgumentTuple);
      block->addChild(in_node);
      in_node->addChild(in_args);
      block->addChild(postProcessReturnTypeNode(out_args));
      return block;
    }
    
    NodePointer demangleTypeImpl() {
      if (!Mangled)
        return nullptr;
      char c = Mangled.next();
      if (c == 'B') {
        if (!Mangled)
          return nullptr;
        c = Mangled.next();
        if (c == 'b')
          return NodeFactory::create(Node::Kind::BuiltinTypeName,
                                       "Builtin.BridgeObject");
        if (c == 'B')
          return NodeFactory::create(Node::Kind::BuiltinTypeName,
                                       "Builtin.UnsafeValueBuffer");
        if (c == 'f') {
          Node::IndexType size;
          if (demangleBuiltinSize(size)) {
            return NodeFactory::create(
                Node::Kind::BuiltinTypeName,
                std::move(DemanglerPrinter() << "Builtin.Float" << size).str());
          }
        }
        if (c == 'i') {
          Node::IndexType size;
          if (demangleBuiltinSize(size)) {
            return NodeFactory::create(
                Node::Kind::BuiltinTypeName,
                (DemanglerPrinter() << "Builtin.Int" << size).str());
          }
        }
        if (c == 'v') {
          Node::IndexType elts;
          if (demangleNatural(elts)) {
            if (!Mangled.nextIf('B'))
              return nullptr;
            if (Mangled.nextIf('i')) {
              Node::IndexType size;
              if (!demangleBuiltinSize(size))
                return nullptr;
              return NodeFactory::create(
                  Node::Kind::BuiltinTypeName,
                  (DemanglerPrinter() << "Builtin.Vec" << elts << "xInt" << size)
                      .str());
            }
            if (Mangled.nextIf('f')) {
              Node::IndexType size;
              if (!demangleBuiltinSize(size))
                return nullptr;
              return NodeFactory::create(
                  Node::Kind::BuiltinTypeName,
                  (DemanglerPrinter() << "Builtin.Vec" << elts << "xFloat"
                                      << size).str());
            }
            if (Mangled.nextIf('p'))
              return NodeFactory::create(
                  Node::Kind::BuiltinTypeName,
                  (DemanglerPrinter() << "Builtin.Vec" << elts << "xRawPointer")
                      .str());
          }
        }
        if (c == 'O')
          return NodeFactory::create(Node::Kind::BuiltinTypeName,
                                       "Builtin.UnknownObject");
        if (c == 'o')
          return NodeFactory::create(Node::Kind::BuiltinTypeName,
                                       "Builtin.NativeObject");
        if (c == 'p')
          return NodeFactory::create(Node::Kind::BuiltinTypeName,
                                       "Builtin.RawPointer");
        if (c == 'w')
          return NodeFactory::create(Node::Kind::BuiltinTypeName,
                                       "Builtin.Word");
        return nullptr;
      }
      if (c == 'a')
        return demangleDeclarationName(Node::Kind::TypeAlias);
  
      if (c == 'b') {
        return demangleFunctionType(Node::Kind::ObjCBlock);
      }
      if (c == 'c') {
        return demangleFunctionType(Node::Kind::CFunctionPointer);
      }
      if (c == 'D') {
        NodePointer type = demangleType();
        if (!type)
          return nullptr;
  
        NodePointer dynamicSelf = NodeFactory::create(Node::Kind::DynamicSelf);
        dynamicSelf->addChild(type);
        return dynamicSelf;
      }
      if (c == 'E') {
        if (!Mangled.nextIf('R'))
          return nullptr;
        if (!Mangled.nextIf('R'))
          return nullptr;
        return NodeFactory::create(Node::Kind::ErrorType, std::string());
      }
      if (c == 'F') {
        return demangleFunctionType(Node::Kind::FunctionType);
      }
      if (c == 'f') {
        return demangleFunctionType(Node::Kind::UncurriedFunctionType);
      }
      if (c == 'G') {
        return demangleBoundGenericType();
      }
      if (c == 'X') {
        if (Mangled.nextIf('b')) {
          NodePointer type = demangleType();
          if (!type)
            return nullptr;
          NodePointer boxType = NodeFactory::create(Node::Kind::SILBoxType);
          boxType->addChild(type);
          return boxType;
        }
      }
      if (c == 'K') {
        return demangleFunctionType(Node::Kind::AutoClosureType);
      }
      if (c == 'M') {
        NodePointer type = demangleType();
        if (!type)
          return nullptr;
        NodePointer metatype = NodeFactory::create(Node::Kind::Metatype);
        metatype->addChild(type);
        return metatype;
      }
      if (c == 'X') {
        if (Mangled.nextIf('M')) {
          NodePointer metatypeRepr = demangleMetatypeRepresentation();
          if (!metatypeRepr) return nullptr;
  
          NodePointer type = demangleType();
          if (!type)
            return nullptr;
          NodePointer metatype = NodeFactory::create(Node::Kind::Metatype);
          metatype->addChild(metatypeRepr);
          metatype->addChild(type);
          return metatype;
        }
      }
      if (c == 'P') {
        if (Mangled.nextIf('M')) {
          NodePointer type = demangleType();
          if (!type) return nullptr;
          auto metatype = NodeFactory::create(Node::Kind::ExistentialMetatype);
          metatype->addChild(type);
          return metatype;
        }
  
        return demangleProtocolList();
      }
  
      if (c == 'X') {
        if (Mangled.nextIf('P')) {
          if (Mangled.nextIf('M')) {
            NodePointer metatypeRepr = demangleMetatypeRepresentation();
            if (!metatypeRepr) return nullptr;
  
            NodePointer type = demangleType();
            if (!type) return nullptr;
  
            auto metatype = NodeFactory::create(Node::Kind::ExistentialMetatype);
            metatype->addChild(metatypeRepr);
            metatype->addChild(type);
            return metatype;
          }
  
          return demangleProtocolList();
        }
      }
      if (c == 'Q') {
        return demangleArchetypeType();
      }
      if (c == 'q') {
        return demangleDependentType();
      }
      if (c == 'x') {
        // Special mangling for the first generic param.
        return getDependentGenericParamType(0, 0);
      }
      if (c == 'w') {
        return demangleAssociatedTypeSimple();
      }
      if (c == 'W') {
        return demangleAssociatedTypeCompound();
      }
      if (c == 'R') {
        NodePointer inout = NodeFactory::create(Node::Kind::InOut);
        NodePointer type = demangleTypeImpl();
        if (!type)
          return nullptr;
        inout->addChild(type);
        return inout;
      }
      if (c == 'S') {
        return demangleSubstitutionIndex();
      }
      if (c == 'T') {
        return demangleTuple(IsVariadic::no);
      }
      if (c == 't') {
        return demangleTuple(IsVariadic::yes);
      }
      if (c == 'u') {
        NodePointer sig = demangleGenericSignature();
        if (!sig) return nullptr;
        NodePointer sub = demangleType();
        if (!sub) return nullptr;
        NodePointer dependentGenericType
          = NodeFactory::create(Node::Kind::DependentGenericType);
        dependentGenericType->addChild(sig);
        dependentGenericType->addChild(sub);
        return dependentGenericType;
      }
      if (c == 'X') {
        if (Mangled.nextIf('f')) {
          return demangleFunctionType(Node::Kind::ThinFunctionType);
        }
        if (Mangled.nextIf('o')) {
          NodePointer type = demangleType();
          if (!type)
            return nullptr;
          NodePointer unowned = NodeFactory::create(Node::Kind::Unowned);
          unowned->addChild(type);
          return unowned;
        }
        if (Mangled.nextIf('u')) {
          NodePointer type = demangleType();
          if (!type)
            return nullptr;
          NodePointer unowned = NodeFactory::create(Node::Kind::Unmanaged);
          unowned->addChild(type);
          return unowned;
        }
        if (Mangled.nextIf('w')) {
          NodePointer type = demangleType();
          if (!type)
            return nullptr;
          NodePointer weak = NodeFactory::create(Node::Kind::Weak);
          weak->addChild(type);
          return weak;
        }
  
        // type ::= 'XF' impl-function-type
        if (Mangled.nextIf('F')) {
          return demangleImplFunctionType();
        }
  
        return nullptr;
      }
      if (isStartOfNominalType(c))
        return demangleDeclarationName(nominalTypeMarkerToNodeKind(c));
      return nullptr;
    }
  
    bool demangleReabstractSignature(NodePointer signature) {
      if (Mangled.nextIf('G')) {
        NodePointer generics = demangleGenericSignature();
        if (!generics) return false;
        signature->addChild(std::move(generics));
      }
  
      NodePointer srcType = demangleType();
      if (!srcType) return false;
      signature->addChild(std::move(srcType));
  
      NodePointer destType = demangleType();
      if (!destType) return false;
      signature->addChild(std::move(destType));
  
      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() {
      NodePointer type = NodeFactory::create(Node::Kind::ImplFunctionType);
  
      if (!demangleImplCalleeConvention(type))
        return nullptr;
  
      if (Mangled.nextIf('C')) {
        if (Mangled.nextIf('b'))
          addImplFunctionAttribute(type, "@convention(block)");
        else if (Mangled.nextIf('c'))
          addImplFunctionAttribute(type, "@convention(c)");
        else if (Mangled.nextIf('m'))
          addImplFunctionAttribute(type, "@convention(method)");
        else if (Mangled.nextIf('O'))
          addImplFunctionAttribute(type, "@convention(objc_method)");
        else if (Mangled.nextIf('w'))
          addImplFunctionAttribute(type, "@convention(witness_method)");
        else
          return nullptr;
      }
  
      // 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(isPseudogeneric);
        if (!generics)
          return nullptr;
        type->addChild(generics);
      }
  
      // Expect the attribute terminator.
      if (!Mangled.nextIf('_'))
        return nullptr;
  
      // Demangle the parameters.
      if (!demangleImplParameters(type))
        return nullptr;
  
      // Demangle the result type.
      if (!demangleImplResults(type))
        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) {
  #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);       \
        }                                                              \
        unreachable("bad context");                               \
      }
      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) {
      StringRef attr;
      if (Mangled.nextIf('t')) {
        attr = "@convention(thin)";
      } else {
        attr = demangleImplConvention(ImplConventionContext::Callee);
      }
      if (attr.empty()) {
        return false;
      }
      type->addChild(NodeFactory::create(Node::Kind::ImplConvention, attr));
      return true;
    }
  
    void addImplFunctionAttribute(NodePointer parent, StringRef attr,
                           Node::Kind kind = Node::Kind::ImplFunctionAttribute) {
      parent->addChild(NodeFactory::create(kind, attr));
    }
  
    // impl-parameter ::= impl-convention type
    bool demangleImplParameters(NodePointer parent) {
      while (!Mangled.nextIf('_')) {
        auto input = demangleImplParameterOrResult(Node::Kind::ImplParameter);
        if (!input) return false;
        parent->addChild(input);
      }
      return true;
    }
  
    // impl-result ::= impl-convention type
    bool demangleImplResults(NodePointer parent) {
      while (!Mangled.nextIf('_')) {
        auto res = demangleImplParameterOrResult(Node::Kind::ImplResult);
        if (!res) return false;
        parent->addChild(res);
      }
      return true;
    }
  
    NodePointer demangleImplParameterOrResult(Node::Kind kind) {
      if (Mangled.nextIf('z')) {
        // Only valid for a result.
        if (kind != Node::Kind::ImplResult)
          return nullptr;
        kind = Node::Kind::ImplErrorResult;
      }
    
      auto getContext = [](Node::Kind kind) -> ImplConventionContext {
        if (kind == Node::Kind::ImplParameter)
          return ImplConventionContext::Parameter;
        else if (kind == Node::Kind::ImplResult
                 || kind == Node::Kind::ImplErrorResult)
          return ImplConventionContext::Result;
        else
          unreachable("unexpected node kind");
      };
  
      auto convention = demangleImplConvention(getContext(kind));
      if (convention.empty()) return nullptr;
      auto type = demangleType();
      if (!type) return nullptr;
  
      NodePointer node = NodeFactory::create(kind);
      node->addChild(NodeFactory::create(Node::Kind::ImplConvention,
                                         convention));
      node->addChild(type);
      
      return node;
    }
  };
  } // end anonymous namespace
  
  NodePointer
  swift::Demangle::demangleSymbolAsNode(const char *MangledName,
                                        size_t MangledNameLength,
                                        const DemangleOptions &Options) {
    Demangler demangler(StringRef(MangledName, MangledNameLength));
    return demangler.demangleTopLevel();
  }
  
  NodePointer
  swift::Demangle::demangleTypeAsNode(const char *MangledName,
                                      size_t MangledNameLength,
                                      const DemangleOptions &Options) {
    Demangler demangler(StringRef(MangledName, MangledNameLength));
    return demangler.demangleTypeName();
  }
  
  namespace {
  class NodePrinter {
  private:
    DemanglerPrinter Printer;
    DemangleOptions Options;
    
  public:
    NodePrinter(DemangleOptions options) : Options(options) {}
    
    std::string printRoot(NodePointer root) {
      print(root);
      return std::move(Printer).str();
    }
  
  private:  
    void printChildren(Node::iterator begin,
                       Node::iterator end,
                       const char *sep = nullptr) {
      for (; begin != end;) {
        print(*begin);
        ++begin;
        if (sep && begin != end)
          Printer << sep;
      }
    }
    
    void printChildren(NodePointer pointer, const char *sep = nullptr) {
      if (!pointer)
        return;
      Node::iterator begin = pointer->begin(), end = pointer->end();
      printChildren(begin, end, sep);
    }
    
    NodePointer getFirstChildOfKind(NodePointer pointer, Node::Kind kind) {
      if (!pointer)
        return nullptr;
      for (NodePointer &child : *pointer) {
        if (child && child->getKind() == kind)
          return child;
      }
      return nullptr;
    }
  
    void printBoundGenericNoSugar(NodePointer pointer) {
      if (pointer->getNumChildren() < 2)
        return;
      NodePointer typelist = pointer->getChild(1);
      print(pointer->getChild(0));
      Printer << "<";
      printChildren(typelist, ", ");
      Printer << ">";
    }
  
    static bool isSwiftModule(NodePointer node) {
      return (node->getKind() == Node::Kind::Module &&
              node->getText() == STDLIB_NAME);
    }
    
    static bool isDebuggerGeneratedModule(NodePointer node) {
        return (node->getKind() == Node::Kind::Module &&
                0 == node->getText().find(LLDB_EXPRESSIONS_MODULE_NAME_PREFIX));
      }
  
    static bool isIdentifier(NodePointer node, StringRef desired) {
      return (node->getKind() == Node::Kind::Identifier &&
              node->getText() == desired);
    }
    
    enum class SugarType {
      None,
      Optional,
      ImplicitlyUnwrappedOptional,
      Array,
      Dictionary
    };
    
    /// Determine whether this is a "simple" type, from the type-simple
    /// production.
    bool isSimpleType(NodePointer pointer) {
      switch (pointer->getKind()) {
      case Node::Kind::Archetype:
      case Node::Kind::ArchetypeRef:
      case Node::Kind::AssociatedType:
      case Node::Kind::AssociatedTypeRef:
      case Node::Kind::BoundGenericClass:
      case Node::Kind::BoundGenericEnum:
      case Node::Kind::BoundGenericStructure:
      case Node::Kind::BuiltinTypeName:
      case Node::Kind::Class:
      case Node::Kind::DependentGenericType:
      case Node::Kind::DependentMemberType:
      case Node::Kind::DependentGenericParamType:
      case Node::Kind::DynamicSelf:
      case Node::Kind::Enum:
      case Node::Kind::ErrorType:
      case Node::Kind::ExistentialMetatype:
      case Node::Kind::Metatype:
      case Node::Kind::MetatypeRepresentation:
      case Node::Kind::Module:
      case Node::Kind::NonVariadicTuple:
      case Node::Kind::Protocol:
      case Node::Kind::QualifiedArchetype:
      case Node::Kind::ReturnType:
      case Node::Kind::SelfTypeRef:
      case Node::Kind::SILBoxType:
      case Node::Kind::Structure:
      case Node::Kind::TupleElementName:
      case Node::Kind::Type:
      case Node::Kind::TypeAlias:
      case Node::Kind::TypeList:
      case Node::Kind::VariadicTuple:
        return true;
  
      case Node::Kind::Allocator:
      case Node::Kind::ArgumentTuple:
      case Node::Kind::AssociatedTypeMetadataAccessor:
      case Node::Kind::AssociatedTypeWitnessTableAccessor:
      case Node::Kind::AutoClosureType:
      case Node::Kind::CFunctionPointer:
      case Node::Kind::Constructor:
      case Node::Kind::Deallocator:
      case Node::Kind::DeclContext:
      case Node::Kind::DefaultArgumentInitializer:
      case Node::Kind::DependentAssociatedTypeRef:
      case Node::Kind::DependentGenericSignature:
      case Node::Kind::DependentGenericParamCount:
      case Node::Kind::DependentGenericConformanceRequirement:
      case Node::Kind::DependentGenericSameTypeRequirement:
      case Node::Kind::DependentPseudogenericSignature:
      case Node::Kind::Destructor:
      case Node::Kind::DidSet:
      case Node::Kind::DirectMethodReferenceAttribute:
      case Node::Kind::Directness:
      case Node::Kind::DynamicAttribute:
      case Node::Kind::ExplicitClosure:
      case Node::Kind::Extension:
      case Node::Kind::FieldOffset:
      case Node::Kind::FullTypeMetadata:
      case Node::Kind::Function:
      case Node::Kind::FunctionSignatureSpecialization:
      case Node::Kind::FunctionSignatureSpecializationParam:
      case Node::Kind::FunctionSignatureSpecializationParamKind:
      case Node::Kind::FunctionSignatureSpecializationParamPayload:
      case Node::Kind::FunctionType:
      case Node::Kind::GenericProtocolWitnessTable:
      case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
      case Node::Kind::GenericSpecialization:
      case Node::Kind::GenericSpecializationNotReAbstracted:
      case Node::Kind::GenericSpecializationParam:
      case Node::Kind::GenericTypeMetadataPattern:
      case Node::Kind::Getter:
      case Node::Kind::Global:
      case Node::Kind::GlobalGetter:
      case Node::Kind::Identifier:
      case Node::Kind::Index:
      case Node::Kind::IVarInitializer:
      case Node::Kind::IVarDestroyer:
      case Node::Kind::ImplConvention:
      case Node::Kind::ImplFunctionAttribute:
      case Node::Kind::ImplFunctionType:
      case Node::Kind::ImplicitClosure:
      case Node::Kind::ImplParameter:
      case Node::Kind::ImplResult:
      case Node::Kind::ImplErrorResult:
      case Node::Kind::InOut:
      case Node::Kind::InfixOperator:
      case Node::Kind::Initializer:
      case Node::Kind::LazyProtocolWitnessTableAccessor:
      case Node::Kind::LazyProtocolWitnessTableCacheVariable:
      case Node::Kind::LocalDeclName:
      case Node::Kind::PrivateDeclName:
      case Node::Kind::MaterializeForSet:
      case Node::Kind::Metaclass:
      case Node::Kind::NativeOwningAddressor:
      case Node::Kind::NativeOwningMutableAddressor:
      case Node::Kind::NativePinningAddressor:
      case Node::Kind::NativePinningMutableAddressor:
      case Node::Kind::NominalTypeDescriptor:
      case Node::Kind::NonObjCAttribute:
      case Node::Kind::Number:
      case Node::Kind::ObjCAttribute:
      case Node::Kind::ObjCBlock:
      case Node::Kind::OwningAddressor:
      case Node::Kind::OwningMutableAddressor:
      case Node::Kind::PartialApplyForwarder:
      case Node::Kind::PartialApplyObjCForwarder:
      case Node::Kind::PostfixOperator:
      case Node::Kind::PrefixOperator:
      case Node::Kind::ProtocolConformance:
      case Node::Kind::ProtocolDescriptor:
      case Node::Kind::ProtocolList:
      case Node::Kind::ProtocolWitness:
      case Node::Kind::ProtocolWitnessTable:
      case Node::Kind::ProtocolWitnessTableAccessor:
      case Node::Kind::ReabstractionThunk:
      case Node::Kind::ReabstractionThunkHelper:
      case Node::Kind::Setter:
      case Node::Kind::SpecializationIsFragile:
      case Node::Kind::SpecializationPassID:
      case Node::Kind::Static:
      case Node::Kind::Subscript:
      case Node::Kind::Suffix:
      case Node::Kind::ThinFunctionType:
      case Node::Kind::TupleElement:
      case Node::Kind::TypeMangling:
      case Node::Kind::TypeMetadata:
      case Node::Kind::TypeMetadataAccessFunction:
      case Node::Kind::TypeMetadataLazyCache:
      case Node::Kind::UncurriedFunctionType:
      case Node::Kind::Unmanaged:
      case Node::Kind::Unowned:
      case Node::Kind::UnsafeAddressor:
      case Node::Kind::UnsafeMutableAddressor:
      case Node::Kind::ValueWitness:
      case Node::Kind::ValueWitnessTable:
      case Node::Kind::Variable:
      case Node::Kind::VTableAttribute:
      case Node::Kind::Weak:
      case Node::Kind::WillSet:
      case Node::Kind::WitnessTableOffset:
      case Node::Kind::ThrowsAnnotation:
        return false;
      }
      unreachable("bad node kind");
    }
  
    SugarType findSugar(NodePointer pointer) {
      if (pointer->getNumChildren() == 1 && 
          pointer->getKind() == Node::Kind::Type)
        return findSugar(pointer->getChild(0));
      
      if (pointer->getNumChildren() != 2)
        return SugarType::None;
      
      if (pointer->getKind() != Node::Kind::BoundGenericEnum &&
          pointer->getKind() != Node::Kind::BoundGenericStructure)
        return SugarType::None;
  
      auto unboundType = pointer->getChild(0)->getChild(0); // drill through Type
      auto typeArgs = pointer->getChild(1);
      
      if (pointer->getKind() == Node::Kind::BoundGenericEnum) {
        // Swift.Optional
        if (isIdentifier(unboundType->getChild(1), "Optional") &&
            typeArgs->getNumChildren() == 1 &&
            isSwiftModule(unboundType->getChild(0))) {
          return SugarType::Optional;
        }
  
        // Swift.ImplicitlyUnwrappedOptional
        if (isIdentifier(unboundType->getChild(1), 
                         "ImplicitlyUnwrappedOptional") &&
            typeArgs->getNumChildren() == 1 &&
            isSwiftModule(unboundType->getChild(0))) {
          return SugarType::ImplicitlyUnwrappedOptional;
        }
  
        return SugarType::None;
      }
  
      assert(pointer->getKind() == Node::Kind::BoundGenericStructure);
  
      // Array
      if (isIdentifier(unboundType->getChild(1), "Array") &&
          typeArgs->getNumChildren() == 1 &&
          isSwiftModule(unboundType->getChild(0))) {
        return SugarType::Array;
      }
  
      // Dictionary
      if (isIdentifier(unboundType->getChild(1), "Dictionary") &&
          typeArgs->getNumChildren() == 2 &&
          isSwiftModule(unboundType->getChild(0))) {
        return SugarType::Dictionary;
      }
  
      return SugarType::None;
    }
    
    void printBoundGeneric(NodePointer pointer) {
      if (pointer->getNumChildren() < 2)
        return;
      if (pointer->getNumChildren() != 2) {
        printBoundGenericNoSugar(pointer);
        return;
      }
  
      if (!Options.SynthesizeSugarOnTypes ||
          pointer->getKind() == Node::Kind::BoundGenericClass)
      {
        // no sugar here
        printBoundGenericNoSugar(pointer);
        return;
      }
  
      SugarType sugarType = findSugar(pointer);
      
      switch (sugarType) {
        case SugarType::None:
          printBoundGenericNoSugar(pointer);
          break;
        case SugarType::Optional:
        case SugarType::ImplicitlyUnwrappedOptional: {
          NodePointer type = pointer->getChild(1)->getChild(0);
          bool needs_parens = !isSimpleType(type);
          if (needs_parens)
            Printer << "(";
          print(type);
          if (needs_parens)
            Printer << ")";
          Printer << (sugarType == SugarType::Optional ? "?" : "!");
          break;
        }
        case SugarType::Array: {
          NodePointer type = pointer->getChild(1)->getChild(0);
          Printer << "[";
          print(type);
          Printer << "]";
          break;
        }
        case SugarType::Dictionary: {
          NodePointer keyType = pointer->getChild(1)->getChild(0);
          NodePointer valueType = pointer->getChild(1)->getChild(1);
          Printer << "[";
          print(keyType);
          Printer << " : ";
          print(valueType);
          Printer << "]";
          break;
        }
      }
    }
  
    void printSimplifiedEntityType(NodePointer context, NodePointer entityType);
  
    void printFunctionType(NodePointer node) {
      assert(node->getNumChildren() == 2 || node->getNumChildren() == 3);
      unsigned startIndex = 0;
      bool throws = false;
      if (node->getNumChildren() == 3) {
        assert(node->getChild(0)->getKind() == Node::Kind::ThrowsAnnotation);
        startIndex++;
        throws = true;
      }
      print(node->getChild(startIndex));
      if (throws) Printer << " throws";
      print(node->getChild(startIndex+1));
    }
  
    void printImplFunctionType(NodePointer fn) {
      enum State { Attrs, Inputs, Results } curState = Attrs;
      auto transitionTo = [&](State newState) {
        assert(newState >= curState);
        for (; curState != newState; curState = State(curState + 1)) {
          switch (curState) {
          case Attrs: Printer << '('; continue;
          case Inputs: Printer << ") -> ("; continue;
          case Results: unreachable("no state after Results");
          }
          unreachable("bad state");
        }
      };
  
      for (auto &child : *fn) {
        if (child->getKind() == Node::Kind::ImplParameter) {
          if (curState == Inputs) Printer << ", ";
          transitionTo(Inputs);
          print(child);
        } else if (child->getKind() == Node::Kind::ImplResult
                   || child->getKind() == Node::Kind::ImplErrorResult) {
          if (curState == Results) Printer << ", ";
          transitionTo(Results);
          print(child);
        } else {
          assert(curState == Attrs);
          print(child);
          Printer << ' ';
        }
      }
      transitionTo(Results);
      Printer << ')';
    }
  
    void printContext(NodePointer context) {
      // TODO: parenthesize local contexts?
      if (Options.DisplayDebuggerGeneratedModule ||
         !isDebuggerGeneratedModule(context))
      {
        print(context, /*asContext*/ true);
        if (context->getKind() == Node::Kind::Module && !Options.DisplayModuleNames)
            return;
        Printer << '.';
      }
    }
  
    void print(NodePointer pointer, bool asContext = false, bool suppressType = false);
  
    unsigned printFunctionSigSpecializationParam(NodePointer pointer,
                                                 unsigned Idx);
  };
  } // end anonymous namespace
  
  static bool isExistentialType(NodePointer node) {
    assert(node->getKind() == Node::Kind::Type);
    node = node->getChild(0);
    return (node->getKind() == Node::Kind::ExistentialMetatype ||
            node->getKind() == Node::Kind::ProtocolList);
  }
  
  /// Print the relevant parameters and return the new index.
  unsigned NodePrinter::printFunctionSigSpecializationParam(NodePointer pointer,
                                                            unsigned Idx) {
    NodePointer firstChild = pointer->getChild(Idx);
    unsigned V = firstChild->getIndex();
    auto K = FunctionSigSpecializationParamKind(V);
    switch (K) {
    case FunctionSigSpecializationParamKind::BoxToValue:
    case FunctionSigSpecializationParamKind::BoxToStack:
      print(pointer->getChild(Idx++));
      return Idx;
    case FunctionSigSpecializationParamKind::ConstantPropFunction:
    case FunctionSigSpecializationParamKind::ConstantPropGlobal: {
      Printer << "[";
      print(pointer->getChild(Idx++));
      Printer << " : ";
      const auto &text = pointer->getChild(Idx++)->getText();
      std::string demangledName = demangleSymbolAsString(text);
      if (demangledName.empty()) {
        Printer << text;
      } else {
        Printer << demangledName;
      }
      Printer << "]";
      return Idx;
    }
    case FunctionSigSpecializationParamKind::ConstantPropInteger:
    case FunctionSigSpecializationParamKind::ConstantPropFloat:
      Printer << "[";
      print(pointer->getChild(Idx++));
      Printer << " : ";
      print(pointer->getChild(Idx++));
      Printer << "]";
      return Idx;
    case FunctionSigSpecializationParamKind::ConstantPropString:
      Printer << "[";
      print(pointer->getChild(Idx++));
      Printer << " : ";
      print(pointer->getChild(Idx++));
      Printer << "'";
      print(pointer->getChild(Idx++));
      Printer << "'";
      Printer << "]";
      return Idx;
    case FunctionSigSpecializationParamKind::ClosureProp:
      Printer << "[";
      print(pointer->getChild(Idx++));
      Printer << " : ";
      print(pointer->getChild(Idx++));
      Printer << ", Argument Types : [";
      for (unsigned e = pointer->getNumChildren(); Idx < e;) {
        NodePointer child = pointer->getChild(Idx);
        // Until we no longer have a type node, keep demangling.
        if (child->getKind() != Node::Kind::Type)
          break;
        print(child);
        ++Idx;
  
        // If we are not done, print the ", ".
        if (Idx < e && pointer->getChild(Idx)->hasText())
          Printer << ", ";
      }
      Printer << "]";
      return Idx;
    default:
      break;
    }
  
    assert(
        ((V & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) ||
         (V & unsigned(FunctionSigSpecializationParamKind::SROA)) ||
         (V & unsigned(FunctionSigSpecializationParamKind::Dead))) &&
        "Invalid OptionSet");
    print(pointer->getChild(Idx++));
    return Idx;
  }
  
  static bool isClassType(NodePointer pointer) {
    return pointer->getKind() == Node::Kind::Class;
  }
  
  static bool useColonForEntityType(NodePointer entity, NodePointer type) {
    switch (entity->getKind()) {
    case Node::Kind::Variable:
    case Node::Kind::Initializer:
    case Node::Kind::DefaultArgumentInitializer:
    case Node::Kind::IVarInitializer:
    case Node::Kind::Class:
    case Node::Kind::Structure:
    case Node::Kind::Enum:
    case Node::Kind::Protocol:
    case Node::Kind::TypeAlias:
    case Node::Kind::OwningAddressor:
    case Node::Kind::OwningMutableAddressor:
    case Node::Kind::NativeOwningAddressor:
    case Node::Kind::NativeOwningMutableAddressor:
    case Node::Kind::NativePinningAddressor:
    case Node::Kind::NativePinningMutableAddressor:
    case Node::Kind::UnsafeAddressor:
    case Node::Kind::UnsafeMutableAddressor:
    case Node::Kind::GlobalGetter:
    case Node::Kind::Getter:
    case Node::Kind::Setter:
    case Node::Kind::MaterializeForSet:
    case Node::Kind::WillSet:
    case Node::Kind::DidSet:
      return true;
  
    case Node::Kind::Subscript:
    case Node::Kind::Function:
    case Node::Kind::ExplicitClosure:
    case Node::Kind::ImplicitClosure:
    case Node::Kind::Allocator:
    case Node::Kind::Constructor:
    case Node::Kind::Destructor:
    case Node::Kind::Deallocator:
    case Node::Kind::IVarDestroyer: {
      // We expect to see a function type here, but if we don't, use the colon.
      type = type->getChild(0);
      while (type->getKind() == Node::Kind::DependentGenericType)
        type = type->getChild(1)->getChild(0);
      return (type->getKind() != Node::Kind::FunctionType &&
              type->getKind() != Node::Kind::UncurriedFunctionType &&
              type->getKind() != Node::Kind::CFunctionPointer &&
              type->getKind() != Node::Kind::ThinFunctionType);
    }
  
    default:
      unreachable("not an entity");
    }
  }
  
  static bool isMethodContext(const NodePointer &context) {
    switch (context->getKind()) {
    case Node::Kind::Structure:
    case Node::Kind::Enum:
    case Node::Kind::Class:
    case Node::Kind::Protocol:
    case Node::Kind::Extension:
      return true;
    default:
      return false;
    }
  }
  
  /// Perform any desired type simplifications for an entity in Simplified mode.
  void NodePrinter::printSimplifiedEntityType(NodePointer context,
                                              NodePointer entityType) {
    // Only do anything special to methods.
    if (!isMethodContext(context)) return print(entityType);
  
    // Strip off a single level of uncurried function type.
    NodePointer type = entityType;
    assert(type->getKind() == Node::Kind::Type);
    type = type->getChild(0);
  
    NodePointer generics;
    if (type->getKind() == Node::Kind::DependentGenericType) {
      generics = type->getChild(0);
      type = type->getChild(1)->getChild(0);
    }
  
    print(entityType);
  }
  
  void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) {
    // Common code for handling entities.
    auto printEntity = [&](bool hasName, bool hasType, StringRef extraName) {
      if (Options.QualifyEntities)
        printContext(pointer->getChild(0));
  
      bool printType = (hasType && !suppressType);
      bool useParens = (printType && asContext);
  
      if (useParens) Printer << '(';
  
      if (hasName) print(pointer->getChild(1));
      Printer << extraName;
  
      if (printType) {
        NodePointer type = pointer->getChild(1 + unsigned(hasName));
        if (useColonForEntityType(pointer, type)) {
          if (Options.DisplayEntityTypes) {
            Printer << " : ";
            print(type);
          }
        } else if (!Options.DisplayEntityTypes) {
          printSimplifiedEntityType(pointer->getChild(0), type);
        } else {
          Printer << " ";
          print(type);
        }
      }
  
      if (useParens) Printer << ')';      
    };
  
    Node::Kind kind = pointer->getKind();
    switch (kind) {
    case Node::Kind::Static:
      Printer << "static ";
      print(pointer->getChild(0), asContext, suppressType);
      return;
    case Node::Kind::Directness:
      Printer << toString(Directness(pointer->getIndex())) << " ";
      return;
    case Node::Kind::Extension:
      assert((pointer->getNumChildren() == 2 || pointer->getNumChildren() == 3)
             && "Extension expects 2 or 3 children.");
      if (Options.QualifyEntities && Options.DisplayExtensionContexts) {
        Printer << "(extension in ";
        // Print the module where extension is defined.
        print(pointer->getChild(0), true);
        Printer << "):";
      }
      print(pointer->getChild(1), asContext);
      if (pointer->getNumChildren() == 3)
        print(pointer->getChild(2), true);
      return;
    case Node::Kind::Variable:
    case Node::Kind::Function:
    case Node::Kind::Subscript:
      printEntity(true, true, "");
      return;
    case Node::Kind::ExplicitClosure:
    case Node::Kind::ImplicitClosure: {
      auto index = pointer->getChild(1)->getIndex();
      DemanglerPrinter printName;
      printName << '(';
      if (pointer->getKind() == Node::Kind::ImplicitClosure)
        printName << "implicit ";
      printName << "closure #" << (index + 1) << ")";
      printEntity(false, false, std::move(printName).str());
      return;
    }
    case Node::Kind::Global:
      printChildren(pointer);
      return;
    case Node::Kind::Suffix:
      if (!Options.DisplayUnmangledSuffix) return;
      Printer << " with unmangled suffix " << QuotedString(pointer->getText());
      return;
    case Node::Kind::Initializer:
      printEntity(false, false, "(variable initialization expression)");
      return;
    case Node::Kind::DefaultArgumentInitializer: {
      auto index = pointer->getChild(1);
      DemanglerPrinter strPrinter;
      strPrinter << "(default argument " << index->getIndex() << ")";
      printEntity(false, false, std::move(strPrinter).str());
      return;
    }
    case Node::Kind::DeclContext:
      print(pointer->getChild(0), asContext);
      return;
    case Node::Kind::Type:
      print(pointer->getChild(0), asContext);
      return;
    case Node::Kind::TypeMangling:
      print(pointer->getChild(0));
      return;
    case Node::Kind::Class:
    case Node::Kind::Structure:
    case Node::Kind::Enum:
    case Node::Kind::Protocol:
    case Node::Kind::TypeAlias:
      printEntity(true, false, "");
      return;
    case Node::Kind::LocalDeclName:
      Printer << '(';
      print(pointer->getChild(1));
      Printer << " #" << (pointer->getChild(0)->getIndex() + 1) << ')';
      return;
    case Node::Kind::PrivateDeclName:
      if (Options.ShowPrivateDiscriminators)
        Printer << '(';
  
      print(pointer->getChild(1));
  
      if (Options.ShowPrivateDiscriminators)
        Printer << " in " << pointer->getChild(0)->getText() << ')';
      return;
    case Node::Kind::Module:
      if (Options.DisplayModuleNames)
        Printer << pointer->getText();
      return;
    case Node::Kind::Identifier:
      Printer << pointer->getText();
      return;
    case Node::Kind::Index:
      Printer << pointer->getIndex();
      return;
    case Node::Kind::AutoClosureType:
      Printer << "@autoclosure ";
      printFunctionType(pointer);
      return;
    case Node::Kind::ThinFunctionType:
      Printer << "@convention(thin) ";
      printFunctionType(pointer);
      return;
    case Node::Kind::FunctionType:
    case Node::Kind::UncurriedFunctionType:
      printFunctionType(pointer);
      return;
    case Node::Kind::ArgumentTuple: {
      bool need_parens = false;
      if (pointer->getNumChildren() > 1)
        need_parens = true;
      else {
        if (!pointer->hasChildren())
          need_parens = true;
        else {
          Node::Kind child0_kind = pointer->getChild(0)->getChild(0)->getKind();
          if (child0_kind != Node::Kind::VariadicTuple &&
              child0_kind != Node::Kind::NonVariadicTuple)
            need_parens = true;
        }
      }
      if (need_parens)
        Printer << "(";
      printChildren(pointer);
      if (need_parens)
        Printer << ")";
      return;
    }
    case Node::Kind::NonVariadicTuple:
    case Node::Kind::VariadicTuple: {
      Printer << "(";
      printChildren(pointer, ", ");
      if (pointer->getKind() == Node::Kind::VariadicTuple)
        Printer << "...";
      Printer << ")";
      return;
    }
    case Node::Kind::TupleElement:
      if (pointer->getNumChildren() == 1) {
        NodePointer type = pointer->getChild(0);
        print(type);
      } else if (pointer->getNumChildren() == 2) {
        NodePointer id = pointer->getChild(0);
        NodePointer type = pointer->getChild(1);
        print(id);
        print(type);
      }
      return;
    case Node::Kind::TupleElementName:
      Printer << pointer->getText() << " : ";
      return;
    case Node::Kind::ReturnType:
      if (pointer->getNumChildren() == 0)
        Printer << " -> " << pointer->getText();
      else {
        Printer << " -> ";
        printChildren(pointer);
      }
      return;
    case Node::Kind::Weak:
      Printer << "weak ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::Unowned:
      Printer << "unowned ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::Unmanaged:
      Printer << "unowned(unsafe) ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::InOut:
      Printer << "inout ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::NonObjCAttribute:
      Printer << "@nonobjc ";
      return;
    case Node::Kind::ObjCAttribute:
      Printer << "@objc ";
      return;
    case Node::Kind::DirectMethodReferenceAttribute:
      Printer << "super ";
      return;
    case Node::Kind::DynamicAttribute:
      Printer << "dynamic ";
      return;
    case Node::Kind::VTableAttribute:
      Printer << "override ";
      return;
    case Node::Kind::FunctionSignatureSpecialization:
    case Node::Kind::GenericSpecialization:
    case Node::Kind::GenericSpecializationNotReAbstracted: {
      if (!Options.DisplayGenericSpecializations) {
        Printer << "specialized ";
        return;
      }
      if (pointer->getKind() == Node::Kind::FunctionSignatureSpecialization) {
        Printer << "function signature specialization <";
      } else if (pointer->getKind() == Node::Kind::GenericSpecialization) {
        Printer << "generic specialization <";
      } else {
        Printer << "generic not re-abstracted specialization <";
      }
      bool hasPrevious = false;
      for (unsigned i = 0, e = pointer->getNumChildren(); i < e; ++i) {
        auto child = pointer->getChild(i);
  
        switch (pointer->getChild(i)->getKind()) {
        case Node::Kind::SpecializationPassID:
          // We skip the SpecializationPassID since it does not contain any
          // information that is useful to our users.
          continue;
  
        case Node::Kind::SpecializationIsFragile:
          break;
  
        default:
          // Ignore empty specializations.
          if (!pointer->getChild(i)->hasChildren())
            continue;
        }
  
        if (hasPrevious)
          Printer << ", ";
        print(pointer->getChild(i));
        hasPrevious = true;
      }
      Printer << "> of ";
      return;
    }
    case Node::Kind::SpecializationIsFragile:
      Printer << "preserving fragile attribute";
      return;
    case Node::Kind::GenericSpecializationParam:
      print(pointer->getChild(0));
      for (unsigned i = 1, e = pointer->getNumChildren(); i < e; ++i) {
        if (i == 1)
          Printer << " with ";
        else
          Printer << " and ";
        print(pointer->getChild(i));
      }
      return;
    case Node::Kind::FunctionSignatureSpecializationParam: {
      uint64_t argNum = pointer->getIndex();
  
      Printer << "Arg[" << argNum << "] = ";
  
      unsigned Idx = printFunctionSigSpecializationParam(pointer, 0);
  
      for (unsigned e = pointer->getNumChildren(); Idx < e;) {
        Printer << " and ";
        Idx = printFunctionSigSpecializationParam(pointer, Idx);
      }
  
      return;
    }
    case Node::Kind::FunctionSignatureSpecializationParamPayload: {
      std::string demangledName = demangleSymbolAsString(pointer->getText());
      if (demangledName.empty()) {
        Printer << pointer->getText();
      } else {
        Printer << demangledName;
      }
      return;
    }
    case Node::Kind::FunctionSignatureSpecializationParamKind: {
      uint64_t raw = pointer->getIndex();
  
      bool printedOptionSet = false;
      if (raw & uint64_t(FunctionSigSpecializationParamKind::Dead)) {
        printedOptionSet = true;
        Printer << "Dead";
      }
  
      if (raw & uint64_t(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) {
        if (printedOptionSet)
          Printer << " and ";
        printedOptionSet = true;
        Printer << "Owned To Guaranteed";
      }
  
      if (raw & uint64_t(FunctionSigSpecializationParamKind::SROA)) {
        if (printedOptionSet)
          Printer << " and ";
        Printer << "Exploded";
        return;
      }
  
      if (printedOptionSet)
        return;
  
      switch (FunctionSigSpecializationParamKind(raw)) {
      case FunctionSigSpecializationParamKind::BoxToValue:
        Printer << "Value Promoted from Box";
        break;
      case FunctionSigSpecializationParamKind::BoxToStack:
        Printer << "Stack Promoted from Box";
        break;
      case FunctionSigSpecializationParamKind::ConstantPropFunction:
        Printer << "Constant Propagated Function";
        break;
      case FunctionSigSpecializationParamKind::ConstantPropGlobal:
        Printer << "Constant Propagated Global";
        break;
      case FunctionSigSpecializationParamKind::ConstantPropInteger:
        Printer << "Constant Propagated Integer";
        break;
      case FunctionSigSpecializationParamKind::ConstantPropFloat:
        Printer << "Constant Propagated Float";
        break;
      case FunctionSigSpecializationParamKind::ConstantPropString:
        Printer << "Constant Propagated String";
        break;
      case FunctionSigSpecializationParamKind::ClosureProp:
        Printer << "Closure Propagated";
        break;
      case FunctionSigSpecializationParamKind::Dead:
      case FunctionSigSpecializationParamKind::OwnedToGuaranteed:
      case FunctionSigSpecializationParamKind::SROA:
        unreachable("option sets should have been handled earlier");
      }
      return;
    }
    case Node::Kind::SpecializationPassID:
      Printer << pointer->getIndex();
      return;
    case Node::Kind::BuiltinTypeName:
      Printer << pointer->getText();
      return;
    case Node::Kind::Number:
      Printer << pointer->getIndex();
      return;
    case Node::Kind::InfixOperator:
      Printer << pointer->getText() << " infix";
      return;
    case Node::Kind::PrefixOperator:
      Printer << pointer->getText() << " prefix";
      return;
    case Node::Kind::PostfixOperator:
      Printer << pointer->getText() << " postfix";
      return;
    case Node::Kind::LazyProtocolWitnessTableAccessor:
      Printer << "lazy protocol witness table accessor for type ";
      print(pointer->getChild(0));
      Printer << " and conformance ";
      print(pointer->getChild(1));
      return;
    case Node::Kind::LazyProtocolWitnessTableCacheVariable:
      Printer << "lazy protocol witness table cache variable for type ";
      print(pointer->getChild(0));
      Printer << " and conformance ";
      print(pointer->getChild(1));
      return;
    case Node::Kind::ProtocolWitnessTableAccessor:
      Printer << "protocol witness table accessor for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::ProtocolWitnessTable:
      Printer << "protocol witness table for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::GenericProtocolWitnessTable:
      Printer << "generic protocol witness table for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
      Printer << "instantiation function for generic protocol witness table for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::ProtocolWitness: {
      Printer << "protocol witness for ";
      print(pointer->getChild(1));
      Printer << " in conformance ";
      print(pointer->getChild(0));
      return;
    }
    case Node::Kind::PartialApplyForwarder:
      if (Options.ShortenPartialApply)
        Printer << "partial apply";
      else
        Printer << "partial apply forwarder";
  
      if (pointer->hasChildren()) {
        Printer << " for ";
        print(pointer->getFirstChild());
      }
      return;
    case Node::Kind::PartialApplyObjCForwarder:
      if (Options.ShortenPartialApply)
        Printer << "partial apply";
      else
        Printer << "partial apply ObjC forwarder";
  
      if (pointer->hasChildren()) {
        Printer << " for ";
        print(pointer->getFirstChild());
      }
      return;
    case Node::Kind::FieldOffset: {
      print(pointer->getChild(0)); // directness
      Printer << "field offset for ";
      auto entity = pointer->getChild(1);
      print(entity, /*asContext*/ false,
               /*suppressType*/ !Options.DisplayTypeOfIVarFieldOffset);
      return;
    }
    case Node::Kind::ReabstractionThunk:
    case Node::Kind::ReabstractionThunkHelper: {
      if (Options.ShortenThunk) {
        Printer << "thunk";
        return;
      }
      Printer << "reabstraction thunk ";
      if (pointer->getKind() == Node::Kind::ReabstractionThunkHelper)
        Printer << "helper ";
      auto generics = getFirstChildOfKind(pointer, Node::Kind::DependentGenericSignature);
      assert(pointer->getNumChildren() == 2 + unsigned(generics != nullptr));
      if (generics) {
        print(generics);
        Printer << " ";
      }
      Printer << "from ";
      print(pointer->getChild(pointer->getNumChildren() - 2));
      Printer << " to ";
      print(pointer->getChild(pointer->getNumChildren() - 1));
      return;
    }
    case Node::Kind::GenericTypeMetadataPattern:
      Printer << "generic type metadata pattern for ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::Metaclass:
      Printer << "metaclass for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::ProtocolDescriptor:
      Printer << "protocol descriptor for ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::FullTypeMetadata:
      Printer << "full type metadata for ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::TypeMetadata:
      Printer << "type metadata for ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::TypeMetadataAccessFunction:
      Printer << "type metadata accessor for ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::TypeMetadataLazyCache:
      Printer << "lazy cache variable for type metadata for ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::AssociatedTypeMetadataAccessor:
      Printer << "associated type metadata accessor for ";
      print(pointer->getChild(1));
      Printer << " in ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::AssociatedTypeWitnessTableAccessor:
      Printer << "associated type witness table accessor for ";
      print(pointer->getChild(1));
      Printer << " : ";
      print(pointer->getChild(2));
      Printer << " in ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::NominalTypeDescriptor:
      Printer << "nominal type descriptor for ";
      print(pointer->getChild(0));
      return;
    case Node::Kind::ValueWitness:
      Printer << toString(ValueWitnessKind(pointer->getIndex()));
      if (Options.ShortenValueWitness) Printer << " for ";
      else Printer << " value witness for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::ValueWitnessTable:
      Printer << "value witness table for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::WitnessTableOffset:
      Printer << "witness table offset for ";
      print(pointer->getFirstChild());
      return;
    case Node::Kind::BoundGenericClass:
    case Node::Kind::BoundGenericStructure:
    case Node::Kind::BoundGenericEnum:
      printBoundGeneric(pointer);
      return;
    case Node::Kind::DynamicSelf:
      Printer << "Self";
      return;
    case Node::Kind::CFunctionPointer: {
      Printer << "@convention(c) ";
      printFunctionType(pointer);
      return;
    }
    case Node::Kind::ObjCBlock: {
      Printer << "@convention(block) ";
      printFunctionType(pointer);
      return;
    }
    case Node::Kind::SILBoxType: {
      Printer << "@box ";
      NodePointer type = pointer->getChild(0);
      print(type);
      return;
    }
    case Node::Kind::Metatype: {
      unsigned Idx = 0;
      if (pointer->getNumChildren() == 2) {
        NodePointer repr = pointer->getChild(Idx);
        print(repr);
        Printer << " ";
        Idx++;
      }
      NodePointer type = pointer->getChild(Idx);
      print(type);
      if (isExistentialType(type)) {
        Printer << ".Protocol";
      } else {
        Printer << ".Type";
      }
      return;
    }
    case Node::Kind::ExistentialMetatype: {
      unsigned Idx = 0;
      if (pointer->getNumChildren() == 2) {
        NodePointer repr = pointer->getChild(Idx);
        print(repr);
        Printer << " ";
        Idx++;
      }
  
      NodePointer type = pointer->getChild(Idx);
      print(type);
      Printer << ".Type";
      return;
    }
    case Node::Kind::MetatypeRepresentation: {
      Printer << pointer->getText();
      return;
    }
    case Node::Kind::ArchetypeRef:
      Printer << pointer->getText();
      return;
    case Node::Kind::AssociatedTypeRef:
      print(pointer->getChild(0));
      Printer << '.' << pointer->getChild(1)->getText();
      return;
    case Node::Kind::SelfTypeRef:
      print(pointer->getChild(0));
      Printer << ".Self";
      return;
    case Node::Kind::ProtocolList: {
      NodePointer type_list = pointer->getChild(0);
      if (!type_list)
        return;
      if (type_list->getNumChildren() == 0)
        Printer << "Any";
      else
        printChildren(type_list, " & ");
      return;
    }
    case Node::Kind::Archetype: {
      Printer << pointer->getText();
      if (pointer->hasChildren()) {
        Printer << " : ";
        print(pointer->getChild(0));
      }
      return;
    }
    case Node::Kind::AssociatedType:
      // Don't print for now.
      return;
    case Node::Kind::QualifiedArchetype: {
      if (Options.ShortenArchetype) {
        Printer << "(archetype)";
        return;
      }
      if (pointer->getNumChildren() < 2)
        return;
      NodePointer number = pointer->getChild(0);
      NodePointer decl_ctx = pointer->getChild(1);
      Printer << "(archetype " << number->getIndex() << " of ";
      print(decl_ctx);
      Printer << ")";
      return;
    }
    case Node::Kind::OwningAddressor:
      printEntity(true, true, ".owningAddressor");
      return;
    case Node::Kind::OwningMutableAddressor:
      printEntity(true, true, ".owningMutableAddressor");
      return;
    case Node::Kind::NativeOwningAddressor:
      printEntity(true, true, ".nativeOwningAddressor");
      return;
    case Node::Kind::NativeOwningMutableAddressor:
      printEntity(true, true, ".nativeOwningMutableAddressor");
      return;
    case Node::Kind::NativePinningAddressor:
      printEntity(true, true, ".nativePinningAddressor");
      return;
    case Node::Kind::NativePinningMutableAddressor:
      printEntity(true, true, ".nativePinningMutableAddressor");
      return;
    case Node::Kind::UnsafeAddressor:
      printEntity(true, true, ".unsafeAddressor");
      return;
    case Node::Kind::UnsafeMutableAddressor:
      printEntity(true, true, ".unsafeMutableAddressor");
      return;
    case Node::Kind::GlobalGetter:
      printEntity(true, true, ".getter");
      return;
    case Node::Kind::Getter:
      printEntity(true, true, ".getter");
      return;
    case Node::Kind::Setter:
      printEntity(true, true, ".setter");
      return;
    case Node::Kind::MaterializeForSet:
      printEntity(true, true, ".materializeForSet");
      return;
    case Node::Kind::WillSet:
      printEntity(true, true, ".willset");
      return;
    case Node::Kind::DidSet:
      printEntity(true, true, ".didset");
      return;
    case Node::Kind::Allocator:
      printEntity(false, true,
                  isClassType(pointer->getChild(0))
                    ? "__allocating_init" : "init");
      return;
    case Node::Kind::Constructor:
      printEntity(false, true, "init");
      return;
    case Node::Kind::Destructor:
      printEntity(false, false, "deinit");
      return;
    case Node::Kind::Deallocator:
      printEntity(false, false,
                  isClassType(pointer->getChild(0))
                    ? "__deallocating_deinit" : "deinit");
      return;
    case Node::Kind::IVarInitializer:
      printEntity(false, false, "__ivar_initializer");
      return;
    case Node::Kind::IVarDestroyer:
      printEntity(false, false, "__ivar_destroyer");
      return;
    case Node::Kind::ProtocolConformance: {
      NodePointer child0 = pointer->getChild(0);
      NodePointer child1 = pointer->getChild(1);
      NodePointer child2 = pointer->getChild(2);
      print(child0);
      if (Options.DisplayProtocolConformances) {
        Printer << " : ";
        print(child1);
        Printer << " in ";
        print(child2);
      }
      return;
    }
    case Node::Kind::TypeList:
      printChildren(pointer);
      return;
    case Node::Kind::ImplConvention:
      Printer << pointer->getText();
      return;
    case Node::Kind::ImplFunctionAttribute:
      Printer << pointer->getText();
      return;
    case Node::Kind::ImplErrorResult:
      Printer << "@error ";
      SWIFT_FALLTHROUGH;
    case Node::Kind::ImplParameter:
    case Node::Kind::ImplResult:
      printChildren(pointer, " ");
      return;
    case Node::Kind::ImplFunctionType:
      printImplFunctionType(pointer);
      return;
    case Node::Kind::ErrorType:
      Printer << "<ERROR TYPE>";
      return;
        
    case Node::Kind::DependentPseudogenericSignature:
    case Node::Kind::DependentGenericSignature: {
      Printer << '<';
      
      unsigned depth = 0;
      unsigned numChildren = pointer->getNumChildren();
      for (;
           depth < numChildren
             && pointer->getChild(depth)->getKind()
                 == Node::Kind::DependentGenericParamCount;
           ++depth) {
        if (depth != 0)
          Printer << "><";
        
        unsigned count = pointer->getChild(depth)->getIndex();
        for (unsigned index = 0; index < count; ++index) {
          if (index != 0)
            Printer << ", ";
          // FIXME: Depth won't match when a generic signature applies to a
          // method in generic type context.
          Printer << archetypeName(index, depth);
        }
      }
      
      if (depth != numChildren) {
        if (!Options.DisplayWhereClauses) {
          Printer << " where ...";
        } else {
          Printer << " where ";
          for (unsigned i = depth; i < numChildren; ++i) {
            if (i > depth)
              Printer << ", ";
            print(pointer->getChild(i));
          }
        }
      }
      Printer << '>';
      return;
    }
    case Node::Kind::DependentGenericParamCount:
      unreachable("should be printed as a child of a "
                  "DependentGenericSignature");
    case Node::Kind::DependentGenericConformanceRequirement: {
      NodePointer type = pointer->getChild(0);
      NodePointer reqt = pointer->getChild(1);
      print(type);
      Printer << ": ";
      print(reqt);
      return;
    }
    case Node::Kind::DependentGenericSameTypeRequirement: {
      NodePointer fst = pointer->getChild(0);
      NodePointer snd = pointer->getChild(1);
      
      print(fst);
      Printer << " == ";
      print(snd);
      return;
    }
    case Node::Kind::DependentGenericParamType: {
      Printer << pointer->getText();
      return;
    }
    case Node::Kind::DependentGenericType: {
      NodePointer sig = pointer->getChild(0);
      NodePointer depTy = pointer->getChild(1);
      print(sig);
      Printer << ' ';
      print(depTy);
      return;
    }
    case Node::Kind::DependentMemberType: {
      NodePointer base = pointer->getChild(0);
      print(base);
      Printer << '.';
      NodePointer assocTy = pointer->getChild(1);
      print(assocTy);
      return;
    }
    case Node::Kind::DependentAssociatedTypeRef: {
      Printer << pointer->getText();
      return;
    }
    case Node::Kind::ThrowsAnnotation: {
      Printer<< " throws ";
      return;
    }
    }
    unreachable("bad node kind!");
  }
  
  std::string Demangle::nodeToString(NodePointer root,
                                     const DemangleOptions &options) {
    if (!root)
      return "";
  
    return NodePrinter(options).printRoot(root);
  }
  
  std::string Demangle::demangleSymbolAsString(const char *MangledName,
                                               size_t MangledNameLength,
                                               const DemangleOptions &Options) {
    auto mangled = StringRef(MangledName, MangledNameLength);
    auto root = demangleSymbolAsNode(MangledName, MangledNameLength, Options);
    if (!root) return mangled.str();
  
    std::string demangling = nodeToString(std::move(root), Options);
    if (demangling.empty())
      return mangled.str();
    return demangling;
  }
  
  std::string Demangle::demangleTypeAsString(const char *MangledName,
                                             size_t MangledNameLength,
                                             const DemangleOptions &Options) {
    auto mangled = StringRef(MangledName, MangledNameLength);
    auto root = demangleTypeAsNode(MangledName, MangledNameLength, Options);
    if (!root) return mangled.str();
    
    std::string demangling = nodeToString(std::move(root), Options);
    if (demangling.empty())
      return mangled.str();
    return demangling;
  }
  
  
  
  