Skip to content

Commit 0cb597e

Browse files
authored
Merge pull request #199 from dylansturg/less_memory_makes_me_happy
Peak memory use optimizations.
2 parents 34ccba1 + 4c8587f commit 0cb597e

File tree

1 file changed

+40
-16
lines changed

1 file changed

+40
-16
lines changed

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
4343

4444
/// Lists the expressions that have been visited, from the outermost expression, where contextual
4545
/// breaks and start/end contextual breaking tokens have been inserted.
46-
private var preVisitedExprs = Set<ExprSyntax>()
46+
private var preVisitedExprs = Set<SyntaxIdentifier>()
47+
48+
/// Tracks the "root" exprs where previsiting for contextual breaks started so that
49+
/// `preVisitedExprs` can be emptied after exiting an expr tree.
50+
private var rootExprs = Set<SyntaxIdentifier>()
4751

4852
/// Lists the tokens that are the closing or final delimiter of a node that shouldn't be split
4953
/// from the preceding token. When breaks are inserted around compound expressions, the breaks are
@@ -850,6 +854,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
850854
return .visitChildren
851855
}
852856

857+
override func visitPost(_ node: MemberAccessExprSyntax) {
858+
clearContextualBreakState(node)
859+
}
860+
853861
override func visit(_ node: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind {
854862
preVisitInsertingContextualBreaks(node)
855863

@@ -881,6 +889,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
881889
return .visitChildren
882890
}
883891

892+
override func visitPost(_ node: FunctionCallExprSyntax) {
893+
clearContextualBreakState(node)
894+
}
895+
884896
/// Arrange the given argument list (or equivalently, tuple expression list) as a list of function
885897
/// arguments.
886898
///
@@ -1076,6 +1088,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
10761088
return .visitChildren
10771089
}
10781090

1091+
override func visitPost(_ node: SubscriptExprSyntax) {
1092+
clearContextualBreakState(node)
1093+
}
1094+
10791095
override func visit(_ node: ExpressionSegmentSyntax) -> SyntaxVisitorContinueKind {
10801096
// TODO: For now, just use the raw text of the node and don't try to format it deeper. In the
10811097
// future, we should find a way to format the expression but without wrapping so that at least
@@ -2271,7 +2287,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
22712287

22722288
/// Appends the before-tokens of the given syntax token to the token stream.
22732289
private func appendBeforeTokens(_ token: TokenSyntax) {
2274-
if let before = beforeMap[token] {
2290+
if let before = beforeMap.removeValue(forKey: token) {
22752291
before.forEach(appendToken)
22762292
}
22772293
}
@@ -2331,7 +2347,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
23312347
/// not incorrectly inserted into the token stream *after* a break or newline.
23322348
private func appendAfterTokensAndTrailingComments(_ token: TokenSyntax) {
23332349
let (wasLineComment, trailingCommentTokens) = afterTokensForTrailingComment(token)
2334-
let afterGroups = afterMap[token] ?? []
2350+
let afterGroups = afterMap.removeValue(forKey: token) ?? []
23352351
var hasAppendedTrailingComment = false
23362352

23372353
if !wasLineComment {
@@ -3177,23 +3193,34 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
31773193
appendToken(.break(.same, size: 0))
31783194
}
31793195

3196+
/// Cleans up state related to inserting contextual breaks throughout expressions during
3197+
/// `visitPost` for an expression that is the root of an expression tree.
3198+
private func clearContextualBreakState<T: ExprSyntaxProtocol>(_ expr: T) {
3199+
let exprID = expr.id
3200+
if rootExprs.remove(exprID) != nil {
3201+
preVisitedExprs.removeAll()
3202+
}
3203+
}
3204+
31803205
/// Visits the given expression node and all of the nested expression nodes, inserting tokens
31813206
/// necessary for contextual breaking throughout the expression. Records the nodes that were
31823207
/// visited so that they can be skipped later.
31833208
private func preVisitInsertingContextualBreaks<T: ExprSyntaxProtocol & Equatable>(_ expr: T) {
3184-
let exprSyntax = ExprSyntax(expr)
3185-
if !preVisitedExprs.contains(exprSyntax) {
3186-
let (visited, _, _) = insertContextualBreaks(exprSyntax, isTopLevel: true)
3187-
preVisitedExprs.formUnion(visited)
3209+
let exprID = expr.id
3210+
if !preVisitedExprs.contains(exprID) {
3211+
rootExprs.insert(exprID)
3212+
insertContextualBreaks(ExprSyntax(expr), isTopLevel: true)
31883213
}
31893214
}
31903215

31913216
/// Recursively visits nested expressions from the given expression inserting contextual breaking
31923217
/// tokens. When visiting an expression node, `preVisitInsertingContextualBreaks(_:)` should be
31933218
/// called instead of this helper.
3219+
@discardableResult
31943220
private func insertContextualBreaks(_ expr: ExprSyntax, isTopLevel: Bool) -> (
3195-
[ExprSyntax], hasCompoundExpression: Bool, hasMemberAccess: Bool
3221+
hasCompoundExpression: Bool, hasMemberAccess: Bool
31963222
) {
3223+
preVisitedExprs.insert(expr.id)
31973224
if let memberAccessExpr = expr.as(MemberAccessExprSyntax.self) {
31983225
// When the member access is part of a calling expression, the break before the dot is
31993226
// inserted when visiting the parent node instead so that the break is inserted before any
@@ -3202,21 +3229,18 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
32023229
expr.parent?.isProtocol(CallingExprSyntaxProtocol.self) != true {
32033230
before(memberAccessExpr.dot, tokens: .break(.contextual, size: 0))
32043231
}
3205-
let children: [ExprSyntax]
32063232
var hasCompoundExpression = false
32073233
if let base = memberAccessExpr.base {
3208-
(children, hasCompoundExpression, _) = insertContextualBreaks(base, isTopLevel: false)
3209-
} else {
3210-
children = []
3234+
(hasCompoundExpression, _) = insertContextualBreaks(base, isTopLevel: false)
32113235
}
32123236
if isTopLevel {
32133237
before(expr.firstToken, tokens: .contextualBreakingStart)
32143238
after(expr.lastToken, tokens: .contextualBreakingEnd)
32153239
}
3216-
return ([expr] + children, hasCompoundExpression, true)
3240+
return (hasCompoundExpression, true)
32173241
} else if let callingExpr = expr.asProtocol(CallingExprSyntaxProtocol.self) {
32183242
let calledExpression = callingExpr.calledExpression
3219-
let (children, hasCompoundExpression, hasMemberAccess) =
3243+
let (hasCompoundExpression, hasMemberAccess) =
32203244
insertContextualBreaks(calledExpression, isTopLevel: false)
32213245

32223246
let shouldGroup =
@@ -3241,7 +3265,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
32413265
before(expr.firstToken, tokens: beforeTokens)
32423266
after(expr.lastToken, tokens: afterTokens)
32433267
}
3244-
return ([expr] + children, true, hasMemberAccess)
3268+
return (true, hasMemberAccess)
32453269
}
32463270

32473271
// Otherwise, it's an expression that isn't calling another expression (e.g. array or
@@ -3250,7 +3274,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
32503274
before(expr.firstToken, tokens: .contextualBreakingStart)
32513275
after(expr.lastToken, tokens: .contextualBreakingEnd)
32523276
let hasCompoundExpression = !expr.is(IdentifierExprSyntax.self)
3253-
return ([expr], hasCompoundExpression, false)
3277+
return (hasCompoundExpression, false)
32543278
}
32553279
}
32563280

0 commit comments

Comments
 (0)