Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: frog/leg/string_validator.dart

Issue 9271037: Inserted string validation as separate task in compiler. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 // Checks a tree structure for whether the string literals are valid.
6
7 class StringValidatorTask extends CompilerTask {
8 // Validator has no state except the compiler, so we just create one
9 // per task.
10 final StringValidator validator;
11
12 StringValidatorTask(Compiler compiler)
13 : super(compiler),
14 validator = new StringValidator(compiler);
15
16 void validate(Node tree) {
17 tree.accept(validator);
18 }
19 }
20
21 class StringValidator extends AbstractVisitor {
22 final Compiler compiler;
23
24 StringValidator(this.compiler);
25
26 void visitNode(Node node) {
27 node.visitChildren(this);
28 }
29
30 visitLiteralString(LiteralString node) {
31 // This is a string literal where the source contains both start and
32 // end quotes.
33 // String literals that are part of string interpolations are
34 // handled there to account for their varying degree of quotedness.
35 SourceString source = node.value;
36 StringQuoting quoting = quotingFromString(source);
37 int leftQuote = quoting.leftQuoteLength;
38 int rightQuote = quoting.rightQuoteLength;
39 SourceString content = source.copyWithoutQuotes(leftQuote, rightQuote);
40 validateString(node, node.token.charOffset + leftQuote, content, quoting);
41 }
42
43 // String interpolation validates the immediate strings and traverses
44 // the sub-expressions.
45 visitStringInterpolation(StringInterpolation node) {
46 LiteralString literalString = node.string;
47 SourceString source = literalString.value;
48 StringQuoting quoting = quotingFromString(source);
49 int offset = literalString.token.charOffset + quoting.leftQuoteLength;
50 SourceString string = source.copyWithoutQuotes(quoting.leftQuoteLength, 0);
51 for (StringInterpolationPart part in node.parts) {
52 validateString(literalString, offset, string, quoting);
53 part.expression.accept(this);
54 literalString = part.string;
55 offset = literalString.token.charOffset;
56 string = literalString.value;
57 }
58 string = string.copyWithoutQuotes(0, quoting.rightQuoteLength);
59 validateString(literalString, offset, string, quoting);
60 }
61
62 static StringQuoting quotingFromString(SourceString sourceString) {
63 Iterator<int> source = sourceString.iterator();
64 bool raw = false;
65 int quoteChar = source.next();
66 if (quoteChar == $AT) {
67 raw = true;
68 quoteChar = source.next();
69 }
70 assert(quoteChar === $SQ || quoteChar === $DQ);
71 // String has one quote. Check it if has three.
karlklose 2012/01/25 08:47:26 one -> at least one
Lasse Reichstein Nielsen 2012/01/26 10:14:20 Done.
72 // If it only have two, the string must be an empty string literal,
73 // and end after the second quote.
74 bool multiline = false;
75 if (source.hasNext() && source.next() == quoteChar && source.hasNext()) {
76 assert(source.next() == quoteChar);
77 multiline = true;
78 }
79 return StringQuoting.get(quoteChar, raw, multiline);
80 }
81
82 void stringParseError(String message, LiteralString node, int offset) {
83 assert(node.quotedString === null);
84 compiler.cancel("$message @ $offset", node);
85 }
86
87 /**
88 * Validates the escape sequences and special characters of a string literal.
89 * Returns the number of actual scalar values in the corresponding Dart
karlklose 2012/01/25 08:47:26 It returns whether the string is valid or not, doe
Lasse Reichstein Nielsen 2012/01/26 10:14:20 True. Old comment is old.
90 * string, or a negative value if the string is invalid.
91 */
92 bool validateString(LiteralString node,
93 int startOffset,
94 SourceString string,
95 StringQuoting quoting) {
96 // We only need to check for invalid x and u escapes, for line
97 // terminators in non-multiline strings, and for invalid Unicode
98 // scalar values (either directly or as u-escape values).
99 int length = 0;
100 int index = startOffset;
101 for(Iterator<int> iter = string.iterator(); iter.hasNext(); length++) {
102 index++;
103 int code = iter.next();
104 if (code === $BACKSLASH) {
105 if (quoting.raw) continue;
106 if (!iter.hasNext()) {
107 stringParseError("Incomplete escape sequence", node, index);
108 return false;
109 }
110 index++;
111 code = iter.next();
112 if (code === $x) {
113 for (int i = 0; i < 2; i++) {
114 if (!iter.hasNext()) {
115 stringParseError("Incomplete escape sequence", node, index);
116 return false;
117 }
118 index++;
119 code = iter.next();
120 if (!isHexDigit(code)) {
121 stringParseError("Invalid character in escape sequence",
122 node, index);
123 return false;
124 }
125 }
126 continue;
127 } else if (code === $u) {
128 int escapeStart = index - 1;
129 index++;
130 code = iter.next();
131 int value = 0;
132 if (code == $OPEN_CURLY_BRACKET) {
133 // expect 1-7 hex digits.
134 int count = 0;
135 index++;
136 code = iter.next();
137 do {
138 if (!isHexDigit(code)) {
139 stringParseError("Invalid character in escape sequence",
140 node, index);
141 return false;
142 }
143 count++;
144 value = value * 16 + hexDigitValue(code);
145 index++;
146 code = iter.next();
147 } while (code != $CLOSE_CURLY_BRACKET);
148 if (count > 7) {
149 stringParseError("Invalid character in escape sequence",
150 node, index - (count - 7));
151 return false;
152 }
153 } else {
154 // Expect four hex digits, including the one just tread.
155 for (int i = 0; i < 4; i++) {
156 if (i > 0) {
157 index++;
158 code = iter.next();
159 }
160 if (!isHexDigit(code)) {
161 stringParseError("Invalid character in escape sequence",
162 node, index);
163 return false;
164 }
165 value = value * 16 + hexDigitValue(code);
166 }
167 }
168 if (0xd800 <= value && ( value <= 0xdfff || value > 0x10ffff)) {
169 stringParseError(
170 "Invalid unicode scalar value U+${value.toRadixString(16)}",
171 node, index);
172 return false;
173 }
174 continue;
175 }
176 }
177 // This handles borth unescaped characters as well as those
178 // characters after a backslash that doesn't have a special
179 // meaning.
180 if (code >= 0xd800 && (code <= 0xdfff || code > 0x10ffff)) {
181 stringParseError(
182 "Invalid unicode scalar value U+${code.toRadixString(16)}",
183 node, index);
184 return false;
185 }
186 if (!quoting.multiline && (code === $LF || code === $CR)) {
187 stringParseError("Line terminator in single-line string",
188 node, index);
189 return false;
190 }
191 }
192 // String literal successfully validated.
193 node.quotedString = new QuotedString(string, quoting, length);
194 return true;
195 }
196 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698