} }

expansion(of:in:) の特性は比較的狭いため、 stringify マクロはむしろ簡単です。 構文木 (x + y からマクロ引数を抽出します。 in #stringify(x + y)) その後、本物の引数をそれぞれ価格として補間することにより、結果のタプル式を形成し、その後 のソース コードとして) 文字列リテラル 。 次に、その文字列が式として解析されます (ExprSyntax を生成します) node) マクロ展開の最終結果なので返されます。 これは、SwiftSyntaxBuilder によって提供される準引用符の単純な蓄積です。 モジュール、主要な構文ノード (ExprSyntax

StringifyMacro

 ")

詳細メイク

があるマクロ make に不可欠な 2 つの項目: マクロをプログラム内で宣言および展開する方法と、それらを個別の関数として実装する方法。 次のセクションでは、追加の重要なコンポーネントを紹介します。

@freestanding(expression) 属性は、マクロにのみ適用されます。 これは、マクロが式マクロであることを意味します。 「独立した」用語は マクロは想像力豊かで先見の明のあるドキュメントであり、メインで展開されるマクロを主張するのは淡いです # 構文. マクロ シグネチャは特性に似ており、パラメーター句 (おそらく空である可能性があります) と、必須ではない結果フォームを備えています。 マクロはファイル スコープでのみ宣言できます。 引数ラベル、パラメーターの種類、または結果の形式が異なる限り、それらは関数と同じ定式化でオーバーロードされる可能性さえあります. は、マクロを拡大するために淡い実装を示しています。 これは有名な式として解析されますが、多くの場合 macro-expansion-expression

  • である必要があります。 、したがって、すべての非組み込みマクロは他のマクロに関して定義され、コンパイラーによって定義が提供される組み込みマクロで終了します。 macro-expansion-expression マクロ定義の両方で、囲んでいるマクロのパラメーターへの参照を開示するか、リテラルにする必要があります。 マクロ展開式 はフォームチェックされます (確かに、引数と結果の種類が意味を蓄積します) が、定義時に展開は実行されません。 マクロ定義 によって参照されるマクロの展開は合理的です。 は、宣言されているマクロが展開されたときに発生します。 詳細については、マクロ展開に関する次の記事を参照してください。 一部のシーケンス var a=#someMacroWithOpaqueResult a=#someMacroWithOpaqueResult // 上のマクロ展開から不透明なフォームへのここでのマクロ展開の累積でコストを保持できません" dir="auto"> @フリースタンディング (式) マクロ
  • someMacroWithOpaqueResult () ->

    一部順序<UInt8

    > var あ =#someMacroWithOpaqueResult a =

    #someMacroWithOpaqueResult // 上のマクロ展開から不透明な形へのここでのマクロ展開の累積でコストを維持できません

  •  

    # マクロ展開式の構文は、Swift が既に の必要性を含んでいるため、具体的に選択されるとすぐになりました。 # プレフィックス付きの式で、本質的にマクロに似ており、そのうちのいくつかは式マクロとして直接実装される可能性があります。 識別子 によって参照されるマクロ) は、@freestanding(expression) で示されるように、式マクロである必要があります。 対応するマクロ宣言

    および トレーリング クロージャ 必須ではなくなりました。 それぞれが見落とされた場合、マクロは空の引数リスト () のように展開されます。 が提供されました。 マクロはスタイル関数の第一級エンティティではなくなったため、値として渡すことができず、「適用されていないマクロ」構文は不要になりました。 これにより、 #line et #line()。 これにはいくつかの前例があり、さらにリンクされたマクロに対して淡い準備ができているプロパティ ラッパーがあります。 ソース コード内でマクロ展開が発生した場合、展開は 2 段階で行われます。 最初のピースはフォームを見てピースであり、マクロへの引数を保持すると、名前付きマクロのパラメーターに対してフォームチェックが行われ、名前付きマクロの最終結果の蓄積がコンテキストに対してチェックされ、マクロ展開が行われます。発生します。 この種別チェックは、特性名に対して実行されるものと同様であり、マクロ定義は含まれません。

  • (_ cost: T) -> T=#prohibitBinaryOperators(コスト、演算子: ["+"]) #addBlocker(x + yz)" dir="auto">

    @freestanding (式)マクロ preventBinaryOperators

    >(

    _ 料金: 

    T, オペレーター : [String]) -> た #externalMacro(モジュール: "

    マクロの例 ", 形状

  • :

    "

    ProhibitBinaryOperators

  • ") @freestanding (式) マクロ addBlocker>(_ 料金: T)
  • ->=#禁止BinaryOperators

    (料金、 演算子 (バツ +y

    は最初に #prohibitBinaryOperators(x + yz, 演算子: [+])。 次に、その展開は ExampleMacros.ProhibitBinaryOperators によって処理される可能性があります。 、これは ExpressionMacro["+"] に準拠する構造体として定義される可能性があります。 .

    例のマクロは (T, String) を返しました、したがって、Int の形式の引数が与えられた場合、マクロを加速した最終結果は、

    <マクロ展開結果>

    マクロ展開式は、マクロの引数のいたるところで発生する可能性があります。 たとえば、次のように考慮してください: #addBlocker (#stringify (1 +

    2

    )) マクロ展開式T であると推測します) は (整数、文字列)、最終結果は同じです。

    マクロ#prohibitBinaryOperators(#stringify(1 + 2), 演算子: ["+"])。 次に、 prohibitBinaryOperators マクロこれらの (テキスト) 引数が与えられると展開されます。 それが生成する展開結果は、おそらくフォームチェックされている可能性があり、フォームチェックを中止する準備ができています #stringify(1 + 2) 再び完璧に上昇 #stringify(1 + 2). 実装レベルの観点から、コンパイラーは、同一のマクロ引数のフォーム・チェックを繰り返し実行することを明確に予約しています。 たとえば、フォームチェック #stringify(1 + 2) prohibitBinaryOperators

  • の展開の最初の部分、または展開された結果に表示されます。 コンパイラは、同一の構文ノードが変更されていないことを認識すると、最初の部分で計算された種類を再利用します。 ここでは、フォーム チェッカーの重要なパフォーマンスの最適化を行います。
  • #line)、マクロはできませんパラメータのデフォルトの引数であるため、淡いです。 ソース領域の現在の関数は、デフォルトの引数として見えた後、特別な習慣を導き出し、それによって呼び出し元が、それらが思われる特性宣言で論争中の名前論争でソース空間情報を利用して展開されます。 ここに重要な現在の習慣があります。 指の代用ですが、すべてのマクロの意味を蓄積しなくなる可能性があり、完全になる可能性があることは間違いありません. その本当の能力は、(構築されていない)マクロであるデフォルトの引数を制限して混乱を解消し、廃墟でこの制限を再検討し始めていることです.

  • マクロ実装ライブラリ

    マクロ定義は

    swift-syntax キット。これは、Swift インストゥルメントの Swift 構文ツリー操作および解析機能を提供します。 SwiftSyntaxMacros モジュールが表示されますマクロを解明するために必要な性能

    すべての「独立型」マクロは、FreestandingMacro

    /// いたるところに代替式を作成するための指定されたコンテキスト。

    静的 関数 拡張( ノード: いくつかの FreestandingMacroExpansionSyntax、

     

    コンテクスト: いくつかの マクロ拡張コンテキスト ) async

    ExprSyntax } FreestandingMacroExpansionSyntaxプロトコルは swift-syntax マクロ展開式 を記述するノード 上記の文法用語。つまり、ソース コードを参照するため、マクロ展開の完全な構文ツリー (すべての空白とコメントを含む) を保持します。 マクロ定義は、ExpressionMacro プロトコルを使用し、展開 (の) による構文変換を実装します。 :in:)、新しい式を構文ノードとして返します。 何らかの理由でマクロ展開が進まない場合、expansion(of:in:) 操作は、ブランドの斬新な構文ノードを作成しようとする試みの論争でエラーをスローする可能性があります。 その後、コンパイラはエラーをユーザーに伝えます。 さらに詳細な診断は、マクロ展開コンテキストによって提供することもできます.

  •  ///
  • { /// マクロで使用する特別なタイトルを生成します。
  • 公共 func makeUniqueName (_ : 弦) -> TokenSyntax 公共 関数 診断
  • (

    _ 
     診断 : 診断)  ///

  • /// - node: ソース空間を作成する構文ノード
  • /// - 場所: 結果
  • /// 空。
  • /// - filePathMode: ソース スペースに含まれるファイル タイトルはどのようになっていますか      ///が結成されました      
    ///  が含まれるソース ファイルをルートとしていません。    

    位置: PositionInSyntaxNode,

    filePathMode 

    : SourceLocationFilePathMode ) -> AbstractSourceLocation ? } makeUniqueName()["+"] の特徴により、斬新で奇妙な名前を埋めることができるため、マクロ展開は、同一のスコープ内の他のすべての宣言と戦うことのない斬新な宣言を作成できます。 珍しいタイトルを含む識別子トークンを生成し、さらに タイトル

    を組み込む準備ができています。 より良いデバッグ性のための識別子。 これにより、マクロ展開引数によって提供されるコードがフォームチェックされるスタイルに影響を与える可能性のある新しい名前を導入しなくなるため、マクロをより衛生的にすることができます。 MacroExpansionContext

    マクロが拡張されている製造環境に関連する詳細情報で構成されるように、時間の経過とともに発展します。 たとえば、ターゲット プラットフォーム (OS、アーキテクチャ、および展開モデルに相当) に関する情報と、-D, コンテキストのフェーズとして統合する必要があります. 診断

    定式化により、マクロの実装が診断をマクロ展開のフェーズとして提示できるようになります。

    うなり声計算するのに淡いことさえある構文ノードの内部配置

    構文ノードが並ぶ最初のソース空間

  • 場合 前にLeadingTrivia ///

    構文ノードの最初のトークンの発信元を参照します。

    ///

    主要な特徴をまっすぐにたどります. 場合

    afterLeadingTrivia

  • 構文ノードの完全なトークンの先端を参照し、正確には

  • } /// ソース空間ファイル コースがどのように形成されるかを説明します。 公共 enum SourceLocationFilePathMode {
  • /// モジュール タイトルとファイル タイトルから構成されるファイル ID (パンチング コースなし),

     
    ///

    おそらくマクロ展開 `#fileID` によって生成される可能性があります。

  • 場合 ファイルID ///

    おそらくマクロ展開 `#filePath` によって生成される可能性のある、パンチの効いたコース タイトル

  • /// 例: `/dwelling/taylor/alison.swift`.
  • 場合

    ファイルパス } ソース領域は、文字列リテラル (ファイル タイトルの) または整数リテラル (行と列の場合)。 makeUniqueName と同様に、 TokenSyntax の紛争中String、この抽象化により、コンパイラーは、これらの値を表すために、適切な大まかな構文ノード (有名な Swift では表現できない可能性があります) を導入します。 /// { /// 公共

  • させて 行: ExprSyntax

    ///

    列を表す主要な式で、`ExpressibleByIntegerLiteral` です。

  • 公共 させて 列: ExprSyntax }

    形状

    : ) -> T    引数は、外部マクロ定義を提示するフォームのモジュール タイトルとフォーム タイトルを設定します。  externalMacro マクロを公開します。他のすべてのマクロを明確にするためにのみ展開されるという点で特別です。 他の場所で使用するのはエラーです。そのため、 @freestanding(expression) 属性。

    組み込みマクロ宣言

    前述のとおり、式マクロは同一のメイン # ( のような組み込み式の必要としての構文#ライン。 式マクロの導入により、これらの構築された式を、Swift の有名なライブラリのフェーズとして描画されるマクロに組み込むことをお勧めします。 特定のマクロの実装はコンパイラによって提供されますが、純粋な構文マクロでは必ずしも実装可能であるとは思われない問題が含まれているだけかもしれません。 一方、マクロ宣言を提供することで、言語の特別な条件を使用し、マクロ用に提供されたすべてのツール アフォーダンスから喜びを蓄積します。
    ソース空間マクロ
      
    //

    ファイルとコース関連情報

    @フリースタンディング

    (式)マクロファイルID

    <た:  ExpressibleByStringLiteral

    >()
    ->@フリースタンディング

    (式)マクロファイル

    <

    T: ExpressibleByStringLiteral

    >

    ()

    -> た @freestanding (式)マクロファイルパス : ExpressibleByStringLiteral

    >() ->

    フレッシュな特徴

  • @freestand(式)マクロ特性<た: ExpressibleByStringLiteral

    >()

    ->// ソース空間情報 @freestanding
  • (式) マクロ行<
  • T
  • : ExpressibleByIntegerLiteral
    >() ->@freestanding (式)マクロ列<T :  

  • T dsohandle

    ソース内の現在のスペースに関する情報を提供する操作コードは主に ExpressionMacro として実装可能です。 スペース を利用した、) 準拠の種類 MacroExpansionContext に対する操作*))。 例外は #file です。 MacroExpansionContext への拡張が必要です。 編集モードかどうかを調べるには、キープ #file#fileID

    のように動作します 対 ; dsohandle、これには肯定が必要ですコンパイラの増加; および #characteristicMacroExpansionContext で利用できなくなったコンテキスト情報が必要になります。 . これらのマクロのフォーム シグネチャには、非常に多くのフォームがあります。現在の設計図の習慣 #file#ラインなど、それらはリテラルのように処理されるため、合法的な ExpressibleBy* プロトコル。 一方、上記の実装は、次のようなコードを作成するのに失敗します:
     

    #ライン などは、リテラルの種類について蓄積したものと一致するデフォルト ルールが必要になります。 現在、これにはコンパイラで特別な向きが必要ですが、デフォルトのジェネリック引数を有効にする言語への将来の拡張により、おそらくこの信念を青写真の形で直接実現できるようになるでしょう.Purpose-C ヘルパー マクロ ザ・スイフト

  • #selector
  • #keyPath 式は、マクロ宣言の観点から表現された構文とフォームチェックの習慣を導き出すことができます。

    (

    _

  • :
  • T)

  • ->
  • セレクター @フリースタンディング

    (式) マクロセレクター>

    (getter プロパティ : T) ->

    セレクタ @freestanding (式) マクロセレクター<T>(setter プロパティ : T) -> セレクター @フリースタンディング(式) マクロ keyPath

    < T>

    (_ 財産:

    T)
     これらのマクロは ExpressionMacro

    この提案の機能に合わせて、どの宣言がすべて参照されているかを調べたいからです。 #selector(getter: Individual.title) に相当するマクロ展開の引数の場所。 一方、構築された実装を派生させるマクロ宣言を提供すると、いくつかの特別な条件が挿入され、それらの特別性が低下します。 より多くの言語から。 オブジェクトリテラル

    @freestanding

    T[String] :

    ExpressibleByColorLiteral

    >

    (

  • 真紅:
  • い草で縛られて

  • ,
  • : 
    い草で縛る , : 

    い草で縛る , アルファ: ラッシュで縛る )) ->@freestanding (式) マクロ imageLiteral<T : ExpressibleByImageLiteral>(resourceName

    :

    ) -> た (式) マクロ fileLiteral<た: ExpressibleByFileReferenceLiteral>

    (リソース名 : ) ->

    T[String]

    モノのリテラルを使用すると、さまざまなプログラム内のリソースを参照できます。種類。 オブジェクト リテラルの 3 つのスタイル (color、assist、file) は、式マクロとして記述することもできます。 上記のフォーム シグネチャは、オブジェクト リテラルに対してフォーム チェックが現在どのように機能しているか正確にはわかりません。 当然のことながら、それらが薄くなった後、コンパイラは現在、特別な名前のフォームを探します (例: _ColorLiteralType["+"] )) を現在のモジュールで使用し、対応する色リテラルを蓄積するため、それを使用します。 その習慣を維持するために、現在実行されているのと同じルックアップを実行して、オブジェクト リテラルのマクロ展開を確認す​​ることをお勧めします (たとえば、 の場合)。 _ColorLiteralType) その後、対応するマクロの一般的な引数としてその形式を利用します。 その定式化、言語の特殊なオブジェクト リテラル式から組み込み実装によるマクロ宣言まで、困難な場合のフォーム チェックの習慣は変わりません

    サンドボックス マクロの実装 SwiftPM プラグインのように、ファイルの設計図とネットワーク蓄積エントリに対抗します。 ここにはそれぞれ、セキュリティ上の予防措置と、拡大するために与えられた肯定マクロ展開ノードとその小さな 1 つのノード (ただし、親ノードまたは親ノードではない) を除いて、マクロが論争に依存しないように奨励する生き生きとした定式化があります。マクロ展開コンテキストによって具体的に提供される情報。 廃墟マクロで他の情報へのエントリを蓄積したい場合、これはおそらくマクロ展開コンテキストを拡張することによって実行されるでしょう。これはさらに、マクロが実際に照会した情報をコンパイラが歌唱するメカニズムを提供します。 マクロ活用・開発ツール

    マクロに関する主な考慮事項の 1 つは、マクロの利用と構築の容易さです。プログラムに? 斬新なマクロをどのように作成してデバッグするのですか?

    マクロの実装が別個の関数であるという議論の余地のない真実により、マクロの作成がより単純になります。 マクロの入力ソース コードを提示するマクロ実装の単体テストを作成できます (express, #stringify(x + y) )、swift-syntax の機能を利用してそのマクロを展開し、結果のコードに構文エラーがなく、予想されるコードと一致することを確認します。結果。 「組み込み」マクロの例のほとんどは、この描画で 構文マクロは、ファイルを見てみましょう .

    式マクロの例 の表現は、Swift フォーラムやその他のインスピレーション源から得たものと同じくらい効果的です。 これらのマクロのプロトタイプ実装は
    Swift-syntax リポジトリで利用可能
    .

  • )
  • マクロは、指定されたクリムゾン、グリーン、ブルー、およびアルファ値で色を宣言するための構文を示します。 次のように宣言して実装することもできます _ColorLiteralType=SwiftBuiltinMacros.ColorLiteralMacro // #colorLiteral struct ColorLiteralMacro: ExpressionMacro の実装 { /// タプルの最初の成分のチケットを指定された /// 小説チケット。 func replaceFirstLabel( of tuple: TupleExprElementListSyntax, with newLabel: String ) -> TupleExprElementListSyntax{ guard let firstElement=tuple.first else { return tuple } return tuple. changing( childAt: 0, with: firstElement.withLabel(.identifier(newLabel)) ) } static func expand( ノードの: some FreestandingMacroExpansionSyntax、コンテキスト内: some MacroExpansionContext ) -> ExprSyntax { let argList=replaceFirstLabel( of: node.argumentList, with: "_colorLiteralRed" ) let initSyntax: ExprSyntax=".init(( argList))" if let LeadingTrivia=node.leadingTrivia { return MacroResult(initSyntax.withLeadingTrivia(leadingTrivia)) } return initSyntax } }" dir="auto">
     //

  • #colorLiteralの宣言 @freestanding(式)マクロ colorLiteral

    い草に縛られて, : ラッシュで縛られて, : い草で縛られて

    , アルファ: い草で縛られて

  • )) -> _ColorLiteralType =
  • SwiftBuiltinMacros. ColorLiteralMacro // #colorLiteral の実装

    struct

    {

    /// /// ノベルチケット

    func

    replaceFirstLabel

    ( tuple

  • : TupleExprElementListSyntax,
    newLabel : 
  • 弦 ) -> TupleExprElemen

    𝚆𝚊𝚝𝚌𝚑 𝙽𝙾𝚆 📺

    anti-Mastodon, Ask HN, Auto-Generate, Billionaires, Blockchain, coding, computer science, CRYPTO, Expression, Show HN, Swift-evolution, Technology, TOP HN Tags:, ,