Skip to content

Commit f2dca3f

Browse files
Add another example for Macro
1 parent 8526152 commit f2dca3f

File tree

4 files changed

+89
-1
lines changed

4 files changed

+89
-1
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,19 @@ Add fonts to the [project](https://github.com/ImaginativeShohag/Why-Not-SwiftUI/
124124

125125
- `fileSize() -> Int` : The file size in KB.
126126

127+
# Macro
128+
129+
## Pre-built Swift macros:
130+
131+
- `#warning("message")`
132+
- `#line`
133+
- `#function`
134+
- `#file`
135+
- `#column`
136+
- `#id` ... `#endif`
137+
- `#filePath`
138+
- `#colorLiteral(red: 0.292, green: 0.081, blue: 0.6, alpha: 255)`
139+
127140
## Licence
128141

129142
```

packages/SwiftMacros/Sources/CustomMacros/CustomMacros.swift

+55-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import SwiftCompilerPlugin
21
import Foundation
2+
import SwiftCompilerPlugin
33
import SwiftSyntax
44
import SwiftSyntaxBuilder
55
import SwiftSyntaxMacros
@@ -28,6 +28,8 @@ public struct StringifyMacro: ExpressionMacro {
2828

2929
// MARK: -
3030

31+
/// Source: https://www.avanderlee.com/swift/macros/
32+
3133
public struct URLMacro: ExpressionMacro {
3234
public static func expansion(
3335
of node: some FreestandingMacroExpansionSyntax,
@@ -83,10 +85,62 @@ enum URLMacroError: Error, CustomStringConvertible {
8385

8486
// MARK: -
8587

88+
/// Source: https://betterprogramming.pub/use-swift-macros-to-initialize-a-structure-516728c5fb49
89+
90+
public struct StructInitMacro: MemberMacro {
91+
public static func expansion(
92+
of node: AttributeSyntax,
93+
providingMembersOf declaration: some DeclGroupSyntax,
94+
in context: some MacroExpansionContext
95+
) throws -> [SwiftSyntax.DeclSyntax] {
96+
guard let structDecl = declaration.as(StructDeclSyntax.self) else {
97+
throw StructInitError.onlyApplicableToStruct
98+
}
99+
100+
let members = structDecl.memberBlock.members
101+
let variableDecl = members.compactMap { $0.decl.as(VariableDeclSyntax.self) }
102+
let variablesName = variableDecl.compactMap { $0.bindings.first?.pattern }
103+
let variablesType = variableDecl.compactMap { $0.bindings.first?.typeAnnotation?.type }
104+
105+
let initializer = try InitializerDeclSyntax(StructInitMacro.generateInitialCode(variablesName: variablesName, variablesType: variablesType)) {
106+
for name in variablesName {
107+
ExprSyntax("self.\(name) = \(name)")
108+
}
109+
}
110+
111+
return [DeclSyntax(initializer)]
112+
}
113+
114+
public static func generateInitialCode(variablesName: [PatternSyntax],
115+
variablesType: [TypeSyntax]) -> SyntaxNodeString
116+
{
117+
var initialCode = "init("
118+
for (name, type) in zip(variablesName, variablesType) {
119+
initialCode += "\(name): \(type), "
120+
}
121+
initialCode = String(initialCode.dropLast(2))
122+
initialCode += ")"
123+
return SyntaxNodeString(stringLiteral: initialCode)
124+
}
125+
}
126+
127+
enum StructInitError: CustomStringConvertible, Error {
128+
case onlyApplicableToStruct
129+
130+
var description: String {
131+
switch self {
132+
case .onlyApplicableToStruct: return "@StructInit can only be applied to a structure"
133+
}
134+
}
135+
}
136+
137+
// MARK: -
138+
86139
@main
87140
struct URLMacroPlugin: CompilerPlugin {
88141
let providingMacros: [Macro.Type] = [
89142
StringifyMacro.self,
90143
URLMacro.self,
144+
StructInitMacro.self,
91145
]
92146
}

packages/SwiftMacros/Sources/SwiftMacros/SwiftMacros.swift

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import Foundation
1212
@freestanding(expression)
1313
public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "CustomMacros", type: "StringifyMacro")
1414

15+
16+
/// Source: https://www.avanderlee.com/swift/macros/
17+
///
1518
/// A macro that produces an unwrapped URL in case of a valid input URL.
1619
/// For example,
1720
///
@@ -20,3 +23,7 @@ public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "C
2023
/// produces an unwrapped `URL` if the URL is valid. Otherwise, it emits a compile-time error.
2124
@freestanding(expression)
2225
public macro URL(_ stringLiteral: String) -> URL = #externalMacro(module: "CustomMacros", type: "URLMacro")
26+
27+
/// Source: https://betterprogramming.pub/use-swift-macros-to-initialize-a-structure-516728c5fb49
28+
@attached(member, names: named(init))
29+
public macro StructInit() = #externalMacro(module: "CustomMacros", type: "StructInitMacro")

packages/SwiftMacros/Sources/SwiftMacrosClient/main.swift

+14
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,22 @@ let b = 25
66

77
let (result, code) = #stringify(a + b)
88

9+
10+
/// Source: https://www.avanderlee.com/swift/macros/
11+
912
print("The value \(result) was produced by the code \"\(code)\"")
1013

1114
let url: URL = #URL("https://imaginativeworld.org")
1215

1316
print("Url: \(url)")
17+
18+
/// Source: https://betterprogramming.pub/use-swift-macros-to-initialize-a-structure-516728c5fb49
19+
20+
@StructInit
21+
struct Book {
22+
var id: Int
23+
var title: String
24+
var subtitle: String
25+
var description: String
26+
var author: String
27+
}

0 commit comments

Comments
 (0)