static struct _StructParseResult _ParseStructEncodingWithScanner()

in FBRetainCycleDetector/Layout/Classes/Parser/FBStructEncodingParser.mm [83:147]


  static struct _StructParseResult _ParseStructEncodingWithScanner(_StringScanner &scanner,
                                                                   NSString *debugStruct) {
    std::vector<std::shared_ptr<BaseType>> types;
    
    // Every struct starts with '{'
    __unused const auto scannedCorrectly = scanner.scanString(kOpenStruct);
    NSCAssert(scannedCorrectly, @"The first character of struct encoding should be {; debug_struct: %@", debugStruct);
    
    // Parse name
    const auto structTypeName = scanner.scanUpToString("=");
    scanner.scanString("=");
    
    while (!(scanner.scanString(kCloseStruct))) {
      if (scanner.scanString(kQuote)) {
        const auto parseResult = scanner.scanUpToString(kQuote);
        scanner.scanString(kQuote);
        if (parseResult.length() > 0) {
          types.push_back(std::make_shared<Unresolved>(parseResult));
        }
      } else if (scanner.currentCharacter() == '{') {
        // We do not want to consume '{' because we will call parser recursively
        const auto locBefore = scanner.index;
        auto parseResult = _ParseStructEncodingWithScanner(scanner, debugStruct);
        
        std::shared_ptr<Unresolved> valueFromBefore;
        if (!types.empty()) {
          valueFromBefore = std::dynamic_pointer_cast<Unresolved>(types.back());
          types.pop_back();
        }
        const auto extractedNameFromBefore = valueFromBefore ? valueFromBefore->value
                                                             : "";
        std::shared_ptr<Struct> type = std::make_shared<Struct>(extractedNameFromBefore,
                                                                scanner.string.substr(locBefore, (scanner.index - locBefore)),
                                                                parseResult.typeName,
                                                                parseResult.containedTypes);
        
        types.emplace_back(type);
      } else {
        // It's a type name (literal), let's advance until we find '"', or '}'
        const auto parseResult = scanner.scanUpToCharacterFromSet(kLiteralEndingCharacters);
        std::string nameFromBefore = "";
        if (types.size() > 0) {
          if (std::shared_ptr<Unresolved> maybeUnresolved = std::dynamic_pointer_cast<Unresolved>(types.back())) {
            nameFromBefore = maybeUnresolved->value;
            types.pop_back();
          }
        }
        std::shared_ptr<Type> type = std::make_shared<Type>(nameFromBefore, parseResult);
        types.emplace_back(type);
      }
    }
    
    std::vector<std::shared_ptr<Type>> filteredVector;
    
    for (const auto &t: types) {
      if (const auto convertedType = std::dynamic_pointer_cast<Type>(t)) {
        filteredVector.emplace_back(convertedType);
      }
    }
    
    return {
      .containedTypes = filteredVector,
      .typeName = structTypeName,
    };
  }