Field (int startOffset, int recursionDepth) { assert myNodeText.charAt(startOffset) == '{'; int autoFieldNumber = myImplicitlyNumberedFieldsCounter; // in the order of appearance inside a field final IntList attrAndLookupBounds=new IntArrayList(); int conversionStart = -1; int formatSpecStart = -1; final List<Field> nestedFields = new ArrayList<>(); int rightBraceOffset = -1; boolean insideItem = false; boolean recovering = false; final int contentEnd = myNodeContentRange.getEndOffset(); int offset = startOffset + 1; while (offset < contentEnd) { final int nextOffset = skipNamedUnicodeEscape(offset); if (offset != nextOffset) { offset = nextOffset; continue; } final char c = myNodeText.charAt(offset); // inside "name" part of the field if (conversionStart == -1 && formatSpecStart == -1) { // '{' can appear inside a lookup item, but everywhere else it means that field ends if (insideItem) { // inside lookup item skip everything up to the closing bracket if (c == ']') { insideItem = false; // remember the end offset of the lookup now, since later we may enter "recovering" state attrAndLookupBounds.add(offset + 1); // if the next character is neither '.', not '[' stop matching attributes and lookups here recovering = offset + 1 < contentEnd && !isAnyCharOf(myNodeText.charAt(offset + 1), ".["); } } else if (isAnyCharOf(c, "[.:!}")) { insideItem = c == '['; if (!recovering) { // avoid duplicate offsets in sequences like "]." or "][" addIfNotLastItem(attrAndLookupBounds, offset); // no name in the field, increment implicitly named fields counter if (attrAndLookupBounds.size() == 1 && attrAndLookupBounds.getInt(0) == startOffset + 1) { myImplicitlyNumberedFieldsCounter++; } } if (c == ':') { formatSpecStart = offset; } else if (c == '!') { conversionStart = offset; } else if (c == '}') { rightBraceOffset = offset; break; } } } else if (c == '}') { rightBraceOffset = offset; break; } else if (conversionStart >= 0) { if (c == ':') { formatSpecStart = offset; } } else { assert formatSpecStart >= 0; if (c == '{') { final Field field = parseField(offset, recursionDepth + 1); nestedFields.add(field); offset = field.getFieldEnd(); continue; } } offset++; } // finish with the trailing attribute or the first name if the field ended unexpectedly if (offset >= contentEnd && conversionStart == -1 && formatSpecStart == -1 && !insideItem && !recovering) { addIfNotLastItem(attrAndLookupBounds, contentEnd); } assert !attrAndLookupBounds.isEmpty(); return new Field(myNodeText, startOffset, attrAndLookupBounds.toIntArray(), conversionStart, formatSpecStart, nestedFields, rightBraceOffset, rightBraceOffset == -1 ? contentEnd : rightBraceOffset + 1, autoFieldNumber, recursionDepth); }