ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift Macro - implement
    IOS/WWDC24 2025. 6. 1. 23:32

    1. 패키지 생성

    Xcode -> File -> New -> Package 선택 시 Swift macro가 있습니다.

    2. 구성 보기

    패키지 생성 시 기본적으로 #stringfy 메크로 선언, 구현, 단위 테스트 코드가 존재합니다.

    3. 메크로 선언

    stringify표현에 사용할 매크로 구현체가 있는 모듈을 #externalMacro로 상세한다.

    메크로에 사용될 구현체는 @main으로 프로그램 진입 시점에 선언

    @main
    struct WWDC_MacroPlugin: CompilerPlugin {
        let providingMacros: [Macro.Type] = [
            StringifyMacro.self,
            SlopeSubsetMacro.self
        ]
    }
    
    • 플러그인 메커니즘
      • 플러그인은 호스트 프로세스와 swift enum을 JSON 직렬화 형식으로 메시지를 주고받음
      • Swift 컴파일러가 플러그인에게 명령을 주고 플러그인은 결과를 되돌려줌
      • stdin, stdout 파이프를 통해서 주고받는데, 플러그인은 호스트 프로세스 외 stdin는 막혀있음
      • 즉 이 부분에서 메크로 구현체가 맵핑되는걸 선언해 줌

    4. 메크로 구현체

    stringifyMacro 구현부를 ExpressionMacro 타입을 구현하기 때문에 다음과 같은 프로토콜을 상속해서 구현체를 구현해야 한다.

    한 단계 깊이 들어가면 FreestandingMacroExpansionSyntax 프로토콜로 parse에 의해 sytanx tree로 구성된 토큰들을 추출할 수 있습니다.

    
    
    // MARK: - FreestandingMacroExpansionSyntax
    
    public protocol FreestandingMacroExpansionSyntax: SyntaxProtocol {
      /// ### Tokens
      /// 
      /// For syntax trees generated by the parser, this is guaranteed to be `#`.
      var pound: TokenSyntax {
        get
        set
      }
      
      /// ### Tokens
      /// 
      /// For syntax trees generated by the parser, this is guaranteed to be `<identifier>`.
      var macroName: TokenSyntax {
        get
        set
      }
      
      var genericArgumentClause: GenericArgumentClauseSyntax? {
        get
        set
      }
      
      /// ### Tokens
      /// 
      /// For syntax trees generated by the parser, this is guaranteed to be `(`.
      var leftParen: TokenSyntax? {
        get
        set
      }
      
      var arguments: LabeledExprListSyntax {
        get
        set
      }
      
      /// ### Tokens
      /// 
      /// For syntax trees generated by the parser, this is guaranteed to be `)`.
      var rightParen: TokenSyntax? {
        get
        set
      }
      
      var trailingClosure: ClosureExprSyntax? {
        get
        set
      }
      
      var additionalTrailingClosures: MultipleTrailingClosureElementListSyntax {
        get
        set
      }
    }
    
    

     

    5. 메크로 테스트

    메크로에 사용하는 테스트 코드는 단위 테스트에 용이하도록 설계되어 있습니다.

    assertMacroExpansion를 사용해 테스트하는데 메서드 시그니처는 다음과 같습니다.

    func assertMacroExpansion(
        _ originalSource: String,
        expandedSource expectedExpandedSource: String,
        diagnostics: [DiagnosticSpec] = [],
        macros: [String : any Macro.Type],
        applyFixIts: [String]? = nil,
        fixedSource expectedFixedSource: String? = nil,
        testModuleName: String = "TestModule",
        testFileName: String = "test.swift",
        indentationWidth: Trivia = .spaces(4),
        file: StaticString = #filePath,
        line: UInt = #line
    )
    

    다음은 사용법  코드입니다.

    import WWDC_MacroMacros
    
    let testMacros: [String: Macro.Type] = [
        "stringify": StringifyMacro.self, // 메크로 맵핑된 구현체를 dictionary형태로
    ]
    #endif
    
    final class WWDC_MacroTests: XCTestCase {
        func testMacro() throws {
            #if canImport(WWDC_MacroMacros)
            assertMacroExpansion(
                """
                #stringify(a + b) // 매크로 표현식
                """,
                expandedSource: """
                (a + b, "a + b") // 예상되는 확장 코드
                """,
                macros: testMacros
            )
            #else
            throw XCTSkip("macros are only supported when running tests for the host platform")
            #endif
        }
    }
    

     

     

    'IOS > WWDC24' 카테고리의 다른 글

    Swift Macro - attach  (2) 2025.06.08
    Swift Macro - Intro  (0) 2025.05.10
    [WWDC24] Swift의 성능 살펴보기 (3/3)  (0) 2025.02.09
    [WWDC24] Swift의 성능 살펴보기 (2 / 3)  (0) 2025.02.08
    [WWDC24] Swift의 성능 살펴보기 (1 / 3)  (0) 2024.12.07
Designed by Tistory.