@@ -13,10 +13,12 @@ class ParseEnumCase<C: MacroExpansionContext>: SyntaxVisitor {
1313
1414 private var workEnum : EnumDeclSyntax ?
1515 private var currentParseMacroVisitor : StructFieldVisitor < C > ?
16- private var currentCaseElement : EnumCaseElementSyntax ?
16+ private var currentCaseElements : EnumCaseElementListSyntax ?
1717 private var caseParseInfo : [ EnumCaseParseInfo ] = [ ]
1818 private( set) var parsedInfo : EnumParseInfo ?
1919
20+ private var hasMatchDefault = false
21+
2022 private var errors : [ Diagnostic ] = [ ]
2123
2224 init ( context: C ) {
@@ -33,30 +35,16 @@ class ParseEnumCase<C: MacroExpansionContext>: SyntaxVisitor {
3335 return . visitChildren
3436 }
3537
36- override func visit( _ node: EnumCaseDeclSyntax ) -> SyntaxVisitorContinueKind {
37- // has multiple declaration in the same `case`, reject
38- guard node. elements. count <= 1 else {
39- errors. append ( . init( node: node, message: ParseEnumMacroError . onlyOneEnumDeclarationForEachCase) )
40- return . skipChildren
41- }
42-
43- return . visitChildren
44- }
45-
4638 override func visit( _ node: AttributeListSyntax ) -> SyntaxVisitorContinueKind {
4739 currentParseMacroVisitor = StructFieldVisitor ( context: context)
4840 currentParseMacroVisitor? . walk ( node)
49- do {
50- try currentParseMacroVisitor? . validate ( )
51- } catch {
52- errors. append ( . init( node: node, message: error) )
53- }
41+ currentParseMacroVisitor? . validate ( errors: & errors)
5442
5543 return . skipChildren
5644 }
5745
58- override func visit( _ node: EnumCaseElementSyntax ) -> SyntaxVisitorContinueKind {
59- currentCaseElement = node
46+ override func visit( _ node: EnumCaseElementListSyntax ) -> SyntaxVisitorContinueKind {
47+ currentCaseElements = node
6048 return . skipChildren
6149 }
6250
@@ -71,7 +59,7 @@ class ParseEnumCase<C: MacroExpansionContext>: SyntaxVisitor {
7159 guard node. belongsTo ( workEnum) else {
7260 return
7361 }
74- guard let currentCaseElement else {
62+ guard let currentCaseElements , !currentCaseElements . isEmpty else {
7563 errors. append ( . init(
7664 node: node,
7765 message: ParseEnumMacroError . unexpectedError ( description: " No enum case declaration " ) ,
@@ -98,33 +86,43 @@ class ParseEnumCase<C: MacroExpansionContext>: SyntaxVisitor {
9886 return
9987 }
10088
101- let caseParameters = currentCaseElement. parameterClause? . parameters ?? [ ]
89+ if matchAction. matchPolicy == . matchDefault {
90+ if hasMatchDefault {
91+ errors. append (
92+ . init(
93+ node: node,
94+ message: ParseEnumMacroError . onlyOneMatchDefaultAllowed,
95+ ) ,
96+ )
97+ return
98+ }
10299
103- let enumParseActions : [ EnumParseAction ]
104- do {
105- enumParseActions = try currentParseMacroVisitor. parseActions. convertToEnumParseAction ( with: caseParameters)
106- } catch {
107- errors. append ( . init( node: caseParameters, message: error) )
108- return
100+ hasMatchDefault = true
101+ } else {
102+ if hasMatchDefault {
103+ errors. append (
104+ . init(
105+ node: node,
106+ message: ParseEnumMacroError . defaultCaseMustBeLast,
107+ ) ,
108+ )
109+ }
109110 }
110111
111- if caseParseInfo. last? . matchAction. matchPolicy == . matchDefault {
112- errors. append (
112+ for currentCaseElement in currentCaseElements {
113+ let enumParseActions = currentParseMacroVisitor. parseActions. convertToEnumParseAction (
114+ with: currentCaseElement,
115+ errors: & errors,
116+ )
117+
118+ caseParseInfo. append (
113119 . init(
114- node: node,
115- message: ParseEnumMacroError . defaultCaseMustBeLast,
120+ matchAction: matchAction,
121+ parseActions: enumParseActions,
122+ caseElementName: currentCaseElement. name,
116123 ) ,
117124 )
118- return
119125 }
120-
121- caseParseInfo. append (
122- . init(
123- matchAction: matchAction,
124- parseActions: enumParseActions,
125- caseElementName: currentCaseElement. name,
126- ) ,
127- )
128126 }
129127
130128 override func visitPost( _ node: EnumDeclSyntax ) {
@@ -139,11 +137,11 @@ class ParseEnumCase<C: MacroExpansionContext>: SyntaxVisitor {
139137 }
140138
141139 func validate( ) throws {
142- for error in errors {
143- context. diagnose ( error)
144- }
145-
146140 if !errors. isEmpty {
141+ for error in errors {
142+ context. diagnose ( error)
143+ }
144+
147145 throw ParseEnumMacroError . unexpectedError ( description: " Enum macro parsing encountered errors " )
148146 }
149147 }
@@ -167,8 +165,11 @@ private extension EnumCaseDeclSyntax {
167165
168166private extension [ StructParseAction ] {
169167 func convertToEnumParseAction(
170- with parameters: EnumCaseParameterListSyntax ,
171- ) throws ( ParseEnumMacroError) -> [ EnumParseAction ] {
168+ with enumCase: EnumCaseElementSyntax ,
169+ errors: inout [ Diagnostic ] ,
170+ ) -> [ EnumParseAction ] {
171+ let arguments = enumCase. parameterClause? . parameters ?? [ ]
172+
172173 var result : [ EnumParseAction ] = [ ]
173174 var parseActionIndex = 0
174175
@@ -177,30 +178,68 @@ private extension [StructParseAction] {
177178 parseActionIndex += 1
178179 }
179180
180- for parameter in parameters {
181+ for argument in arguments {
181182 while parseActionIndex < count, case let . skip( skipInfo) = self [ parseActionIndex] {
182183 addAction ( . skip( skipInfo) )
183184 }
184185
185186 guard parseActionIndex < count else {
186- throw ParseEnumMacroError . parameterParseNumberNotMatch
187+ errors. append (
188+ . init(
189+ node: argument,
190+ message: ParseEnumMacroError . caseArgumentsMoreThanMacros,
191+ ) ,
192+ )
193+ break
187194 }
188195
189196 guard case let . parse( parseInfo) = self [ parseActionIndex] else {
190- throw ParseEnumMacroError . unexpectedError ( description : " countered skip action " )
197+ fatalError ( " countered skip action " )
191198 }
192199
193200 addAction (
194201 . parse(
195202 . init(
196203 parseInfo: parseInfo,
197- firstName: parameter . firstName,
198- type: parameter . type,
204+ firstName: argument . firstName,
205+ type: argument . type,
199206 ) ,
200207 ) ,
201208 )
202209 }
203210
211+ if parseActionIndex != count {
212+ while parseActionIndex < count {
213+ let parseAction = self [ parseActionIndex]
214+
215+ errors. append (
216+ . init(
217+ node: parseAction. source,
218+ message: ParseEnumMacroError . macrosMoreThanCaseArguments,
219+ notes: [ . init(
220+ node: Syntax ( enumCase) ,
221+ message: MacrosMoreThanCaseArgumentsNote ( enumCase: enumCase. description) ,
222+ ) ] ,
223+ ) ,
224+ )
225+
226+ parseActionIndex += 1
227+ }
228+ }
229+
204230 return result
205231 }
206232}
233+
234+ struct MacrosMoreThanCaseArgumentsNote : NoteMessage {
235+ let enumCase : String
236+
237+ var message : String {
238+ " The enum case ` \( enumCase) ` has less associated values than parse/skip macros. "
239+ }
240+
241+ let noteID : SwiftDiagnostics . MessageID = . init(
242+ domain: " observer.universe.BinaryParseKit.MoreThanCaseArgumentsNote " ,
243+ id: " macrosMoreThanCaseArguments " ,
244+ )
245+ }
0 commit comments