Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 593   Methods: 18
NCLOC: 306   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ReducedModelBrace.java 70.8% 78% 83.3% 76.2%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.model.definitions.reducedmodel;
 38   
 39    import java.util.Stack;
 40   
 41    /** Keeps track of the true braces (i.e., "() {}[]"). This reduced sub-model is used to balance braces for both
 42    * indenting and highlighting purposes. For example, when the user's caret is immediately after a closing brace,
 43    * this allows the DefinitionsPane to produced a highlight extending from the closing brace to its match.
 44    * @version $Id: ReducedModelBrace.java 5437 2011-08-05 03:48:19Z rcartwright $
 45    * @author JavaPLT
 46    */
 47    public class ReducedModelBrace extends AbstractReducedModel {
 48   
 49    private volatile ReducedModelControl _parent; // contains the walker which is moved by moveWalkerGetState
 50   
 51  1582 public ReducedModelBrace(ReducedModelControl parent) {
 52  1582 super();
 53  1582 _parent = parent;
 54    }
 55   
 56  62498 public void insertChar(char ch) {
 57  62498 switch(ch) {
 58  670 case '{':
 59  632 case '}':
 60  43 case '[':
 61  38 case ']':
 62  733 case '(':
 63  726 case ')':
 64  2842 _insertBrace(String.valueOf(ch));
 65  2842 break;
 66  59656 default:
 67  59656 _insertGap(1);
 68  59656 break;
 69    }
 70    }
 71   
 72    /** Helper function for top level brace insert functions.
 73    * <OL>
 74    * <li> at Head: not special case
 75    * <li> at Tail: not special case
 76    * <li> between two things (offset is 0):
 77    * <ol>
 78    * <li> insert brace
 79    * <li> move next
 80    * <li> offset = 0
 81    * </ol>
 82    * <li> inside gap:
 83    * <ol>
 84    * <li> shrink gap to size of gap - offset.
 85    * <li> insert brace
 86    * <li> insert gap the size of offset.
 87    * <li> move next twice
 88    * <li> offset = 0
 89    * </ol>
 90    * <li> inside multiple char brace:
 91    * <ol>
 92    * <li> break
 93    * <li> insert brace
 94    * </ol>
 95    * </OL>
 96    * @param text the String type of the brace to insert
 97    */
 98  2842 private void _insertBrace(String text) {
 99  2813 if (_cursor.atStart() || _cursor.atEnd()) _cursor.insertNewBrace(text); // inserts brace and goes to next
 100  26 else if (current().isGap()) _cursor.insertBraceToGap(text);
 101  3 else _cursor.insertNewBrace(text);
 102    }
 103   
 104    /** Inserts a gap between the characters in a multiple character brace. However, since ReducedModelBrace doesn't keep
 105    * track of comment braces and escape sequences, we just throw an exception since the condition in insertGap
 106    * that spawns this method doesn't arise.
 107    */
 108  0 protected void insertGapBetweenMultiCharBrace(int length) {
 109  0 throw new RuntimeException("ReducedModelBrace does not keep track of multi-character braces.");
 110    }
 111   
 112    /** Updates ReducedModelBrace to reflect cursor movement. Negative values move left from the cursor, positive
 113    * values move right. All functionality has been refactored into TokenList. ASSUMES that count is within range.
 114    * @param count indicates the direction and magnitude of cursor movement
 115    */
 116  474470 public void move(int count) { _cursor.move(count); }
 117   
 118    /** Updates ReducedModelBrace to reflect text deletion. Negative values mean text left of the cursor, positive
 119    * values mean text to the right. All functionality has been refactored into TokenList. Assumes that count is
 120    * with range.
 121    */
 122  337 public void delete(int count) {
 123  0 if (count == 0) return;
 124  337 _cursor.delete(count);
 125  337 return;
 126    }
 127   
 128    /** If the current brace is a /, a *, a // or a \n, it's not matchable. This means it is ignored on balancing and
 129    * on next/prev brace finding. All other braces are matchable.
 130    */
 131  4072 private boolean _isCurrentBraceMatchable() { return _cursor.current().isMatchable(); }
 132   
 133  4065 public boolean isShadowed() { return _parent.isShadowed(); }
 134   
 135    /** Returns distance from current location of cursor to the location of the previous significant brace including
 136    * opening comment braces (but not closing ones since they are not "FREE"). For example,
 137    * given "(...|)" where | signifies the cursor, previousBrace returns 4 because it goes to the position preceding the (.
 138    * Given "* /|*", it returns 1 (the distance to the position of this brace) since you're in the middle of it and going
 139    * backward finds it.
 140    */
 141  0 public int previousBrace() {
 142  0 int relDistance;
 143  0 int dist = 0;
 144  0 resetWalkerLocationToCursor(); //reset the interface to the comment model
 145   
 146  0 TokenList.Iterator copyCursor = _cursor.copy();
 147  0 if (! copyCursor.atStart()) copyCursor.prev();
 148   
 149  0 if (copyCursor.atStart()) {
 150  0 copyCursor.dispose();
 151  0 return -1;
 152    }
 153   
 154    //initialize the size.
 155  0 dist += _cursor.getBlockOffset();
 156  0 relDistance = dist;
 157   
 158    // if we're in the middle of the first brace element, we're not going to find any previous braces
 159   
 160  0 while (! copyCursor.atStart()) {
 161  0 if (! copyCursor.current().isGap()) {
 162  0 if (moveWalkerGetState(-relDistance) == FREE) {
 163  0 copyCursor.dispose();
 164  0 return dist + copyCursor.current().getSize();
 165    }
 166  0 relDistance = 0;
 167    }
 168   
 169  0 dist += copyCursor.current().getSize();
 170  0 relDistance += copyCursor.current().getSize();
 171  0 copyCursor.prev();
 172    }
 173  0 copyCursor.dispose();
 174  0 return -1;
 175    }
 176   
 177    /** Determines the distance to the location before the next open brace. For example, |...( where | is the cursor,
 178    * returns 3 since it is 3 moves to the position preceding the (. NOTE: /|* returns the next brace. It does not
 179    * return this brace because you are past it.
 180    */
 181  0 public int nextBrace() {
 182  0 int relDistance = 0;
 183  0 int dist = 0;
 184  0 TokenList.Iterator copyCursor = _cursor.copy();
 185   
 186  0 resetWalkerLocationToCursor();
 187   
 188  0 if (copyCursor.atStart()) copyCursor.next();
 189  0 int offset = getBlockOffset();
 190  0 if (offset > 0) {
 191  0 dist = copyCursor.current().getSize() - offset;
 192  0 relDistance = dist;
 193  0 copyCursor.next();
 194    }
 195    // there are no braces on the last brace element - it's empty
 196  0 while (! copyCursor.atEnd()) {
 197  0 if (! copyCursor.current().isGap()) {
 198  0 if (moveWalkerGetState(relDistance) == FREE) {
 199  0 copyCursor.dispose();
 200  0 return dist;
 201    }
 202  0 relDistance = 0;
 203    }
 204  0 relDistance += copyCursor.current().getSize();
 205  0 dist += copyCursor.current().getSize();
 206  0 copyCursor.next();
 207    }
 208  0 copyCursor.dispose();
 209  0 return -1;
 210    }
 211   
 212    /** If the current ReducedToken is an open significant brace and the offset is 0 (i.e., if we're immediately left of
 213    * said brace), push the current Brace onto a Stack and iterate forwards, keeping track of the distance covered.
 214    * - For every closed significant Brace, if it matches the top of the Stack, pop the Stack. Increase the distance
 215    * by the size of the Brace. If the Stack is Empty, we have a balance. Return distance. If the closed Brace does
 216    * not match the top of the Stack, return -1; We have an unmatched open Brace at the top of the Stack.
 217    * - For every open significant Brace, push onto the Stack. Increase distance by size of the Brace, continue.
 218    * - Anything else, increase distance by size of the ReducedToken, continue.
 219    */
 220  3982 public int balanceForward() {
 221    // System.err.println("-------------------------------------------");
 222  3982 resetWalkerLocationToCursor();
 223    // System.err.println("Balancing forward with iterator cursor at " + absOffset() + " and walker at " + _parent.walkerOffset());
 224   
 225  3982 Stack<Brace> braceStack = new Stack<Brace>();
 226  3982 TokenList.Iterator iter = _cursor.copy();
 227   
 228  3982 if (! openBraceImmediatelyLeft() || isShadowed()) {
 229    // System.err.println("openBraceImmediatelyLeft(): " + openBraceImmediatelyLeft());
 230  8 iter.dispose();
 231    // System.err.println("! atStart, atFirstItem, or no closed brace");
 232    // System.err.println("balanceForward immediately aborted; returning -1");
 233  8 return -1;
 234    }
 235   
 236  3974 iter.prev();
 237  3974 ReducedToken curToken = iter.current();
 238   
 239  3974 assert curToken instanceof Brace; // In fact, it is a significant matchable open brace.
 240   
 241    // int openBraceDistance = - curToken.getSize();
 242   
 243    // moveWalkerGetState(openBraceDistance);
 244  3974 braceStack.push((Brace) curToken);
 245  3974 iter.next(); // undoes iter.prev() above
 246    // moveWalkerGetState(-openBraceDistance);
 247   
 248  3974 int relDistance = 0; // distance from iter position to walker position
 249  3974 int distance = 0; // distance from _cursor position to iter position
 250   
 251    /* Loop until either:
 252    * (i) we get a match and the stack is empty (success);
 253    * (ii) we reach the end of a file and haven't found a match and abort; or
 254    * (iii) we reach a close brace that doesn't have a match and abort.
 255    */
 256  3974 while (! iter.atEnd() && ! braceStack.isEmpty()) {
 257  7430 curToken = iter.current(); // a ReducedToken is either a Gap or a Brace
 258  7430 if (! curToken.isGap()) { // curToken is a Brace
 259  5909 Brace curBrace = (Brace) curToken;
 260  5909 ReducedModelState curBraceState = moveWalkerGetState(relDistance); // walker moves right
 261  5909 relDistance = 0;
 262    // System.err.println("curBrace = " + curBrace + "curBraceState = " + curBraceState);
 263    // System.err.println("Walker is now at offset " + _parent.walkerOffset() + " distance = " + distance);
 264  5909 if (curBraceState == FREE && ! curToken.isCommentStart()) { // not shadowed
 265    // System.err.println(curBrace + " is not shadowed");
 266    // check for closed brace
 267  5698 if (curBrace.isClosedBrace()) {
 268    // System.err.println(curBrace + " is CLOSED at distance " + distance);
 269  4836 Brace popped = braceStack.pop();
 270  4836 if (! curBrace.isMatch(popped)) {
 271  1 iter.dispose();
 272    // System.err.println("! encountered closed brace that didn't match");
 273    // System.err.println("! encountered closed brace " + curBrace + " that didn't match; returning -1");
 274  1 return -1;
 275    }
 276    }
 277    // otherwise, this must be an open brace
 278    else {
 279  862 braceStack.push(curBrace);
 280    // System.err.println(curBrace + " pushed on stack");
 281    }
 282    }
 283    // else System.err.println(curToken + " at distance " + distance + " is shadowed");
 284    }
 285    // increment distances of size of current token
 286  7429 int size = curToken.getSize();
 287  7429 distance += size;
 288  7429 relDistance += size;
 289    // System.err.println("distance " + distance + " was incremented by " + size);
 290   
 291  7429 iter.next();
 292    }
 293   
 294    // check if we exited because of failure
 295  3973 if (! braceStack.isEmpty()) {
 296  0 iter.dispose();
 297    // System.err.println("Unmatched braces in stack: balancebackward returning -1");
 298    // System.err.println("! ran to end of file. distance: " + distance);
 299  0 return -1;
 300    }
 301    // success
 302    else {
 303  3973 iter.dispose();
 304    // System.err.println("balancebackward returning " + distance);
 305  3973 return distance;
 306    }
 307    }
 308   
 309    // /** This is no longer used internally -- highlight is always started on left. */
 310    // public boolean openBraceImmediatelyRight() {
 311    // if (_cursor.atEnd()) {
 312    // return false;
 313    // }
 314    // else {
 315    // return ((_cursor.getBlockOffset() == 0) && _cursor.current().isOpen() &&
 316    // _isCurrentBraceMatchable());
 317    // }
 318    // }
 319   
 320  4004 public boolean openBraceImmediatelyLeft() {
 321  15 if (_cursor.atStart() || _cursor.atFirstItem()) return false;
 322    else {
 323  3989 int offset = getBlockOffset();
 324  3989 prev(); // does not affect offset
 325  3989 assert offset == getBlockOffset();
 326    // System.err.println(" + openBraceImmediatelyLeft() {");
 327    // System.err.println(" getBlockOffset(): " + getBlockOffset());
 328    // System.err.println(" current().isOpen(): " + current().isOpen());
 329    // System.err.println(" _isCurrentBraceMatchable(): " + _isCurrentBraceMatchable());
 330    // System.err.println(" }");
 331   
 332  3989 boolean isLeft = (getBlockOffset() == 0 && current().isOpen() && _isCurrentBraceMatchable());
 333    // System.err.println("In openBraceLeft, token to left: " + _cursor);
 334  3989 next();
 335  3989 return isLeft;
 336    }
 337    }
 338   
 339  116 public boolean closedBraceImmediatelyLeft() {
 340  15 if (_cursor.atStart() || _cursor.atFirstItem()) return false;
 341    else {
 342  101 int offset = getBlockOffset();
 343  101 prev(); // does not affect block offset
 344  101 assert offset == getBlockOffset();
 345    // System.err.println(" + closedBraceImmediatelyLeft() {");
 346    // System.err.println(" getBlockOffset(): " + getBlockOffset());
 347    // System.err.println(" current().isClosed(): " + _current().isClosed());
 348    // System.err.println(" _isCurrentBraceMatchable(): " + _isCurrentBraceMatchable());
 349    // System.err.println(" }");
 350   
 351  101 boolean isLeft = (offset == 0 && current().isClosed() && _isCurrentBraceMatchable());
 352    // System.err.println("In closedBraceLeft, token to left: " + _cursor);
 353  101 next(); // restore current token
 354  101 return isLeft;
 355    }
 356    }
 357   
 358    /* If the previous ReducedToken is a closed significant brace, offset is 0 (i.e., if we're immediately right of said
 359    * brace), push the previous Brace onto a Stack and iterate backwards, keeping track of the distance covered.
 360    * - For every open significant Brace, if it matches the top of the Stack, pop the Stack. Increase the distance by
 361    * the size of the Brace. If the Stack is Empty, we have a balance. Return distance. If the open Brace does not
 362    * match the top of the Stack, return -1; We have an unmatched closed Brace at the top of the Stack.
 363    * - For every closed significant Brace, push onto the Stack. Increase distance by size of the Brace, continue.
 364    * - Anything else, increase distance by size of the ReducedToken, continue.
 365    */
 366  94 public int balanceBackward() {
 367    // System.err.println("-------------------------------------------");
 368   
 369  94 Stack<Brace> braceStack = new Stack<Brace>();
 370  94 TokenList.Iterator iter = _cursor.copy();
 371  94 resetWalkerLocationToCursor(); // _walker aligned to _cursor
 372    // System.err.println("Balancing backward with iterator cursor at " + absOffset() + " and walker at " + _parent.walkerOffset());
 373   
 374  94 if (! closedBraceImmediatelyLeft() || isShadowed()) {
 375    // System.err.println("closedBraceImmediatelyLeft(): " + closedBraceImmediatelyLeft());
 376  4 iter.dispose();
 377    // System.err.println("balanceBackward immediately aborted; returning -1");
 378  4 return -1;
 379    }
 380   
 381  90 int relDistance = 0; // distance from iter position to walker position
 382  90 int distance = 0; // distance from iter position to _cursor postion
 383   
 384    // move one token left, changing iter but not walker
 385  90 iter.prev();
 386  90 assert iter.current() instanceof Brace; // In fact, it is a significant closed brace.
 387   
 388    /* We loop until:
 389    * (i) we get a match and the stack is empty and report success
 390    * (ii) we reach the start of a file and haven't found a match and aborrt
 391    * (iii) we reach an open brace that doesn't have a match and abort
 392    */
 393  90 do {
 394  493 ReducedToken curToken = iter.current();
 395  493 int size = curToken.getSize();
 396  493 distance += size;
 397  493 relDistance += size;
 398    // System.err.println("distance " + distance + " was incremented by " + size);
 399   
 400  493 if (! curToken.isGap()) { // curToken is a Brace
 401  340 Brace curBrace = (Brace) curToken;
 402  340 ReducedModelState curBraceState = moveWalkerGetState(- relDistance); // walker moves left
 403  340 relDistance = 0;
 404    // System.err.println("curBrace = " + curBrace + "curBraceState = " + curBraceState);
 405    // System.err.println("Walker is now at offset " + _parent.walkerOffset() + " distance = " + distance);
 406  340 if (curBraceState == FREE && ! curToken.isCommentStart()) { // curBrace NOT shadowed
 407    // System.err.println(curBrace + " is not shadowed");
 408  335 if (curBrace.isOpenBrace()) {
 409    // System.err.println(curBrace + " is OPEN at distance " + distance);
 410  162 Brace popped = braceStack.pop();
 411  162 if (! curBrace.isMatch(popped)) {
 412  6 iter.dispose();
 413    // System.err.println("! encountered open brace " + curBrace + " that didn't match; returning -1");
 414  6 return -1;
 415    }
 416    }
 417    else { // curBrace is closed
 418    // System.err.println(curBrace + " pushed on stack");
 419  173 braceStack.push(curBrace);
 420    }
 421    }
 422    }
 423    // else System.err.println(curToken + " at distance " + distance + " is shadowed");
 424  487 iter.prev();
 425    }
 426  487 while (! iter.atStart() && ! braceStack.isEmpty());
 427   
 428   
 429    // test to see if we exited without a match
 430  84 if (! braceStack.isEmpty()) {
 431  1 iter.dispose();
 432    // System.err.println("! ran to end of brace stack");
 433    // System.err.println("Unmatched braces in stack: balancebackward returning -1");
 434  1 return -1;
 435    }
 436    // success
 437    else {
 438  83 iter.dispose();
 439    // System.err.println("balancebackward returning " + distance);
 440  83 return distance;
 441    }
 442    }
 443   
 444  7738 protected ReducedModelState moveWalkerGetState(int relDistance) { return _parent.moveWalkerGetState(relDistance); }
 445   
 446  5251 protected void resetWalkerLocationToCursor() { _parent.resetLocation(); }
 447   
 448    /** Determines the brace (type and distance) enclosing the beginning of the current line (except the first line). The
 449    * matching brace obviously must appear on the preceding line or before. To find the enclosing brace one must first
 450    * move past this newline. If there is not a line enclosing brace, returns BraceInfo.NULL. Usually called when
 451    * distToStart() = 0.
 452    */
 453  821 public BraceInfo _getLineEnclosingBrace() {
 454  821 Stack<Brace> braceStack = new Stack<Brace>();
 455  821 TokenList.Iterator iter = _cursor.copy();
 456  821 resetWalkerLocationToCursor(); // Why not use _parent._rmc._cursor instead of _parent._rmc._walker?
 457    // this is the distance to front edge of the preceding newline.
 458  821 final int distToStart = _parent.getDistToStart();
 459    // System.err.println("_getLineEnclosingBrace.distToStart = " + distToStart);
 460   
 461  821 if (distToStart == -1) {
 462  214 iter.dispose();
 463  214 return BraceInfo.NULL;
 464    }
 465   
 466  607 int relDistance = distToStart + 1; // distance to end of preceding line
 467  607 int distance = 1; // distance from right edge of newline
 468   
 469    // move to the proper location, then add the rest of the block and go to the previous.
 470  607 iter.move(-relDistance);
 471    // System.err.println("After moving to start, reduced model = " + _parent.simpleString());
 472  607 final int offset = iter.getBlockOffset();
 473  607 relDistance += offset;
 474  607 distance += offset;
 475   
 476  607 if (iter.atStart() || iter.atFirstItem()) { // no preceding brace exists
 477  66 iter.dispose();
 478  66 return BraceInfo.NULL;
 479    }
 480   
 481  541 iter.prev(); // move to reduced token preceding the newline.
 482   
 483   
 484  541 String braceType;
 485   
 486    // either we get a match and the stack is empty
 487    // or we reach the start of a file and haven't found a match
 488    // or we have a open brace that doesn't have a match,
 489    // so we abort
 490  541 while (! iter.atStart()) {
 491   
 492  1983 ReducedToken curToken = iter.current();
 493  1983 int size = curToken.getSize();
 494  1983 distance += size;
 495    // System.err.println("Adding " + size + " to dist for token " + curToken);
 496  1983 relDistance += size;
 497   
 498  1983 if (! curToken.isGap()) {
 499   
 500  1335 Brace curBrace = (Brace) curToken;
 501   
 502  1335 if (moveWalkerGetState(-relDistance) == FREE && ! curToken.isCommentStart()) {
 503    // open
 504  1277 if (curBrace.isOpenBrace()) {
 505  878 if (braceStack.isEmpty()) {
 506  492 braceType = curBrace.getType();
 507    // distance to brace == distance;
 508  492 iter.dispose();
 509  492 return new BraceInfo(braceType, distance);
 510    }
 511  386 Brace popped = braceStack.pop();
 512  386 if (! curBrace.isMatch(popped)) {
 513  8 iter.dispose();
 514  8 return BraceInfo.NULL;
 515    }
 516    }
 517    // closed
 518  399 else braceStack.push(curBrace);
 519    }
 520  835 relDistance = 0;
 521    }
 522    // no matter what, we always want to increase the distance
 523    // by the size of the token we have just gone over
 524  1483 iter.prev();
 525    }
 526   
 527    // Enclosing brace not found
 528  41 iter.dispose();
 529  41 return BraceInfo.NULL;
 530    }
 531   
 532    /** Determines the brace enclosing the current location. */
 533  354 protected BraceInfo _getEnclosingBrace() {
 534  354 Stack<Brace> braceStack = new Stack<Brace>();
 535  354 TokenList.Iterator iter = _cursor.copy();
 536  354 resetWalkerLocationToCursor();
 537  354 int relDistance = 0;
 538  354 int distance = relDistance;
 539   
 540    // Move to the proper location, then add the rest of the block and go to the previous.
 541   
 542  354 int offset = iter.getBlockOffset();
 543  354 relDistance += offset;
 544  354 distance += offset;
 545   
 546  354 if (iter.atStart() || iter.atFirstItem()) {
 547  255 iter.dispose();
 548  255 return BraceInfo.NULL;
 549    }
 550   
 551  99 iter.prev();
 552   
 553  99 String braceType;
 554   
 555    // either we get a match and the stack is empty or we reach the start of a file and haven't found a match
 556    // or we have a open brace that doesn't have a match, so we abort
 557  99 while (! iter.atStart()) {
 558   
 559  239 ReducedToken curToken = iter.current();
 560  239 int size = curToken.getSize();
 561  239 distance += size;
 562  239 relDistance += size;
 563   
 564  239 if (! curToken.isGap()) {
 565  154 Brace curBrace = (Brace) curToken;
 566  154 if (moveWalkerGetState(-relDistance) == FREE && ! curToken.isCommentStart()) {
 567    // open
 568  154 if (curBrace.isOpenBrace()) {
 569  119 if (braceStack.isEmpty()) {
 570  84 braceType = curBrace.getType();
 571  84 iter.dispose();
 572  84 return new BraceInfo(braceType, distance);
 573    }
 574  35 Brace popped = braceStack.pop();
 575  35 if (! curBrace.isMatch(popped)) {
 576  0 iter.dispose();
 577  0 return BraceInfo.NULL;
 578    }
 579    }
 580    // closed
 581  35 else braceStack.push(curBrace);
 582    }
 583  70 relDistance = 0;
 584    }
 585    // no matter what, we always want to increase the distance
 586    // by the size of the token we have just gone over
 587  155 iter.prev();
 588    }
 589   
 590  15 iter.dispose();
 591  15 return BraceInfo.NULL;
 592    }
 593    }