Pada artikel ini saya tidak akan berbicara tentang fitur-fitur baru dari generator parser - saya sudah cukup menggambarkannya di bagian sebelumnya. Sebagai gantinya, saya ingin memberi tahu Anda apa yang saya lakukan di Core Developer Sprint minggu lalu sebelum semuanya terhapus dari ingatan saya. Meskipun sebagian besar materi entah bagaimana terkait dengan PEG. Jadi saya harus menunjukkan beberapa kode yang menetapkan arah dalam pelaksanaan parser PEG untuk Python 3.9.
Konten Seri Parser Python PEG Setiap tahun selama empat tahun terakhir, tim pengembangan inti Python telah berkumpul untuk sprint mingguan di lokasi yang eksotis. Sprint ini disponsori oleh tuan rumah dan PSF. Selama dua tahun pertama, kami mengunjungi Facebook di Mountain View, tahun lalu Microsoft memiliki jalur di Bellevue, dan Bloomberg di London dipilih untuk sprint ini. (Saya harus mengatakan bahwa itu terlihat sangat keren.) Kemuliaan bagi pengembang inti Pablo Galindo Salgado untuk pengorganisasian!
Kali ini lebih dari 30 pengembang, serta dua Padawans, mengumpulkan kami. Orang-orang bekerja di berbagai bagian: dari 3,8 blocker ke PEP baru. Saya berharap blog PSF tentang prestasi kami. Salah satu poin utama adalah bahwa jumlah PR terbuka kurang dari 1000, lebih dari 100 PR sedang menunggu tinjauan mereka. Bahkan ada kompetisi dengan papan peringkat - 10 peserta teratas yang menggelar PR dalam jumlah yang lebih besar.
Bagi saya, selalu alasan utama untuk menghadiri acara semacam itu adalah pertemuan dengan orang-orang yang saya ajak berkolaborasi online sepanjang tahun, tetapi yang saya lihat hanya sekali atau dua kali setahun. Sprint ini di Eropa, jadi kami melihat komposisi yang sedikit berbeda, dan ini sangat penting. Meskipun demikian, saya juga bekerja cukup produktif, yang akan saya bicarakan.
Sebagian besar waktu saya di sprint, saya bekerja dengan Pablo dan Emily Morhouse pada generator parser berbasis PEG, yang saya harap suatu hari nanti akan menggantikan generator parser berbasis pgen saat ini. Ini bukan kode yang sama dengan generator yang saya tulis, tetapi sangat mirip. Pablo telah berkontribusi pada versi ini.
Hari pertama sprint, Senin, saya bekerja terutama pada artikel 7 dan 8 dari siklus ini. Awalnya, saya berencana untuk menerbitkannya bersama, tetapi tidak punya waktu di akhir hari. Jadi dia membaginya menjadi dua bagian dan menerbitkan bagian pertama yang ditujukan untuk pembuatan metagram. Pada hari Jumat sore, saya akhirnya menemukan waktu untuk menyelesaikan Bagian 8. Namun, saya masih harus menghilangkan cerita potongan karena saya masih belum memiliki contoh yang baik.
Pada hari Selasa, saya mulai mengerjakan tata bahasa PEG untuk Python. Bahkan lebih dekat ke kode daripada spesifikasi abstrak sebelum menambahkan tindakan. Kami memahami bahwa kami perlu memeriksa tata bahasa yang dikembangkan pada kode Python asli. Jadi ketika saya sedang menyelesaikan tata bahasa saya, Emily sedang membuat skrip untuk pengujian batch. Setelah itu, alur kerja saya kira-kira seperti ini:
- Jalankan skrip untuk menguji beberapa direktori dengan kode Python
- Untuk menyelidiki masalah pertama di mana ia jatuh
- Tata bahasa yang benar untuk menyelesaikan masalah ini
- Ulangi sampai tidak ada masalah
- Pergi ke direktori berikutnya
Saya mulai dengan kode proyek pgen saya sendiri. Pada akhirnya, tata bahasa saya mampu menganalisis semua konstruksi Python yang digunakan dalam pgen, dan saya pindah ke modul perpustakaan standar. Pertama, berfokus pada Lib/test
, lalu Lib/asyncio
dan akhirnya Lib
, yaitu, pada kenyataannya, seluruh pustaka standar (setidaknya yang ditulis dengan Python). Pada akhir minggu saya dapat merayakan: satu-satunya file di perpustakaan standar tempat jatuhnya penganalisa baru adalah file dengan penyandian yang buruk. Mereka hanya ada sebagai data uji untuk memverifikasi bahwa masalah penyandian akan ditangani dengan cara yang benar; dan beberapa file untuk Python 2 yang diperlukan sebagai test case untuk lib2to3 .
Kemudian saya menambahkan beberapa kode untuk menghitung runtime parser dalam skrip Emily, dan sepertinya parser PEG baru sedikit lebih cepat daripada parser pgen lama. Ini tidak berarti bahwa segalanya akan semakin menanjak! Ada lebih dari 100 aturan dalam tata bahasa (160 baris), dan untuk membuatnya menghasilkan AST, kita perlu menambahkan tindakan ke masing-masing (lihat Bagian 6).
Sebelumnya, saya melakukan beberapa percobaan untuk melihat seberapa besar ukuran file akan meningkat setelah menambahkan tindakan. Saya sampai pada kesimpulan bahwa itu akan menjadi 2-3 kali lebih besar. Ini adalah tata bahasa dari eksperimen ini:
start[mod_ty]: a=stmt* ENDMARKER{ Module(a, NULL, p->arena) } stmt[stmt_ty]: compound_stmt | simple_stmt compound_stmt[stmt_ty]: pass_stmt | if_stmt pass_stmt[stmt_ty]: a='pass' NEWLINE { _Py_Pass(EXTRA(a, a)) } if_stmt[stmt_ty]: | 'if' c=expr ':' t=suite e=[else_clause] { _Py_If(c, t, e, EXTRA(c, c)) } else_clause[asdl_seq*]: | 'elif' c=expr ':' t=suite e=[else_clause] { singleton_seq(p, _Py_If(c, t, e, EXTRA(c, c))) } | 'else' ':' s=suite { s } suite[asdl_seq*]: | a=simple_stmt { singleton_seq(p, a) } | NEWLINE INDENT b=stmt+ DEDENT { b } simple_stmt[stmt_ty]: a=expr_stmt NEWLINE { a } expr_stmt[stmt_ty]: a=expr { _Py_Expr(a, EXTRA(a, a)) } expr[expr_ty]: | l=expr '+' r=term { _Py_BinOp(l, Add, r, EXTRA(l, r)) } | l=expr '-' r=term { _Py_BinOp(l, Sub, r, EXTRA(l, r)) } | term term[expr_ty]: | l=term '*' r=factor { _Py_BinOp(l, Mult, r, EXTRA(l, r)) } | l=term '/' r=factor { _Py_BinOp(l, Div, r, EXTRA(l, r)) } | factor factor[expr_ty]: | l=primary '**' r=factor { _Py_BinOp(l, Pow, r, EXTRA(l, r)) } | primary primary[expr_ty]: | f=primary '(' e=expr ')' { _Py_Call(f, singleton_seq(p, e), NULL, EXTRA(f, e)) } | atom atom[expr_ty]: | '(' e=expr ')' { e } | NAME | NUMBER | STRING
Ada banyak hal di sini yang harus saya jelaskan.
- Tindakan ditulis dalam C. Seperti dalam generator Python dari bagian 6, masing-masing adalah satu ekspresi.
- Teks dalam tanda kurung segera setelah nama aturan menentukan jenis hasil untuk metode aturan yang sesuai. Sebagai contoh,
atom[expr_ty]
berarti expr_ty
akan dikembalikan untuk atom
. Jika Anda melihat file Include/Python-ast.h
di repositori CPython, Anda akan melihat bahwa tipe ini adalah struktur yang digunakan untuk mewakili ekspresi di AST internal. - Jika alternatif hanya memiliki satu elemen, maka tindakan dapat dihilangkan, karena perilaku default untuk itu adalah hanya mengembalikan simpul AST yang dihasilkan. Kalau tidak, tindakan harus ditentukan secara eksplisit.
- Kode C yang dihasilkan juga perlu diproses. Misalnya, diasumsikan bahwa beberapa file header CPython akan dimasukkan. Misalnya, di mana tipe
expr_ty
, yah, dan banyak hal lain yang diperlukan. - Variabel
p
berisi pointer ke struktur Parser
yang digunakan oleh analyzer yang dihasilkan. (Dan ya, ini berarti lebih baik tidak menentukan elemen tunggal dalam aturan p
- jika tidak, kode C yang dihasilkan tidak akan dikompilasi!) EXTRA(node1, node2)
adalah makro yang berkembang menjadi seperangkat argumen tambahan yang harus diteruskan ke setiap fungsi konstruksi AST. Ini menghemat banyak waktu saat menulis tindakan - jika tidak, Anda harus menentukan nomor garis awal dan akhir, offset kolom, dan juga penunjuk ke arena yang digunakan untuk distribusi. (Node AST bukan objek Python dan menggunakan tata letak yang lebih efisien.)- Karena beberapa perilaku menarik preprosesor C di
EXTRA()
, kami tidak dapat menggunakan makro untuk membuat simpul AST, tetapi harus menggunakan fungsi dasar. Inilah mengapa Anda melihat, misalnya, _Py_Binop(...)
, bukan Binop(...)
. Di masa depan saya akan memikirkan cara menyelesaikannya secara berbeda. - Untuk elemen berulang (
foo*
atau foo+
), pembuat kode membuat aturan tambahan dari tipe asdl_seq*
. Ini adalah struktur data yang AST gunakan untuk mewakili pengulangan. Di beberapa tempat, kita perlu membuat pengulangan seperti itu hanya dari satu elemen, dan untuk ini kita telah mendefinisikan fungsi bantu singleton_seq()
.
Mungkin beberapa dari ini kedengarannya aneh, dan saya tidak akan berdebat. Ini adalah prototipe, dan tujuan utamanya adalah untuk menunjukkan bahwa pada prinsipnya memungkinkan untuk menghasilkan AST yang berfungsi menggunakan parser yang dihasilkan dari tata bahasa PEG. Semua ini berfungsi tanpa perubahan apa pun pada tokenizer yang ada atau kompiler bytecode. Prototipe dapat mengkompilasi ekspresi sederhana dan if
, dan AST yang dihasilkan dapat dikompilasi menjadi bytecode dan dieksekusi.
Hal-hal lain yang saya lakukan sebagai bagian dari sprint ini:
- Saya meyakinkan Lukasz Lang untuk mengubah PEP 585 (usulannya untuk tipe petunjuk di masa depan) untuk fokus pada obat generik, bukan pada serangkaian ide, seperti sebelumnya. PEP baru terlihat jauh lebih baik, dan pada pertemuan pengetikan beberapa hari yang lalu, di mana perwakilan pengembang utilitas pemeriksaan tipe Python (mypy, pytype, dan Pyre) hadir, ia menerima persetujuan umum. (Ini tidak sama dengan dukungan oleh Dewan Pemerintahan!)
- Membantu Yuri Selivanov dalam mengembangkan API untuk tipe frozenmap , yang ingin dia tambahkan ke stdlib. Beberapa kontributor lain juga berkontribusi pada desain - saya pikir kami menyelesaikan sprint dengan beberapa papan penuh contoh dan fragmen API. Hasilnya adalah PEP 603 , dan saat ini sedang dalam diskusi aktif . (Satu catatan: implementasi dari tipe data yang diusulkan sudah ada di CPython, sebagai bagian dari implementasi PEP 567 , modul
contextvars
. Ini adalah struktur data yang sangat menarik, Hash Array Mapped Trie
, yang menggabungkan tabel hash dengan pohon awalan) - Yuri, seperti biasa, penuh dengan ide. Dia juga bekerja pada kelompok pengecualian (sebuah ide dari Trio ) yang ingin dia implementasikan dalam asyncio dengan Python 3.9. PEP sepertinya tidak ada di sana terakhir kali saya melihat, tapi saya ingat satu papan penuh diagram.
- Kami telah secara aktif mendiskusikan proposal Lucas untuk siklus rilis Python yang lebih pendek. Ini menghasilkan PEP 602 , di mana ia menyarankan membuatnya setiap tahun, pada bulan Oktober. (Ada alasan bagus untuk ini: ini disebabkan oleh jadwal konferensi Python dan sprint inti.) Ini masih sangat banyak dibahas . Setidaknya ada dua penawaran balasan: di PEP 598, Nick Coglan menawarkan rilis dua tahun, sementara memungkinkan untuk fitur baru di patch; Steve Dower juga ingin melihat rilis dua tahunan, tetapi tanpa fitur ini (belum ada PEP).
- Tiga anggota Dewan Pemerintahan yang menghadiri sprint (Brett Cannon, Carol Willing dan saya) datang bersama dan membahas visi kami untuk pengembangan inti Python di masa depan. (Saya tidak ingin membicarakan hal ini banyak, karena kami berencana untuk membicarakannya di PyCon berikutnya di AS. Namun, kami mungkin akan menyarankan memulai penggalangan dana sehingga PSF dapat mempekerjakan beberapa pengembang untuk mendukung dan mempercepat pengembangan kernel).
- Saya melakukan percakapan makan siang yang menarik dengan Joanna Nanjeki - salah satu dari mereka yang menghadiri upacara tersebut. Dia menceritakan kisah bagaimana dia tahu tentang Internet ketika dia berusia 8 tahun dan membawa adik laki-lakinya ke kafe internet sementara ibu mereka bekerja. Di sana dia menemukan Google dan email dan digantung di sana pada minggu pertama.
- Acara beralkohol utama dalam seminggu adalah beberapa koktail Zombie Apocalypse, yang beberapa dari kami pesan di bar Alchemist. Disajikan dalam labu Erlenmeyer 2 liter dengan banyak asap palsu yang dihasilkan dari menuangkan alkohol kering pada campuran alkohol biasa, setiap minuman dirancang untuk empat orang.
- Pada Jumat malam, Lisa Roach membawa kami ke restoran India yang bagus di dekat hotelnya. Itu melalui empat stasiun metro, yang merupakan petualangan nyata (jam sibuk, dan kami hampir kehilangan Christian Hymes beberapa kali). Makanan itu sepadan!
- Di beberapa titik, kami mengambil foto grup. Itu terlihat sangat futuristik, tapi itu benar-benar pemandangan London.

Pada artikel selanjutnya, saya berharap untuk berbagi beberapa kemajuan dengan tindakan untuk membuat node AST.
Lisensi untuk artikel ini dan kode yang dikutip: CC BY-NC-SA 4.0