Beberapa tahun yang lalu, saya melaksanakan semula bahasa khusus domain (DSL) yang pada asalnya direka untuk enjin peraturan di tempat kerja. Pelaksanaan semula mainan telah ditulis dalam Javascript (asalnya dalam Python), dan dikeluarkan kepada GitHub. Saya tidak menjangkakan ia akan berbuat banyak, kerana ia direka khusus untuk kes penggunaan yang sangat khusus yang tidak sepatutnya saya dedahkan.
Gambar yang agak comel yang dimuntahkan oleh bing copilot
Matlamat utama reka bentuk adalah sesuatu yang boleh bersiri dengan mudah. Kelengkapan Turing tidak membimbangkan, kerana saya hanya memerlukannya untuk melakukan 2 perkara sahaja:
Saya mula-mula mula menulis fungsi tanpa nama dalam Python. Walau bagaimanapun, apabila saya cuba menyebarkan kerja ke satu set benang/proses, jurubahasa mengadu bahawa lambdas tidak boleh bersiri. Pada masa itu, saya memerlukan logik untuk hidup di luar kod utama, jadi saya akhirnya mencipta DSL untuk tujuan tersebut.
Perkara pertama yang terlintas di fikiran ialah lisp, kerana saya suka bagaimana kod itu agak menyerupai tatasusunan/senarai. Persamaan adalah perkara yang baik, kerana saya telah menyimpan konfigurasi dalam YAML. Oleh itu, saya tidak perlu risau untuk mencipta cara baharu untuk mewakili logik.
Menyimpan bahasa sebagai senarai membawa kelebihan alternatif, saya tidak perlu mencipta parser dari awal, iaitu tidak perlu tokenize / melakukan analisis leksikal (lexer). Dengan kata lain, pengarang adalah lexer. Apa yang saya perlu laksanakan ialah mengambil senarai input, mencari sama ada ia adalah program (kami memanggilnya peraturan) dan melaksanakannya berkenaan dengan konteks.
const schema = ["condition.Equal", ["basic.Field", "foo"], ["basic.Field", "bar"]]; // returns a function that checks if context.foo === context.bar const rule = ruler.parse(rule) const context = {foo: "meow", bar: "woof"}; rule(context) // returns false
Semuanya berfungsi dengan baik dan seperti yang diharapkan. Kemudian beberapa hari yang lalu saya terjumpa artikel untuk melaksanakan skema dalam Python. Saya mungkin membaca artikel itu sebelum ini, ketika saya meluangkan banyak masa untuk mempelajari Clojure. Walau bagaimanapun, kali ini, saya memutuskan untuk melaksanakan semula perpustakaan sekali lagi, kembali dengan Python, dari awal.
Jadi kali ini saya perlu tokenize, dan melakukan lexer sendiri. Jika saya hanya berurusan dengan nombor, semuanya mudah, tetapi apabila ia datang kepada rentetan perkara menjadi lebih rumit. Saya mengikuti tutorial lain, dan menemui semula projek make-a-lisp. Akhirnya saya menyerah, dan menggunakan lexer yang disediakan oleh hy-lang.
Lexer mengambil ungkapan s dan mengembalikan struktur yang menyerupai pokok sintaks abstrak. Dari situ, saya membina penghurai saya dengan melintasi pokok, mengembalikan peraturan sebagai penutup yang mengambil kamus sebagai konteks.
const schema = ["condition.Equal", ["basic.Field", "foo"], ["basic.Field", "bar"]]; // returns a function that checks if context.foo === context.bar const rule = ruler.parse(rule) const context = {foo: "meow", bar: "woof"}; rule(context) // returns false
Tiada kelebihan sebenar untuk pelaksanaan baharu, kerana saya telah meninggalkan kerja selama beberapa tahun. Pelaksanaan yang saya tinggalkan mungkin masih berjalan dengan baik sehingga kini (lebih baik selepas begitu banyak lelaran yang membawa kepadanya). Walau bagaimanapun, saya masih belajar satu atau dua perkara sepanjang perjalanan ini. Jika anda rasa ini menarik, sila semak Javascript (di mana ia menjangkakan skema peraturan dalam tatasusunan), atau versi Python baharu (s-ungkapan).
Atas ialah kandungan terperinci Membuat semula DSL enjin peraturan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!