Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Xcode
- UICollectionView
- Protocol
- combine
- Observable
- swift documentation
- ribs
- 애니메이션
- tableView
- Refactoring
- collectionview
- Human interface guide
- uitableview
- 스위프트
- ios
- UITextView
- swiftUI
- SWIFT
- uiscrollview
- 리펙토링
- Clean Code
- HIG
- map
- clean architecture
- 클린 코드
- 리펙터링
- MVVM
- 리팩토링
- RxCocoa
- rxswift
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] Swift Macro 구현 방법 (swift-syntax, SwiftCompilerPlugin, SwiftSyntax, SwiftSyntaxBuilder, SwiftSyntaxMacros) 본문
Swift Macro
[iOS - swift] Swift Macro 구현 방법 (swift-syntax, SwiftCompilerPlugin, SwiftSyntax, SwiftSyntaxBuilder, SwiftSyntaxMacros)
jake-kim 2023. 9. 8. 01:55Swift Macro 시작
- Xcode 15 Beta 이상, 스위프트 5.9이상에서 Xcode -> New -> Package하여 Swift Macro 생성하면 아래처럼 3가지의 파일이 생성 (프로젝트 명을 "MySample"로 생성)
- main.swift
- MySample.swift
- MySampleMacro.swift
- 지난 포스팅 글에서 알아본 것은 main.swift, MySample.swift파일
- main.swift: 정의한 매크로를 테스트하는 파일
- MySample.swift: 직접 정의한 매크로 로직을 외부에서 사용할 수 있도록 인터페이스를 맞춰주는 파일
- (구체적인 내용은 이전 포스팅 글 참고)
- MySampleMacro.swift은 매크로 로직이 들어있는 핵심적인 파일
Swift Macro 구현 방법 (MySampleMacro.swift 파일 알아보기)
- Swift Macro 프로젝트를 생성하면 기본적으로 만들어진 {생성이름}Macro.swift파일에 매크로 로직이 존재
- 가장 위 코드부터 보면 4가지 import를 수행
- SwiftCompilerPlugin: 컴파일러의 동작을 사용자 지정하거나 확장하기 위해 사용
- ex) 특정 Swift 언어 기능을 확장하거나 다른 언어와의 통합을 지원
- SwiftSyntax: (아래에서 계속)
- SwiftSyntaxBuilder: result builder 스타일로 swift코드를 generate해주는 역할
- SwiftSyntaxMacros: syntatic macro를 지원해주는 역할
- SwiftCompilerPlugin: 컴파일러의 동작을 사용자 지정하거나 확장하기 위해 사용
SwiftSyntax를 사용하여 StringifyMacro구현
- SwiftSyntax란?
- SwiftSyntax는 단어 그대로 Swift를 Syntax (구문) 별로 tree 자료구조 형태로 표현한 것을 의미
- tree 자료구조 형태로 표현하여, parse, inspect, generate, transform를 사용하여 Swift Souce Code로 만들 수 있는 기능
- SwiftSyntax를 이용하는 이유부터 구체적인 개념은 이 포스팅 글 참고
- StringfyMacro는 매크로 두 개 중 (freestandingMacro, attachedMacro), 독립적으로 쓰이는 기능이므로 FreestandingMacro 중 ExpressionMacro를 사용
- 단순히 이 ExpressionMacro를 준수하는 StringifyMacro 구조체를 정의
public struct StringifyMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
// TODO:
}
}
- expansion 함수를 보면 node라는 인수와 반환 타입 ExprSyntax가 중요
- node: SwiftSyntax의 목적은 tree형태로 구문을 저장하여 각 node들이 모여서 tree가 되는데 이 때의 node가 바로 이 인수를 의미
- ExprSyntax: 구조체 형태의 expression syntax (표현식 구문)이라고 이해
- 이 함수가 실행되는 순간에는 이미 SwiftSyntax에 의해 트리 형태로 표현이 되었으며, 구문에 대한 node가 들어오면 node에서 표현식을 가져와서 해당 표현식을 그냥 리턴하면 1+2 값이 계산된 것이 반환되며, description으로하면 "1+2"로 리턴
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
guard let argument = node.argumentList.first?.expression else {
fatalError("compiler bug: the macro does not have any arguments")
}
return "(\(argument), \(literal: argument.description))"
}
- 반환값을 보면 문자열로 리턴하는데 이 문자열 역시도 ExprSyntax라는 하나의 표현식이므로 내부적으로 알아서 이 구문을 분석하여 사용하는쪽에 반환
return "(\(argument), \(literal: argument.description))"
- 이렇게하면 매크로 구현이 완료되며 외부에 인터페이스를 열어주는 작업도 필요한데, 이것은 또 다른 파일에서 수행
{생성이름}.swift에 인터페이스 선언
- 인터페이스 작성
- 매크로의 타입 @freestanding(expression)을 선언
- 접근제한자는 public으로 하고 #externalMacro를 사용하여 매크로를 표현 (module에는 로직이 적용된 .swift 파일 이름을 적고, type에는 로직이 적용된 struct 이름을 명시)
// MySample.swift
@freestanding(expression)
public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MySampleMacros", type: "StringifyMacro")
- #externalMacro는 단순히 매크로 인터페이스를 선언할 때 사용하는 것
- 인터페이스까지 선언했으며 테스트는 main.swift에서 수행
main.swift 파일에서 테스트
- 인터페이스가 정의된 MySample 모듈을 import한 후 매크로 사용 #stringify
// main.swift
import MySample
let a = 17
let b = 25
let (result, code) = #stringify(a + b)
print("The value \(result) was produced by the code \"\(code)\"")
* 참고
https://developer.apple.com/documentation/swift/externalmacro(module:type:)
https://swiftpackageindex.com/apple/swift-syntax/508.0.1/documentation/swiftsyntax/exprsyntax
https://swiftpackageindex.com/apple/swift-syntax/508.0.1/documentation/swiftsyntax
https://github.com/apple/swift-syntax
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/
'Swift Macro' 카테고리의 다른 글
[iOS - swift] Swift Macro 예제 - toDouble, isNumber (문자열로 된 숫자 판단하는 Macro, toDouble) (0) | 2023.09.16 |
---|---|
[iOS - swift] Swift Macro 예제 - URLMacro (0) | 2023.09.14 |
[iOS - swift] Swift Macro에서 사용되는 SwiftSyntax 개념 (0) | 2023.09.09 |
[iOS - swift] Swift Macro 시작하기 (매크로 생성, 형태) (0) | 2023.09.07 |
[iOS - swift] Swift Macro의 종류 (Freestanding, Attached) (0) | 2023.09.06 |
Comments