package org.dsource.ddt.ide.core_text; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.Token; import melnorme.lang.ide.core_text.PatternRule_Fixed; public class NestedDelimiterRule extends PatternRule_Fixed { protected final char[] anotherStart; protected final char[][] startSequences; protected char[][] innerStartSequences; protected int fOpenDelims = 0; public NestedDelimiterRule(String start, String innerStart, String end, IToken token, char escapeCharacter, boolean breaksOnEOF) { super(start, end, token, escapeCharacter, false, breaksOnEOF); this.anotherStart = innerStart.toCharArray(); startSequences = new char[][] { fStartSequence }; innerStartSequences = new char[][] { fStartSequence, anotherStart }; } @Override protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) { if(resume) { return Token.UNDEFINED; // We can't evaluate this rule mid-way, need to restart } if (anySequenceMatched(scanner, startSequences)) { if (anyEndSequenceMatched(scanner)) return fToken; } return Token.UNDEFINED; } protected boolean anySequenceMatched(ICharacterScanner scanner, char[][] possibleSequences) { int ch = scanner.read(); for (int i = 0; i < possibleSequences.length; i++) { char[] sequence = possibleSequences[i]; if(ch == sequence[0] && sequenceDetected(scanner, sequence, false)) return true; } scanner.unread(); return false; } protected boolean anyEndSequenceMatched(ICharacterScanner scanner) { fOpenDelims = 1; int ch; int readCount = 1; while((ch = scanner.read()) != ICharacterScanner.EOF) { if (ch == fEndSequence[0] && sequenceDetected(scanner, fEndSequence, false)) { if(--fOpenDelims == 0) return true; readCount += fEndSequence.length - 1; continue; } if (anySequenceMatched(scanner, innerStartSequences)) { fOpenDelims++; } readCount++; } if (fBreaksOnEOF) return true; do { scanner.unread(); } while (--readCount > 0); return false; } }