Membangun AST node demi node dengan newTree memadai untuk makro kecil, tetapi cepat melelahkan ketika pohonnya bertambah. Pustaka macros menyediakan tiga perangkat yang melengkapi satu sama lain, yaitu NimNode beserta properti kind untuk menginspeksi argumen, parseStmt yang mengubah teks menjadi AST, dan blok quote do yang menulis AST dengan sintaks Nim biasa lengkap dengan celah penyisipan. Topik ini mempraktikkan ketiganya pada makro yang sama ukurannya dengan makro nyata.
Menginspeksi argumen dengan kind#
Setiap NimNode membawa kind yang menyatakan jenisnya, dan makro yang menerima untyped dapat memeriksanya sebelum memutuskan bentuk keluaran. Makro berikut meneruskan argumennya apa adanya, tetapi mencetak kind-nya pada waktu kompilasi, sehingga perbedaan bentuk argumen terlihat langsung.
# NimNode: menginspeksi node lewat kind pada waktu kompilasi
import macros
macro periksa(x: untyped): untyped =
echo "kind: ", x.kind
result = x
echo periksa(1 + 2 * 3)
echo periksa("teks")
echo periksa([1, 2, 3])# kompilasi dan jalankan makro penginspeksi kind
nim r -f --hints:off perangkat_node.nimkind: nnkInfix
kind: nnkStrLit
kind: nnkBracket
7
teks
[1, 2, 3]Enam baris pertama keluaran semuanya hasil kompilasi, tiga baris berikutnya hasil program, dan pola dua fase ini khas makro. Properti lain seperti len dan indeks [i] juga tersedia pada NimNode, sehingga makro dapat menelusuri anak-anaknya, menghitung argumennya, dan membangun cabang yang berbeda menurut bentuk masukan. Kombinasi case terhadap kind inilah pola baku makro yang menerima banyak bentuk, yaitu setiap nilai nnk menjadi satu cabang pemeriksaan, dan modul macros menyediakan proc error untuk menolak bentuk yang tidak didukung dengan pesan kesalahan yang dirumuskan sendiri oleh pembuat makro.
Pasangan dari parseStmt adalah parseExpr yang mengurai satu ekspresi alih-alih kumpulan pernyataan, sehingga hasilnya berupa node ekspresi yang siap disisipkan ke posisi yang membutuhkan nilai. Keduanya sering dipakai berdampingan dengan quote do, yaitu bagian tetap ditulis dalam quote, sedangkan bagian yang baru diketahui saat kompilasi disusun lewat penguraian teks lalu disisipkan lewat celah penyisipan.
parseStmt dari teks menjadi AST#
Proc parseStmt menjalankan pengurai Nim terhadap sebuah teks dan mengembalikan AST-nya, sehingga makro dapat menerima kode dalam bentuk string, misalnya dari berkas konfigurasi yang dibaca pada waktu kompilasi. Makro berikut mengurai teks, mencetak pohonnya dengan treeRepr, lalu meneruskannya agar dinyatakan sungguhan pada program.
# parseStmt mengubah teks menjadi AST pada waktu kompilasi
import macros
macro muat(kode: static string): untyped =
let pohon = parseStmt(kode)
echo pohon.treeRepr
result = pohon
muat("let x = 40 + 2")
echo x# kompilasi dan jalankan makro pemuat teks
nim r -f --hints:off parsestmt.nimStmtList
LetSection
IdentDefs
Ident "x"
Empty
Infix
Ident "+"
IntLit 40
IntLit 2
42Parameter makro bertipe static string menuntut argumen berupa teks yang diketahui saat kompilasi, dan itulah syarat agar parseStmt dapat bekerja. Pohon hasil penguraian menyimpan deklarasi x lengkap dengan ekspresinya, Empty menjadi penanda bagian yang tidak diisi seperti tipe eksplisit, dan pengenal x kemudian hidup di lingkup pemanggil sebagaimana layaknya kode yang ditulis langsung.
quote do dengan celah penyisipan#
Blok quote do menulis AST dalam bentuk sintaks Nim biasa, dan pengenal yang dibungkus tanda petik terbalik menjadi celah penyisipan yang diganti nilai dari lingkup makro. Perbandingannya dengan newTree nyata, yaitu makro yang sama dapat dibaca tanpa memikirkan jenis node sama sekali. Makro berikut menciptakan proc baru pada waktu kompilasi, lengkap dengan namanya yang disisipkan dari parameter.
# quote do menyusun AST dari sintaks Nim biasa
import macros
macro buatPengali(nama: untyped, faktor: int): untyped =
result = quote do:
proc `nama`(x: int): int =
x * `faktor`
buatPengali(tigaKali, 3)
buatPengali(limaKali, 5)
echo tigaKali(10)
echo limaKali(10)# kompilasi dan jalankan makro pembuat proc
nim r -f --hints:off quote_proc.nim30
50Dua pemanggilan makro melahirkan dua proc berbeda, yaitu tigaKali dan limaKali, dan keduanya sah dipanggil seperti proc yang ditulis manual karena memang menjadi bagian program pada waktu kompilasi. Seluruh tubuh proc di dalam quote do juga ikut menjadi AST hasil, sehingga pemanggil buatPengali sama sekali tidak melihat mekanisme pembangunannya dan hanya menemukan dua proc siap pakai di lingkup modulnya.
Blok quote do menerima lebih dari satu pernyataan, sehingga makro yang menghasilkan deklarasi bertingkat seperti tipe beserta proc pendampingnya tetap ditulis sebagai satu blok kode yang terbaca alami. Untuk pemeriksaan, hasil quote do dapat disisipi echo pada waktu kompilasi atau dibandingkan dengan harapan lewat treeRepr, dan kebiasaan ini menyingkat pencarian kesalahan konstruksi yang mungkin tersembunyi di antara banyak baris bloknya. Pola ini menjadi tulang punggung pustaka yang menjanjikan kode dalam bentuk DSL kecil, misalnya pernyataan routes: pada pustaka web Nim.
Kesalahan umum#
- Memanggil proc pemeriksa AST pada posisi waktu berjalan. Pernyataan seperti
echo treeRepr(3)ditolak denganError: type mismatchyang mengharapkanproc treeRepr(n: NimNode): string, karena pemeriksa pohon hanya bermakna pada node AST, dan pemeriksaan yang benar dilakukan di dalam makro terhadap argumennya. - Lupa menyisipkan dengan tanda petik terbalik di dalam
quote do. Pengenal tanpa penyisipan diperlakukan sebagai nama tetap pada AST hasil, sehinggaproc nama(x: int)menciptakan proc bernamanamauntuk semua pemanggilan, bukan proc dengan nama dari parameter. - Memakai argumen biasa sebagai masukan
parseStmt. Parameter makro harus dinyatakanstatic stringagar menuntut teks yang diketahui saat kompilasi, karena teks yang baru ada saat program berjalan tidak dapat dikembalikan menjadi AST pada waktu kompilasi.
Ringkasan#
NimNodemembawakind,len, dan akses indeks, sehingga makro dapat menginspeksi dan mencabang menurut bentuk argumennya pada waktu kompilasi.parseStmtmengubah teks yang diketahui saat kompilasi menjadi AST, dantreeReprmencetak pohonnya untuk pemeriksaan.- Blok
quote domenulis AST dengan sintaks Nim biasa, penyisipan berlangsung lewat pengenal bertanda petik terbalik, dan hasilnya dapat berupa proc baru yang langsung dipanggil. Ketiga perangkat ini berbagi satu tipe yang sama, yaituNimNode, sehingga hasil satu perangkat menjadi masukan perangkat lainnya tanpa konversi dan makro yang besar tersusun dari bagian-bagian kecil yang dapat diperiksa satu per satu.
Referensi#
- Module macros — Nim documentation
— Tipe
NimNode,parseStmt,treeRepr, dan semantikquote dopada pustaka makro. - Manual Nim: Macro invocation — Nim documentation — Aturan pemanggilan makro dan batasan parameternya.
- Nim Tutorial Part III — Nim documentation
— Tutorial resmi pemrograman makro beserta contoh
quotedan penyisipan pengenal.