Sebelum kode ditulis, fitur ditetapkan dalam spesifikasi yang menjadi kontrak implementasi. Topik ini membahas cara menulis spesifikasi untuk fitur for-loop rentang, mulai dari tata bahasa tambahan dalam notasi BNF, semantik operasional, hingga contoh program valid dan invalid. Berkas spesifikasi_for.md di samping topik ini berisi dokumen spesifikasi lengkap yang menjadi rujukan untuk implementasi dan test suite. Setelah membaca topik ini, pembaca dapat menulis spesifikasi fitur yang cukup presisi untuk dijadikan kontrak oleh setiap tahap pipeline.
Mengapa spesifikasi ditulis lebih dulu#
Spesifikasi ditulis sebelum kode sebab spesifikasi menjadi kontrak yang mengikat setiap tahap pipeline. Lexer harus menerima semua bentuk yang diizinkan tata bahasa, parser harus membangun AST yang merepresentasikan struktur sintaksis, semantik harus menegakkan aturan tipe dan scope, serta codegen harus membangkitkan bytecode yang menjalankan semantik pernyataan. Tanpa spesifikasi, keputusan desain tersebar di seluruh kode, dan perubahan satu tahap dapat merusak tahap lain secara diam-diam.
Spesifikasi fitur baru terdiri atas empat bagian, yang menjadi daftar periksa implementasi, sehingga setiap keputusan kode dapat ditelusuri kembali ke satu aturan pada spesifikasi:
- Leksikal tambahan, yaitu token baru yang dikenal lexer.
- Tata bahasa tambahan dalam notasi BNF, yaitu produksi baru yang dipakai parser.
- Semantik operasional, yaitu aturan tipe, scope, dan perilaku runtime.
- Contoh program valid dan invalid, yaitu masukan yang harus diterima dan masukan yang harus ditolak beserta pesan errornya.
Struktur spesifikasi for-loop#
Spesifikasi for-loop rentang pada spesifikasi_for.md di samping topik ini mengikuti empat bagian tersebut. Bagian leksikal menambahkan tiga token, yaitu FOR, IN, dan DOTDOT, dengan DOTDOT dikenali lewat maximal munch pada dua titik berturut sebelum titik tunggal. Bagian tata bahasa menambah produksi for_stmt := "for" IDENT "in" range_expr block, dengan range_expr berpresedensi lebih rendah daripada aritmetika, sehingga 1 + 2 .. 5 * 2 dikelompokkan sebagai (1 + 2) .. (5 * 2). Pemilihan presedensi ini menentukan struktur AST dan memengaruhi codegen, sebab kedua endpoint dapat berupa ekspresi aritmetika yang dievaluasi sekali sebelum loop dimulai.
Bagian semantik menetapkan lima aturan. Ekspresi setelah in harus berbentuk Range, endpoint harus int, rentang a..b menyatakan himpunan [a, b) eksklusif ujung kanan, variabel loop dilingkupkan ke blok loop, dan variabel loop keluar dari scope setelah loop selesai. Bagian contoh program memuat tiga program valid, yaitu penjumlahan, pencetakan iterasi, dan rentang kosong, serta tiga program invalid, yaitu ekspresi setelah in bukan Range, kata kunci in hilang, dan kurung kurawal pembuka blok hilang. Keluaran yang diharapkan dan pesan error dituliskan untuk setiap contoh, sehingga test suite dapat menguji keduanya secara langsung.
# Spesifikasi Fitur: for-loop rentang
Dokumen ini adalah kontrak implementasi untuk fitur for-loop rentang
yang ditambahkan ke bahasa mini. Setiap tahap pipeline, yaitu lexer,
parser, semantik, IR, dan codegen, wajib memenuhi kontrak ini.
## Leksikal tambahan
Tiga token baru ditambahkan ke lexer:
- `FOR` dari kata kunci `for`.
- `IN` dari kata kunci `in`.
- `DOTDOT` dari dua titik berturut `..`, dikenali lewat maximal munch
sebelum titik tunggal, sebab titik tunggal tidak dipakai pada v1.
Kata kunci `for` dan `in` ditambahkan ke daftar kata kunci yang dilarang
dipakai sebagai identifier.
## Tata bahasa tambahan (BNF)
Notasi: `*` berarti nol atau lebih, `?` berarti nol atau satu, dan `|`
berarti pilihan. Karakter dalam tanda kutip adalah terminal literal.
```
statement := for_stmt | ... // produksi lama dipertahankan
for_stmt := "for" IDENT "in" range_expr block
range_expr := arith (".." arith)?
arith := term (("+" | "-") term)*
term := factor ("*" factor)*
factor := INT | IDENT | "(" expression ")"
block := "{" statement* "}"
```
Operator `..` berpresedensi lebih rendah daripada `+`, `-`, dan `*`,
sehingga `1 + 2 .. 5 * 2` dikelompokkan sebagai `(1 + 2) .. (5 * 2)`.
## Semantik operasional
Aturan semantik for-loop rentang:
1. Ekspresi setelah `in` harus bertipe Range, yaitu berbentuk `a..b`.
Bila bukan Range, semantik menolak dengan error "for-in mengharapkan
rentang (a..b)".
2. Endpoint a dan b harus bertipe int. Bila tidak, semantik menolak
dengan error "endpoint rentang harus int".
3. Rentang `a..b` menyatakan himpunan bilangan bulat [a, b), yaitu dari
a (inklusif) hingga b (eksklusif). Bila a >= b, rentang kosong dan
badan loop tidak dijalankan.
4. Variabel loop, yaitu IDENT setelah `for`, dideklarasikan dalam scope
blok loop. Variabel ini menampung nilai iterasi saat ini, mulai dari
a, dinaikkan satu per satu hingga mencapai b (eksklusif).
5. Setelah loop selesai, variabel loop keluar dari scope dan tidak
terlihat pada pernyataan sesudah loop.
## Contoh program valid
Program berikut menjumlahkan bilangan 1 sampai 4:
```
let total = 0
for i in 1..5 {
total = total + i
}
print total
```
Keluaran: `10`.
Program berikut mencetak tiap nilai iterasi:
```
for i in 1..4 {
print i
}
```
Keluaran: `1`, `2`, `3`.
Program berikut menunjukkan rentang kosong, di mana badan loop tidak
dijalankan:
```
for i in 5..5 {
print i
}
print 99
```
Keluaran: `99`.
## Contoh program invalid
Program berikut salah sebab ekspresi setelah `in` bukan Range:
```
for i in 5 {
print i
}
```
Error semantik: `for-in mengharapkan rentang (a..b)`.
Program berikut salah sebab kata kunci `in` hilang:
```
for i 1..5 {
print i
}
```
Error parse: `token 'in' diharapkan`.
Program berikut salah sebab kurung kurawal pembuka blok hilang:
```
for i in 1..5
print i
}
```
Error parse: `token '{' diharapkan`.
## Yang tidak termasuk
Hal-hal berikut di luar lingkup fitur for-loop rentang pada modul ini:
- Iterasi atas array atau string, yang membutuhkan tipe koleksi.
- Rentang dengan langkah, misalnya `1..10 step 2`.
- Rentang inklusif ujung kanan, misalnya `1..=5`.Berkas spesifikasi di atas menjadi rujukan kanonis untuk topik implementasi dan test suite. Setiap keputusan implementasi yang menyimpang dari spesifikasi adalah bug, dan setiap kasus uji yang ditambahkan ke test suite harus dapat ditelusuri ke aturan semantik atau contoh program pada spesifikasi. Dengan demikian, spesifikasi menjadi titik rujukan tunggal yang menyatukan keempat tahap pipeline, sehingga lexer, parser, semantik, dan codegen yang ditulis terpisah tetap sejalan satu sama lain.
Kontrak sebagai pintu masuk dan keluar#
Spesifikasi berfungsi sebagai pintu masuk dan pintu keluar implementasi. Sebagai pintu masuk, spesifikasi memberi tahu pembaca kode apa yang harus dikenal lexer, apa yang harus diparsing, dan apa yang harus diperiksa semantik. Sebagai pintu keluar, spesifikasi memberi tahu pembaca kode keluaran apa yang harus dihasilkan untuk masukan tertentu, sehingga test suite dapat memverifikasi keluaran secara langsung tanpa bergantung pada detail implementasi. Pemisahan masukan dan keluaran ini membuat test suite tetap valid meskipun implementasi ditulis ulang.
Bila sebuah kasus uji gagal, perbaikan dapat dijalankan dua arah. Bila implementasi menyimpang dari spesifikasi, implementasi diperbaiki. Bila spesifikasi ternyata tidak menangkap kasus penting, spesifikasi diperbarui terlebih dahulu, kemudian implementasi dan test suite disesuaikan. Disiplin ini menjaga spesifikasi tetap menjadi sumber kebenaran, bukan kode, sehingga perdebatan tentang perilaku yang benar selalu dapat dikembalikan ke satu dokumen. Implementasi dan test suite pada modul ini mengacu pada spesifikasi_for.md secara eksplisit sebagai kontrak yang harus dipenuhi.
Ringkasan#
- Spesifikasi ditulis sebelum kode sebab spesifikasi menjadi kontrak yang mengikat setiap tahap pipeline, yaitu lexer, parser, semantik, IR, dan codegen.
- Empat bagian spesifikasi adalah leksikal tambahan, tata bahasa BNF, semantik operasional, dan contoh program valid serta invalid.
- Spesifikasi for-loop rentang menambah tiga token, satu produksi tata bahasa, lima aturan semantik, serta tiga contoh valid dan tiga contoh invalid.
- Spesifikasi berfungsi sebagai pintu masuk dan pintu keluar implementasi, sehingga test suite dapat memverifikasi keluaran secara langsung tanpa bergantung pada detail implementasi.
Referensi#
- Backus–Naur form — Wikipedia — Notasi BNF yang dipakai untuk menuliskan tata bahasa tambahan for-loop.
- Operational semantics — Wikipedia — Konsep semantik operasional sebagai cara menuliskan perilaku runtime.
- The Rust Reference: For loops and ranges — Rust Project
— Sintaksis rentang
a..bdengan ujung kanan eksklusif yang menjadi rujukan semantik for-loop rentang.