잉? 나는 따로 구조체에서 Init을 선언해주지 않았는데 뜨네?이게모지? memberwise initialization
이는 컴파일러가 자동으로 init메서드를 생성해주기 때문이다.
그렇다면 만약 WhatisMacro에 어떤 프로퍼티도 추가해주고 야 이것도 자동 컴파일러가 하게 해줘!
🍎음...비효율적인데? 물론 swift compiler는 오픈소스야 잠만. 우리회의해보자...
🧑🏼💻어? 그럼 일일이 너네랑 회의해야해? 확장서 개그지같네;;
그래서 나온놈이 매크로다! 🧑🏼💻얘가 원하는데로 컴파일러를 수정하지 않고 Swift Package로 배포하는 방법!
매크로 어떻게 선언하는데?
public macro OptionSet<RawType>() =
#externalMacro(module: "SwiftMacros", type: "OptionSetMacro")
1. macro keyword 선언
2. macro name 여기서는 OptionSet이다.
3. 인수선언 여기서는 없다
4. swift 표준 라이브러리 externalMacro를 사용하여 swift에 매크로의 구현위치를 알려준다. 여기서는 SwiftMacros모듈은 @OptionSet매크로를 구현하는 OptionSetMacro를 포함한다.
주의해야할점!! 매크로는 항상 public! 왜인지 생각해보면 너무나 당연하다. 매크로를 선언하는 코드는 매크로를 사용하는 코드의 모듈과 다르므로 당연히 public으로 해야한다.
독립매크로(Freestanding macro)
선언에 첨부되지 않고 자체적으로 나타난다.
이름앞에 #작성하고 이름뒤에 소괄호속에 인수를 넣는다.
첨부매크로(Attached Macros)
매크로가 첨부된 선언을 수정 약간.. 역할? 소스코드에서 해당 매크로를 호출할수 있는 위치, 생성할 수 있는 코드의 종류를 결정한다고 한다. 즉 1. 어디에 적용되는지 2. 어느타입의 코드에 확장되는지 3. 그 확장이 코드의 어느곳에 삽입되는지
이름앞에 @작성하고 이름뒤 소괄호속에 인수를 넣는다. 어떤 선언과 연관되어 동작하는가!!
그래서 매크로 어떻게 만드는데?
File>New>Package를 보면 swiftMacro가 있다. AST를 사용하여 Swift code와 상호작용하기위해 SwiftSyntax 모듈을 사용하는데 여렇게 추가해주면 자동으로 SwiftSyntax에 대한 의존성을 추가해준다. 이렇듯 스위프트패키지 매니저를 통해 배포할수있어 버전관리, 팀내 배포가 용이하다.
자 매크로를 추가하였다. 글면 자동으로 이렇게 생긴얘가 생긴다.뭘까 얘는?
프로덕츠를 보면 이 두가지가 있는데 이는 외부에서 우리가 이 패키지추가할때 두가지가 뜨게 된다.
// Library that exposes a macro as part of its API, which is used in client programs.
.target(name: "MyMacro", dependencies: ["MyMacroMacros"]),
clientProgram에게 API의 일부로서 매크로를 노출한다.
MyMacro파일에 가면 이렇게 하나의 매크로가 만들어져 있다. 위에서 본 첨부매크로네? 어? 그리고 externalMacro네. 저기구현이 있구나? 즉 얘이름은 stringify고 genric type 인자 하나 받고 리턴타입으로 그 타입과 스트링타입 튜플형태로 받는구나. 그리고! 구현부는 MyMacroMacros라는 외부 플러그인의 stringifyMacro타입에 정의되어있구나!
컴파일러가 그러면 이 타입을 보면서 아 구현부구나? 파악하게된다. 그리고 맨 아래보면 외부에 제공할 매크로의 타입을 넣어주면된다.
소스코드를 컴파일 할때 모든 매크로를 확장한다. 일단 주의해야할것이 매크로는 Add something이라고 생각하면 된다. 즉 매크로에 의해 뭔가가 삭제되거나 수정되지 않는다. 조그만하게 코드로 만들어놓고 그것을 컴파일할때 자동으로 확장한다? 이렇게 이해하면 된다!
- 컴파일러는 코드를 읽고 구문의 메모리 표현을 생성한다
- 컴파일러는 메모리 표현의 일부분을 매크로 구현에 전송하여 매크로를 확장한다.
- 컴파일러는 확장된 형태로 매크로 호출을 대체한다.
- 컴파일러는 확장된소스코드를 사용하여 완료될때까지 계속 진행한다.
let magicNumber = #fourCharacterCode("ABCD")
이전의 LLVM 정리해놓은것을 보신분들은 아시겠지만 파싱의 단계에서 토큰단위로 분석을 하고 AST(추상구문트리)를 만든다. 해당 구조와 상호작용하는 코드를 더 쉽게 작성하기위해 코드의 구조를 만드는 것인데 위와 같이 magicNumber라는 매크로를 확장하는단계이다.
매크로 부르는쪽에서 매크로의 이름과 해당하는 인수 정보가 들어있다.그리고 나서 string literal이 제대로 들어왔는지 Semantic analysis를 진행한다.!!( 와 아는거 다나와서 신남). 여기서 타입체크 실패하면 에러뜨겟지
컴파일러는 매크로를 호출하는 위치를 코드에서 찾고, 해당 매크로를 구현한 외부바이너리를 로드한다 AST부분을 매크로의 구현부분에 전달한다.
즉! #fourCharacterCode 구현은 확장할때 입력으로 이부분의 AST를 읽는다
매크로는 이게 끝이아니다 진짜 무궁무진하다.. 아니 너무길다..사실 이거를 완벽이해하진 못했다.하지만 저보다 더 탐구하고 싶은 사람들을 위해 좋은 자료남길께요
이분 자료 진짜좋습니다
'Swift' 카테고리의 다른 글
Swift Performance-wwdc24 (0) | 2024.06.17 |
---|---|
힙메모리 분석 - WWDC24 (1) | 2024.06.15 |
초기화(initialization.. 편의? 지정?) (0) | 2024.03.05 |
Function(1급시민 , inout & 클로저✨) (0) | 2024.03.04 |
Assertions && Preconditions (0) | 2024.03.02 |