Xiaodi Wu スペース: Current )実装: 部分的な実装は main で提供されます 実験的機能フラグの下 マクロ 。 サンプル マクロ リポジトリ は、実験するための定式化を提示します概要: (ピッチ) ( ピッチ #2) (レビュー #1) (改訂のために返された) (ピッチ #3) (レビュー #2) (承認) 序章 式マクロは、新しいスタイルの式で Swift を後押しする定式化を提示します。おそらく、新しいコードを作成するための引数に対する私的な恣意的な構文変換。 エクスプレッション マクロは、新しい言語関数を導入することによって、以前はおそらく考慮に入れられていたメソッドで Swift をブーストするために考慮に入れる可能性があることを蓄積し、ビルダーがより表現力豊かなライブラリを作成し、余分なボイラープレートを排除するのに役立ちます. モチベーション 式マクロは は、言語にマクロを導入するための有名な動機を示しています。 肯定的な式は、言語が実行時の習慣を因数分解するための立派な抽象化をすでに提示していることを維持するための住居です。 一方、 #file のような面倒なコーディングの例外がいくつかあります。 および #line、式は、コンパイル中のこの描画のソース コードを動機付けたり、調整したりすることはできません。 このような利用条件では、外部のソース生成機器が必要になり、他のツールと通常はきれいに混合されなくなります. 決議案 この提案は、ソース内の式のように薄い式マクロの信念を導入します。コード (# でマーク) ) であり、式に展開されます。 式マクロは、最初にマクロを実際に展開する必要なく、式のマクロ展開の構成を記述する、特性のように注目に値するパラメーターと結果フォームを導出できます。
特定のマクロ展開は、構文ツリーでのソースからソースへの変換で実装されます。式マクロは、マクロ展開自体の構文ツリーと共に提供されます。 (例: # で開始) および最適な引数で終わる)、展開された構文ツリーに書き換えます。 その展開された構文ツリーは、マクロの最終結果の蓄積に向けてフォーム チェックされる可能性があります わかりやすい例として、stringifyを考えてみましょう 入力として単一の引数を取り、それぞれの本物の引数を含むタプルと、さらにその引数のソース コードを含む文字列リテラルを生成するマクロ。 このマクロは、次のようにソース コードではおそらく淡いものになるでしょう:
おそらくおそらく マクロのフォーム署名は宣言のフェーズであり、よく似ています。特性:
@freestanding
T[String]>
(
_-> (T, 弦)
x + y おそらくフォームチェックされるでしょう。 形式が正しくない場合 (例として、x の場合) は Int です。 および y は 文字列 ) です。 、マクロは展開されなくなる可能性があります。 有効な形式の場合、ジェネリック パラメーター T は x + y の最終結果に推測される可能性があります、そしてその形式は、マクロの最終的な結果の蓄積を経由して運ばれます。 このドローチェック モデルにはいくつかの利点があります: マクロの実装は、有効に型付けされた引数を入力として導出することが保証されているため、 インストゥルメントは注目に値するマクロを関数のように扱うことができ、マクロ引数は他の Swift コードと同じガイドラインに従うため、コード補完、構文強調表示などに対して同じアフォーダンスを提供します。 マクロ展開式は、マクロを拡大せずに部分的にフォームチェックすることさえできます。 これにより、インストゥルメントは、マクロ展開を実行することなく、結果のような結果を安らかに導き出すことができます。同じマクロがフォーム推論全体で繰り返し展開されることがなくなるため、集合時間のパフォーマンスが向上するのと同じくらい効果的です。 stringify
(1 + 2 )
#stringify(x + y)
) として構文ツリーを生成します出力。 結果の構文ツリーは、マクロの結果フォームを使用してステップでフォーム チェックされます。} }
stringify マクロはむしろ簡単です。 構文木 (x + y からマクロ引数を抽出します。 in #stringify(x + y)) その後、本物の引数をそれぞれ価格として補間することにより、結果のタプル式を形成し、その後 のソース コードとして) 文字列リテラル 。 次に、その文字列が式として解析されます (ExprSyntax を生成します) node) マクロ展開の最終結果なので返されます。 これは、SwiftSyntaxBuilder によって提供される準引用符の単純な蓄積です。 モジュール、主要な構文ノード (ExprSyntax を作成することによって実装されます。 この場合、式について) に準拠 ExpressibleByStringInterpolation、keep present 構文ノードは、展開された Swift コードを含む文字列リテラルに補間することもできます。
」
StringifyMacro
")
があるマクロ make に不可欠な 2 つの項目: マクロをプログラム内で宣言および展開する方法と、それらを個別の関数として実装する方法。 次のセクションでは、追加の重要なコンポーネントを紹介します。
@freestanding(expression) 属性は、マクロにのみ適用されます。 これは、マクロが式マクロであることを意味します。 「独立した」用語は マクロは想像力豊かで先見の明のあるドキュメントであり、メインで展開されるマクロを主張するのは淡いです # 構文. マクロ シグネチャは特性に似ており、パラメーター句 (おそらく空である可能性があります) と、必須ではない結果フォームを備えています。 マクロはファイル スコープでのみ宣言できます。 引数ラベル、パラメーターの種類、または結果の形式が異なる限り、それらは関数と同じ定式化でオーバーロードされる可能性さえあります.
macro-expansion-expression マクロ定義の両方で、囲んでいるマクロのパラメーターへの参照を開示するか、リテラルにする必要があります。 マクロ展開式 はフォームチェックされます (確かに、引数と結果の種類が意味を蓄積します) が、定義時に展開は実行されません。 マクロ定義 によって参照されるマクロの展開は合理的です。 は、宣言されているマクロが展開されたときに発生します。 詳細については、マクロ展開に関する次の記事を参照してください。
someMacroWithOpaqueResult () ->
一部順序<UInt8
> var あ =#someMacroWithOpaqueResult a
=
#someMacroWithOpaqueResult // 上のマクロ展開から不透明な形へのここでのマクロ展開の累積でコストを維持できません ["+"] マクロ展開 の #
マクロ展開式の構文は、Swift が既に の必要性を含んでいるため、具体的に選択されるとすぐになりました。 #
プレフィックス付きの式で、本質的にマクロに似ており、そのうちのいくつかは式マクロとして直接実装される可能性があります。 識別子 によって参照されるマクロ) は、@freestanding(expression) で示されるように、式マクロである必要があります。 対応するマクロ宣言
両方 特性名引数節 および トレーリング クロージャ 必須ではなくなりました。 それぞれが見落とされた場合、マクロは空の引数リスト
() のように展開されます。 が提供されました。 マクロはスタイル関数の第一級エンティティではなくなったため、値として渡すことができず、「適用されていないマクロ」構文は不要になりました。 これにより、 #line et #line()
。 これにはいくつかの前例があり、さらにリンクされたマクロに対して淡い準備ができているプロパティ ラッパーがあります。 ソース コード内でマクロ展開が発生した場合、展開は 2 段階で行われます。 最初のピースはフォームを見てピースであり、マクロへの引数を保持すると、名前付きマクロのパラメーターに対してフォームチェックが行われ、名前付きマクロの最終結果の蓄積がコンテキストに対してチェックされ、マクロ展開が行われます。発生します。 この種別チェックは、特性名に対して実行されるものと同様であり、マクロ定義は含まれません。
に代入されます。 定義の。 例えば: (_ cost: T) -> T=#prohibitBinaryOperators(コスト、演算子: ["+"]) #addBlocker(x + yz)" dir="auto">@freestanding (式)マクロ preventBinaryOperators
["+"] マクロ展開の
#
マクロ展開式の構文は、Swift が既にの必要性を含んでいるため、具体的に選択されるとすぐになりました。 #
プレフィックス付きの式で、本質的にマクロに似ており、そのうちのいくつかは式マクロとして直接実装される可能性があります。識別子 によって参照されるマクロ) は、
@freestanding(expression) で示されるように、式マクロである必要があります。 対応するマクロ宣言
両方
特性名引数節 および
トレーリング クロージャ 必須ではなくなりました。 それぞれが見落とされた場合、マクロは空の引数リスト
() のように展開されます。 が提供されました。 マクロはスタイル関数の第一級エンティティではなくなったため、値として渡すことができず、「適用されていないマクロ」構文は不要になりました。 これにより、#line et
#line()
。 これにはいくつかの前例があり、さらにリンクされたマクロに対して淡い準備ができているプロパティ ラッパーがあります。 ソース コード内でマクロ展開が発生した場合、展開は 2 段階で行われます。 最初のピースはフォームを見てピースであり、マクロへの引数を保持すると、名前付きマクロのパラメーターに対してフォームチェックが行われ、名前付きマクロの最終結果の蓄積がコンテキストに対してチェックされ、マクロ展開が行われます。発生します。 この種別チェックは、特性名に対して実行されるものと同様であり、マクロ定義は含まれません。
@freestanding (式)マクロ preventBinaryOperators
_ 料金: T, オペレーター : [String]) -> た #externalMacro(モジュール: "マクロの例 ", 形状
:
"ProhibitBinaryOperators
(料金、 演算子
z)
ここで、のマクロ展開#addBlocker(x + yz)
は最初に #prohibitBinaryOperators(x + yz, 演算子: [“+“])。 次に、その展開は ExampleMacros.ProhibitBinaryOperators によって処理される可能性があります。 、これは
ExpressionMacro["+"] に準拠する構造体として定義される可能性があります。 .
大きい展開により、新しいソース コードが (構文ツリーで) 生成されます。次に、そのソース コードは、真のマクロ結果フォームをそのコンテキスト フォームとして使用してフォーム チェックされます。 たとえば、stringify例のマクロは
(T, String) を返しました、したがって、
Int の形式の引数が与えられた場合、マクロを加速した最終結果は、
マクロ展開式は、マクロの引数のいたるところで発生する可能性があります。 たとえば、次のように考慮してください: #addBlocker (#stringify (1 +
2))
マクロ定義はswift-syntax キット。これは、Swift インストゥルメントの Swift 構文ツリー操作および解析機能を提供します。 SwiftSyntaxMacros モジュールが表示されますマクロを解明するために必要な性能 すべての「独立型」マクロは、FreestandingMacro に準拠しています。 プロトコル: /// いたるところに代替式を作成するための指定されたコンテキスト。
静的 関数 拡張( の ノード: いくつかの FreestandingMacroExpansionSyntax、
SwiftSyntaxMacros モジュールが表示されますマクロを解明するために必要な性能 すべての「独立型」マクロは、FreestandingMacro に準拠しています。 プロトコル: /// いたるところに代替式を作成するための指定されたコンテキスト。
静的 関数 拡張( の ノード: いくつかの FreestandingMacroExpansionSyntax、
の
コンテクスト: いくつかの マクロ拡張コンテキスト ) async
ExprSyntax } FreestandingMacroExpansionSyntaxプロトコルは
swift-syntax
マクロ展開式
を記述するノード 上記の文法用語。つまり、ソース コードを参照するため、マクロ展開の完全な構文ツリー (すべての空白とコメントを含む) を保持します。 マクロ定義は、
ExpressionMacro プロトコルを使用し、
何らかの理由でマクロ展開が進まない場合、展開 (の) による構文変換を実装します。 :in:)
、新しい式を構文ノードとして返します。 expansion(of:in:)
操作は、ブランドの斬新な構文ノードを作成しようとする試みの論争でエラーをスローする可能性があります。 その後、コンパイラはエラーをユーザーに伝えます。 さらに詳細な診断は、マクロ展開コンテキストによって提供することもできます.
_ 診断 : 診断) ///
/// - filePathMode: ソース スペースに含まれるファイル タイトルはどのようになっていますか///が結成されました
フレッシュな特徴@freestand(式)マクロ特性<た: ExpressibleByStringLiteral
>()
->// ソース空間情報 @freestanding
(式) マクロ行< T : ExpressibleByIntegerLiteral T
>() ->@freestanding (式)マクロ列<T :セレクタ
@freestanding
(式) マクロセレクター<T>(setter プロパティ : T) -> セレクター @フリースタンディング(式) マクロ keyPath
< T>(_ 財産:
T)
この提案の機能に合わせて、どの宣言がすべて参照されているかを調べたいからです。
#selector(getter: Individual.title) に相当するマクロ展開の引数の場所。 一方、構築された実装を派生させるマクロ宣言を提供すると、いくつかの特別な条件が挿入され、それらの特別性が低下します。 より多くの言語から。
オブジェクトリテラル@freestanding
T[String] :
ExpressibleByColorLiteral>(
真紅: い草で縛られて
, 緑
:い草で縛る , 青:い草で縛る
,
アルファ: ラッシュで縛る )) ->@freestanding (式) マクロ imageLiteral<T : ExpressibleByImageLiteral>(resourceName:
弦) -> た (式) マクロ fileLiteral<た: ExpressibleByFileReferenceLiteral>
(リソース名 : 弦) ->
T[String]
モノのリテラルを使用すると、さまざまなプログラム内のリソースを参照できます。種類。 オブジェクト リテラルの 3 つのスタイル (color、assist、file) は、式マクロとして記述することもできます。 上記のフォーム シグネチャは、オブジェクト リテラルに対してフォーム チェックが現在どのように機能しているか正確にはわかりません。 当然のことながら、それらが薄くなった後、コンパイラは現在、特別な名前のフォームを探します (例: _ColorLiteralType["+"] )) を現在のモジュールで使用し、対応する色リテラルを蓄積するため、それを使用します。 その習慣を維持するために、現在実行されているのと同じルックアップを実行して、オブジェクト リテラルのマクロ展開を確認することをお勧めします (たとえば、 の場合)。 _ColorLiteralType
) その後、対応するマクロの一般的な引数としてその形式を利用します。 その定式化、言語の特殊なオブジェクト リテラル式から組み込み実装によるマクロ宣言まで、困難な場合のフォーム チェックの習慣は変わりません の宣言 @freestanding(式)マクロ colorLiteralい草に縛られて, 緑: ラッシュで縛られて, 青: い草で縛られて
, アルファ: い草で縛られて)) -> _ColorLiteralType = SwiftBuiltinMacros. ColorLiteralMacro
// #colorLiteral の実装
struct{
/// ) -> TupleExprElemen
𝚆𝚊𝚝𝚌𝚑 𝙽𝙾𝚆 📺