1+ import Foundation
2+
3+ // MARK: - Macro Tutorial Examples
4+ // This file demonstrates the concepts from the "Creating Macros with SyntaxKit" tutorial
5+
6+ // MARK: - Example 1: Extension Macro Usage
7+ // This shows how the @MyMacro would be used (as defined in the tutorial)
8+
9+ protocol MyProtocol {
10+ var description : String { get }
11+ }
12+
13+ // Example of what the macro would generate:
14+ @MyMacro
15+ enum Color : String {
16+ case red = " red "
17+ case green = " green "
18+ case blue = " blue "
19+ }
20+
21+ // The macro would generate:
22+ // extension Color: MyProtocol {
23+ // typealias MyType = String
24+ // static let myProperty = ["red", "green", "blue"]
25+ // var description: String {
26+ // return myProperty.joined(separator: ", ")
27+ // }
28+ // }
29+ //
30+ // struct ColorWrapper {
31+ // let value: Color
32+ // init(value: Color) {
33+ // self.value = value
34+ // }
35+ // var description: String {
36+ // return value.description
37+ // }
38+ // }
39+
40+ // MARK: - Example 2: Freestanding Expression Macro Usage
41+ // This shows how the #stringify macro would be used
42+
43+ // let result = #stringify(42 + 8)
44+ // result would be (50, "42 + 8")
45+
46+ // MARK: - Example 3: Complex Macro Generation
47+ // This shows what a complex macro might generate
48+
49+ struct User {
50+ var status : UserStatus
51+ var name : String
52+ }
53+
54+ enum UserStatus : String {
55+ case active = " active "
56+ case inactive = " inactive "
57+ case pending = " pending "
58+ }
59+
60+ // A complex macro might generate an extension like this:
61+ extension User {
62+ enum Status : String {
63+ case active = " active "
64+ case inactive = " inactive "
65+ case pending = " pending "
66+ }
67+
68+ var isValid : Bool {
69+ if status == . active {
70+ return true
71+ } else {
72+ return false
73+ }
74+ }
75+
76+ func updateStatus( newStatus: Status ) {
77+ status = newStatus
78+ print ( " Status updated to \( newStatus) " )
79+ }
80+
81+ static func createDefault( ) -> User {
82+ return User ( status: . pending, name: " Default " )
83+ }
84+ }
85+
86+ // MARK: - Example 4: SyntaxKit Code Generation
87+ // This shows how SyntaxKit would be used to generate the above code
88+
89+ import SyntaxKit
90+
91+ // Example of generating the User extension using SyntaxKit
92+ let userExtension = Extension ( " User " ) {
93+ // Add a nested enum
94+ Enum ( " Status " ) {
95+ EnumCase ( " active " ) . equals ( " active " )
96+ EnumCase ( " inactive " ) . equals ( " inactive " )
97+ EnumCase ( " pending " ) . equals ( " pending " )
98+ } . inherits ( " String " )
99+
100+ // Add a computed property with complex logic
101+ ComputedProperty ( " isValid " ) {
102+ If ( VariableExp ( " status == .active " ) , then: {
103+ Return { Literal . boolean ( true ) }
104+ } , else: {
105+ Return { Literal . boolean ( false ) }
106+ } )
107+ }
108+
109+ // Add a method with parameters
110+ Function ( " updateStatus " , parameters: [ Parameter ( " newStatus " , type: " Status " ) ] ) {
111+ Assignment ( " status " , VariableExp ( " newStatus " ) )
112+ Call ( " print " ) {
113+ ParameterExp ( unlabeled: " \" Status updated to \\ (newStatus) \" " )
114+ }
115+ }
116+
117+ // Add a static method
118+ Function ( " createDefault " , parameters: [ ] ) {
119+ Return {
120+ Init ( " User " ) {
121+ Parameter ( name: " status " , value: " .pending " )
122+ Parameter ( name: " name " , value: " \" Default \" " )
123+ }
124+ }
125+ } . static ( )
126+
127+ } . inherits ( " Identifiable " , " Codable " )
128+
129+ // MARK: - Example 5: Error Handling in Macros
130+ // This shows how macros should handle errors
131+
132+ enum MacroError : Error , CustomStringConvertible {
133+ case onlyWorksWithEnums
134+ case invalidCaseName( String )
135+ case missingRawValue
136+
137+ var description : String {
138+ switch self {
139+ case . onlyWorksWithEnums:
140+ return " This macro can only be applied to enums "
141+ case . invalidCaseName( let name) :
142+ return " Invalid case name: \( name) "
143+ case . missingRawValue:
144+ return " Enum cases must have raw values "
145+ }
146+ }
147+ }
148+
149+ // MARK: - Example 6: Testing Macros
150+ // This shows how macros should be tested
151+
152+ /*
153+ // Example test for the MyMacro
154+ func testExtensionMacro() throws {
155+ assertMacroExpansion(
156+ """
157+ @MyMacro
158+ enum Color: String {
159+ case red = "red"
160+ case blue = "blue"
161+ }
162+ """,
163+ expandedSource: """
164+ enum Color: String {
165+ case red = "red"
166+ case blue = "blue"
167+ }
168+
169+ extension Color: MyProtocol {
170+ typealias MyType = String
171+ static let myProperty = ["red", "blue"]
172+ var description: String {
173+ return myProperty.joined(separator: ", ")
174+ }
175+ }
176+
177+ struct ColorWrapper {
178+ let value: Color
179+ init(value: Color) {
180+ self.value = value
181+ }
182+ var description: String {
183+ return value.description
184+ }
185+ }
186+ """,
187+ macros: ["MyMacro": MyMacro.self]
188+ )
189+ }
190+ */
191+
192+ // MARK: - Example 7: Integration with SwiftSyntax
193+ // This shows how SyntaxKit can be mixed with raw SwiftSyntax
194+
195+ /*
196+ // You can mix SyntaxKit with raw SwiftSyntax
197+ let syntaxKitStruct = Struct("Generated") {
198+ Variable(.let, name: "value", type: "String")
199+ }
200+
201+ // Convert to SwiftSyntax and modify
202+ var structDecl = syntaxKitStruct.syntax.as(StructDeclSyntax.self)!
203+ structDecl = structDecl.with(\.modifiers, DeclModifierListSyntax {
204+ DeclModifierSyntax(name: .keyword(.public))
205+ })
206+
207+ // Convert back to SyntaxKit if needed
208+ let modifiedStruct = Struct(structDecl)
209+ */
210+
211+ // MARK: - Usage Examples
212+
213+ // Example usage of the generated code
214+ let color = Color . red
215+ print ( color. description) // Would print: "red, green, blue"
216+
217+ let user = User ( status: . pending, name: " John " )
218+ print ( user. isValid) // Would print: false
219+
220+ user. updateStatus ( newStatus: . active)
221+ print ( user. isValid) // Would print: true
222+
223+ let defaultUser = User . createDefault ( )
224+ print ( defaultUser. name) // Would print: "Default"
225+ print ( defaultUser. status) // Would print: .pending
0 commit comments