public ArrayList<StructureSkipSuggestion> getParentSkipSuggestions(int failureIndex) {
   ArrayList<StructureSkipSuggestion> parentSkips = new ArrayList<StructureSkipSuggestion>();
   int errorLineIndex = failureIndex;
   int maxBW = Math.max(failureIndex - MAX_NR_OF_LINES, 0);
   int nrOfStructs = 0;
   while (errorLineIndex > maxBW && nrOfStructs < MAX_NR_OF_STRUCTURES) {
     nrOfStructs++;
     int startSkipIndex = findParentBegin(errorLineIndex);
     ArrayList<StructureSkipSuggestion> skips = selectRegion(startSkipIndex);
     if (skips.isEmpty()) {
       StructureSkipSuggestion closingSkip = new StructureSkipSuggestion();
       closingSkip.setSkipLocations(
           IndentInfo.cloneIndentInfo(getHistory().getLine(startSkipIndex)),
           IndentInfo.cloneIndentInfo(getHistory().getLine(failureIndex)),
           startSkipIndex,
           failureIndex);
       parentSkips.add(closingSkip);
     }
     parentSkips.addAll(skips);
     if (skips.size() > 0) errorLineIndex = skips.get(0).getIndexHistoryStart();
     else errorLineIndex = -1;
   }
   addNextRegionMerges(parentSkips);
   return parentSkips;
 }
 public StructureSkipSuggestion getErroneousPrefix(int failureIndex) {
   StructureSkipSuggestion prefix = new StructureSkipSuggestion();
   if (getHistory().getIndexLastLine() >= 0)
     prefix.setSkipLocations(
         IndentInfo.cloneIndentInfo(getHistory().getLine(0)),
         IndentInfo.cloneIndentInfo(getHistory().getLine(failureIndex)),
         0,
         failureIndex);
   return prefix;
 }
 private StructureSkipSuggestion mergeRegions(
     StructureSkipSuggestion fwSuggestion, StructureSkipSuggestion bwSuggestion) {
   StructureSkipSuggestion mergedSkip = new StructureSkipSuggestion();
   mergedSkip.setSkipLocations(
       IndentInfo.cloneIndentInfo(bwSuggestion.getStartSkip()),
       IndentInfo.cloneIndentInfo(fwSuggestion.getEndSkip()),
       bwSuggestion.getIndexHistoryStart(),
       fwSuggestion.getIndexHistoryEnd());
   mergedSkip.setAdditionalTokens(bwSuggestion.getAdditionalTokens());
   return mergedSkip;
 }
 public ArrayList<StructureSkipSuggestion> getBlockSuggestions(int structStartIndex) {
   ArrayList<StructureSkipSuggestion> result = getCurrentRegionSkips(structStartIndex);
   int endIndex =
       Math.min(getHistory().getIndexLastLine() + 1, structStartIndex + MAX_NR_OF_LINES);
   for (int i = structStartIndex; i < endIndex; i++) {
     IndentInfo startSkip = IndentInfo.cloneIndentInfo(getHistory().getLine(structStartIndex));
     IndentInfo endSkip = IndentInfo.cloneIndentInfo(getHistory().getLine(i));
     StructureSkipSuggestion block = new StructureSkipSuggestion();
     block.setSkipLocations(startSkip, endSkip, structStartIndex, i);
     result.add(block);
   }
   return result;
 }
 private void addSeperatorIncludingRegion_Backwards(
     ArrayList<StructureSkipSuggestion> prevRegions, StructureSkipSuggestion previousRegion) {
   int indexStart = previousRegion.getIndexHistoryStart();
   if (indexStart > 0 && isSeparatorEndingLine(indexStart - 1)) {
     char[] toParse = structTokens.removeSeparatorAtTheEnd(readLine(indexStart - 1));
     IndentInfo startSkip2 = IndentInfo.cloneIndentInfo(getHistory().getLine(indexStart - 1));
     IndentInfo endSkip2 = IndentInfo.cloneIndentInfo(previousRegion.getEndSkip());
     StructureSkipSuggestion previousRegion2 = new StructureSkipSuggestion();
     previousRegion2.setSkipLocations(
         startSkip2, endSkip2, indexStart - 1, previousRegion.getIndexHistoryEnd());
     previousRegion2.setAdditionalTokens(toParse);
     prevRegions.add(previousRegion2);
   }
 }
 private int skipLine(int indexLine) {
   IndentInfo line = getHistory().getLine(indexLine);
   IndentationHandler skipIndentHandler = new IndentationHandler();
   getHistory().setTokenIndex(Math.max(0, line.getTokensSeen() - 1));
   skipIndentHandler.setInLeftMargin(false);
   getHistory().readRecoverToken(myParser, false);
   while (myParser.currentToken != SGLR.EOF) {
     getHistory().readRecoverToken(myParser, false);
     skipIndentHandler.updateIndentation(myParser.currentToken);
     if (skipIndentHandler.lineMarginEnded()) {
       return indexLine += 1;
     }
   }
   return getHistory().getIndexLastLine(); // EOF
 }
 private ArrayList<StructureSkipSuggestion> selectRegion(int indexLine) {
   if (isScopeClosingLine(indexLine)) return new ArrayList<StructureSkipSuggestion>();
   ArrayList<Integer> endLocations = findCurrentEnd(indexLine);
   ArrayList<StructureSkipSuggestion> skipSuggestions = new ArrayList<StructureSkipSuggestion>();
   IndentInfo startLine = IndentInfo.cloneIndentInfo(getHistory().getLine(indexLine));
   for (Integer endSkipIndex : endLocations) {
     if (endSkipIndex > indexLine) {
       IndentInfo endSkip = IndentInfo.cloneIndentInfo(getHistory().getLine(endSkipIndex));
       StructureSkipSuggestion skipConstruct = new StructureSkipSuggestion();
       skipConstruct.setSkipLocations(startLine, endSkip, indexLine, endSkipIndex);
       skipSuggestions.add(skipConstruct);
       addSeparatorIncludingRegion_Forwards(skipSuggestions, skipConstruct);
       addSeperatorIncludingRegion_Backwards(skipSuggestions, skipConstruct);
     }
   }
   return skipSuggestions;
 }
 private ArrayList<Integer> findCurrentEnd(int indexStartLine) {
   int indentStartLine = separatorIndent(indexStartLine);
   boolean hasIndentChilds = false;
   boolean isSecondLine = true;
   ArrayList<Integer> endLocations = new ArrayList<Integer>();
   int indexNextLine = skipLine(indexStartLine);
   while (myParser.currentToken != SGLR.EOF
       && 0 <= indexNextLine
       && indexNextLine <= getHistory().getIndexLastLine()) {
     IndentInfo nextLine = getHistory().getLine(indexNextLine);
     // FIXME: get nextLine may be null
     int indentSkipPosition = nextLine.getIndentValue();
     indentShift shift = calculateShift(indentStartLine, indentSkipPosition);
     switch (shift) {
       case DEDENT:
         endLocations.add(indexNextLine);
         return endLocations;
       case INDENT:
         hasIndentChilds = true;
         break;
       case SAME_INDENT:
         if (hasIndentChilds && isScopeClosingLine(indexNextLine)) {
           indexNextLine = skipLine(indexNextLine);
           endLocations.add(indexNextLine);
           return endLocations;
         }
         if ((!isSecondLine || !isScopeOpeningLine(indexNextLine))
             && !isSeparatorStartingLine(indexNextLine)) {
           endLocations.add(indexNextLine);
           return endLocations;
         }
         break;
       default:
         break;
     }
     isSecondLine = false;
     indexNextLine = skipLine(indexNextLine);
   }
   endLocations.add(getHistory().getIndexLastLine()); // EOF
   return endLocations;
 }
 private int findParentBegin(int startLineIndex) {
   int indentStartLine = separatorIndent(startLineIndex);
   int indexHistoryLines = startLineIndex;
   while (indexHistoryLines > 0) {
     indexHistoryLines -= 1;
     int indentSkipPosition = separatorIndent(indexHistoryLines); // currentLine.getIndentValue();
     indentShift shift = calculateShift(indentStartLine, indentSkipPosition);
     if (shift == indentShift.DEDENT) {
       if (isScopeOpeningLine(indexHistoryLines)) {
         IndentInfo prevLine = getHistory().getLine(indexHistoryLines - 1);
         if ((!isScopeClosingLine(indexHistoryLines - 1))
             && calculateShift(indentSkipPosition, prevLine.getIndentValue())
                 == indentShift.SAME_INDENT) {
           return indexHistoryLines - 1;
         }
       }
       return indexHistoryLines;
     }
   }
   return 0; // SOF
 }
 private ArrayList<StructureSkipSuggestion> selectPrevRegion(int indexEnd) {
   ArrayList<StructureSkipSuggestion> prevRegions = new ArrayList<StructureSkipSuggestion>();
   boolean onClosing = isScopeClosingLine(indexEnd);
   int indexStart = findPreviousBegin(indexEnd, onClosing);
   if (onClosing) {
     if (indexEnd > 0) {
       if (isScopeClosingLine(indexEnd - 1)) prevRegions.addAll(selectPrevRegion(indexEnd - 1));
       else prevRegions.addAll(selectRegion(indexEnd - 1));
     }
     indexEnd++;
   }
   IndentInfo endSkip = IndentInfo.cloneIndentInfo(getHistory().getLine(indexEnd));
   if (indexStart < 0) return prevRegions;
   IndentInfo startSkip = IndentInfo.cloneIndentInfo(getHistory().getLine(indexStart));
   StructureSkipSuggestion previousRegion = new StructureSkipSuggestion();
   previousRegion.setSkipLocations(startSkip, endSkip, indexStart, indexEnd);
   prevRegions.add(previousRegion);
   addSeperatorIncludingRegion_Backwards(prevRegions, previousRegion);
   addSeparatorIncludingRegion_Forwards(prevRegions, previousRegion);
   return prevRegions;
 }
 private void addSeparatorIncludingRegion_Forwards(
     ArrayList<StructureSkipSuggestion> regions, StructureSkipSuggestion aRegion) {
   if (isSeparatorStartingLine(aRegion.getIndexHistoryEnd())) {
     IndentInfo startSkip = IndentInfo.cloneIndentInfo(aRegion.getStartSkip());
     IndentInfo endSkip = IndentInfo.cloneIndentInfo(aRegion.getEndSkip());
     int indentShift = separatorIndent(aRegion.getIndexHistoryEnd()) - endSkip.getIndentValue();
     endSkip.setTokensSeen(endSkip.getTokensSeen() + indentShift);
     StructureSkipSuggestion previousRegion3 = new StructureSkipSuggestion();
     previousRegion3.setSkipLocations(
         startSkip, endSkip, aRegion.getIndexHistoryStart(), aRegion.getIndexHistoryEnd());
     regions.add(previousRegion3);
   }
 }
 private String readLine(IndentInfo line) {
   int startTok = line.getTokensSeen();
   String lineContent = getHistory().readLine(startTok, myParser.currentInputStream);
   return lineContent;
 }