private void loop()

in tools/query_breakdown/src/main/java/com/google/bigquery/QueryBreakdown.java [128:210]


  private void loop(String inputQuery, int replacementLimit, Node parent, int depth,
      LocationTracker locationTracker) {
    // termination for branch if it is deeper than the current solution
    if (depth > minimumUnparseableComp) {
      return;
    }
    try {
      // parses the query
      parser.parseQuery(inputQuery);
    } catch (SqlParseException e) {
      /* generates new queries through deletion and replacement */
      SqlParserPos pos = e.getPos();

      // if statement checks for EOF and validator
      if ((pos.getLineNum() != 0 && pos.getColumnNum() != 0)
          && !(e.getCause().toString().contains("Encountered \"<EOF>\""))
          && !(e.getCause().toString().contains("Encountered: <EOF>"))
          && !e.getCause().toString().contains("SqlValidatorException")) {
        // gets the error location in the original query
        Pair originalStart =
            locationTracker.getOriginalPosition(pos.getLineNum(), pos.getColumnNum());
        Pair originalEnd =
            locationTracker.getOriginalPosition(pos.getEndLineNum(), pos.getEndColumnNum());

        /* deletion: gets the new query, creates a node, and calls the loop again */
        // gets the new query
        String deletionQuery = deletion(inputQuery, pos.getLineNum(), pos.getColumnNum(),
            pos.getEndLineNum(), pos.getEndColumnNum());

        // updates the location tracker to reflect the deletion
        LocationTracker deletedLt = locationTracker.delete
            (pos.getLineNum(), pos.getColumnNum(), pos.getEndLineNum(), pos.getEndColumnNum());

        // counts number of characters deleted keeping in mind multi-line new line addition
        int deletionNumber = (pos.getLineNum() == pos.getEndLineNum()) ? inputQuery.length() -
            deletionQuery.length() : inputQuery.length() - deletionQuery.length() + 1;

        // creates a node for this deletion
        Node deletionNode = new Node(parent, originalStart.getX(), originalStart.getY(),
            originalEnd.getX(), originalEnd.getY(), deletionNumber);

        // calls the loop again
        loop(deletionQuery, replacementLimit, deletionNode, depth + 1, deletedLt);

        /* replacement: gets the new queries, creates nodes, and calls the loop for each of them */
        ArrayList<ReplacedComponent> replacementQueries = replacement(inputQuery, replacementLimit,
            pos.getLineNum(), pos.getColumnNum(), pos.getEndLineNum(), pos.getEndColumnNum(),
            e.getExpectedTokenNames());

        // recursively loops through the new queries
        for (ReplacedComponent r: replacementQueries) {
          // updates the location tracker to reflect the replacement
          LocationTracker replacedLt = locationTracker.replace(pos.getLineNum(), pos.getColumnNum(),
              pos.getEndLineNum(), pos.getEndColumnNum(), r.getOriginal(), r.getReplacement());

          // creates the node
          Node replacementNode = new Node(parent, originalStart.getX(), originalStart.getY(),
              originalEnd.getX(), originalEnd.getY(), r.getOriginal(), r.getReplacement(),
              r.getOriginal().length());

          // calls the loop again
          loop(r.getQuery(), replacementLimit, replacementNode, depth + 1, replacedLt);
        }

        /* termination to end the loop if the instance was not a full run through the query.
        In other words, it ensures that the termination condition is not hit on the way back
        up the tree */
        return;
      }
    } catch (Exception e) {
      /* this is boiler plate code when a different exception is thrown from using
         a different parser
       */
      return;
    }

    // termination condition: if the parsing doesn't throw exceptions, then the leaf is reached
    if (depth < minimumUnparseableComp) {
      minimumUnparseableComp = depth;
      solution = parent;
      finalString = inputQuery;
    }
  }