ข้าม​ไป​ยัง​เนื้อหา

สร้าง​ภาษา​โปรแกรม​ของ​คุณ​เอง — interpreter ด้วย Rust std ล้วน

ภาษา​โปรแกรม​ไม่ใช่​เวทมนตร์ มัน​คือ​โปรแกรม​ที่​อ่าน​ข้อความ​แล้ว​ตัดสิน​ใจ​ว่า​จะ​ทำ​อะไร​ต่อ — และ​คุณ​เขียน​มัน​เอง​ได้​ภายใน​แปดบท คอร์ส​นี้​พาสร้าง interpreter ของ​ภาษา​เล็กๆ ชื่อ nok ตั้งแต่​ตัว​อักษร​แรก​จนถึง REPL ที่​รัน script ได้​จริง ด้วย Rust standard library ล้วน ไม่มี external crate สัก​ตัว สิ่ง​ที่​ทำให้​คอร์ส​นี้​ไม่ใช่​การ​แปล​ตำรา​คือ ตำรา​ที่​ทุก​คน​อ่าน​เขียน​ด้วย Java จึง​ต้อง​ใช้ Visitor pattern เพื่อ​ชดเชย​สิ่ง​ที่ Java ไม่มี ส่วน Rust มี enum กับ match ที่​ทำงานนั้นได้ตรงๆ exception กลาย​เป็น Result และ ownership เป็น​ตัว​บังคับ​ให้ environment ต้อง​เป็น Rc RefCell ไม่ใช่​รสนิยม​ของ​ผู้​เขียน คุณ​จึง​ได้​เรียน​สอง​เรื่อง​พร้อม​กัน​คือ ภาษา​ทำงาน​อย่างไร และ Rust ทำให้การ​ออกแบบ​เปลี่ยน​ไป​ตรง​ไหน 8 บท​ลงมือ​จริง
ความคืบหน้า0 / 8 บทเรียน

ต้อง​มี Rust ระดับ​อ่าน​ออก​และ​คอมไพล์​เอง​ได้ ส่วน​ทฤษฎี​คอมไพเลอร์​ไม่​ต้อง​มี​มา​ก่อน​เลย

  • Rust ระดับ​ที่​ผ่าน ownership กับ borrow มา​แล้ว ไม่​ต้อง​เชี่ยวชาญ แต่​ต้อง​เคย​โดน borrow checker ปฏิเสธ​และ​เข้าใจ​ว่า​ทำไม คอร์ส​นี้​จะ​พา​ไป​เจอ​จุด​ที่​มัน​ปฏิเสธ​ด้วย​เหตุผล​ที่​ดี
  • ไม่​ต้อง​รู้​ทฤษฎี​คอมไพเลอร์​มา​ก่อน ไม่มี​บท​ไหน​ขอ​ให้​รู้จัก LL, LR หรือ context-free grammar มา​ก่อน ทุก​คำ​ที่​ใช้​ถูก​อธิบาย​ตอน​ที่​มัน​โผล่​มา​ครั้ง​แรก
  • ไม่​ต้อง​ติดตั้ง​อะไร​เพิ่ม​เลย นอกจาก Rust toolchain ที่​มี​อยู่​แล้ว เพราะ​ทั้ง​คอร์ส​ใช้ standard library ล้วน
  • ถ้า​เพิ่ง​จบ​คอร์ส​อื่น​ใน​เส้นทาง Rust คอร์ส​นี้​เป็น​บท​ปิด​ของ​ซีรีส์ แต่​ไม่​ได้​ต่อยอด code จาก​คอร์ส​ไหน เริ่ม​จาก file เปล่า​ได้​เลย

เส้น​ขอบเขต — คอร์ส​นี้​สร้าง​อะไร และ​ไม่​สร้าง​อะไร

หัวข้อ​ที่​มีชื่อ​ว่า “เส้น​ขอบเขต — คอร์ส​นี้​สร้าง​อะไร และ​ไม่​สร้าง​อะไร”

หัวข้อ​นี้​ประกาศ​ขอบเขต​ล่วงหน้า เพื่อ​ไม่​ให้​ใคร​อ่าน​จบ​แล้ว​รู้สึก​ว่า​ถูก​สัญญา​เกิน​จริง

สิ่ง​ที่​ได้​เมื่อ​จบ​คือ interpreter ที่​รัน​ภาษา​ซึ่ง​มี​ตัวแปร เงื่อนไข ลูป ฟังก์ชัน closure class และ method ได้​จริง พร้อม REPL และ​ตัว​รัน script

รายการ​นี้​เป็น​เส้น​ขอบเขต ไม่ใช่​ข้อ​แก้ตัว — ทุก​ข้อ​จงใจ​ตัด​ออก​เพื่อ​ให้​ส่วน​ที่​เหลือ​รัน​ได้​จริง​ใน 8 บท

  • ไม่มี inheritance class ใน​คอร์ส​นี้​มี property กับ method แต่​สืบทอด​กัน​ไม่​ได้ นี่​คือ​ของ​ที่ ถูก​ตัด​ออก​อย่าง​ตั้งใจ และ​บท​ที่ 8 จะ​บอกว่า​ถ้า​อยาก​ทำ​ต่อ​ต้อง​เติม​อะไร
  • ไม่ใช่ bytecode VM คอร์ส​นี้​เดิน​บน​ต้นไม้​โดยตรง ซึ่ง​เข้าใจ​ง่าย​กว่า​และ​ช้า​กว่า​โดย​ธรรมชาติ การ​คอมไพล์​ลง bytecode เป็น​คนละ​คอร์ส ไม่ใช่​บท​ที่ 9
  • ไม่มี garbage collector เรา​ยืม​ระบบ ownership กับ Rc ของ Rust มา​ใช้​แทน ซึ่ง​แลก​มา​ด้วย ข้อ​จำกัด​จริง​ที่​บท​ที่ 7 จะ​พูดถึงตรงๆ
  • ไม่​อ้าง​เรื่อง​ความเร็ว​เลย​สัก​จุด ไม่มี​ตัวเลข benchmark ไม่มี​การ​เทียบ​กับ​ภาษา​อื่น เพราะ​คอร์ส​นี้​ไม่​ได้​วัด​เรื่อง​นั้น

หัวข้อ​นี้​บอกว่า​คอร์ส​นี้​ต่าง​จาก​ต้นทาง​ตรง​ไหน และ​ทำไม​ความ​ต่าง​นั้น​ถึง​เป็น​สาระ

ตำรา​ต้นทาง​เขียน​ด้วย Java ซึ่ง​ไม่มี sum type จึง​ต้อง​ใช้ Visitor pattern เพื่อ​ให้​เพิ่ม การ​ทำงาน​ใหม่​บน​โครงสร้าง​เดิม​ได้​โดย​ไม่​แก้​ทุก​คลาส

Rust ไม่มี​ปัญหา​นั้น enum เก็บ​ทุก​กรณี​ไว้​ใน​ที่​เดียว และ match บังคับ​ให้​เขียน​ครบ​ทุก​กรณี ตั้งแต่​ตอน​คอมไพล์ สิ่ง​ที่ Java ต้อง​ใช้​แปด​คลาส​กับ interface หนึ่ง​ตัว Rust เขียน​เป็น enum เดียว​กับ match เดียว

ความ​ต่าง​นี้​ไม่​ได้​อยู่​แค่​ผิว มัน​เปลี่ยน​ลำดับ​การ​สอน​ทั้ง​คอร์ส และ​เปลี่ยน​ว่า​อะไร​คือ ส่วน​ที่​ยาก จุด​ที่​ยาก​ที่สุด​ของ​คอร์ส​นี้​ไม่ใช่ parser แต่​คือ​ตอน​ที่ ownership บอกว่า environment แบบ​ที่​ตำรา​วาด​ไว้ เขียน​ใน Rust ตรงๆ ไม่​ได้

หัวข้อ​นี้​อธิบาย​ว่า​ทำไม​ผู้​อ่าน​ตรวจสอบ code ใน​คอร์ส​นี้​เอง​ได้​ทั้งหมด

code ทุก​บล็อก​ใน​บทเรียน​ไม่​ได้​ถูก​พิมพ์​ขึ้น​มา​ใหม่ มัน​ถูก​คัด​มา​จาก file จริง​ใน scripts/rust-interpreter/ ที่ commit ไว้​ใน​รี​โป​นี้ และ​มี​เทสต์เทียบ​ที​ละ byte

ผล​รัน​ทุก​อัน​ที่​บทเรียน​แสดง ก็​ถูก​คัด​มา​จาก stdout ที่​รัน​จริง​เช่น​กัน พร้อม​ป้าย​กำกับ​ว่า รัน​ด้วย rustc รุ่น​ไหน​และ edition อะไร ถ้า​คุณ​รัน​แล้ว​ได้​ไม่​เท่า​กัน แปล​ว่า​มี​อะไร​ผิด ไม่ใช่ “แล้ว​แต่​เครื่อง”

แผนผัง​นี้​จะ​เติม​ขึ้น​เอง​เมื่อ​บทเรียน​ถูก​เพิ่ม​เข้า​มา