Index: pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart |
diff --git a/pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart |
index 972f295d08eb733c3f595ca888b42f5f67895139..3affe47d4ceb5ba467ee28e6c2f992eebba8cb92 100644 |
--- a/pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart |
+++ b/pkg/front_end/lib/src/fasta/scanner/array_based_scanner.dart |
@@ -4,7 +4,7 @@ |
library fasta.scanner.array_based_scanner; |
-import 'error_token.dart' show ErrorToken; |
+import 'error_token.dart' show ErrorToken, UnmatchedToken; |
import 'keyword.dart' show Keyword; |
@@ -18,6 +18,7 @@ import 'token.dart' |
KeywordToken, |
StringToken, |
SymbolToken, |
+ SyntheticSymbolToken, |
Token; |
import 'token_constants.dart' |
@@ -29,7 +30,7 @@ import 'token_constants.dart' |
import 'characters.dart' show $LF, $STX; |
-import 'abstract_scanner.dart' show AbstractScanner; |
+import 'abstract_scanner.dart' show AbstractScanner, closeBraceInfoFor; |
import '../util/link.dart' show Link; |
@@ -319,4 +320,55 @@ abstract class ArrayBasedScanner extends AbstractScanner { |
groupingStack = groupingStack.tail; |
} |
} |
+ |
+ void unmatchedBeginGroup(BeginGroupToken begin) { |
+ // We want to ensure that unmatched BeginGroupTokens are reported as |
+ // errors. However, the diet parser assumes that groups are well-balanced |
+ // and will never look at the endGroup token. This is a nice property that |
+ // allows us to skip quickly over correct code. By inserting an additional |
+ // synthetic token in the stream, we can keep ignoring endGroup tokens. |
+ // |
+ // [begin] --next--> [tail] |
+ // [begin] --endG--> [synthetic] --next--> [next] --next--> [tail] |
+ // |
+ // This allows the diet parser to skip from [begin] via endGroup to |
+ // [synthetic] and ignore the [synthetic] token (assuming it's correct), |
+ // then the error will be reported when parsing the [next] token. |
+ // |
+ // For example, tokenize("{[1};") produces: |
+ // |
+ // SymbolToken({) --endGroup------------------------+ |
+ // | | |
+ // next | |
+ // v | |
+ // SymbolToken([) --endGroup--+ | |
+ // | | | |
+ // next | | |
+ // v | | |
+ // StringToken(1) | | |
+ // | | | |
+ // next | | |
+ // v | | |
+ // SymbolToken(])<------------+ <-- Synthetic token | |
+ // | | |
+ // next | |
+ // v | |
+ // UnmatchedToken([) | |
+ // | | |
+ // next | |
+ // v | |
+ // SymbolToken(})<----------------------------------+ |
+ // | |
+ // next |
+ // v |
+ // SymbolToken(;) |
+ // | |
+ // next |
+ // v |
+ // EOF |
+ PrecedenceInfo info = closeBraceInfoFor(begin); |
+ appendToken(new SyntheticSymbolToken(info, tokenStart)); |
+ begin.endGroup = tail; |
+ appendErrorToken(new UnmatchedToken(begin)); |
+ } |
} |