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
- Protocol
- combine
- RxCocoa
- HIG
- Observable
- MVVM
- UICollectionView
- Human interface guide
- uitableview
- swiftUI
- rxswift
- Clean Code
- UITextView
- map
- 리펙터링
- Refactoring
- 스위프트
- SWIFT
- 클린 코드
- collectionview
- ios
- 리팩토링
- ribs
- 애니메이션
- 리펙토링
- Xcode
- clean architecture
- swift documentation
- uiscrollview
- tableView
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] Swift Macro 예제 - toDouble, isNumber (문자열로 된 숫자 판단하는 Macro, toDouble) 본문
Swift Macro
[iOS - swift] Swift Macro 예제 - toDouble, isNumber (문자열로 된 숫자 판단하는 Macro, toDouble)
jake-kim 2023. 9. 16. 01:32toDouble 매크로 소개
- String타입의 숫자를 Double 형태로 바꾸는 매크로이며, 컴파일 타임에 숫자가 아닌 문자열을 미리 컴파일 에러를 발생하게하는것이 목표
toDouble 매크로 구현
- Swift macro 프로젝트 생성
- ToDouble 매크로 선언
// ToDouble.swift
import Foundation
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros
public struct ToDouble: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
// TODO ...
}
}
- SwiftSyntax에 의하여 구문이 tree형태 자료구조로 표현되어 node로 부터 입력된 문자열 값 획득이 가능
- 문자열을 가지고 하나의 인수만 입력되었는지 판단
guard
let argument = node.argumentList.first?.expression,
let segments = argument.as(StringLiteralExprSyntax.self)?.segments,
segments.count == 1,
case .stringSegment(let literalSegment)? = segments.first
else {
throw CustomError.message("#ToDouble requires a static string literal")
}
- literalSegment.context.text로 입력된 문자열값을 가져와서 isNumber로 비교
- isNumber의 로직은 regularExpression을 이용한 방법이 성능이 CharacterSet보다 좋기 때문에 이것을 사용
- (regularExpression과 CharacterSet 성능 비교는 이전 포스팅 글 참고)
let inputString = literalSegment.content.text
if inputString.isNumber {
return "Double(\(argument))!"
} else {
throw CustomError.message("is not number: \(argument)")
}
private extension String {
var isNumber: Bool {
range(
of: "^[0-9]*$",
options: .regularExpression
) != nil
}
}
- 전체 코드
// ToDouble.swift
import Foundation
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros
public struct ToDouble: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
guard
let argument = node.argumentList.first?.expression,
let segments = argument.as(StringLiteralExprSyntax.self)?.segments,
segments.count == 1,
case .stringSegment(let literalSegment)? = segments.first
else {
throw CustomError.message("#ToDouble requires a static string literal")
}
let inputString = literalSegment.content.text
if inputString.isNumber {
return "Double(\(argument))!"
} else {
throw CustomError.message("is not number: \(argument)")
}
}
}
private extension String {
var isNumber: Bool {
range(
of: "^[0-9]*$",
options: .regularExpression
) != nil
}
}
- 플러그인에 추가
// Plugins.swift
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros
@main
struct ExNumberPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
StringifyMacro.self, // 프로젝트 생성시 자동으로 추가된 것
ToDouble.self
]
}
- 인터페이스 정의
// ExNumber.swift
// MARK: - ToDouble
@freestanding(expression)
public macro toDouble<T>(_ value: T) -> (T, String) = #externalMacro(module: "ExNumberMacros", type: "ToDouble")
- 사용하는 쪽 테스트를 위해 main.swift에 예제 코드 작성
// MARK: - toDouble
let numberValue = #toDouble("123")
let numberValue2 = #toDouble("123.456")
(빌드하면 제대로 구현된 것 확인 완료)
'Swift Macro' 카테고리의 다른 글
[iOS - swift] Swift Macro 예제 - URLMacro (0) | 2023.09.14 |
---|---|
[iOS - swift] Swift Macro에서 사용되는 SwiftSyntax 개념 (0) | 2023.09.09 |
[iOS - swift] Swift Macro 구현 방법 (swift-syntax, SwiftCompilerPlugin, SwiftSyntax, SwiftSyntaxBuilder, SwiftSyntaxMacros) (0) | 2023.09.08 |
[iOS - swift] Swift Macro 시작하기 (매크로 생성, 형태) (0) | 2023.09.07 |
[iOS - swift] Swift Macro의 종류 (Freestanding, Attached) (0) | 2023.09.06 |
Comments