แมโคร
- แมโครของ Rust ใช้เพื่อลดการเขียนโค้ดซ้ำและลดงานที่ต้องทำซ้ำ
- โหนดของประโยคใน
sqleibniz ต้อง implement เทรต Node ซึ่งทำให้เกิดโค้ดซ้ำจำนวนมาก
- สามารถใช้แมโครเพื่อทำให้การประกาศ struct และการ implement เทรต
Node เป็นอัตโนมัติได้
แมโครสำหรับกำจัดโค้ดซ้ำ
- แมโครทำหน้าที่ประกาศ struct, เพิ่มคอมเมนต์เอกสาร และ implement ฟังก์ชันที่ทำให้ตรงตามเทรต
Node
- แมโครสามารถเพิ่มฟิลด์ได้หลากหลายผ่านการประกาศ metavariable แบบทำซ้ำ
การทดสอบ
- ใน Rust สามารถทำรูปแบบที่คล้ายกับ table-driven test ของ Go ได้
- สามารถใช้แมโคร
test_group_pass_assert! และ test_group_fail! เพื่อทดสอบคู่ของอินพุตและเอาต์พุตที่คาดหวังได้หลายแบบ
การทดสอบพาร์เซอร์
- ในโมดูลพาร์เซอร์ก็ใช้แมโครลักษณะคล้ายกันเพื่อทดสอบผลลัพธ์ของคำสั่ง SQL
- มีการใช้ฟังก์ชัน
sql_stmt_prefix เพื่อทดสอบคำสั่ง SQL EXPLAIN
ข้อเสียของแมโคร
rust-analyzer ทำงานได้ไม่ดีภายในแมโคร และเอกสารประกอบก็ยังมีไม่มาก
การจับคู่ตัวอักษร
- สามารถใช้แมโคร
matches! ของ Rust เพื่อเปรียบเทียบตัวอักษรได้อย่างง่ายดาย
- มีตัวอย่างการตรวจสอบว่าอักขระที่กำหนดเป็นตัวเลขแบบ SQLite หรือไม่
การจับคู่โทเค็น
- หลังจาก lexer แปลงสตรีมของอักขระเป็นสตรีมของโทเค็นแล้ว พาร์เซอร์จะใช้สิ่งนั้นเพื่อสร้างต้นไม้ไวยากรณ์
- ใช้คำสั่ง
match เพื่อจดจำประเภทของโทเค็น
การแสดงข้อผิดพลาด
- มีการจัดการข้อผิดพลาดเพื่อแสดงข้อความผิดพลาดที่ชัดเจนให้ผู้ใช้
ความสามารถแบบเลือกได้
- ใช้ชนิด
Option ของ Rust เพื่อตรวจสอบว่ามีค่าหรือไม่ รวมถึงเช็กเงื่อนไขหรือกำหนดค่าเริ่มต้นได้
- ใช้เมธอดอย่าง
is_some_and, map, map_or เพื่อให้อ่านโค้ดได้ง่ายขึ้น
ตัววนซ้ำ
- ใช้ iterator ของ Rust เพื่อกรองอักขระและประมวลผลให้ตรงกับกฎการพาร์สตัวเลขของ SQLite
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ประสบปัญหาในการใช้ Rust เพราะ
borrow checkerและความยากของการจัดการหน่วยความจำ แม้จะชอบองค์ประกอบของการเขียนโปรแกรมเชิงฟังก์ชัน (FP) ใน Rust แต่ก็ตัดสินใจมองหาภาษาอื่น และพบว่า OCaml น่าพอใจดูเหมือนจะยังมีประสบการณ์กับ Rust และแนวคิดด้าน PL ไม่มากนัก คิดว่าการกำหนด AST ด้วย algebraic data types จะง่ายกว่า ส่วนแมโครแม้จะทำงานต่างกันไปในแต่ละภาษา แต่โดยหลักแล้วใช้เพื่อลดโค้ดซ้ำและลดงานเขียนซ้ำๆ
พาร์เซอร์ที่เขียนด้วย Haskell โดดเด่นมากในแง่ความเรียบง่ายและความอ่านง่าย อ่านได้แทบจะเหมือน BNF และแทบไม่มีขั้นตอนเชิงเทคนิคมาบดบัง ทำให้โฟกัสกับไวยากรณ์จริงได้
เคยเขียนพาร์เซอร์ด้วย Ragel, Go, Java, C++, และ C มาก่อน การเขียน JSON parser ด้วย C อาจง่ายกว่าโค้ด Rust ก็ได้ โครงสร้างพื้นฐานของพาร์เซอร์พัฒนาไปมาก จนถึงจุดที่สามารถสร้างพาร์เซอร์ด้วย eBNF ได้
เคยเขียนตัว disassembler และ emulator ของ eBPF ด้วย Rust และคิดว่า Rust เหมาะกับงาน parsing อย่างไรก็ตาม การใช้แมโครให้ความรู้สึกต่างจากการทำงานภายในตัวภาษาเอง
ชอบบรรยายของ Rob Pike เรื่อง lexical scanning ใน Go มาก เป็นแนวทางที่ให้ความรู้และสง่างาม
สามารถใช้ไลบรารี parser combinator เพื่อดีพลอยพาร์เซอร์โปรโตคอลประสิทธิภาพสูงในสภาพแวดล้อมแบบ embedded ได้ และยังสามารถใช้ไลบรารีเดียวกันนี้เขียน embedded protocol parser ได้ด้วย
ตอนเขียนพาร์เซอร์ AST ทั้งชุดใน Rust พบว่าการแสดงลำดับชั้นของชนิด AST แบบเฉพาะเจาะจงทำได้ยาก ต้องใช้เทคนิคด้านชนิดข้อมูลแปลกๆ และแมโคร
การพาร์สไวยากรณ์ของ sqlite เป็นงานที่ยาก sqlite เป็นแหล่งแรงบันดาลใจที่ดี แผนภาพ railroad มีประโยชน์มาก และตัวสร้างพาร์เซอร์ Lemon ก็ยังไม่ได้รับการยอมรับเท่าที่ควร
ภาษาที่มี algebraic data types เหมาะกับการพาร์สไวยากรณ์ของ sqlite และ Typescript ก็อาจเป็นตัวเลือกที่ดีเช่นกัน มีการเขียนบทแนะนำสั้นๆ เกี่ยวกับวิธีเขียนพาร์เซอร์ด้วย Rust