langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java
changeset 33362 65ec6de1d6b4
child 34752 9c262a013456
equal deleted inserted replaced
33361:1c96344ecd49 33362:65ec6de1d6b4
       
     1 /*
       
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 package jdk.jshell;
       
    26 
       
    27 import java.util.Set;
       
    28 import java.util.stream.Collectors;
       
    29 import java.util.stream.Stream;
       
    30 
       
    31 /**
       
    32  * Within a String, mask code comments and ignored modifiers (within context).
       
    33  *
       
    34  * @author Robert Field
       
    35  */
       
    36 class MaskCommentsAndModifiers {
       
    37 
       
    38     private final static Set<String> IGNORED_MODIFERS =
       
    39             Stream.of( "public", "protected", "private", "static", "final" )
       
    40                     .collect( Collectors.toSet() );
       
    41 
       
    42     private final StringBuilder sbCleared = new StringBuilder();
       
    43     private final StringBuilder sbMask = new StringBuilder();
       
    44     private final String str;
       
    45     private final int length;
       
    46     private final boolean maskModifiers;
       
    47     private int next = 0;
       
    48     private boolean wasMasked = false;
       
    49     private boolean inside = false;
       
    50 
       
    51     @SuppressWarnings("empty-statement")
       
    52     public MaskCommentsAndModifiers(String s, boolean maskModifiers) {
       
    53         this.str = s;
       
    54         this.length = s.length();
       
    55         this.maskModifiers = maskModifiers;
       
    56         do { } while (next());
       
    57     }
       
    58 
       
    59     public String cleared() {
       
    60         return sbCleared.toString();
       
    61     }
       
    62 
       
    63     public String mask() {
       
    64         return sbMask.toString();
       
    65     }
       
    66 
       
    67     public boolean wasMasked() {
       
    68         return wasMasked;
       
    69     }
       
    70 
       
    71     /**
       
    72      * Read the next character
       
    73      */
       
    74     private int read() {
       
    75         if (next >= length) {
       
    76             return -1;
       
    77         }
       
    78         return str.charAt(next++);
       
    79     }
       
    80 
       
    81     private void write(StringBuilder sb, int ch) {
       
    82         sb.append((char)ch);
       
    83     }
       
    84 
       
    85     private void write(int ch) {
       
    86         write(sbCleared, ch);
       
    87         write(sbMask, Character.isWhitespace(ch) ? ch : ' ');
       
    88     }
       
    89 
       
    90     private void writeMask(int ch) {
       
    91         wasMasked = true;
       
    92         write(sbMask, ch);
       
    93         write(sbCleared, Character.isWhitespace(ch) ? ch : ' ');
       
    94     }
       
    95 
       
    96     private void write(CharSequence s) {
       
    97         for (int cp : s.chars().toArray()) {
       
    98             write(cp);
       
    99         }
       
   100     }
       
   101 
       
   102     private void writeMask(CharSequence s) {
       
   103         for (int cp : s.chars().toArray()) {
       
   104             writeMask(cp);
       
   105         }
       
   106     }
       
   107 
       
   108     private boolean next() {
       
   109         return next(read());
       
   110     }
       
   111 
       
   112     private boolean next(int c) {
       
   113         if (c < 0) {
       
   114             return false;
       
   115         }
       
   116 
       
   117         if (c == '\'' || c == '"') {
       
   118             inside = true;
       
   119             write(c);
       
   120             int match = c;
       
   121             c = read();
       
   122             while (c != match) {
       
   123                 if (c < 0) {
       
   124                     return false;
       
   125                 }
       
   126                 if (c == '\n' || c == '\r') {
       
   127                     write(c);
       
   128                     return true;
       
   129                 }
       
   130                 if (c == '\\') {
       
   131                     write(c);
       
   132                     c = read();
       
   133                 }
       
   134                 write(c);
       
   135                 c = read();
       
   136             }
       
   137             write(c);
       
   138             return true;
       
   139         }
       
   140 
       
   141         if (c == '/') {
       
   142             c = read();
       
   143             if (c == '*') {
       
   144                 writeMask('/');
       
   145                 writeMask(c);
       
   146                 int prevc = 0;
       
   147                 while ((c = read()) != '/' || prevc != '*') {
       
   148                     if (c < 0) {
       
   149                         return false;
       
   150                     }
       
   151                     writeMask(c);
       
   152                     prevc = c;
       
   153                 }
       
   154                 writeMask(c);
       
   155                 return true;
       
   156             } else if (c == '/') {
       
   157                 writeMask('/');
       
   158                 writeMask(c);
       
   159                 while ((c = read()) != '\n' && c != '\r') {
       
   160                     if (c < 0) {
       
   161                         return false;
       
   162                     }
       
   163                     writeMask(c);
       
   164                 }
       
   165                 writeMask(c);
       
   166                 return true;
       
   167             } else {
       
   168                 inside = true;
       
   169                 write('/');
       
   170                 // read character falls through
       
   171             }
       
   172         }
       
   173 
       
   174         if (Character.isJavaIdentifierStart(c)) {
       
   175             if (maskModifiers && !inside) {
       
   176                 StringBuilder sb = new StringBuilder();
       
   177                 do {
       
   178                     write(sb, c);
       
   179                     c = read();
       
   180                 } while (Character.isJavaIdentifierPart(c));
       
   181                 String id = sb.toString();
       
   182                 if (IGNORED_MODIFERS.contains(id)) {
       
   183                     writeMask(sb);
       
   184                 } else {
       
   185                     write(sb);
       
   186                     if (id.equals("import")) {
       
   187                         inside = true;
       
   188                     }
       
   189                 }
       
   190                 return next(c); // recurse to handle left-over character
       
   191             }
       
   192         } else if (!Character.isWhitespace(c)) {
       
   193             inside = true;
       
   194         }
       
   195 
       
   196         if (c < 0) {
       
   197             return false;
       
   198         }
       
   199         write(c);
       
   200         return true;
       
   201     }
       
   202 }