| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:convert' show UTF8; | 5 import 'dart:convert' show UTF8; |
| 6 | 6 |
| 7 import 'package:front_end/src/fasta/scanner/recover.dart' | 7 import 'package:front_end/src/fasta/scanner/recover.dart' |
| 8 show defaultRecoveryStrategy; | 8 show defaultRecoveryStrategy; |
| 9 import 'package:front_end/src/fasta/scanner.dart' as fasta; | 9 import 'package:front_end/src/fasta/scanner.dart' as fasta; |
| 10 import 'package:front_end/src/fasta/scanner/token.dart' as fasta; | 10 import 'package:front_end/src/fasta/scanner/token.dart' as fasta; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 assertValidBeginTokens(tokens); | 49 assertValidBeginTokens(tokens); |
| 50 if (result.hasErrors) { | 50 if (result.hasErrors) { |
| 51 List<int> bytes = UTF8.encode(source); | 51 List<int> bytes = UTF8.encode(source); |
| 52 tokens = defaultRecoveryStrategy(bytes, tokens, result.lineStarts); | 52 tokens = defaultRecoveryStrategy(bytes, tokens, result.lineStarts); |
| 53 assertValidTokenStream(tokens, errorsFirst: true); | 53 assertValidTokenStream(tokens, errorsFirst: true); |
| 54 } | 54 } |
| 55 return extractErrors(tokens, listener); | 55 return extractErrors(tokens, listener); |
| 56 } | 56 } |
| 57 | 57 |
| 58 void _assertOpenClosePair(String source) { | 58 void _assertOpenClosePair(String source) { |
| 59 fasta.BeginGroupToken open = _scan(source); | 59 analyzer.BeginToken open = _scan(source); |
| 60 fasta.Token close = open.next; | 60 fasta.Token close = open.next; |
| 61 expect(close.next.isEof, isTrue); | 61 expect(close.next.isEof, isTrue); |
| 62 expect(open.endGroup, close); | 62 expect(open.endGroup, close); |
| 63 expect(open.isSynthetic, isFalse); | 63 expect(open.isSynthetic, isFalse); |
| 64 expect(close.isSynthetic, isFalse); | 64 expect(close.isSynthetic, isFalse); |
| 65 } | 65 } |
| 66 | 66 |
| 67 void _assertOpenOnly(String source) { | 67 void _assertOpenOnly(String source) { |
| 68 fasta.BeginGroupToken open = _scan(source); | 68 analyzer.BeginToken open = _scan(source); |
| 69 fasta.Token close = open.next; | 69 fasta.Token close = open.next; |
| 70 expect(close.next.isEof, isTrue); | 70 expect(close.next.isEof, isTrue); |
| 71 expect(open.endGroup, close); | 71 expect(open.endGroup, close); |
| 72 expect(open.isSynthetic, isFalse); | 72 expect(open.isSynthetic, isFalse); |
| 73 expect(close.isSynthetic, isTrue); | 73 expect(close.isSynthetic, isTrue); |
| 74 } | 74 } |
| 75 | 75 |
| 76 void test_lt() { | 76 void test_lt() { |
| 77 // fasta does not automatically insert a closer for '<' | 77 // fasta does not automatically insert a closer for '<' |
| 78 // because it could be part of an expression rather than an opener | 78 // because it could be part of an expression rather than an opener |
| 79 fasta.BeginGroupToken lt = _scan('<'); | 79 analyzer.BeginToken lt = _scan('<'); |
| 80 expect(lt.next.isEof, isTrue); | 80 expect(lt.next.isEof, isTrue); |
| 81 expect(lt.isSynthetic, isFalse); | 81 expect(lt.isSynthetic, isFalse); |
| 82 } | 82 } |
| 83 | 83 |
| 84 void test_lt_gt() { | 84 void test_lt_gt() { |
| 85 _assertOpenClosePair('< >'); | 85 _assertOpenClosePair('< >'); |
| 86 } | 86 } |
| 87 | 87 |
| 88 @override | 88 @override |
| 89 void test_open_curly_bracket() { | 89 void test_open_curly_bracket() { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 110 _assertOpenClosePair('[ ]'); | 110 _assertOpenClosePair('[ ]'); |
| 111 } | 111 } |
| 112 | 112 |
| 113 @override | 113 @override |
| 114 void test_mismatched_closer() { | 114 void test_mismatched_closer() { |
| 115 // When openers and closers are mismatched, | 115 // When openers and closers are mismatched, |
| 116 // fasta favors considering the opener to be mismatched, | 116 // fasta favors considering the opener to be mismatched, |
| 117 // and inserts synthetic closers as needed. | 117 // and inserts synthetic closers as needed. |
| 118 // `(])` is parsed as `()])` where the first `)` is synthetic | 118 // `(])` is parsed as `()])` where the first `)` is synthetic |
| 119 // and the trailing `])` are unmatched. | 119 // and the trailing `])` are unmatched. |
| 120 fasta.BeginGroupToken openParen = _scan('(])'); | 120 analyzer.BeginToken openParen = _scan('(])'); |
| 121 fasta.Token closeParen = openParen.next; | 121 fasta.Token closeParen = openParen.next; |
| 122 fasta.Token closeBracket = closeParen.next; | 122 fasta.Token closeBracket = closeParen.next; |
| 123 fasta.Token closeParen2 = closeBracket.next; | 123 fasta.Token closeParen2 = closeBracket.next; |
| 124 fasta.Token eof = closeParen2.next; | 124 fasta.Token eof = closeParen2.next; |
| 125 | 125 |
| 126 expect(openParen.endToken, same(closeParen)); | 126 expect(openParen.endToken, same(closeParen)); |
| 127 expect(closeParen.isSynthetic, isTrue); | 127 expect(closeParen.isSynthetic, isTrue); |
| 128 expect(eof.isEof, isTrue); | 128 expect(eof.isEof, isTrue); |
| 129 } | 129 } |
| 130 | 130 |
| 131 @override | 131 @override |
| 132 void test_mismatched_opener() { | 132 void test_mismatched_opener() { |
| 133 // When openers and closers are mismatched, | 133 // When openers and closers are mismatched, |
| 134 // fasta favors considering the opener to be mismatched | 134 // fasta favors considering the opener to be mismatched |
| 135 // and inserts synthetic closers as needed. | 135 // and inserts synthetic closers as needed. |
| 136 // `([)` is parsed as `([])` where `]` is synthetic. | 136 // `([)` is parsed as `([])` where `]` is synthetic. |
| 137 fasta.BeginGroupToken openParen = _scan('([)'); | 137 analyzer.BeginToken openParen = _scan('([)'); |
| 138 fasta.BeginGroupToken openBracket = openParen.next; | 138 analyzer.BeginToken openBracket = openParen.next; |
| 139 fasta.Token closeBracket = openBracket.next; // <-- synthetic | 139 fasta.Token closeBracket = openBracket.next; // <-- synthetic |
| 140 fasta.Token closeParen = closeBracket.next; | 140 fasta.Token closeParen = closeBracket.next; |
| 141 fasta.Token eof = closeParen.next; | 141 fasta.Token eof = closeParen.next; |
| 142 | 142 |
| 143 expect(openParen.endToken, same(closeParen)); | 143 expect(openParen.endToken, same(closeParen)); |
| 144 expect(closeParen.isSynthetic, isFalse); | 144 expect(closeParen.isSynthetic, isFalse); |
| 145 expect(openBracket.endToken, same(closeBracket)); | 145 expect(openBracket.endToken, same(closeBracket)); |
| 146 expect(closeBracket.isSynthetic, isTrue); | 146 expect(closeBracket.isSynthetic, isTrue); |
| 147 expect(eof.isEof, isTrue); | 147 expect(eof.isEof, isTrue); |
| 148 } | 148 } |
| 149 | 149 |
| 150 @override | 150 @override |
| 151 void test_mismatched_opener_in_interpolation() { | 151 void test_mismatched_opener_in_interpolation() { |
| 152 // When openers and closers are mismatched, | 152 // When openers and closers are mismatched, |
| 153 // fasta favors considering the opener to be mismatched | 153 // fasta favors considering the opener to be mismatched |
| 154 // and inserts synthetic closers as needed. | 154 // and inserts synthetic closers as needed. |
| 155 // r'"${({(}}"' is parsed as r'"${({()})}"' | 155 // r'"${({(}}"' is parsed as r'"${({()})}"' |
| 156 // where both ')' are synthetic | 156 // where both ')' are synthetic |
| 157 var stringStart = _scan(r'"${({(}}"'); | 157 var stringStart = _scan(r'"${({(}}"'); |
| 158 var interpolationStart = stringStart.next as fasta.BeginGroupToken; | 158 var interpolationStart = stringStart.next as analyzer.BeginToken; |
| 159 var openParen1 = interpolationStart.next as fasta.BeginGroupToken; | 159 var openParen1 = interpolationStart.next as analyzer.BeginToken; |
| 160 var openBrace = openParen1.next as fasta.BeginGroupToken; | 160 var openBrace = openParen1.next as analyzer.BeginToken; |
| 161 var openParen2 = openBrace.next as fasta.BeginGroupToken; | 161 var openParen2 = openBrace.next as analyzer.BeginToken; |
| 162 var closeParen2 = openParen2.next; | 162 var closeParen2 = openParen2.next; |
| 163 var closeBrace = closeParen2.next; | 163 var closeBrace = closeParen2.next; |
| 164 var closeParen1 = closeBrace.next; | 164 var closeParen1 = closeBrace.next; |
| 165 var interpolationEnd = closeParen1.next; | 165 var interpolationEnd = closeParen1.next; |
| 166 var stringEnd = interpolationEnd.next; | 166 var stringEnd = interpolationEnd.next; |
| 167 var eof = stringEnd.next; | 167 var eof = stringEnd.next; |
| 168 | 168 |
| 169 expect(interpolationStart.endToken, same(interpolationEnd)); | 169 expect(interpolationStart.endToken, same(interpolationEnd)); |
| 170 expect(interpolationEnd.isSynthetic, isFalse); | 170 expect(interpolationEnd.isSynthetic, isFalse); |
| 171 expect(openParen1.endToken, same(closeParen1)); | 171 expect(openParen1.endToken, same(closeParen1)); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 @override | 257 @override |
| 258 @failingTest | 258 @failingTest |
| 259 void test_string_simple_unterminated_interpolation_identifier() { | 259 void test_string_simple_unterminated_interpolation_identifier() { |
| 260 // See defaultRecoveryStrategy recoverString | 260 // See defaultRecoveryStrategy recoverString |
| 261 super.test_string_simple_unterminated_interpolation_identifier(); | 261 super.test_string_simple_unterminated_interpolation_identifier(); |
| 262 } | 262 } |
| 263 | 263 |
| 264 @override | 264 @override |
| 265 void test_unmatched_openers() { | 265 void test_unmatched_openers() { |
| 266 // fasta inserts missing closers except for '<' | 266 // fasta inserts missing closers except for '<' |
| 267 var openBrace = _scan('{[(<') as fasta.BeginGroupToken; | 267 var openBrace = _scan('{[(<') as analyzer.BeginToken; |
| 268 var openBracket = openBrace.next as fasta.BeginGroupToken; | 268 var openBracket = openBrace.next as analyzer.BeginToken; |
| 269 var openParen = openBracket.next as fasta.BeginGroupToken; | 269 var openParen = openBracket.next as analyzer.BeginToken; |
| 270 var openLT = openParen.next as fasta.BeginGroupToken; | 270 var openLT = openParen.next as analyzer.BeginToken; |
| 271 var closeParen = openLT.next; | 271 var closeParen = openLT.next; |
| 272 var closeBracket = closeParen.next; | 272 var closeBracket = closeParen.next; |
| 273 var closeBrace = closeBracket.next; | 273 var closeBrace = closeBracket.next; |
| 274 var eof = closeBrace.next; | 274 var eof = closeBrace.next; |
| 275 | 275 |
| 276 expect(openBrace.endGroup, same(closeBrace)); | 276 expect(openBrace.endGroup, same(closeBrace)); |
| 277 expect(openBracket.endGroup, same(closeBracket)); | 277 expect(openBracket.endGroup, same(closeBracket)); |
| 278 expect(openParen.endGroup, same(closeParen)); | 278 expect(openParen.endGroup, same(closeParen)); |
| 279 expect(eof.isEof, true); | 279 expect(eof.isEof, true); |
| 280 } | 280 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 295 // The default recovery strategy used by scanString | 295 // The default recovery strategy used by scanString |
| 296 // places all error tokens at the head of the stream. | 296 // places all error tokens at the head of the stream. |
| 297 while (token.type == analyzer.TokenType.BAD_INPUT) { | 297 while (token.type == analyzer.TokenType.BAD_INPUT) { |
| 298 translateErrorToken(token, | 298 translateErrorToken(token, |
| 299 (ScannerErrorCode errorCode, int offset, List<Object> arguments) { | 299 (ScannerErrorCode errorCode, int offset, List<Object> arguments) { |
| 300 listener.errors.add(new TestError(offset, errorCode, arguments)); | 300 listener.errors.add(new TestError(offset, errorCode, arguments)); |
| 301 }); | 301 }); |
| 302 token = token.next; | 302 token = token.next; |
| 303 } | 303 } |
| 304 if (!token.previous.isEof) { | 304 if (!token.previous.isEof) { |
| 305 var head = new fasta.SymbolToken(analyzer.TokenType.EOF, -1); | 305 var head = new analyzer.Token.eof(-1); |
| 306 token.previous = head; | 306 token.previous = head; |
| 307 head.next = token; | 307 head.next = token; |
| 308 } | 308 } |
| 309 return token; | 309 return token; |
| 310 } | 310 } |
| 311 | 311 |
| 312 /// Assert that the tokens in the stream are correctly connected prev/next. | 312 /// Assert that the tokens in the stream are correctly connected prev/next. |
| 313 void assertValidTokenStream(fasta.Token firstToken, | 313 void assertValidTokenStream(fasta.Token firstToken, |
| 314 {bool errorsFirst: false}) { | 314 {bool errorsFirst: false}) { |
| 315 fasta.Token token = firstToken; | 315 fasta.Token token = firstToken; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 326 while (!token.isEof) { | 326 while (!token.isEof) { |
| 327 if (errorsFirst) expect(token, isNotErrorToken); | 327 if (errorsFirst) expect(token, isNotErrorToken); |
| 328 previous = token; | 328 previous = token; |
| 329 token = token.next; | 329 token = token.next; |
| 330 expect(token, isNotNull, reason: previous.toString()); | 330 expect(token, isNotNull, reason: previous.toString()); |
| 331 expect(token.previous, previous, reason: token.toString()); | 331 expect(token.previous, previous, reason: token.toString()); |
| 332 } | 332 } |
| 333 expect(token.next, token, reason: 'Invalid trailing EOF'); | 333 expect(token.next, token, reason: 'Invalid trailing EOF'); |
| 334 } | 334 } |
| 335 | 335 |
| 336 /// Assert that all [fasta.BeginGroupToken] has a valid `endGroup` | 336 /// Assert that all [analyzer.BeginToken] has a valid `endGroup` |
| 337 /// that is in the stream. | 337 /// that is in the stream. |
| 338 void assertValidBeginTokens(fasta.Token firstToken) { | 338 void assertValidBeginTokens(fasta.Token firstToken) { |
| 339 var openerStack = <fasta.BeginGroupToken>[]; | 339 var openerStack = <analyzer.BeginToken>[]; |
| 340 fasta.BeginGroupToken lastClosedGroup; | 340 analyzer.BeginToken lastClosedGroup; |
| 341 fasta.Token token = firstToken; | 341 fasta.Token token = firstToken; |
| 342 while (!token.isEof) { | 342 while (!token.isEof) { |
| 343 if (token is fasta.BeginGroupToken) { | 343 if (token is analyzer.BeginToken) { |
| 344 if (token.lexeme != '<') | 344 if (token.lexeme != '<') |
| 345 expect(token.endGroup, isNotNull, reason: token.lexeme); | 345 expect(token.endGroup, isNotNull, reason: token.lexeme); |
| 346 if (token.endGroup != null) openerStack.add(token); | 346 if (token.endGroup != null) openerStack.add(token); |
| 347 } else if (openerStack.isNotEmpty && openerStack.last.endGroup == token) { | 347 } else if (openerStack.isNotEmpty && openerStack.last.endGroup == token) { |
| 348 lastClosedGroup = openerStack.removeLast(); | 348 lastClosedGroup = openerStack.removeLast(); |
| 349 expect(token.isSynthetic, token.next is fasta.UnmatchedToken, | 349 expect(token.isSynthetic, token.next is fasta.UnmatchedToken, |
| 350 reason: 'Expect synthetic closer then error token'); | 350 reason: 'Expect synthetic closer then error token, ' |
| 351 'but found "$token" followed by "${token.next}"'); |
| 351 } else if (token is fasta.UnmatchedToken) { | 352 } else if (token is fasta.UnmatchedToken) { |
| 352 expect(lastClosedGroup?.endGroup?.next, same(token), | 353 expect(lastClosedGroup?.endGroup?.next, same(token), |
| 353 reason: 'Unexpected error token for group: $lastClosedGroup'); | 354 reason: 'Unexpected error token for group: $lastClosedGroup'); |
| 354 expect(token.begin, lastClosedGroup); | 355 expect(token.begin, lastClosedGroup); |
| 355 } | 356 } |
| 356 token = token.next; | 357 token = token.next; |
| 357 } | 358 } |
| 358 expect(openerStack, isEmpty, reason: 'Missing closers'); | 359 expect(openerStack, isEmpty, reason: 'Missing closers'); |
| 359 } | 360 } |
| 360 } | 361 } |
| OLD | NEW |