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,
};
}