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    }