Nimのpragmaを自分で定義する
はじめに
こんにちは、Neoと申します。
この記事では、Nimのユーザー定義pragmaについて解説します。
pragmaとは
Nimのpragmaについては、こちらの記事が詳しく解説してくれています。
pragmaの仕組み
pragmaは、macro/templateか、{.pragma.}
pragmaを使って定義できます。
template myPragma(symbol: string; val: untyped): untyped =
discard
let a {.myPragma("a").} = 1
この例では、myPragma
というtemplateを定義して変数a
にpragmaとして使用しています。そして、次のようなコードと同じように解釈されます。
myPragma("a"):
let a = 1
また、{.pragma.}
プラグマを使うと、複数のpragmaをまとめて1つのプラグマにしたり、custom pragma
を定義できたりします。
when majorVersion >= 1:
{.pragma: deprOrErr, error.}
else:
{.pragma: deprOrErr, deprecated.}
この例では、majorVersion
という変数が1以上の時はerror
、それ以外ならdeprecated
と同じ効果を表すdeprOrErr
pragmaを定義しています。
カンマで区切ってさらに他のpragmaも追加すれば、2つ以上のpragmaを1つのpragmaにまとめられます。
custom pragma
{.pragma.}
pragmaをつけたtemplateで、custom pragma
を定義できます。
template sample1 {.pragma.}
template sample2(name = "") {.pragma.}
template sample3(title: string, t: typedesc) {.pragma.}
定義したcustom pragma
とその引数は、macros
モジュールのhasCustomPragma
,getCustomPragmaVal
などで検知できるので、macroのためにつける注釈として便利です。
自分で定義してみる
macroを使って、渡されたプロシージャの名前の末尾に"Cmd"を追加し、戻り値の型をint
型にするcmd
pragmaを書いてみました。
import macros
macro cmd(theProc: untyped): untyped =
result = theProc
result.name = newIdentNode(theProc.name.strVal&"Cmd")
result[3][0] = newIdentNode("int")
proc cd(dir = "~") {.cmd.} =
# do something
result = 0
cdCmd() # OK
cd() # Error
cd
というプロシージャを定義していますが、cmd
pragmaによって名前が書き換えられているため、cd
ではなくcdCmd
という識別子で呼び出す必要があります。また、戻り値の型がint
型に書き換えられています。
おわりに
macroやtemplateの知識が必要なので、少しだけハードルが高いかもしれませんが、使いこなせれば強力だと思いました。
最後までお読みいただきありがとうございました!
Discussion