+ private void skipUntilTerminatorEnd(Terminator terminator) throws InvalidSyntaxException {
+ if (terminator.hasEndSequence())
+ currentIndex = getEndSequenceIndex(terminator) + terminator.endSequence.length();
+ else
+ currentIndex += terminator.startSequence.length();
+ }
+
+ private TokenizerMatch buildPreservedToken(StringBuilder token, Terminator terminator) throws InvalidSyntaxException {
+ if (hasAccumulatedToken(token))
+ return new TokenizerMatch(token.toString(), null, terminator);
+
+ if (terminator.hasEndSequence())
+ return buildComplexPreservedToken(terminator);
+ else
+ return buildSimplePreservedToken(terminator);
+ }
+
+ private TokenizerMatch buildSimplePreservedToken(Terminator terminator) {
+ currentIndex += terminator.startSequence.length();
+ return new TokenizerMatch(terminator.startSequence, null, terminator);
+ }
+
+ private TokenizerMatch buildComplexPreservedToken(Terminator terminator) throws InvalidSyntaxException {
+ int endSequenceIndex = getEndSequenceIndex(terminator);
+ String reminder = source.substring(currentIndex + terminator.startSequence.length(), endSequenceIndex);
+ currentIndex = endSequenceIndex + terminator.endSequence.length();
+
+ return new TokenizerMatch(terminator.startSequence, reminder, terminator);
+ }
+
+ private int getEndSequenceIndex(Terminator terminator) throws InvalidSyntaxException {
+ int endSequenceIndex = source.indexOf(terminator.endSequence,
+ currentIndex + terminator.startSequence.length());
+
+ if (endSequenceIndex < 0)
+ throw new InvalidSyntaxException("Expected \"" + terminator.endSequence + "\" but not found.");
+
+ return endSequenceIndex;
+ }
+
+ private boolean hasAccumulatedToken(StringBuilder token) {
+ return token.length() > 0;
+ }
+
+ private boolean isOngoingToken() {
+ return getOrFindTokenTerminator() == null;
+ }
+
+ public boolean hasMoreTokens() {
+ return currentIndex < source.length();
+ }
+
+ /**
+ * Attempts to cache terminator search result.
+ */
+ public Terminator getOrFindTokenTerminator() {
+ if (currentIndex == cachedTerminatorIndex)
+ return cachedTerminator;
+
+ cachedTerminatorIndex = currentIndex;
+ cachedTerminator = findTokenTerminator();
+ return cachedTerminator;
+ }
+
+ private Terminator findTokenTerminator() {
+ for (Terminator terminator : terminators)
+ if (terminator.matches(source, currentIndex))
+ return terminator;
+ return null;
+ }
+
+ public boolean consumeIfNextToken(final String token) throws InvalidSyntaxException {