Một khi đã chốt baseline, chúng tôi bắt đầu viết mã nguồn cho native compiler chính thức. Sprint 126 thiết lập kiến trúc module cho trình biên dịch mới viết bằng DUY.
Quyết định kiến trúc quan trọng nhất là: Không sử dụng global mutable state.
Trong các trình biên dịch cũ, người ta thường dùng các biến toàn cục (global variables) để lưu trữ Symbol Table hoặc danh sách lỗi để tiện truy cập từ bất kỳ đâu trong code. Cách làm này rất nhanh khi viết ứng dụng nhỏ, nhưng là thảm họa khi biên dịch đa luồng hoặc khi thực hiện bootstrap lặp lại (multi-pass bootstrap), vì trạng thái của lượt compile trước dễ bị rò rỉ sang lượt compile sau. Nếu compiler trước đó bị crash hoặc chưa dọn sạch bảng biểu tượng, lượt compile sau sẽ dùng lại dữ liệu rác đó và phán quyết sai ngữ nghĩa.
Chúng tôi chia compiler thành các package/module độc lập:
- source database quản lý files và spans.
- lexer và parser làm việc trên token stream.
- semantic core giải quyết name resolution và type checking.
- IR builder và verifier quản lý representation trung gian.
- driver điều phối toàn bộ pipeline.
Mọi dữ liệu giữa các phase phải được truyền qua các data structures có schema/version rõ ràng. Chúng tôi viết các schema tests để tự động kiểm tra tính toàn vẹn của AST và IR serialization. Điều này đảm bảo span/diagnostic không bao giờ bị mất vị trí dòng cột khi đi qua các tầng phân tích. Lớp kiến trúc này ban đầu đòi hỏi viết nhiều code boilerplate hơn, nhưng nó mang lại sự an tâm tuyệt đối khi chúng tôi bắt đầu chạy song song các luồng biên dịch.
Bình luận (0)
Đang tải bình luận...