Index: pkg/compiler/lib/src/string_validator.dart |
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart |
deleted file mode 100644 |
index d967e44799ccca757a2ae93acca71b2888500869..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/string_validator.dart |
+++ /dev/null |
@@ -1,235 +0,0 @@ |
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-// Check the validity of string literals. |
- |
-library stringvalidator; |
- |
-import "dart:collection"; |
- |
-import "dart2jslib.dart"; |
-import "tree/tree.dart"; |
-import "util/characters.dart"; |
-import "scanner/scannerlib.dart" show Token; |
- |
-class StringValidator { |
- final DiagnosticListener listener; |
- |
- StringValidator(this.listener); |
- |
- DartString validateInterpolationPart(Token token, StringQuoting quoting, |
- {bool isFirst: false, |
- bool isLast: false}) { |
- String source = token.value; |
- int leftQuote = 0; |
- int rightQuote = 0; |
- if (isFirst) leftQuote = quoting.leftQuoteLength; |
- if (isLast) rightQuote = quoting.rightQuoteLength; |
- String content = copyWithoutQuotes(source, leftQuote, rightQuote); |
- return validateString(token, |
- token.charOffset + leftQuote, |
- content, |
- quoting); |
- } |
- |
- static StringQuoting quotingFromString(String sourceString) { |
- Iterator<int> source = sourceString.codeUnits.iterator; |
- bool raw = false; |
- int leftQuoteLength = 1; |
- source.moveNext(); |
- int quoteChar = source.current; |
- if (quoteChar == $r) { |
- raw = true; |
- source.moveNext(); |
- quoteChar = source.current; |
- } |
- assert(quoteChar == $SQ || quoteChar == $DQ); |
- // String has at least one quote. Check it if has three. |
- // If it only has two, the string must be an empty string literal, |
- // and end after the second quote. |
- bool multiline = false; |
- if (source.moveNext() && source.current == quoteChar && source.moveNext()) { |
- int code = source.current; |
- assert(code == quoteChar); // If not, there is a bug in the parser. |
- leftQuoteLength = 3; |
- |
- // Check if a multiline string starts with optional whitespace followed by |
- // a newline (CR, LF or CR+LF). |
- // We also accept if the these characters are escaped by a backslash. |
- int newLineLength = 1; |
- while (true) { |
- // Due to string-interpolations we are not guaranteed to see the |
- // trailing quoting characters. The invocations to `moveNext()` may |
- // therefore return false and the `current`-getter return `null`. The |
- // code does not need to handle this specially (as it will not find the |
- // newline characters). |
- source.moveNext(); |
- code = source.current; |
- if (code == $BACKSLASH) { |
- newLineLength++; |
- source.moveNext(); |
- code = source.current; |
- } |
- if (code == $TAB || code == $SPACE) { |
- newLineLength++; |
- continue; |
- } |
- if (code == $CR) { |
- if (source.moveNext() && source.current == $LF) { |
- newLineLength++; |
- } |
- leftQuoteLength += newLineLength; |
- } else if (code == $LF) { |
- leftQuoteLength += newLineLength; |
- } |
- break; |
- } |
- } |
- return StringQuoting.getQuoting(quoteChar, raw, leftQuoteLength); |
- } |
- |
- /** |
- * Return the string [string] witout its [initial] first and [terminal] last |
- * characters. This is intended to be used to remove quotes from string |
- * literals (including an initial 'r' for raw strings). |
- */ |
- String copyWithoutQuotes(String string, int initial, int terminal) { |
- assert(0 <= initial); |
- assert(0 <= terminal); |
- assert(initial + terminal <= string.length); |
- return string.substring(initial, string.length - terminal); |
- } |
- |
- void stringParseError(String message, Token token, int offset) { |
- listener.reportFatalError( |
- token, MessageKind.GENERIC, {'text': "$message @ $offset"}); |
- } |
- |
- /** |
- * Validates the escape sequences and special characters of a string literal. |
- * Returns a DartString if valid, and null if not. |
- */ |
- DartString validateString(Token token, |
- int startOffset, |
- String string, |
- StringQuoting quoting) { |
- // We need to check for invalid x and u escapes, for line |
- // terminators in non-multiline strings, and for invalid Unicode |
- // scalar values (either directly or as u-escape values). We also check |
- // for unpaired UTF-16 surrogates. |
- int length = 0; |
- int index = startOffset; |
- bool containsEscape = false; |
- bool previousWasLeadSurrogate = false; |
- bool invalidUtf16 = false; |
- var stringIter = string.codeUnits.iterator; |
- for(HasNextIterator<int> iter = new HasNextIterator(stringIter); |
- iter.hasNext; |
- length++) { |
- index++; |
- int code = iter.next(); |
- if (code == $BACKSLASH) { |
- if (quoting.raw) continue; |
- containsEscape = true; |
- if (!iter.hasNext) { |
- stringParseError("Incomplete escape sequence",token, index); |
- return null; |
- } |
- index++; |
- code = iter.next(); |
- if (code == $x) { |
- for (int i = 0; i < 2; i++) { |
- if (!iter.hasNext) { |
- stringParseError("Incomplete escape sequence", token, index); |
- return null; |
- } |
- index++; |
- code = iter.next(); |
- if (!isHexDigit(code)) { |
- stringParseError("Invalid character in escape sequence", |
- token, index); |
- return null; |
- } |
- } |
- // A two-byte hex escape can't generate an invalid value. |
- continue; |
- } else if (code == $u) { |
- int escapeStart = index - 1; |
- index++; |
- code = iter.hasNext ? iter.next() : 0; |
- int value = 0; |
- if (code == $OPEN_CURLY_BRACKET) { |
- // expect 1-6 hex digits. |
- int count = 0; |
- while (iter.hasNext) { |
- code = iter.next(); |
- index++; |
- if (code == $CLOSE_CURLY_BRACKET) { |
- break; |
- } |
- if (!isHexDigit(code)) { |
- stringParseError("Invalid character in escape sequence", |
- token, index); |
- return null; |
- } |
- count++; |
- value = value * 16 + hexDigitValue(code); |
- } |
- if (code != $CLOSE_CURLY_BRACKET || count == 0 || count > 6) { |
- int errorPosition = index - count; |
- if (count > 6) errorPosition += 6; |
- stringParseError("Invalid character in escape sequence", |
- token, errorPosition); |
- return null; |
- } |
- } else { |
- // Expect four hex digits, including the one just read. |
- for (int i = 0; i < 4; i++) { |
- if (i > 0) { |
- if (iter.hasNext) { |
- index++; |
- code = iter.next(); |
- } else { |
- code = 0; |
- } |
- } |
- if (!isHexDigit(code)) { |
- stringParseError("Invalid character in escape sequence", |
- token, index); |
- return null; |
- } |
- value = value * 16 + hexDigitValue(code); |
- } |
- } |
- code = value; |
- } |
- } |
- if (code >= 0x10000) length++; |
- // This handles both unescaped characters and the value of unicode |
- // escapes. |
- if (previousWasLeadSurrogate) { |
- if (!isUtf16TrailSurrogate(code)) { |
- invalidUtf16 = true; |
- break; |
- } |
- previousWasLeadSurrogate = false; |
- } else if (isUtf16LeadSurrogate(code)) { |
- previousWasLeadSurrogate = true; |
- } else if (!isUnicodeScalarValue(code)) { |
- invalidUtf16 = true; |
- break; |
- } |
- } |
- if (previousWasLeadSurrogate || invalidUtf16) { |
- stringParseError("Invalid Utf16 surrogate", token, index); |
- return null; |
- } |
- // String literal successfully validated. |
- if (quoting.raw || !containsEscape) { |
- // A string without escapes could just as well have been raw. |
- return new DartString.rawString(string, length); |
- } |
- return new DartString.escapedString(string, length); |
- } |
-} |