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 library fasta.parser.parser; | 5 library fasta.parser.parser; |
6 | 6 |
7 import '../fasta_codes.dart' | 7 import '../fasta_codes.dart' |
8 show | 8 show |
9 FastaCode, | 9 FastaCode, |
10 FastaMessage, | 10 FastaMessage, |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 /// | 173 /// |
174 /// An assertion can legally occur as a statement. However, assertions are also | 174 /// An assertion can legally occur as a statement. However, assertions are also |
175 /// experimentally allowed in initializers. For improved error recovery, we | 175 /// experimentally allowed in initializers. For improved error recovery, we |
176 /// also attempt to parse asserts as expressions. | 176 /// also attempt to parse asserts as expressions. |
177 enum Assert { | 177 enum Assert { |
178 Expression, | 178 Expression, |
179 Initializer, | 179 Initializer, |
180 Statement, | 180 Statement, |
181 } | 181 } |
182 | 182 |
183 enum TypeContinuation { | |
Paul Berry
2017/06/24 14:16:26
It would be nice to have a comment explaining what
ahe
2017/06/26 10:14:00
I want to reserve that word for you :-)
| |
184 Typedef, | |
185 } | |
186 | |
183 /// An event generating parser of Dart programs. This parser expects all tokens | 187 /// An event generating parser of Dart programs. This parser expects all tokens |
184 /// in a linked list (aka a token stream). | 188 /// in a linked list (aka a token stream). |
185 /// | 189 /// |
186 /// The class [Scanner] is used to generate a token stream. See the file | 190 /// The class [Scanner] is used to generate a token stream. See the file |
187 /// [scanner.dart](../scanner.dart). | 191 /// [scanner.dart](../scanner.dart). |
188 /// | 192 /// |
189 /// Subclasses of the class [Listener] are used to listen to events. | 193 /// Subclasses of the class [Listener] are used to listen to events. |
190 /// | 194 /// |
191 /// Most methods of this class belong in one of three major categories: parse | 195 /// Most methods of this class belong in one of three major categories: parse |
192 /// methods, peek methods, and skip methods. Parse methods all have the prefix | 196 /// methods, peek methods, and skip methods. Parse methods all have the prefix |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
608 | 612 |
609 Token parseScript(Token token) { | 613 Token parseScript(Token token) { |
610 listener.handleScript(token); | 614 listener.handleScript(token); |
611 return token.next; | 615 return token.next; |
612 } | 616 } |
613 | 617 |
614 Token parseTypedef(Token token) { | 618 Token parseTypedef(Token token) { |
615 Token typedefKeyword = token; | 619 Token typedefKeyword = token; |
616 listener.beginFunctionTypeAlias(token); | 620 listener.beginFunctionTypeAlias(token); |
617 Token equals; | 621 Token equals; |
618 if (optional('=', peekAfterNominalType(token.next))) { | 622 Token afterType = parseType(token.next, |
623 isOptional: true, continuation: TypeContinuation.Typedef); | |
624 if (afterType == null) { | |
619 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); | 625 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); |
620 token = parseTypeVariablesOpt(token); | 626 token = parseTypeVariablesOpt(token); |
621 equals = token; | 627 equals = token; |
622 token = expect('=', token); | 628 token = expect('=', token); |
623 token = parseType(token); | 629 token = parseType(token); |
624 } else { | 630 } else { |
625 token = parseType(token.next, isOptional: true); | 631 token = afterType; |
626 token = parseIdentifier(token, IdentifierContext.typedefDeclaration); | 632 token = parseIdentifier(token, IdentifierContext.typedefDeclaration); |
627 token = parseTypeVariablesOpt(token); | 633 token = parseTypeVariablesOpt(token); |
628 token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); | 634 token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); |
629 } | 635 } |
630 listener.endFunctionTypeAlias(typedefKeyword, equals, token); | 636 listener.endFunctionTypeAlias(typedefKeyword, equals, token); |
631 return expect(';', token); | 637 return expect(';', token); |
632 } | 638 } |
633 | 639 |
634 Token parseMixinApplication(Token token) { | 640 Token parseMixinApplication(Token token) { |
635 listener.beginMixinApplication(token); | 641 listener.beginMixinApplication(token); |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
961 count++; | 967 count++; |
962 } | 968 } |
963 } | 969 } |
964 Token endBrace = token; | 970 Token endBrace = token; |
965 token = expect('}', token); | 971 token = expect('}', token); |
966 listener.endEnum(enumKeyword, endBrace, count); | 972 listener.endEnum(enumKeyword, endBrace, count); |
967 return token; | 973 return token; |
968 } | 974 } |
969 | 975 |
970 Token parseClassOrNamedMixinApplication(Token token) { | 976 Token parseClassOrNamedMixinApplication(Token token) { |
977 listener.beginClassOrNamedMixinApplication(token); | |
971 Token begin = token; | 978 Token begin = token; |
972 Token abstractKeyword; | 979 if (optional('abstract', token)) { |
980 token = parseModifier(token); | |
981 listener.handleModifiers(1); | |
982 } else { | |
983 listener.handleModifiers(0); | |
984 } | |
973 Token classKeyword = token; | 985 Token classKeyword = token; |
974 if (optional('abstract', token)) { | 986 token = expect("class", token); |
975 abstractKeyword = token; | 987 Token name = token; |
976 token = token.next; | 988 token = |
977 classKeyword = token; | 989 parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration); |
978 } | 990 token = parseTypeVariablesOpt(token); |
979 assert(optional('class', classKeyword)); | 991 if (optional('=', token)) { |
980 int modifierCount = 0; | |
981 if (abstractKeyword != null) { | |
982 parseModifier(abstractKeyword); | |
983 modifierCount++; | |
984 } | |
985 listener.handleModifiers(modifierCount); | |
986 bool isMixinApplication = optional('=', peekAfterNominalType(token)); | |
987 Token name = token.next; | |
988 | |
989 if (isMixinApplication) { | |
990 token = parseIdentifier(name, IdentifierContext.namedMixinDeclaration); | |
991 listener.beginNamedMixinApplication(begin, name); | 992 listener.beginNamedMixinApplication(begin, name); |
992 } else { | |
993 token = parseIdentifier(name, IdentifierContext.classDeclaration); | |
994 listener.beginClassDeclaration(begin, name); | |
995 } | |
996 | |
997 token = parseTypeVariablesOpt(token); | |
998 | |
999 if (optional('=', token)) { | |
1000 Token equals = token; | 993 Token equals = token; |
1001 token = token.next; | 994 token = token.next; |
1002 return parseNamedMixinApplication( | 995 return parseNamedMixinApplication( |
1003 token, begin, classKeyword, name, equals); | 996 token, begin, classKeyword, name, equals); |
1004 } else { | 997 } else { |
998 listener.beginClassDeclaration(begin, name); | |
1005 return parseClass(token, begin, classKeyword, name); | 999 return parseClass(token, begin, classKeyword, name); |
1006 } | 1000 } |
1007 } | 1001 } |
1008 | 1002 |
1009 Token parseNamedMixinApplication( | 1003 Token parseNamedMixinApplication( |
1010 Token token, Token begin, Token classKeyword, Token name, Token equals) { | 1004 Token token, Token begin, Token classKeyword, Token name, Token equals) { |
1011 token = parseMixinApplication(token); | 1005 token = parseMixinApplication(token); |
1012 Token implementsKeyword = null; | 1006 Token implementsKeyword = null; |
1013 if (optional('implements', token)) { | 1007 if (optional('implements', token)) { |
1014 implementsKeyword = token; | 1008 implementsKeyword = token; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1132 bool notEofOrValue(String value, Token token) { | 1126 bool notEofOrValue(String value, Token token) { |
1133 return !identical(token.kind, EOF_TOKEN) && | 1127 return !identical(token.kind, EOF_TOKEN) && |
1134 !identical(value, token.stringValue); | 1128 !identical(value, token.stringValue); |
1135 } | 1129 } |
1136 | 1130 |
1137 bool isGeneralizedFunctionType(Token token) { | 1131 bool isGeneralizedFunctionType(Token token) { |
1138 return optional('Function', token) && | 1132 return optional('Function', token) && |
1139 (optional('<', token.next) || optional('(', token.next)); | 1133 (optional('<', token.next) || optional('(', token.next)); |
1140 } | 1134 } |
1141 | 1135 |
1142 Token parseType(Token token, {bool isOptional: false}) { | 1136 Token parseType(Token token, |
Paul Berry
2017/06/24 14:16:26
It would be nice to have a comment here explaining
ahe
2017/06/26 10:14:01
Done.
| |
1137 {bool isOptional: false, TypeContinuation continuation}) { | |
1138 if (continuation != null) { | |
ahe
2017/06/24 10:10:31
A little bit of context here:
My plan is to move
| |
1139 switch (continuation) { | |
Paul Berry
2017/06/24 14:16:26
Nit: It seems odd to have a null check followed by
ahe
2017/06/26 10:14:00
Done.
| |
1140 case TypeContinuation.Typedef: | |
1141 if (optional('=', peekAfterNominalType(token))) { | |
1142 return null; // This isn't a type, it's a new-style typedef. | |
1143 } | |
1144 break; | |
1145 | |
1146 default: | |
1147 throw "Internal error: Unhandled continuation '$continuation'."; | |
1148 } | |
1149 } | |
1143 if (isOptional) { | 1150 if (isOptional) { |
1144 do { | 1151 do { |
1145 if (optional("void", token)) { | 1152 if (optional("void", token)) { |
1146 if (isGeneralizedFunctionType(token.next)) { | 1153 if (isGeneralizedFunctionType(token.next)) { |
1147 // This is a type, parse it. | 1154 // This is a type, parse it. |
1148 break; | 1155 break; |
1149 } else { | 1156 } else { |
1150 listener.handleVoidKeyword(token); | 1157 listener.handleVoidKeyword(token); |
1151 return token.next; | 1158 return token.next; |
1152 } | 1159 } |
(...skipping 2872 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4025 return reportUnrecoverableError( | 4032 return reportUnrecoverableError( |
4026 token, () => code.format(uri, token.charOffset, string)); | 4033 token, () => code.format(uri, token.charOffset, string)); |
4027 } | 4034 } |
4028 } | 4035 } |
4029 | 4036 |
4030 typedef FastaMessage NoArgument(Uri uri, int charOffset); | 4037 typedef FastaMessage NoArgument(Uri uri, int charOffset); |
4031 | 4038 |
4032 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); | 4039 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); |
4033 | 4040 |
4034 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); | 4041 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); |
OLD | NEW |