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 "dart2jslib.dart"; | 9 import "dart2jslib.dart"; |
10 import "tree/tree.dart"; | 10 import "tree/tree.dart"; |
(...skipping 27 matching lines...) Expand all Loading... |
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); |
45 } | 45 } |
46 | 46 |
47 static StringQuoting quotingFromString(SourceString sourceString) { | 47 static StringQuoting quotingFromString(SourceString sourceString) { |
48 Iterator<int> source = sourceString.iterator(); | 48 Iterator<int> source = sourceString.iterator; |
49 bool raw = false; | 49 bool raw = false; |
50 int quoteLength = 1; | 50 int quoteLength = 1; |
51 int quoteChar = source.next(); | 51 source.moveNext(); |
52 if (identical(quoteChar, $r)) { | 52 int quoteChar = source.current; |
| 53 if (quoteChar == $r) { |
53 raw = true; | 54 raw = true; |
54 quoteChar = source.next(); | 55 source.moveNext(); |
| 56 quoteChar = source.current; |
55 } | 57 } |
56 assert(quoteChar == $SQ || quoteChar == $DQ); | 58 assert(quoteChar == $SQ || quoteChar == $DQ); |
57 // String has at least one quote. Check it if has three. | 59 // String has at least one quote. Check it if has three. |
58 // If it only have two, the string must be an empty string literal, | 60 // If it only have two, the string must be an empty string literal, |
59 // and end after the second quote. | 61 // and end after the second quote. |
60 bool multiline = false; | 62 bool multiline = false; |
61 if (source.hasNext && source.next() == quoteChar && source.hasNext) { | 63 if (source.moveNext() && source.current == quoteChar && source.moveNext()) { |
62 int code = source.next(); | 64 int code = source.current; |
63 assert(code == quoteChar); // If not, there is a bug in the parser. | 65 assert(code == quoteChar); // If not, there is a bug in the parser. |
64 quoteLength = 3; | 66 quoteLength = 3; |
65 // Check if a multiline string starts with a newline (CR, LF or CR+LF). | 67 // Check if a multiline string starts with a newline (CR, LF or CR+LF). |
66 if (source.hasNext) { | 68 if (source.moveNext()) { |
67 code = source.next(); | 69 code = source.current; |
68 if (code == $CR) { | 70 if (code == $CR) { |
69 quoteLength += 1; | 71 quoteLength += 1; |
70 if (source.hasNext && source.next() == $LF) { | 72 if (source.moveNext() && source.current == $LF) { |
71 quoteLength += 1; | 73 quoteLength += 1; |
72 } | 74 } |
73 } else if (code == $LF) { | 75 } else if (code == $LF) { |
74 quoteLength += 1; | 76 quoteLength += 1; |
75 } | 77 } |
76 } | 78 } |
77 } | 79 } |
78 return StringQuoting.getQuoting(quoteChar, raw, quoteLength); | 80 return StringQuoting.getQuoting(quoteChar, raw, quoteLength); |
79 } | 81 } |
80 | 82 |
(...skipping 11 matching lines...) Expand all Loading... |
92 StringQuoting quoting) { | 94 StringQuoting quoting) { |
93 // We need to check for invalid x and u escapes, for line | 95 // We need to check for invalid x and u escapes, for line |
94 // terminators in non-multiline strings, and for invalid Unicode | 96 // terminators in non-multiline strings, and for invalid Unicode |
95 // scalar values (either directly or as u-escape values). We also check | 97 // scalar values (either directly or as u-escape values). We also check |
96 // for unpaired UTF-16 surrogates. | 98 // for unpaired UTF-16 surrogates. |
97 int length = 0; | 99 int length = 0; |
98 int index = startOffset; | 100 int index = startOffset; |
99 bool containsEscape = false; | 101 bool containsEscape = false; |
100 bool previousWasLeadSurrogate = false; | 102 bool previousWasLeadSurrogate = false; |
101 bool invalidUtf16 = false; | 103 bool invalidUtf16 = false; |
102 for(Iterator<int> iter = string.iterator(); iter.hasNext; length++) { | 104 for(HasNextIterator<int> iter = new HasNextIterator(string.iterator); |
| 105 iter.hasNext; |
| 106 length++) { |
103 index++; | 107 index++; |
104 int code = iter.next(); | 108 int code = iter.next(); |
105 if (code == $BACKSLASH) { | 109 if (code == $BACKSLASH) { |
106 if (quoting.raw) continue; | 110 if (quoting.raw) continue; |
107 containsEscape = true; | 111 containsEscape = true; |
108 if (!iter.hasNext) { | 112 if (!iter.hasNext) { |
109 stringParseError("Incomplete escape sequence",token, index); | 113 stringParseError("Incomplete escape sequence",token, index); |
110 return null; | 114 return null; |
111 } | 115 } |
112 index++; | 116 index++; |
(...skipping 10 matching lines...) Expand all Loading... |
123 stringParseError("Invalid character in escape sequence", | 127 stringParseError("Invalid character in escape sequence", |
124 token, index); | 128 token, index); |
125 return null; | 129 return null; |
126 } | 130 } |
127 } | 131 } |
128 // A two-byte hex escape can't generate an invalid value. | 132 // A two-byte hex escape can't generate an invalid value. |
129 continue; | 133 continue; |
130 } else if (code == $u) { | 134 } else if (code == $u) { |
131 int escapeStart = index - 1; | 135 int escapeStart = index - 1; |
132 index++; | 136 index++; |
133 code = iter.next(); | 137 code = iter.hasNext ? iter.next() : 0; |
134 int value = 0; | 138 int value = 0; |
135 if (code == $OPEN_CURLY_BRACKET) { | 139 if (code == $OPEN_CURLY_BRACKET) { |
136 // expect 1-6 hex digits. | 140 // expect 1-6 hex digits. |
137 int count = 0; | 141 int count = 0; |
138 index++; | 142 while (iter.hasNext) { |
139 code = iter.next(); | 143 code = iter.next(); |
140 do { | 144 index++; |
| 145 if (code == $CLOSE_CURLY_BRACKET) { |
| 146 break; |
| 147 } |
141 if (!isHexDigit(code)) { | 148 if (!isHexDigit(code)) { |
142 stringParseError("Invalid character in escape sequence", | 149 stringParseError("Invalid character in escape sequence", |
143 token, index); | 150 token, index); |
144 return null; | 151 return null; |
145 } | 152 } |
146 count++; | 153 count++; |
147 value = value * 16 + hexDigitValue(code); | 154 value = value * 16 + hexDigitValue(code); |
148 index++; | 155 } |
149 code = iter.next(); | 156 if (code != $CLOSE_CURLY_BRACKET || count == 0 || count > 6) { |
150 } while (code != $CLOSE_CURLY_BRACKET); | 157 int errorPosition = index - count; |
151 if (count > 6) { | 158 if (count > 6) errorPosition += 6; |
152 stringParseError("Invalid character in escape sequence", | 159 stringParseError("Invalid character in escape sequence", |
153 token, index - (count - 6)); | 160 token, errorPosition); |
154 return null; | 161 return null; |
155 } | 162 } |
156 } else { | 163 } else { |
157 // Expect four hex digits, including the one just read. | 164 // Expect four hex digits, including the one just read. |
158 for (int i = 0; i < 4; i++) { | 165 for (int i = 0; i < 4; i++) { |
159 if (i > 0) { | 166 if (i > 0) { |
160 index++; | 167 if (iter.hasNext) { |
161 code = iter.next(); | 168 index++; |
| 169 code = iter.next(); |
| 170 } else { |
| 171 code = 0; |
| 172 } |
162 } | 173 } |
163 if (!isHexDigit(code)) { | 174 if (!isHexDigit(code)) { |
164 stringParseError("Invalid character in escape sequence", | 175 stringParseError("Invalid character in escape sequence", |
165 token, index); | 176 token, index); |
166 return null; | 177 return null; |
167 } | 178 } |
168 value = value * 16 + hexDigitValue(code); | 179 value = value * 16 + hexDigitValue(code); |
169 } | 180 } |
170 } | 181 } |
171 code = value; | 182 code = value; |
(...skipping 20 matching lines...) Expand all Loading... |
192 return null; | 203 return null; |
193 } | 204 } |
194 // String literal successfully validated. | 205 // String literal successfully validated. |
195 if (quoting.raw || !containsEscape) { | 206 if (quoting.raw || !containsEscape) { |
196 // A string without escapes could just as well have been raw. | 207 // A string without escapes could just as well have been raw. |
197 return new DartString.rawString(string, length); | 208 return new DartString.rawString(string, length); |
198 } | 209 } |
199 return new DartString.escapedString(string, length); | 210 return new DartString.escapedString(string, length); |
200 } | 211 } |
201 } | 212 } |
OLD | NEW |