| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // Check the validity of string literals. | 5 // Check the validity of string literals. |
| 6 | 6 |
| 7 #library("stringvalidator"); | 7 #library("stringvalidator"); |
| 8 | 8 |
| 9 #import("leg.dart"); | 9 #import("leg.dart"); |
| 10 #import("scanner/scannerlib.dart"); | 10 #import("scanner/scannerlib.dart"); |
| 11 #import("tree/tree.dart"); | 11 #import("tree/tree.dart"); |
| 12 #import("elements/elements.dart"); | 12 #import("elements/elements.dart"); |
| 13 #import("util/characters.dart"); | 13 #import("util/characters.dart"); |
| 14 | 14 |
| 15 class StringValidator { | 15 class StringValidator { |
| 16 final DiagnosticListener listener; | 16 final DiagnosticListener listener; |
| 17 | 17 |
| 18 StringValidator(this.listener); | 18 StringValidator(this.listener); |
| 19 | 19 |
| 20 QuotedString validateQuotedString(Token token) { | 20 DartString validateQuotedString(Token token) { |
| 21 SourceString source = token.value; | 21 SourceString source = token.value; |
| 22 StringQuoting quoting = quotingFromString(source); | 22 StringQuoting quoting = quotingFromString(source); |
| 23 int leftQuote = quoting.leftQuoteLength; | 23 int leftQuote = quoting.leftQuoteLength; |
| 24 int rightQuote = quoting.rightQuoteLength; | 24 int rightQuote = quoting.rightQuoteLength; |
| 25 SourceString content = source.copyWithoutQuotes(leftQuote, rightQuote); | 25 SourceString content = source.copyWithoutQuotes(leftQuote, rightQuote); |
| 26 return validateString(token, | 26 return validateString(token, |
| 27 token.charOffset + leftQuote, | 27 token.charOffset + leftQuote, |
| 28 content, | 28 content, |
| 29 quoting); | 29 quoting); |
| 30 } | 30 } |
| 31 | 31 |
| 32 QuotedString validateInterpolationPart(Token token, StringQuoting quoting, | 32 DartString validateInterpolationPart(Token token, StringQuoting quoting, |
| 33 [bool isFirst = false, | 33 [bool isFirst = false, |
| 34 bool isLast = false]) { | 34 bool isLast = false]) { |
| 35 SourceString source = token.value; | 35 SourceString source = token.value; |
| 36 int leftQuote = 0; | 36 int leftQuote = 0; |
| 37 int rightQuote = 0; | 37 int rightQuote = 0; |
| 38 if (isFirst) leftQuote = quoting.leftQuoteLength; | 38 if (isFirst) leftQuote = quoting.leftQuoteLength; |
| 39 if (isLast) rightQuote = quoting.rightQuoteLength; | 39 if (isLast) rightQuote = quoting.rightQuoteLength; |
| 40 SourceString content = source.copyWithoutQuotes(leftQuote, rightQuote); | 40 SourceString content = source.copyWithoutQuotes(leftQuote, rightQuote); |
| 41 return validateString(token, | 41 return validateString(token, |
| 42 token.charOffset + leftQuote, | 42 token.charOffset + leftQuote, |
| 43 content, | 43 content, |
| 44 quoting); | 44 quoting); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 63 } | 63 } |
| 64 return StringQuoting.get(quoteChar, raw, multiline); | 64 return StringQuoting.get(quoteChar, raw, multiline); |
| 65 } | 65 } |
| 66 | 66 |
| 67 void stringParseError(String message, Token token, int offset) { | 67 void stringParseError(String message, Token token, int offset) { |
| 68 listener.cancel("$message @ $offset", token : token); | 68 listener.cancel("$message @ $offset", token : token); |
| 69 } | 69 } |
| 70 | 70 |
| 71 /** | 71 /** |
| 72 * Validates the escape sequences and special characters of a string literal. | 72 * Validates the escape sequences and special characters of a string literal. |
| 73 * Returns a QuotedString if valid, and null if not. | 73 * Returns a DartString if valid, and null if not. |
| 74 */ | 74 */ |
| 75 QuotedString validateString(Token token, | 75 DartString validateString(Token token, |
| 76 int startOffset, | 76 int startOffset, |
| 77 SourceString string, | 77 SourceString string, |
| 78 StringQuoting quoting) { | 78 StringQuoting quoting) { |
| 79 // We only need to check for invalid x and u escapes, for line | 79 // We only need to check for invalid x and u escapes, for line |
| 80 // terminators in non-multiline strings, and for invalid Unicode | 80 // terminators in non-multiline strings, and for invalid Unicode |
| 81 // scalar values (either directly or as u-escape values). | 81 // scalar values (either directly or as u-escape values). |
| 82 int length = 0; | 82 int length = 0; |
| 83 int index = startOffset; | 83 int index = startOffset; |
| 84 bool containsEscape = false; |
| 84 for(Iterator<int> iter = string.iterator(); iter.hasNext(); length++) { | 85 for(Iterator<int> iter = string.iterator(); iter.hasNext(); length++) { |
| 85 index++; | 86 index++; |
| 86 int code = iter.next(); | 87 int code = iter.next(); |
| 87 if (code === $BACKSLASH) { | 88 if (code === $BACKSLASH) { |
| 88 if (quoting.raw) continue; | 89 if (quoting.raw) continue; |
| 90 containsEscape = true; |
| 89 if (!iter.hasNext()) { | 91 if (!iter.hasNext()) { |
| 90 stringParseError("Incomplete escape sequence",token, index); | 92 stringParseError("Incomplete escape sequence",token, index); |
| 91 return null; | 93 return null; |
| 92 } | 94 } |
| 93 index++; | 95 index++; |
| 94 code = iter.next(); | 96 code = iter.next(); |
| 95 if (code === $x) { | 97 if (code === $x) { |
| 96 for (int i = 0; i < 2; i++) { | 98 for (int i = 0; i < 2; i++) { |
| 97 if (!iter.hasNext()) { | 99 if (!iter.hasNext()) { |
| 98 stringParseError("Incomplete escape sequence", token, index); | 100 stringParseError("Incomplete escape sequence", token, index); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 // This handles both unescaped characters and the value of unicode | 157 // This handles both unescaped characters and the value of unicode |
| 156 // escapes. | 158 // escapes. |
| 157 if (!isUnicodeScalarValue(code)) { | 159 if (!isUnicodeScalarValue(code)) { |
| 158 stringParseError( | 160 stringParseError( |
| 159 "Invalid Unicode scalar value U+${code.toRadixString(16)}", | 161 "Invalid Unicode scalar value U+${code.toRadixString(16)}", |
| 160 token, index); | 162 token, index); |
| 161 return null; | 163 return null; |
| 162 } | 164 } |
| 163 } | 165 } |
| 164 // String literal successfully validated. | 166 // String literal successfully validated. |
| 165 return new QuotedString(string, quoting, length); | 167 if (quoting.raw || !containsEscape) { |
| 168 // A string without escapes could just as well have been raw. |
| 169 return new DartString.rawString(string, length); |
| 170 } |
| 171 return new DartString.escapedString(string, length); |
| 166 } | 172 } |
| 167 } | 173 } |
| OLD | NEW |