changeset 49146:e10490e39e62 raw-string-literal

0000000: Raw String Literals in javac
author jlaskey
date Thu, 15 Feb 2018 10:47:28 -0400
parents f8645e716519
children 452e6e327383
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
diffstat 4 files changed, 108 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Thu Feb 15 08:52:14 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Thu Feb 15 10:47:28 2018 -0400
@@ -181,7 +181,8 @@
         DIAMOND_WITH_ANONYMOUS_CLASS_CREATION(JDK9, Fragments.FeatureDiamondAndAnonClass, DiagKind.NORMAL),
         UNDERSCORE_IDENTIFIER(MIN, JDK8),
         PRIVATE_INTERFACE_METHODS(JDK9, Fragments.FeaturePrivateIntfMethods, DiagKind.PLURAL),
-        LOCAL_VARIABLE_TYPE_INFERENCE(JDK10);
+        LOCAL_VARIABLE_TYPE_INFERENCE(JDK10),
+        RAW_STRING_LITERALS(JDK10, Fragments.FeatureRawStringLiterals, DiagKind.PLURAL);
 
         enum DiagKind {
             NORMAL,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java	Thu Feb 15 08:52:14 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java	Thu Feb 15 10:47:28 2018 -0400
@@ -33,6 +33,7 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 
 import java.nio.CharBuffer;
+import java.util.Properties;
 
 import static com.sun.tools.javac.parser.Tokens.*;
 import static com.sun.tools.javac.util.LayoutCharacters.*;
@@ -138,6 +139,23 @@
         errPos = pos;
     }
 
+    /** Process line terminators in strings
+     */
+    private void scanLineTerminator(int pos) {
+        Assert.check(reader.ch == CR || reader.ch == LF);
+        if (reader.ch == CR) {
+            if (reader.peekChar() == LF) {
+                reader.scanChar();
+            } else {
+                reader.putChar('\n', true);
+            }
+            processLineTerminator(pos, reader.bp);
+        } else {
+            reader.putChar(true);
+            processLineTerminator(pos, reader.bp);
+        }
+    }
+
     /** Read next character in character or string literal and copy into sbuf.
      */
     private void scanLitChar(int pos) {
@@ -188,6 +206,17 @@
         }
     }
 
+    /** Read next character in raw string literal and copy into sbuf.
+     */
+    protected void scanRawStringLitChar(int pos, int repeat) {
+        if (reader.ch == '`' && reader.peekChar() == '`' && repeat == 0) {
+            reader.scanChar();
+            reader.putChar('`', true);
+        } else if (reader.bp != reader.buflen) {
+            reader.putChar(true);
+        }
+    }
+
     private void scanDigits(int pos, int digitRadix) {
         char saveCh;
         int savePos;
@@ -628,6 +657,17 @@
                     break loop;
                 case '\"':
                     reader.scanChar();
+                    /*
+                        // If multi-line double quoted strings are introduced,
+                        // replace the the next while statement with the following.
+                        while (reader.ch != '\"' && reader.bp < reader.buflen) {
+                            if (reader.ch == LF || reader.ch == CR) {
+                                scanLineTerminator(pos);
+                            } else {
+                                scanLitChar(pos);
+                            }
+                        }
+                    */
                     while (reader.ch != '\"' && reader.ch != CR && reader.ch != LF && reader.bp < reader.buflen)
                         scanLitChar(pos);
                     if (reader.ch == '\"') {
@@ -637,6 +677,40 @@
                         lexError(pos, Errors.UnclosedStrLit);
                     }
                     break loop;
+                case '`':
+                    checkSourceLevel(pos, Feature.RAW_STRING_LITERALS);
+                    if (reader.peekBack() != '`') {
+                        reader.scanChar();
+                        lexError(pos, Errors.IllegalChar("\\u0060 in raw string literal delimiter"));
+                        break loop;
+                    }
+                    boolean oldState = reader.setUnicodeConversion(false);
+                    int repeats = reader.skipRepeats();
+                    reader.scanChar();
+                    while (reader.bp < reader.buflen) {
+                        if (reader.ch == '`') {
+                            int count = reader.skipRepeats();
+                            if (repeats == count) {
+                                break;
+                            }
+                            for (int i = 0; i <= count; i++) {
+                                reader.putChar('`', false);
+                            }
+                            reader.scanChar();
+                        } else if (reader.ch == LF || reader.ch == CR) {
+                            scanLineTerminator(pos);
+                        } else {
+                            scanRawStringLitChar(pos, 0);
+                        }
+                    }
+                    reader.setUnicodeConversion(oldState);
+                    if (reader.ch == '`') {
+                        tk = TokenKind.STRINGLITERAL;
+                        reader.scanChar();
+                    } else {
+                        lexError(pos, Errors.UnclosedStrLit);
+                    }
+                    break loop;
                 default:
                     if (isSpecial(reader.ch)) {
                         scanOperator();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java	Thu Feb 15 08:52:14 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java	Thu Feb 15 10:47:28 2018 -0400
@@ -64,6 +64,10 @@
      */
     protected int unicodeConversionBp = -1;
 
+    /** Control conversion of unicode characters
+     */
+    protected boolean unicodeConversion = true;
+
     protected Log log;
     protected Names names;
 
@@ -152,11 +156,17 @@
         return new String(sbuf, 0, sp);
     }
 
+    protected boolean setUnicodeConversion(boolean newState) {
+        boolean oldState = unicodeConversion;
+        unicodeConversion = newState;
+        return oldState;
+    }
+
     /** Convert unicode escape; bp points to initial '\' character
      *  (Spec 3.3).
      */
     protected void convertUnicode() {
-        if (ch == '\\' && unicodeConversionBp != bp) {
+        if (ch == '\\' && unicodeConversion && unicodeConversionBp != bp ) {
             bp++; ch = buf[bp];
             if (ch == 'u') {
                 do {
@@ -252,6 +262,24 @@
         return buf[bp + 1];
     }
 
+    protected char peekBack() {
+        return buf[bp];
+    }
+
+    /**
+     * Skips consecutive occurrences of the current character, leaving bp positioned
+     * at the last occurrence. Returns the occurrence count.
+     */
+    protected int skipRepeats() {
+        int start = bp;
+        while (bp < buflen) {
+            if (buf[bp] != buf[bp + 1])
+                break;
+            bp++;
+        }
+        return bp - start;
+    }
+
     /**
      * Returns a copy of the input buffer, up to its inputLength.
      * Unicode escape sequences are not translated.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Feb 15 08:52:14 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Feb 15 10:47:28 2018 -0400
@@ -2708,6 +2708,9 @@
 compiler.misc.feature.private.intf.methods=\
     private interface methods
 
+compiler.misc.feature.raw.string.literals=\
+    raw string literals
+
 compiler.warn.underscore.as.identifier=\
     as of release 9, ''_'' is a keyword, and may not be used as an identifier