@@ -16,22 +16,22 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
1616 public typealias Path = SmallProjectionPath
1717
1818 public enum Kind {
19- /// The selected argument value does not escape.
19+ /// The argument value does not escape.
2020 ///
2121 /// 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
2424 ///
2525 case notEscaping
2626
27- /// The selected argument value escapes to the specified selection (= first payload) .
27+ /// The argument value escapes to the function return value .
2828 ///
2929 /// 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
3232 ///
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 .
3535 /// For example, "exclusive" is true for the following function:
3636 ///
3737 /// @_effect(escaping c => return)
@@ -46,6 +46,14 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
4646 ///
4747 case escapingToReturn( Path , Bool ) // toPath, exclusive
4848
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+ ///
4957 case escapingToArgument( Int , Path , Bool ) // toArgumentIndex, toPath, exclusive
5058 }
5159
@@ -111,21 +119,28 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
111119 return argumentIndex == rhsArgIdx && rhsPath. matches ( pattern: pathPattern)
112120 }
113121
114- public var description : String {
115- let selectedArg = " % \( argumentIndex) " + ( pathPattern. isEmpty ? " " : " . \( pathPattern) " )
122+ public var headerDescription : String {
123+ " % \( argumentIndex) \( isDerived ? " " : " ! " ) : "
124+ }
116125
126+ public var bodyDescription : String {
127+ let patternStr = pathPattern. isEmpty ? " " : " \( pathPattern) "
117128 switch kind {
118129 case . notEscaping:
119- return " ! \( selectedArg ) "
130+ return " noescape \( patternStr ) "
120131 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 ) "
123134 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 ) "
126137 }
127138 }
128139
140+ public var description : String {
141+ headerDescription + bodyDescription
142+ }
143+
129144 public var customMirror : Mirror { Mirror ( self , children: [ ] ) }
130145}
131146
@@ -164,8 +179,27 @@ public struct FunctionEffects : CustomStringConvertible, CustomReflectable {
164179 argumentEffects = argumentEffects. filter { !$0. isDerived }
165180 }
166181
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+
167201 public var description : String {
168- return " [ " + argumentEffects . map { $0 . description } . joined ( separator : " , " ) + " ] "
202+ return argumentEffectsDescription
169203 }
170204
171205 public var customMirror : Mirror { Mirror ( self , children: [ ] ) }
@@ -237,24 +271,37 @@ extension StringParser {
237271 return ArgumentEffect . Path ( )
238272 }
239273
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 ':' " )
245279 }
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)
253303 }
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 " )
258305 }
259306
260307 mutating func parseArgumentIndexFromSIL( ) throws -> Int {
@@ -267,13 +314,6 @@ extension StringParser {
267314 try throwError ( " expected parameter " )
268315 }
269316
270- mutating func parsePathPatternFromSIL( ) throws -> ArgumentEffect . Path {
271- if consume ( " . " ) {
272- return try parseProjectionPathFromSIL ( )
273- }
274- return ArgumentEffect . Path ( )
275- }
276-
277317 private mutating func parseEscapingArrow( ) throws -> Bool {
278318 if consume ( " => " ) { return true }
279319 if consume ( " -> " ) { return false }
0 commit comments