boolean (int offset, LiteralType literalType) { int pos = offset; while (pos < myBufferEndOffset) { char c = locateCharAt(pos); if (c == '\\') { pos += mySymbolLength; // on (encoded) backslash we also need to skip the next symbol (e.g. \\u005c" is translated to \") if (pos < myBufferEndOffset) { if (locateCharAt(pos) == '{' && literalType != LiteralType.CHAR) { pos += mySymbolLength; myTokenEndOffset = pos; if (myStateStack.topInt() == 0) myStateStack.popInt(); if (literalType == LiteralType.TEXT_BLOCK) { myStateStack.push(STATE_TEXT_BLOCK_TEMPLATE | (1 << 16)); } else { myStateStack.push(STATE_DEFAULT | (1 << 16)); } return true; } } } else if (c == literalType.c) { if (literalType == LiteralType.TEXT_BLOCK) { if ((pos += mySymbolLength) < myBufferEndOffset && locateCharAt(pos) == '"') { if ((pos += mySymbolLength) < myBufferEndOffset && locateCharAt(pos) == '"') { myTokenEndOffset = pos + mySymbolLength; return false; } } continue; } else { myTokenEndOffset = pos + mySymbolLength; return false; } } else if ((c == '\n' || c == '\r') && mySymbolLength == 1 && literalType != LiteralType.TEXT_BLOCK) { myTokenEndOffset = pos; return false; } pos += mySymbolLength; } myTokenEndOffset = pos; return false; } private int getClosingComment(int offset) { int pos = offset; while (pos < myBufferEndOffset) { char c = locateCharAt(pos); pos += mySymbolLength; if (c == '*' && pos < myBufferEndOffset && locateCharAt(pos) == '/') break; } return pos + mySymbolLength; } private int getLineTerminator(int offset) { int pos = offset; while (pos < myBufferEndOffset) { char c = locateCharAt(pos); if (c == '\r' || c == '\n') break; pos += mySymbolLength; } return pos; } private char charAt(int offset) { return myBufferArray != null ? myBufferArray[offset] : myBuffer.charAt(offset); } private char locateCharAt(int offset) { mySymbolLength = 1; char first = charAt(offset); if (first != '\\') return first; int pos = offset + 1; if (pos < myBufferEndOffset && charAt(pos) == '\\') return first; boolean escaped = true; int i = offset; while (--i >= 0 && charAt(i) == '\\') escaped = !escaped; if (!escaped) return first; if (pos < myBufferEndOffset && charAt(pos) != 'u') return first; //noinspection StatementWithEmptyBody while (++pos < myBufferEndOffset && charAt(pos) == 'u'); if (pos + 3 >= myBufferEndOffset) return first; int result = 0; for (int max = pos + 4; pos < max; pos++) { result <<= 4; char c = charAt(pos); if ('0' <= c && c <= '9') result += c - '0'; else if ('a' <= c && c <= 'f') result += (c - 'a') + 10; else if ('A' <= c && c <= 'F') result += (c - 'A') + 10; else return first; } mySymbolLength = pos - offset; return (char)result; } @NotNull @Override public CharSequence getBufferSequence() { return myBuffer; } @Override public int getBufferEnd() { return myBufferEndOffset; } enum LiteralType { STRING('"'), CHAR('\''), TEXT_BLOCK('"'); final char c; LiteralType(char c) { this.c = c; } } }