@@ -68,36 +68,7 @@ extension TokenConsumer {
68
68
) -> Bool {
69
69
var subparser = self . lookahead ( )
70
70
71
- var hasAttribute = false
72
- var attributeProgress = LoopProgressCondition ( )
73
- while subparser. hasProgressed ( & attributeProgress) {
74
- if subparser. at ( . atSign) {
75
- _ = subparser. consumeAttributeList ( )
76
- hasAttribute = true
77
- } else if subparser. at ( . poundIf) && subparser. consumeIfConfigOfAttributes ( ) {
78
- hasAttribute = true
79
- } else {
80
- break
81
- }
82
- }
83
-
84
- var hasModifier = false
85
- if subparser. currentToken. isLexerClassifiedKeyword || subparser. currentToken. rawTokenKind == . identifier {
86
- var modifierProgress = LoopProgressCondition ( )
87
- while let ( modifierKind, handle) = subparser. at ( anyIn: DeclarationModifier . self) ,
88
- modifierKind != . class,
89
- subparser. hasProgressed ( & modifierProgress)
90
- {
91
- hasModifier = true
92
- subparser. eat ( handle)
93
- if modifierKind != . open && subparser. at ( . leftParen) && modifierKind. canHaveParenthesizedArgument {
94
- // When determining whether we are at a declaration, don't consume anything in parentheses after 'open'
95
- // so we don't consider a function call to open as a decl modifier. This matches the C++ parser.
96
- subparser. consumeAnyToken ( )
97
- subparser. consume ( to: . rightParen)
98
- }
99
- }
100
- }
71
+ let ( hasAttribute, hasModifier) = subparser. skipAttributesAndModifiers ( )
101
72
102
73
if hasAttribute {
103
74
if subparser. at ( . rightBrace) || subparser. at ( . endOfFile) || subparser. at ( . poundEndif) {
@@ -112,17 +83,7 @@ extension TokenConsumer {
112
83
switch subparser. at ( anyIn: DeclarationKeyword . self) ? . 0 {
113
84
case . lhs( . actor ) :
114
85
// actor Foo {}
115
- if subparser. peek ( ) . rawTokenKind == . identifier {
116
- return true
117
- }
118
- // actor may be somewhere in the modifier list. Eat the tokens until we get
119
- // to something that isn't the start of a decl. If that is an identifier,
120
- // it's an actor declaration, otherwise, it isn't.
121
- var lookahead = subparser. lookahead ( )
122
- repeat {
123
- lookahead. consumeAnyToken ( )
124
- } while lookahead. atStartOfDeclaration ( allowInitDecl: allowInitDecl, requiresDecl: requiresDecl)
125
- return lookahead. at ( . identifier)
86
+ return subparser. atStartOfActor ( allowInitDecl: allowInitDecl, requiresDecl: requiresDecl)
126
87
case . lhs( . case) :
127
88
// When 'case' appears inside a function, it's probably a switch
128
89
// case, not an enum case declaration.
@@ -146,23 +107,7 @@ extension TokenConsumer {
146
107
return false
147
108
}
148
109
149
- var lookahead = subparser. lookahead ( )
150
-
151
- // Consume 'using'
152
- lookahead. consumeAnyToken ( )
153
-
154
- // Allow parsing 'using' as declaration only if
155
- // it's immediately followed by either `@` or
156
- // an identifier.
157
- if lookahead. atStartOfLine {
158
- return false
159
- }
160
-
161
- guard lookahead. at ( . atSign) || lookahead. at ( . identifier) else {
162
- return false
163
- }
164
-
165
- return true
110
+ return subparser. atStartOfUsing ( )
166
111
case . some( _) :
167
112
// All other decl start keywords unconditionally start a decl.
168
113
return true
@@ -200,6 +145,80 @@ extension TokenConsumer {
200
145
}
201
146
}
202
147
148
+ extension Parser . Lookahead {
149
+ fileprivate mutating func skipAttributesAndModifiers( ) -> ( hasAttribute: Bool , hasModifier: Bool ) {
150
+ var hasAttribute = false
151
+ var attributeProgress = LoopProgressCondition ( )
152
+ while self . hasProgressed ( & attributeProgress) {
153
+ if self . at ( . atSign) {
154
+ _ = self . consumeAttributeList ( )
155
+ hasAttribute = true
156
+ } else if self . at ( . poundIf) && self . consumeIfConfigOfAttributes ( ) {
157
+ hasAttribute = true
158
+ } else {
159
+ break
160
+ }
161
+ }
162
+
163
+ var hasModifier = false
164
+ if self . currentToken. isLexerClassifiedKeyword || self . currentToken. rawTokenKind == . identifier {
165
+ var modifierProgress = LoopProgressCondition ( )
166
+ while let ( modifierKind, handle) = self . at ( anyIn: DeclarationModifier . self) ,
167
+ modifierKind != . class,
168
+ self . hasProgressed ( & modifierProgress)
169
+ {
170
+ hasModifier = true
171
+ self . eat ( handle)
172
+ if modifierKind != . open && self . at ( . leftParen) && modifierKind. canHaveParenthesizedArgument {
173
+ // When determining whether we are at a declaration, don't consume anything in parentheses after 'open'
174
+ // so we don't consider a function call to open as a decl modifier. This matches the C++ parser.
175
+ self . consumeAnyToken ( )
176
+ self . consume ( to: . rightParen)
177
+ }
178
+ }
179
+ }
180
+
181
+ return ( hasAttribute, hasModifier)
182
+ }
183
+
184
+ fileprivate mutating func atStartOfActor(
185
+ allowInitDecl: Bool ,
186
+ requiresDecl: Bool
187
+ ) -> Bool {
188
+ if self . peek ( ) . rawTokenKind == . identifier {
189
+ return true
190
+ }
191
+ // actor may be somewhere in the modifier list. Eat the tokens until we get
192
+ // to something that isn't the start of a decl. If that is an identifier,
193
+ // it's an actor declaration, otherwise, it isn't.
194
+ var lookahead = self . lookahead ( )
195
+ repeat {
196
+ lookahead. consumeAnyToken ( )
197
+ } while lookahead. atStartOfDeclaration ( allowInitDecl: allowInitDecl, requiresDecl: requiresDecl)
198
+ return lookahead. at ( . identifier)
199
+ }
200
+
201
+ fileprivate mutating func atStartOfUsing( ) -> Bool {
202
+ var lookahead = self . lookahead ( )
203
+
204
+ // Consume 'using'
205
+ lookahead. consumeAnyToken ( )
206
+
207
+ // Allow parsing 'using' as declaration only if
208
+ // it's immediately followed by either `@` or
209
+ // an identifier.
210
+ if lookahead. atStartOfLine {
211
+ return false
212
+ }
213
+
214
+ guard lookahead. at ( . atSign) || lookahead. at ( . identifier) else {
215
+ return false
216
+ }
217
+
218
+ return true
219
+ }
220
+ }
221
+
203
222
extension Parser {
204
223
struct DeclAttributes {
205
224
var attributes : RawAttributeListSyntax
0 commit comments