@@ -16,22 +16,22 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
16
16
public typealias Path = SmallProjectionPath
17
17
18
18
public enum Kind {
19
- /// The selected argument value does not escape.
19
+ /// The argument value does not escape.
20
20
///
21
21
/// Syntax examples:
22
- /// !%0 // argument 0 does not escape
23
- /// !%0.** // argument 0 and all transitively contained values do not escape
22
+ /// [%0: noescape] // argument 0 does not escape
23
+ /// [%0: noescape **] // argument 0 and all transitively contained values do not escape
24
24
///
25
25
case notEscaping
26
26
27
- /// The selected argument value escapes to the specified selection (= first payload) .
27
+ /// The argument value escapes to the function return value .
28
28
///
29
29
/// Syntax examples:
30
- /// %0. s1 => %r // field 2 of argument 0 exclusively escapes via return.
31
- /// %0. s1 -> %1 // field 2 of argument 0 - and other values - escape to argument 1.
30
+ /// [%0: escape s1 => %r] // field 2 of argument 0 exclusively escapes via return.
31
+ /// [%0: escape s1 -> %r] // field 2 of argument 0 - and other values - escape via return
32
32
///
33
- /// The "exclusive" flag (= second payload) is true if only the selected argument escapes
34
- /// to the specified selection, but nothing else escapes to it .
33
+ /// The "exclusive" flag (= second payload) is true if only the argument escapes,
34
+ /// but nothing else escapes to the return value .
35
35
/// For example, "exclusive" is true for the following function:
36
36
///
37
37
/// @_effect(escaping c => return)
@@ -46,6 +46,14 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
46
46
///
47
47
case escapingToReturn( Path , Bool ) // toPath, exclusive
48
48
49
+ /// Like `escapingToReturn`, but the argument escapes to another argument.
50
+ ///
51
+ /// Example: The argument effects of
52
+ /// func argToArgEscape(_ r: inout Class, _ c: Class) { r = c }
53
+ ///
54
+ /// would be
55
+ /// [%1: escape => %0] // Argument 1 escapes to argument 0
56
+ ///
49
57
case escapingToArgument( Int , Path , Bool ) // toArgumentIndex, toPath, exclusive
50
58
}
51
59
@@ -111,21 +119,28 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
111
119
return argumentIndex == rhsArgIdx && rhsPath. matches ( pattern: pathPattern)
112
120
}
113
121
114
- public var description : String {
115
- let selectedArg = " % \( argumentIndex) " + ( pathPattern. isEmpty ? " " : " . \( pathPattern) " )
122
+ public var headerDescription : String {
123
+ " % \( argumentIndex) \( isDerived ? " " : " ! " ) : "
124
+ }
116
125
126
+ public var bodyDescription : String {
127
+ let patternStr = pathPattern. isEmpty ? " " : " \( pathPattern) "
117
128
switch kind {
118
129
case . notEscaping:
119
- return " ! \( selectedArg ) "
130
+ return " noescape \( patternStr ) "
120
131
case . escapingToReturn( let toPath, let exclusive) :
121
- let pathStr = ( toPath. isEmpty ? " " : " . \( toPath) " )
122
- return " \( selectedArg ) \( exclusive ? " => " : " -> " ) %r \( pathStr ) "
132
+ let toPathStr = ( toPath. isEmpty ? " " : " . \( toPath) " )
133
+ return " escape \( patternStr ) \( exclusive ? " => " : " -> " ) %r \( toPathStr ) "
123
134
case . escapingToArgument( let toArgIdx, let toPath, let exclusive) :
124
- let pathStr = ( toPath. isEmpty ? " " : " . \( toPath) " )
125
- return " \( selectedArg ) \( exclusive ? " => " : " -> " ) % \( toArgIdx) \( pathStr ) "
135
+ let toPathStr = ( toPath. isEmpty ? " " : " . \( toPath) " )
136
+ return " escape \( patternStr ) \( exclusive ? " => " : " -> " ) % \( toArgIdx) \( toPathStr ) "
126
137
}
127
138
}
128
139
140
+ public var description : String {
141
+ headerDescription + bodyDescription
142
+ }
143
+
129
144
public var customMirror : Mirror { Mirror ( self , children: [ ] ) }
130
145
}
131
146
@@ -164,8 +179,27 @@ public struct FunctionEffects : CustomStringConvertible, CustomReflectable {
164
179
argumentEffects = argumentEffects. filter { !$0. isDerived }
165
180
}
166
181
182
+ public var argumentEffectsDescription : String {
183
+ var currentArgIdx = - 1
184
+ var currentIsDerived = false
185
+ var result = " "
186
+ for effect in argumentEffects {
187
+ if effect. argumentIndex != currentArgIdx || effect. isDerived != currentIsDerived {
188
+ if currentArgIdx >= 0 { result += " ] \n " }
189
+ result += " [ \( effect. headerDescription) "
190
+ currentArgIdx = effect. argumentIndex
191
+ currentIsDerived = effect. isDerived
192
+ } else {
193
+ result += " , "
194
+ }
195
+ result += effect. bodyDescription
196
+ }
197
+ if currentArgIdx >= 0 { result += " ] \n " }
198
+ return result
199
+ }
200
+
167
201
public var description : String {
168
- return " [ " + argumentEffects . map { $0 . description } . joined ( separator : " , " ) + " ] "
202
+ return argumentEffectsDescription
169
203
}
170
204
171
205
public var customMirror : Mirror { Mirror ( self , children: [ ] ) }
@@ -237,24 +271,37 @@ extension StringParser {
237
271
return ArgumentEffect . Path ( )
238
272
}
239
273
240
- mutating func parseEffectFromSIL ( for function : Function , isDerived : Bool ) throws -> ArgumentEffect {
241
- if consume ( " ! " ) {
242
- let argIdx = try parseArgumentIndexFromSIL ( )
243
- let path = try parsePathPatternFromSIL ( )
244
- return ArgumentEffect ( . notEscaping , argumentIndex : argIdx , pathPattern : path , isDerived : isDerived )
274
+ mutating func parseEffectsFromSIL ( to effects : inout FunctionEffects ) throws {
275
+ let argumentIndex = try parseArgumentIndexFromSIL ( )
276
+ let isDerived = !consume ( " ! " )
277
+ if !consume ( " : " ) {
278
+ try throwError ( " expected ':' " )
245
279
}
246
- let fromArgIdx = try parseArgumentIndexFromSIL ( )
247
- let fromPath = try parsePathPatternFromSIL ( )
248
- let exclusive = try parseEscapingArrow ( )
249
- if consume ( " %r " ) {
250
- let toPath = try parsePathPatternFromSIL ( )
251
- return ArgumentEffect ( . escapingToReturn( toPath, exclusive) ,
252
- argumentIndex: fromArgIdx, pathPattern: fromPath, isDerived: isDerived)
280
+ repeat {
281
+ let effect = try parseEffectFromSIL ( argumentIndex: argumentIndex, isDerived: isDerived)
282
+ effects. argumentEffects. append ( effect)
283
+ } while consume ( " , " )
284
+ }
285
+
286
+ mutating func parseEffectFromSIL( argumentIndex: Int , isDerived: Bool ) throws -> ArgumentEffect {
287
+ if consume ( " noescape " ) {
288
+ let path = try parseProjectionPathFromSIL ( )
289
+ return ArgumentEffect ( . notEscaping, argumentIndex: argumentIndex, pathPattern: path, isDerived: isDerived)
290
+ }
291
+ if consume ( " escape " ) {
292
+ let fromPath = try parseProjectionPathFromSIL ( )
293
+ let exclusive = try parseEscapingArrow ( )
294
+ if consume ( " %r " ) {
295
+ let toPath = consume ( " . " ) ? try parseProjectionPathFromSIL ( ) : ArgumentEffect . Path ( )
296
+ return ArgumentEffect ( . escapingToReturn( toPath, exclusive) ,
297
+ argumentIndex: argumentIndex, pathPattern: fromPath, isDerived: isDerived)
298
+ }
299
+ let toArgIdx = try parseArgumentIndexFromSIL ( )
300
+ let toPath = consume ( " . " ) ? try parseProjectionPathFromSIL ( ) : ArgumentEffect . Path ( )
301
+ return ArgumentEffect ( . escapingToArgument( toArgIdx, toPath, exclusive) ,
302
+ argumentIndex: argumentIndex, pathPattern: fromPath, isDerived: isDerived)
253
303
}
254
- let toArgIdx = try parseArgumentIndexFromSIL ( )
255
- let toPath = try parsePathPatternFromSIL ( )
256
- return ArgumentEffect ( . escapingToArgument( toArgIdx, toPath, exclusive) ,
257
- argumentIndex: fromArgIdx, pathPattern: fromPath, isDerived: isDerived)
304
+ try throwError ( " unknown effect " )
258
305
}
259
306
260
307
mutating func parseArgumentIndexFromSIL( ) throws -> Int {
@@ -267,13 +314,6 @@ extension StringParser {
267
314
try throwError ( " expected parameter " )
268
315
}
269
316
270
- mutating func parsePathPatternFromSIL( ) throws -> ArgumentEffect . Path {
271
- if consume ( " . " ) {
272
- return try parseProjectionPathFromSIL ( )
273
- }
274
- return ArgumentEffect . Path ( )
275
- }
276
-
277
317
private mutating func parseEscapingArrow( ) throws -> Bool {
278
318
if consume ( " => " ) { return true }
279
319
if consume ( " -> " ) { return false }
0 commit comments