Skip to content

Commit 63acf1f

Browse files
committed
last lint fix?
1 parent 538bf82 commit 63acf1f

7 files changed

Lines changed: 543 additions & 266 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// Closure+Body.swift
3+
// SyntaxKit
4+
//
5+
// Created by Leo Dion.
6+
// Copyright © 2025 BrightDigit.
7+
//
8+
// Permission is hereby granted, free of charge, to any person
9+
// obtaining a copy of this software and associated documentation
10+
// files (the “Software”), to deal in the Software without
11+
// restriction, including without limitation the rights to use,
12+
// copy, modify, merge, publish, distribute, sublicense, and/or
13+
// sell copies of the Software, and to permit persons to whom the
14+
// Software is furnished to do so, subject to the following
15+
// conditions:
16+
//
17+
// The above copyright notice and this permission notice shall be
18+
// included in all copies or substantial portions of the Software.
19+
//
20+
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
21+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
// OTHER DEALINGS IN THE SOFTWARE.
28+
//
29+
30+
import SwiftSyntax
31+
32+
extension Closure {
33+
/// Builds the body block for the closure.
34+
internal func buildBodyBlock() -> CodeBlockItemListSyntax {
35+
CodeBlockItemListSyntax(
36+
body.compactMap(buildBodyItem)
37+
)
38+
}
39+
40+
/// Builds a body item from a code block.
41+
private func buildBodyItem(from codeBlock: CodeBlock) -> CodeBlockItemSyntax? {
42+
if let decl = codeBlock.syntax.as(DeclSyntax.self) {
43+
return CodeBlockItemSyntax(item: .decl(decl)).with(\.trailingTrivia, .newline)
44+
} else if let paramExp = codeBlock as? ParameterExp {
45+
return buildParameterExpressionItem(paramExp)
46+
} else if let exprBlock = codeBlock as? ExprCodeBlock {
47+
return CodeBlockItemSyntax(item: .expr(exprBlock.exprSyntax)).with(
48+
\.trailingTrivia, .newline
49+
)
50+
} else if let expr = codeBlock.syntax.as(ExprSyntax.self) {
51+
return CodeBlockItemSyntax(item: .expr(expr)).with(
52+
\.trailingTrivia, .newline
53+
)
54+
} else if let stmt = codeBlock.syntax.as(StmtSyntax.self) {
55+
return CodeBlockItemSyntax(item: .stmt(stmt)).with(\.trailingTrivia, .newline)
56+
}
57+
return nil
58+
}
59+
60+
/// Builds a parameter expression item.
61+
private func buildParameterExpressionItem(_ paramExp: ParameterExp) -> CodeBlockItemSyntax? {
62+
if let exprBlock = paramExp.value as? ExprCodeBlock {
63+
return CodeBlockItemSyntax(item: .expr(exprBlock.exprSyntax)).with(
64+
\.trailingTrivia, .newline
65+
)
66+
} else if let expr = paramExp.value.syntax.as(ExprSyntax.self) {
67+
return CodeBlockItemSyntax(item: .expr(expr)).with(
68+
\.trailingTrivia, .newline
69+
)
70+
} else if let paramExpr = paramExp.syntax.as(ExprSyntax.self) {
71+
return CodeBlockItemSyntax(item: .expr(paramExpr)).with(
72+
\.trailingTrivia, .newline
73+
)
74+
}
75+
return nil
76+
}
77+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// Closure+Capture.swift
3+
// SyntaxKit
4+
//
5+
// Created by Leo Dion.
6+
// Copyright © 2025 BrightDigit.
7+
//
8+
// Permission is hereby granted, free of charge, to any person
9+
// obtaining a copy of this software and associated documentation
10+
// files (the “Software”), to deal in the Software without
11+
// restriction, including without limitation the rights to use,
12+
// copy, modify, merge, publish, distribute, sublicense, and/or
13+
// sell copies of the Software, and to permit persons to whom the
14+
// Software is furnished to do so, subject to the following
15+
// conditions:
16+
//
17+
// The above copyright notice and this permission notice shall be
18+
// included in all copies or substantial portions of the Software.
19+
//
20+
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
21+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
// OTHER DEALINGS IN THE SOFTWARE.
28+
//
29+
30+
import SwiftSyntax
31+
32+
/// Represents capture specifier and name information for closure captures.
33+
private struct CaptureInfo {
34+
let specifier: ClosureCaptureSpecifierSyntax?
35+
let name: TokenSyntax
36+
37+
init(from param: ParameterExp) {
38+
if let refExp = param.value as? ReferenceExp {
39+
self.init(fromReference: refExp)
40+
} else {
41+
self.init(fromParameter: param)
42+
}
43+
}
44+
45+
private init(fromReference refExp: ReferenceExp) {
46+
let keyword: Keyword
47+
switch refExp.captureReferenceType.lowercased() {
48+
case "weak":
49+
keyword = .weak
50+
case "unowned":
51+
keyword = .unowned
52+
default:
53+
keyword = .weak // fallback to weak
54+
}
55+
56+
self.specifier = ClosureCaptureSpecifierSyntax(
57+
specifier: .keyword(keyword, trailingTrivia: .space)
58+
)
59+
60+
if let varExp = refExp.captureExpression as? VariableExp {
61+
self.name = .identifier(varExp.name)
62+
} else {
63+
self.name = .identifier("self") // fallback
64+
}
65+
}
66+
67+
private init(fromParameter param: ParameterExp) {
68+
self.specifier = nil
69+
70+
if let varExp = param.value as? VariableExp {
71+
self.name = .identifier(varExp.name)
72+
} else {
73+
self.name = .identifier("self") // fallback
74+
}
75+
}
76+
}
77+
78+
extension Closure {
79+
/// Builds the capture clause for the closure.
80+
internal func buildCaptureClause() -> ClosureCaptureClauseSyntax? {
81+
guard !capture.isEmpty else {
82+
return nil
83+
}
84+
85+
return ClosureCaptureClauseSyntax(
86+
leftSquare: .leftSquareToken(),
87+
items: ClosureCaptureListSyntax(
88+
capture.map(buildCaptureItem)
89+
),
90+
rightSquare: .rightSquareToken()
91+
)
92+
}
93+
94+
/// Builds a capture item from a parameter expression.
95+
private func buildCaptureItem(from param: ParameterExp) -> ClosureCaptureSyntax {
96+
let captureInfo = CaptureInfo(from: param)
97+
98+
return ClosureCaptureSyntax(
99+
specifier: captureInfo.specifier,
100+
name: captureInfo.name,
101+
initializer: nil,
102+
trailingComma: nil
103+
)
104+
}
105+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//
2+
// Closure+Signature.swift
3+
// SyntaxKit
4+
//
5+
// Created by Leo Dion.
6+
// Copyright © 2025 BrightDigit.
7+
//
8+
// Permission is hereby granted, free of charge, to any person
9+
// obtaining a copy of this software and associated documentation
10+
// files (the “Software”), to deal in the Software without
11+
// restriction, including without limitation the rights to use,
12+
// copy, modify, merge, publish, distribute, sublicense, and/or
13+
// sell copies of the Software, and to permit persons to whom the
14+
// Software is furnished to do so, subject to the following
15+
// conditions:
16+
//
17+
// The above copyright notice and this permission notice shall be
18+
// included in all copies or substantial portions of the Software.
19+
//
20+
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
21+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
// OTHER DEALINGS IN THE SOFTWARE.
28+
//
29+
30+
import SwiftSyntax
31+
32+
extension Closure {
33+
/// Builds the signature for the closure.
34+
internal func buildSignature(captureClause: ClosureCaptureClauseSyntax?)
35+
-> ClosureSignatureSyntax?
36+
{
37+
guard needsSignature else {
38+
return nil
39+
}
40+
41+
return ClosureSignatureSyntax(
42+
attributes: buildAttributeList(),
43+
capture: captureClause,
44+
parameterClause: buildParameterClause().map { .parameterClause($0) },
45+
effectSpecifiers: nil,
46+
returnClause: buildReturnClause(),
47+
inKeyword: .keyword(.in, leadingTrivia: .space, trailingTrivia: .space)
48+
)
49+
}
50+
51+
/// Builds the attribute list for the closure signature.
52+
private func buildAttributeList() -> AttributeListSyntax {
53+
guard !attributes.isEmpty else {
54+
return AttributeListSyntax([])
55+
}
56+
57+
return AttributeListSyntax(
58+
attributes.enumerated().map { idx, attr in
59+
AttributeListSyntax.Element(
60+
AttributeSyntax(
61+
atSign: .atSignToken(),
62+
attributeName: IdentifierTypeSyntax(
63+
name: .identifier(attr.name),
64+
trailingTrivia: (capture.isEmpty || idx != attributes.count - 1)
65+
? Trivia() : .space
66+
),
67+
leftParen: nil,
68+
arguments: nil,
69+
rightParen: nil
70+
)
71+
)
72+
}
73+
)
74+
}
75+
76+
/// Builds the parameter clause for the closure signature.
77+
private func buildParameterClause() -> ClosureParameterClauseSyntax? {
78+
guard !parameters.isEmpty else {
79+
return nil
80+
}
81+
82+
return ClosureParameterClauseSyntax(
83+
leftParen: .leftParenToken(),
84+
parameters: ClosureParameterListSyntax(
85+
parameters.map(buildParameterSyntax)
86+
),
87+
rightParen: .rightParenToken()
88+
)
89+
}
90+
91+
/// Builds parameter syntax from a closure parameter.
92+
private func buildParameterSyntax(from param: ClosureParameter) -> ClosureParameterSyntax {
93+
ClosureParameterSyntax(
94+
attributes: AttributeListSyntax([]),
95+
firstName: .identifier(param.name),
96+
secondName: nil,
97+
colon: param.name.isEmpty ? nil : .colonToken(trailingTrivia: .space),
98+
type: param.type?.typeSyntax as? TypeSyntax,
99+
ellipsis: nil,
100+
trailingComma: nil
101+
)
102+
}
103+
104+
/// Builds the return clause for the closure signature.
105+
private func buildReturnClause() -> ReturnClauseSyntax? {
106+
returnType.map {
107+
ReturnClauseSyntax(
108+
arrow: .arrowToken(trailingTrivia: .space),
109+
type: $0.typeSyntax
110+
)
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)