| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 part of scanner; | 5 part of scanner; |
| 6 | 6 |
| 7 const int EOF_TOKEN = 0; | 7 const int EOF_TOKEN = 0; |
| 8 | 8 |
| 9 const int KEYWORD_TOKEN = $k; | 9 const int KEYWORD_TOKEN = $k; |
| 10 const int IDENTIFIER_TOKEN = $a; | 10 const int IDENTIFIER_TOKEN = $a; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 * The precedence info for this token. [info] determines the kind and the | 96 * The precedence info for this token. [info] determines the kind and the |
| 97 * precedence level of this token. | 97 * precedence level of this token. |
| 98 * | 98 * |
| 99 * Defined as getter to save a field in the [KeywordToken] subclass. | 99 * Defined as getter to save a field in the [KeywordToken] subclass. |
| 100 */ | 100 */ |
| 101 PrecedenceInfo get info; | 101 PrecedenceInfo get info; |
| 102 | 102 |
| 103 /** | 103 /** |
| 104 * The string represented by this token, a substring of the source code. | 104 * The string represented by this token, a substring of the source code. |
| 105 * | 105 * |
| 106 * For [StringToken]s the value includes the quotes, explicit escapes, etc. | 106 * For [StringToken]s the [value] includes the quotes, explicit escapes, etc. |
| 107 * | |
| 108 */ | 107 */ |
| 109 String get value; | 108 String get value; |
| 110 | 109 |
| 111 /** | 110 /** |
| 112 * For symbol and keyword tokens, returns the string value reprenseted by this | 111 * For symbol and keyword tokens, returns the string value represented by this |
| 113 * token. For [StringToken]s this method returns [:null:]. | 112 * token. For [StringToken]s this method returns [:null:]. |
| 114 * | 113 * |
| 115 * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time | 114 * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time |
| 116 * constant originating in the [PrecedenceInfo] or in the [Keyword] instance. | 115 * constant originating in the [PrecedenceInfo] or in the [Keyword] instance. |
| 117 * This allows testing for keywords and symbols using [:identical:], e.g., | 116 * This allows testing for keywords and symbols using [:identical:], e.g., |
| 118 * [:identical('class', token.value):]. | 117 * [:identical('class', token.value):]. |
| 119 * | 118 * |
| 120 * Note that returning [:null:] for string tokens is important to identify | 119 * Note that returning [:null:] for string tokens is important to identify |
| 121 * symbols and keywords, we cannot use [value] instead. The string literal | 120 * symbols and keywords, we cannot use [value] instead. The string literal |
| 122 * "$a($b" | 121 * "$a($b" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 133 */ | 132 */ |
| 134 int get kind => info.kind; | 133 int get kind => info.kind; |
| 135 | 134 |
| 136 /** | 135 /** |
| 137 * The precedence level for this token. | 136 * The precedence level for this token. |
| 138 */ | 137 */ |
| 139 int get precedence => info.precedence; | 138 int get precedence => info.precedence; |
| 140 | 139 |
| 141 /** | 140 /** |
| 142 * True if this token is an identifier. Some keywords allowed as identifiers, | 141 * True if this token is an identifier. Some keywords allowed as identifiers, |
| 143 * see implementaiton in [KeywordToken]. | 142 * see implementation in [KeywordToken]. |
| 144 */ | 143 */ |
| 145 bool isIdentifier(); | 144 bool isIdentifier(); |
| 146 | 145 |
| 147 /** | 146 /** |
| 148 * Returns a textual representation of this token to be used for debugging | 147 * Returns a textual representation of this token to be used for debugging |
| 149 * purposes. The resulting string might contain information about the | 148 * purposes. The resulting string might contain information about the |
| 150 * structure of the token, for example 'StringToken(foo)' for the identifier | 149 * structure of the token, for example 'StringToken(foo)' for the identifier |
| 151 * token 'foo'. | 150 * token 'foo'. |
| 152 * | 151 * |
| 153 * Use [value] for the text actually parsed by the token. | 152 * Use [value] for the text actually parsed by the token. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 164 return 1; | 163 return 1; |
| 165 } else { | 164 } else { |
| 166 return value.length; | 165 return value.length; |
| 167 } | 166 } |
| 168 } | 167 } |
| 169 | 168 |
| 170 int get hashCode => computeHashCode(charOffset, info, value); | 169 int get hashCode => computeHashCode(charOffset, info, value); |
| 171 } | 170 } |
| 172 | 171 |
| 173 /** | 172 /** |
| 174 * A symbol token represents the symbol in its precendence info. | 173 * A [SymbolToken] represents the symbol in its precendence info. |
| 175 * Also used for end of file with EOF_INFO. | 174 * Also used for end of file with EOF_INFO. |
| 176 */ | 175 */ |
| 177 class SymbolToken extends Token { | 176 class SymbolToken extends Token { |
| 178 | 177 |
| 179 final PrecedenceInfo info; | 178 final PrecedenceInfo info; |
| 180 | 179 |
| 181 SymbolToken(this.info, int charOffset) : super(charOffset); | 180 SymbolToken(this.info, int charOffset) : super(charOffset); |
| 182 | 181 |
| 183 String get value => info.value; | 182 String get value => info.value; |
| 184 | 183 |
| 185 String get stringValue => info.value; | 184 String get stringValue => info.value; |
| 186 | 185 |
| 187 bool isIdentifier() => false; | 186 bool isIdentifier() => false; |
| 188 | 187 |
| 189 String toString() => "SymbolToken($value)"; | 188 String toString() => "SymbolToken($value)"; |
| 190 } | 189 } |
| 191 | 190 |
| 192 /** | 191 /** |
| 193 * A [BeginGroupToken] reprsents a symbol that may be the beginning of | 192 * A [BeginGroupToken] represents a symbol that may be the beginning of |
| 194 * a pair of brackets, i.e., ( { [ < or ${ | 193 * a pair of brackets, i.e., ( { [ < or ${ |
| 195 * The [endGroup] token points to the matching closing bracked in case | 194 * The [endGroup] token points to the matching closing bracked in case |
| 196 * it can be identified during scanning. | 195 * it can be identified during scanning. |
| 197 */ | 196 */ |
| 198 class BeginGroupToken extends SymbolToken { | 197 class BeginGroupToken extends SymbolToken { |
| 199 Token endGroup; | 198 Token endGroup; |
| 200 | 199 |
| 201 BeginGroupToken(PrecedenceInfo info, int charOffset) | 200 BeginGroupToken(PrecedenceInfo info, int charOffset) |
| 202 : super(info, charOffset); | 201 : super(info, charOffset); |
| 203 } | 202 } |
| 204 | 203 |
| 205 /** | 204 /** |
| 206 * A keyword token. | 205 * A keyword token. |
| 207 */ | 206 */ |
| 208 class KeywordToken extends Token { | 207 class KeywordToken extends Token { |
| 209 final Keyword keyword; | 208 final Keyword keyword; |
| 210 | 209 |
| 211 KeywordToken(this.keyword, int charOffset) : super(charOffset); | 210 KeywordToken(this.keyword, int charOffset) : super(charOffset); |
| 212 | 211 |
| 213 PrecedenceInfo get info => keyword.info; | 212 PrecedenceInfo get info => keyword.info; |
| 214 | 213 |
| 215 String get value => keyword.syntax; | 214 String get value => keyword.syntax; |
| 216 | 215 |
| 217 String get stringValue => keyword.syntax; | 216 String get stringValue => keyword.syntax; |
| 218 | 217 |
| 219 bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn; | 218 bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn; |
| 220 | 219 |
| 221 String toString() => "KeywordToken($value)"; | 220 String toString() => "KeywordToken($value)"; |
| 222 } | 221 } |
| 223 | 222 |
| 224 /** | 223 /** |
| 225 * A String-valued token. Represents identifiers, string literals, | 224 * A String-valued token. Represents identifiers, string literals, |
| 226 * number literals, comments and error tokens, using the corresponding | 225 * number literals, comments, and error tokens, using the corresponding |
| 227 * precedence info. | 226 * precedence info. |
| 228 */ | 227 */ |
| 229 class StringToken extends Token { | 228 class StringToken extends Token { |
| 230 /** | 229 /** |
| 231 * The length threshold above which substring tokens are computed lazily. | 230 * The length threshold above which substring tokens are computed lazily. |
| 232 * | 231 * |
| 233 * For string tokens that are substrings of the program source, the actual | 232 * For string tokens that are substrings of the program source, the actual |
| 234 * substring extraction is performed lazily. This is beneficial because | 233 * substring extraction is performed lazily. This is beneficial because |
| 235 * not all scanned code is actually used. For unused parts, the substrings | 234 * not all scanned code is actually used. For unused parts, the substrings |
| 236 * are never computed and allocated. | 235 * are never computed and allocated. |
| 237 */ | 236 */ |
| 238 static const int LAZY_THRESHOLD = 4; | 237 static const int LAZY_THRESHOLD = 4; |
| 239 | 238 |
| 240 var valueOrLazySubstring; | 239 var /* String | LazySubtring */ valueOrLazySubstring; |
| 241 | 240 |
| 242 final PrecedenceInfo info; | 241 final PrecedenceInfo info; |
| 243 | 242 |
| 244 /** | 243 /** |
| 245 * Creates a non-lazy string token. If [canonicalize] is true, the string | 244 * Creates a non-lazy string token. If [canonicalize] is true, the string |
| 246 * is canonicalized before the token is created. | 245 * is canonicalized before the token is created. |
| 247 */ | 246 */ |
| 248 StringToken.fromString(this.info, String value, int charOffset, | 247 StringToken.fromString(this.info, String value, int charOffset, |
| 249 [bool canonicalize = false]) | 248 {bool canonicalize : false}) |
| 250 : valueOrLazySubstring = canonicalizedString(value, canonicalize), | 249 : valueOrLazySubstring = canonicalizedString(value, canonicalize), |
| 251 super(charOffset); | 250 super(charOffset); |
| 252 | 251 |
| 253 /** | 252 /** |
| 254 * Creates a lazy string token. If [canonicalize] is true, the string | 253 * Creates a lazy string token. If [canonicalize] is true, the string |
| 255 * is canonicalized before the token is created. | 254 * is canonicalized before the token is created. |
| 256 */ | 255 */ |
| 257 StringToken.fromSubstring(this.info, String data, int start, int end, | 256 StringToken.fromSubstring(this.info, String data, int start, int end, |
| 258 int charOffset, [bool canonicalize = false]) | 257 int charOffset, {bool canonicalize : false}) |
| 259 : super(charOffset) { | 258 : super(charOffset) { |
| 260 int length = end - start; | 259 int length = end - start; |
| 261 if (length <= LAZY_THRESHOLD) { | 260 if (length <= LAZY_THRESHOLD) { |
| 262 valueOrLazySubstring = canonicalizedString(data.substring(start, end), | 261 valueOrLazySubstring = canonicalizedString(data.substring(start, end), |
| 263 canonicalize); | 262 canonicalize); |
| 264 } else { | 263 } else { |
| 265 valueOrLazySubstring = | 264 valueOrLazySubstring = |
| 266 new LazySubstring(data, start, length, canonicalize); | 265 new LazySubstring(data, start, length, canonicalize); |
| 267 } | 266 } |
| 268 } | 267 } |
| 269 | 268 |
| 270 /** | 269 /** |
| 271 * Creates a lazy string token. If [asciiOnly] is false, the byte array | 270 * Creates a lazy string token. If [asciiOnly] is false, the byte array |
| 272 * is passed through a UTF-8 decoder. | 271 * is passed through a UTF-8 decoder. |
| 273 */ | 272 */ |
| (...skipping 27 matching lines...) Expand all Loading... |
| 301 } | 300 } |
| 302 } | 301 } |
| 303 | 302 |
| 304 String get stringValue => null; | 303 String get stringValue => null; |
| 305 | 304 |
| 306 bool isIdentifier() => identical(kind, IDENTIFIER_TOKEN); | 305 bool isIdentifier() => identical(kind, IDENTIFIER_TOKEN); |
| 307 | 306 |
| 308 String toString() => "StringToken($value)"; | 307 String toString() => "StringToken($value)"; |
| 309 | 308 |
| 310 static final HashSet<String> canonicalizedSubstrings = | 309 static final HashSet<String> canonicalizedSubstrings = |
| 311 new HashSet(); | 310 new HashSet<String>(); |
| 312 | 311 |
| 313 static String canonicalizedString(String s, bool canonicalize) { | 312 static String canonicalizedString(String s, bool canonicalize) { |
| 314 if (!canonicalize) return s; | 313 if (!canonicalize) return s; |
| 315 var result = canonicalizedSubstrings.lookup(s); | 314 var result = canonicalizedSubstrings.lookup(s); |
| 316 if (result != null) return result; | 315 if (result != null) return result; |
| 317 canonicalizedSubstrings.add(s); | 316 canonicalizedSubstrings.add(s); |
| 318 return s; | 317 return s; |
| 319 } | 318 } |
| 320 | 319 |
| 321 static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) { | 320 static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) { |
| 322 var s; | 321 var s; |
| 323 if (asciiOnly) { | 322 if (asciiOnly) { |
| 324 // getRange returns an iterator, it does not copy the data. | 323 // getRange returns an iterator, it does not copy the data. |
| 325 s = new String.fromCharCodes(data.getRange(start, end)); | 324 s = new String.fromCharCodes(data.getRange(start, end)); |
| 326 } else { | 325 } else { |
| 327 // TODO(lry): this is measurably slow. Also sublist is copied eagerly. | 326 // TODO(lry): this is measurably slow. Also sublist is copied eagerly. |
| 328 var bytes = data.sublist(start, end); | 327 var bytes = data.sublist(start, end); |
| 329 s = UTF8.decode(bytes); | 328 s = UTF8.decode(bytes); |
| 330 } | 329 } |
| 331 return canonicalizedString(s, true); | 330 return canonicalizedString(s, true); |
| 332 } | 331 } |
| 333 } | 332 } |
| 334 | 333 |
| 335 /** | 334 /** |
| 336 * This class represents the necessary information to compute a substring | 335 * This class represents the necessary information to compute a substring |
| 337 * lazily. The substring can either originate in a string or in a [:List<int>:] | 336 * lazily. The substring can either originate from a string or from |
| 338 * of UTF-8 bytes. | 337 * a [:List<int>:] of UTF-8 bytes. |
| 339 */ | 338 */ |
| 340 abstract class LazySubstring { | 339 abstract class LazySubstring { |
| 341 /** The original data, either a string or a List<int> */ | 340 /** The original data, either a string or a List<int> */ |
| 342 get data; | 341 get data; |
| 343 | 342 |
| 344 int get start; | 343 int get start; |
| 345 int get length; | 344 int get length; |
| 346 | 345 |
| 347 /** | 346 /** |
| 348 * If this substring is based on a String, the boolean indicates wheter the | 347 * If this substring is based on a String, the [boolValue] indicates wheter |
| 349 * resulting substring should be canonicalized. | 348 * the resulting substring should be canonicalized. |
| 350 * | 349 * |
| 351 * For substrings based on a byte array, the boolean value is true if the | 350 * For substrings based on a byte array, the [boolValue] is true if the |
| 352 * array only holds ASCII characters. The resulting substring will be | 351 * array only holds ASCII characters. The resulting substring will be |
| 353 * canonicalized after decoding. | 352 * canonicalized after decoding. |
| 354 */ | 353 */ |
| 355 bool get boolValue; | 354 bool get boolValue; |
| 356 | 355 |
| 357 LazySubstring.internal(); | 356 LazySubstring.internal(); |
| 358 | 357 |
| 359 factory LazySubstring(data, int start, int length, bool b) { | 358 factory LazySubstring(data, int start, int length, bool b) { |
| 360 // See comment on [CompactLazySubstring]. | 359 // See comment on [CompactLazySubstring]. |
| 361 if (start < 0x100000 && length < 0x200) { | 360 if (start < 0x100000 && length < 0x200) { |
| 362 int fields = (start << 9); | 361 int fields = (start << 9); |
| 363 fields = fields | length; | 362 fields = fields | length; |
| 364 fields = fields << 1; | 363 fields = fields << 1; |
| 365 if (b) fields |= 1; | 364 if (b) fields |= 1; |
| 366 return new CompactLazySubstring(data, fields); | 365 return new CompactLazySubstring(data, fields); |
| 367 } else { | 366 } else { |
| 368 return new FullLazySubstring(data, start, length, b); | 367 return new FullLazySubstring(data, start, length, b); |
| 369 } | 368 } |
| 370 } | 369 } |
| 371 } | 370 } |
| 372 | 371 |
| 373 /** | 372 /** |
| 374 * This class encodes [start], [length] and [boolValue] in a single | 373 * This class encodes [start], [length] and [boolValue] in a single |
| 375 * 30 bit integer. It uses 20 bits for [start], which covers source files | 374 * 30 bit integer. It uses 20 bits for [start], which covers source files |
| 376 * of 1M. [length] has 9 bits, which covers 512 characters. | 375 * of 1MB. [length] has 9 bits, which covers 512 characters. |
| 377 * | 376 * |
| 378 * The file html_dart2js.dart is currently around 1M. | 377 * The file html_dart2js.dart is currently around 1MB. |
| 379 */ | 378 */ |
| 380 class CompactLazySubstring extends LazySubstring { | 379 class CompactLazySubstring extends LazySubstring { |
| 381 final data; | 380 final data; |
| 382 final int fields; | 381 final int fields; |
| 383 | 382 |
| 384 CompactLazySubstring(this.data, this.fields) : super.internal(); | 383 CompactLazySubstring(this.data, this.fields) : super.internal(); |
| 385 | 384 |
| 386 int get start => fields >> 10; | 385 int get start => fields >> 10; |
| 387 int get length => (fields >> 1) & 0x1ff; | 386 int get length => (fields >> 1) & 0x1ff; |
| 388 bool get boolValue => (fields & 1) == 1; | 387 bool get boolValue => (fields & 1) == 1; |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 658 | 657 |
| 659 const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO = | 658 const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO = |
| 660 const PrecedenceInfo('\$', 0, | 659 const PrecedenceInfo('\$', 0, |
| 661 STRING_INTERPOLATION_IDENTIFIER_TOKEN); | 660 STRING_INTERPOLATION_IDENTIFIER_TOKEN); |
| 662 | 661 |
| 663 const PrecedenceInfo HEXADECIMAL_INFO = | 662 const PrecedenceInfo HEXADECIMAL_INFO = |
| 664 const PrecedenceInfo('hexadecimal', 0, HEXADECIMAL_TOKEN); | 663 const PrecedenceInfo('hexadecimal', 0, HEXADECIMAL_TOKEN); |
| 665 | 664 |
| 666 const PrecedenceInfo COMMENT_INFO = | 665 const PrecedenceInfo COMMENT_INFO = |
| 667 const PrecedenceInfo('comment', 0, COMMENT_TOKEN); | 666 const PrecedenceInfo('comment', 0, COMMENT_TOKEN); |
| OLD | NEW |