    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package escjava.translate;
    004
    005    import javafe.util.ClipPolicy;
    006    import escjava.ast.TagConstants;
    007
    008    public class AssocDeclClipPolicy extends ClipPolicy {
    009
    010      public boolean containsEndOfConstruct(/*@ non_null @*/ String s, int pos) {
    011        if (s.startsWith(TagConstants.toString(TagConstants.NON_NULL), pos) ||
    012            s.startsWith(TagConstants.toString(TagConstants.UNINITIALIZED), pos) ||
    013            (s.startsWith(TagConstants.toString(TagConstants.MONITORED), pos) &&
    014             !s.startsWith(TagConstants.toString(TagConstants.MONITORED_BY),
    015                           pos))) {
    016          return true;
    017        }
    018
    019        // look forward
    020        FORWARD:
    021        for (int i = pos; i < s.length(); i++) {
    022          char ch = s.charAt(i);
    023          // System.out.println("DEBUG:  FORWARD ch='" + ch + "'");
    024          if (ch == '\"') {
    025            // Find end of string literal.
    026            do {
    027              i = s.indexOf('\"', i+1);
    028              if (i == -1) {
    029                // Something's strange is going on; this should never happen.
    030                // End the forward search
    031                break FORWARD;
    032              }
    033              // check the character at i-1 for being a backslash
    034            } while (s.charAt(i-1) == '\\');
    035          } else if (ch == '\'') {
    036            // Find end of character literal
    037            // The following loop should never execute more than twice.
    038            do {
    039              i = s.indexOf('\'', i+1);
    040              if (i == -1) {
    041                // Something's strange is going on; this should never happen.
    042                // End the forward search
    043                break FORWARD;
    044              }
    045              // check the character at i-1 for being a backslash
    046            } while (s.charAt(i-1) == '\\');
    047          } else if (ch == '\\') {
    048            // escape character
    049            i++;  // This will skip over one of the escaped characters, but that's
    050                  // good enough even if there's more than one escaped character.
    051          } else if (ch == ';') {
    052            // This indicates the end of the pragma
    053            return true;
    054          } else if (s.startsWith("//", i)) {
    055            // The rest of the line is a comment, so we have not yet found the end
    056            // of the current construct.
    057            break FORWARD;
    058          } else if (s.startsWith("/*", i)) {
    059            int k = s.indexOf("*/", i+2);
    060            if (k == -1) {
    061              // This should never happen.
    062              break FORWARD;
    063            }
    064            // skip nested comment
    065            i = k+1 /* +1 as will be done by the 'for' loop */;
    066          } else if (s.startsWith("*/", i) || s.startsWith("</esc>", i)) {
    067            return true;
    068          }
    069        }
    070
    071        // look backward (but if we reach character 0, we have no hope, so let's
    072        // loop back only until 1; this also means that we can use i-1 as an index
    073        // inside the loop body)
    074        for (int i = pos; 1 <= --i; ) {
    075          char ch = s.charAt(i);
    076          // System.out.println("DEBUG:  BACKWARD ch='" + ch + "'");
    077          if (ch == '/') {
    078            if (s.charAt(i-1) == '/') {
    079              // the pragma ends at end-of-line
    080              return true;
    081            }
    082          } else if (ch == '\"') {
    083            // Search backwards for the beginning of the string literal.
    084            do {
    085              i = s.lastIndexOf('\"', i-1);
    086              if (i == -1) {
    087                // This should never happen.  Since things seem screwed up, let's just
    088                // return 'true', which will have the effect of not introducing an
    089                // ellipsis (which would probably just confuse the user even more).
    090                return true;
    091              }
    092            } while (0 < i && s.charAt(i-1) == '\\');
    093          } else if (ch == '\'') {
    094            // Search backwards for the beginning of the character literal.
    095            // The following loop should never execute more than twice.
    096            do {
    097              i = s.lastIndexOf('\'', i-1);
    098              if (i == -1) {
    099                // This should never happen.  Since things seem screwed up, let's just
    100                // return 'true', which will have the effect of not introducing an
    101                // ellipsis (which would probably just confuse the user even more).
    102                return true;
    103              }
    104            } while (0 < i && s.charAt(i-1) == '\\');
    105          } else if (s.startsWith("*/", i-1) ||
    106                     (2 <= i && s.startsWith("*/*", i-2))) {
    107            // This must be a nested /*...*/-comment (in the second case, it's
    108            // a nested comment followed by a "*"), which is legal only inside
    109            // a //-comment, so we might as well end our search now.
    110            return true;
    111          } else if (s.startsWith("/*", i-1)) {
    112            // We are now looking at either the start of the comment.
    113            // So, as far as we can tell, the construct may spill over
    114            // to the next line.
    115            return false;
    116          } else if (4 <= i && s.startsWith("<esc>", i-4)) {
    117            // The begin-comment marker must have been "/*", because if it
    118            // were "//" we would have found the "</esc>" in the forward loop
    119            // above.  So, as far as we can tell, the construct may spill over
    120            // to the next line.
    121            return false;
    122          }
    123        }
    124
    125        // We have been unable to determine that the construct ends on this line
    126        return false;
    127      }
    128    }