Skip to content

Commit 5d6860d

Browse files
authored
Merge pull request #990 from DougGregor/cmake-swiftsyntaxmacros
2 parents c09d8a1 + 298f2f0 commit 5d6860d

File tree

6 files changed

+356
-248
lines changed

6 files changed

+356
-248
lines changed

Sources/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ add_subdirectory(SwiftSyntax)
1111
add_subdirectory(SwiftDiagnostics)
1212
add_subdirectory(SwiftParser)
1313
add_subdirectory(SwiftOperators)
14+
add_subdirectory(SwiftSyntaxBuilder)
15+
add_subdirectory(_SwiftSyntaxMacros)
1416
add_subdirectory(SwiftCompilerSupport)

Sources/SwiftDiagnostics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
add_library(SwiftDiagnostics STATIC
1010
Diagnostic.swift
11+
DiagnosticsFormatter.swift
1112
FixIt.swift
1213
Message.swift
1314
Note.swift
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# This source file is part of the Swift.org open source project
2+
#
3+
# Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
4+
# Licensed under Apache License v2.0 with Runtime Library Exception
5+
#
6+
# See http://swift.org/LICENSE.txt for license information
7+
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
add_library(SwiftSyntaxBuilder STATIC
10+
BuildBuildable.swift
11+
HasTrailingComma.swift
12+
Indenter.swift
13+
Syntax+StringInterpolation.swift
14+
15+
ConvenienceInitializers/BinaryOperatorExprConvenienceInitializers.swift
16+
ConvenienceInitializers/BooleanLiteralExprConvenienceInitializers.swift
17+
ConvenienceInitializers/CatchClauseConvenienceInitializer.swift
18+
ConvenienceInitializers/CustomAttributeConvenienceInitializers.swift
19+
ConvenienceInitializers/DictionaryExprConvenienceInitializers.swift
20+
ConvenienceInitializers/FloatLiteralExprConvenienceInitializers.swift
21+
ConvenienceInitializers/FunctionCallExprConvenienceInitializers.swift
22+
ConvenienceInitializers/IdentifierExprConvenienceInitializers.swift
23+
ConvenienceInitializers/IdentifierPatternConvenienceInitializers.swift
24+
ConvenienceInitializers/IfStmtConvenienceInitializers.swift
25+
ConvenienceInitializers/IntegerLiteralExprConvenienceInitializers.swift
26+
ConvenienceInitializers/MemberAccessExprConvenienceInitializers.swift
27+
ConvenienceInitializers/PrefixOperatorExprConvenienceInitializers.swift
28+
ConvenienceInitializers/SimpleTypeIdentifierConvenienceInitializers.swift
29+
ConvenienceInitializers/StringConvenienceInitializers.swift
30+
ConvenienceInitializers/StringLiteralExprConvenienceInitializers.swift
31+
ConvenienceInitializers/TernaryExprConvenienceInitializers.swift
32+
ConvenienceInitializers/TupleExprElementConvenienceInitializers.swift
33+
ConvenienceInitializers/TypeAnnotationConvenienceInitializers.swift
34+
ConvenienceInitializers/VariableDeclConvenienceInitializers.swift
35+
generated/BuildableBaseProtocols.swift
36+
generated/BuildableCollectionNodes.swift
37+
generated/BuildableNodes.swift
38+
generated/ExpressibleAsProtocols.swift
39+
generated/ResultBuildersFile.swift
40+
generated/Token.swift
41+
gyb_generated/SyntaxExpressibleByStringInterpolationConformances.swift
42+
)
43+
44+
target_link_libraries(SwiftSyntaxBuilder PUBLIC
45+
SwiftParser
46+
SwiftSyntax
47+
)
48+
49+
set_property(GLOBAL APPEND PROPERTY SWIFTSYNTAX_EXPORTS SwiftSyntaxBuilder)
50+
51+
# NOTE: workaround for CMake not setting up include flags yet
52+
set_target_properties(SwiftSyntaxBuilder PROPERTIES
53+
INTERFACE_INCLUDE_DIRECTORIES
54+
"${CMAKE_Swift_MODULE_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR}")
55+
56+
install(TARGETS SwiftSyntaxBuilder
57+
EXPORT SwiftSyntaxTargets
58+
ARCHIVE DESTINATION lib
59+
LIBRARY DESTINATION lib
60+
RUNTIME DESTINATION bin)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# This source file is part of the Swift.org open source project
2+
#
3+
# Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
4+
# Licensed under Apache License v2.0 with Runtime Library Exception
5+
#
6+
# See http://swift.org/LICENSE.txt for license information
7+
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
add_library(_SwiftSyntaxMacros STATIC
10+
ExpressionMacro.swift
11+
Macro.swift
12+
MacroEvaluationContext.swift
13+
MacroResult.swift
14+
MacroSystem+Builtin.swift
15+
MacroSystem+Examples.swift
16+
MacroSystem.swift
17+
Syntax+MacroEvaluation.swift
18+
)
19+
20+
target_link_libraries(_SwiftSyntaxMacros PUBLIC
21+
SwiftParser
22+
SwiftSyntaxBuilder
23+
)
24+
25+
set_property(GLOBAL APPEND PROPERTY SWIFTSYNTAX_EXPORTS _SwiftSyntaxMacros)
26+
27+
# NOTE: workaround for CMake not setting up include flags yet
28+
set_target_properties(_SwiftSyntaxMacros PROPERTIES
29+
INTERFACE_INCLUDE_DIRECTORIES
30+
"${CMAKE_Swift_MODULE_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR}")
31+
32+
install(TARGETS _SwiftSyntaxMacros
33+
EXPORT SwiftSyntaxTargets
34+
ARCHIVE DESTINATION lib
35+
LIBRARY DESTINATION lib
36+
RUNTIME DESTINATION bin)
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
import SwiftSyntax
2+
import SwiftSyntaxBuilder
3+
4+
struct ColumnMacro: ExpressionMacro {
5+
static var name: String { "column" }
6+
7+
static func apply(
8+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
9+
) -> MacroResult<ExprSyntax> {
10+
let line = macro.startLocation(
11+
converter: context.sourceLocationConverter
12+
).column ?? 0
13+
return .init("\(line)")
14+
}
15+
}
16+
17+
struct LineMacro: ExpressionMacro {
18+
static var name: String { "line" }
19+
20+
static func apply(
21+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
22+
) -> MacroResult<ExprSyntax> {
23+
let line = macro.startLocation(
24+
converter: context.sourceLocationConverter
25+
).line ?? 0
26+
return .init("\(line)")
27+
}
28+
}
29+
30+
extension PatternBindingSyntax {
31+
/// When the variable is declaring a single binding, produce the name of
32+
/// that binding.
33+
fileprivate var singleBindingName: String? {
34+
if let identifierPattern = pattern.as(IdentifierPatternSyntax.self) {
35+
return identifierPattern.identifier.text
36+
}
37+
38+
return nil
39+
}
40+
}
41+
42+
struct FunctionMacro: ExpressionMacro {
43+
static var name: String { "function" }
44+
45+
/// Form a function name.
46+
private static func formFunctionName(
47+
_ baseName: String, _ parameters: ParameterClauseSyntax?,
48+
isSubscript: Bool = false
49+
) -> String {
50+
let argumentNames: [String] = parameters?.parameterList.map { param in
51+
if let argumentName = param.firstName?.text,
52+
!isSubscript || param.secondName != nil {
53+
return "\(argumentName):"
54+
}
55+
56+
return "_:"
57+
} ?? []
58+
59+
return "\(baseName)(\(argumentNames.joined(separator: "")))"
60+
}
61+
62+
private static func findEnclosingName(
63+
_ macro: MacroExpansionExprSyntax
64+
) -> String? {
65+
var currentNode = Syntax(macro)
66+
while let parent = currentNode.parent {
67+
switch parent.as(SyntaxEnum.self) {
68+
case .accessorDecl(let accessor):
69+
if let accessorList = accessor.parent?.as(AccessorListSyntax.self),
70+
let accessorBlock = accessorList.parent?.as(AccessorBlockSyntax.self),
71+
let binding = accessorBlock.parent?.as(PatternBindingSyntax.self),
72+
let varName = binding.singleBindingName {
73+
return varName
74+
}
75+
76+
break
77+
78+
case .functionDecl(let function):
79+
return formFunctionName(
80+
function.identifier.text, function.signature.input
81+
)
82+
83+
case .initializerDecl(let initializer):
84+
return formFunctionName("init", initializer.signature.input)
85+
86+
case .subscriptDecl(let subscriptDecl):
87+
return formFunctionName(
88+
"subscript", subscriptDecl.indices, isSubscript: true
89+
)
90+
91+
case .enumCaseElement(let enumCase):
92+
return formFunctionName(
93+
enumCase.identifier.text, enumCase.associatedValue
94+
)
95+
96+
case .structDecl(let structDecl):
97+
return structDecl.identifier.text
98+
99+
case .enumDecl(let enumDecl):
100+
return enumDecl.identifier.text
101+
102+
case .classDecl(let classDecl):
103+
return classDecl.identifier.text
104+
105+
case .actorDecl(let actorDecl):
106+
return actorDecl.identifier.text
107+
108+
case .protocolDecl(let protocolDecl):
109+
return protocolDecl.identifier.text
110+
111+
case .extensionDecl(let extensionDecl):
112+
// FIXME: It would be nice to be able to switch on type syntax...
113+
let extendedType = extensionDecl.extendedType
114+
if let simple = extendedType.as(SimpleTypeIdentifierSyntax.self) {
115+
return simple.name.text
116+
}
117+
118+
if let member = extendedType.as(MemberTypeIdentifierSyntax.self) {
119+
return member.name.text
120+
}
121+
122+
return nil
123+
124+
default:
125+
break
126+
}
127+
128+
currentNode = parent
129+
}
130+
131+
return nil
132+
}
133+
134+
static func apply(
135+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
136+
) -> MacroResult<ExprSyntax> {
137+
let name = findEnclosingName(macro) ?? context.moduleName
138+
let literal: ExprSyntax = #""\#(name)""#
139+
if let leadingTrivia = macro.leadingTrivia {
140+
return .init(literal.withLeadingTrivia(leadingTrivia))
141+
}
142+
143+
return .init(literal)
144+
}
145+
}
146+
147+
struct ColorLiteralMacro: ExpressionMacro {
148+
static var name: String { "colorLiteral" }
149+
150+
static func apply(
151+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
152+
) -> MacroResult<ExprSyntax> {
153+
let initSyntax: ExprSyntax = ".init(\(macro.argumentList))"
154+
if let leadingTrivia = macro.leadingTrivia {
155+
return MacroResult(initSyntax.withLeadingTrivia(leadingTrivia))
156+
}
157+
return MacroResult(initSyntax)
158+
}
159+
}
160+
161+
struct FileLiteralMacro: ExpressionMacro {
162+
static var name: String { "fileLiteral" }
163+
164+
static func apply(
165+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
166+
) -> MacroResult<ExprSyntax> {
167+
let initSyntax: ExprSyntax = ".init(\(macro.argumentList))"
168+
if let leadingTrivia = macro.leadingTrivia {
169+
return MacroResult(initSyntax.withLeadingTrivia(leadingTrivia))
170+
}
171+
return MacroResult(initSyntax)
172+
}
173+
}
174+
175+
struct ImageLiteralMacro: ExpressionMacro {
176+
static var name: String { "imageLiteral" }
177+
178+
static func apply(
179+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
180+
) -> MacroResult<ExprSyntax> {
181+
let initSyntax: ExprSyntax = ".init(\(macro.argumentList))"
182+
if let leadingTrivia = macro.leadingTrivia {
183+
return MacroResult(initSyntax.withLeadingTrivia(leadingTrivia))
184+
}
185+
return MacroResult(initSyntax)
186+
}
187+
}
188+
189+
struct FilePathMacro: ExpressionMacro {
190+
static var name: String { "filePath" }
191+
192+
static func apply(
193+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
194+
) -> MacroResult<ExprSyntax> {
195+
let fileName = context.sourceLocationConverter.location(
196+
for: .init(utf8Offset: 0)
197+
).file ?? "<unknown file>"
198+
let fileLiteral: ExprSyntax = #""\#(fileName)""#
199+
if let leadingTrivia = macro.leadingTrivia {
200+
return MacroResult(fileLiteral.withLeadingTrivia(leadingTrivia))
201+
}
202+
return MacroResult(fileLiteral)
203+
}
204+
}
205+
206+
struct FileIDMacro: ExpressionMacro {
207+
static var name: String { "fileID" }
208+
209+
static func apply(
210+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
211+
) -> MacroResult<ExprSyntax> {
212+
var fileName = context.sourceLocationConverter.location(
213+
for: .init(utf8Offset: 0)
214+
).file ?? "<unknown file>"
215+
216+
// Only keep everything after the last slash.
217+
if let lastSlash = fileName.lastIndex(of: "/") {
218+
fileName = String(fileName[fileName.index(after: lastSlash)...])
219+
}
220+
221+
let fileLiteral: ExprSyntax = #""\#(context.moduleName)/\#(fileName)""#
222+
if let leadingTrivia = macro.leadingTrivia {
223+
return MacroResult(fileLiteral.withLeadingTrivia(leadingTrivia))
224+
}
225+
return MacroResult(fileLiteral)
226+
}
227+
}
228+
229+
struct FileMacro: ExpressionMacro {
230+
static var name: String { "file" }
231+
232+
static func apply(
233+
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
234+
) -> MacroResult<ExprSyntax> {
235+
// FIXME: Macro evaluation context needs to know the semantics of #file,
236+
// which is a feature check.
237+
return FilePathMacro.apply(macro, in: context)
238+
}
239+
}
240+
241+
extension MacroSystem {
242+
public static var builtinMacroSystem: MacroSystem = {
243+
var macroSystem = MacroSystem()
244+
try! macroSystem.add(ColorLiteralMacro.self)
245+
try! macroSystem.add(ColumnMacro.self)
246+
try! macroSystem.add(FileIDMacro.self)
247+
try! macroSystem.add(FileLiteralMacro.self)
248+
try! macroSystem.add(FilePathMacro.self)
249+
try! macroSystem.add(FunctionMacro.self)
250+
try! macroSystem.add(ImageLiteralMacro.self)
251+
try! macroSystem.add(LineMacro.self)
252+
return macroSystem
253+
}()
254+
}

0 commit comments

Comments
 (0)