Berry là ngôn ngữ kịch bản nhúng kiểu động siêu nhẹ
(berry-lang.github.io)- Berry là một ngôn ngữ kịch bản kiểu động dành cho các thiết bị nhúng hiệu năng thấp; với ARM Cortex M4, lõi trình thông dịch có kích thước dưới 40KiB và có thể chạy với heap dưới 4KiB
- Runtime gồm trình biên dịch one-pass và VM dựa trên thanh ghi, toàn bộ mã được viết bằng ANSI C99 nên dễ tích hợp vào mã nhúng hiện có
- Để tối ưu hiệu năng, int, real, boolean, string không được tạo thành đối tượng lớp; chỉ list, map, range được xử lý như đối tượng lớp
- Các tính năng ngôn ngữ hỗ trợ đồng thời lập trình mệnh lệnh, hướng đối tượng và hàm, đồng thời bao gồm GC, FFI, xử lý ngoại lệ, tệp bytecode và mô-đun mở rộng
- Với cơ chế cấu hình đối tượng tại thời điểm biên dịch và cố định trong flash, có thể giảm mức sử dụng RAM của mã, lớp và mô-đun, phù hợp với môi trường bị ràng buộc mạnh về bộ nhớ
Runtime hướng đến môi trường nhúng
- Berry là ngôn ngữ kịch bản kiểu động để dùng trên các thiết bị nhúng hiệu năng thấp như vi xử lý
- Với CPU ARM Cortex M4, Thumb ISA và trình biên dịch ARMCC, kích thước mã của lõi trình thông dịch dưới 40KiB
- Trong cùng điều kiện, có thể chạy với heap dưới 4KiB
- Trình thông dịch được viết bằng ANSI C99, bao gồm trình biên dịch bytecode one-pass và máy ảo dựa trên thanh ghi
- Thiết kế kiểu dữ liệu ưu tiên hiệu năng thực thi, phân biệt giữa kiểu giá trị và kiểu đối tượng
- Các kiểu không phải đối tượng lớp: int, real, boolean, string
- Các kiểu là đối tượng lớp: list, map, range
- Cấu hình đối tượng tại thời điểm biên dịch lưu phần lớn đối tượng hằng vào phân đoạn dữ liệu mã chỉ đọc, qua đó giảm mức sử dụng RAM khi khởi động trình thông dịch
Tính năng ngôn ngữ và mô hình thực thi
- Các kiểu cơ bản gồm nil, boolean, integer, real, string, class, instance, module, list, map, range
- Biểu thức và toán tử hỗ trợ phép gán, quan hệ, logic, số học, bit, trường, chỉ số, nối chuỗi, toán tử điều kiện, dấu ngoặc, bytes buffer
- Cấu trúc điều khiển cung cấp
if elif else end,while,for,break,continue - Tính năng hàm bao gồm biến cục bộ và phạm vi khối, câu lệnh trả về, định nghĩa hàm lồng nhau, closure dựa trên Upvalue, hàm ẩn danh và biểu thức lambda
- Lớp chỉ hỗ trợ kế thừa đơn công khai, đồng thời cung cấp phương thức, nạp chồng toán tử, phương thức khởi tạo và phương thức hủy
- GC sử dụng Mark-Sweep GC
- Xử lý ngoại lệ cho phép ném giá trị ngoại lệ tùy ý bằng câu lệnh
raise, và hỗ trợ nhiều chế độ catch - Tính năng tệp bytecode cho phép xuất hàm ra tệp bytecode rồi nạp lại để thực thi
Mô-đun, tích hợp C, ví dụ
- Quản lý mô-đun hỗ trợ cả mô-đun tích hợp sẵn và mô-đun mở rộng
- Mô-đun mở rộng gồm mô-đun script, mô-đun tệp bytecode và mô-đun thư viện chia sẻ như
*.so,*.dll - Có thể cố định mã, lớp và mô-đun trong flash để giảm mức sử dụng RAM
- Cung cấp hỗ trợ Regex tùy chọn và LVGL mapping tùy chọn
- Mô-đun mở rộng gồm mô-đun script, mô-đun tệp bytecode và mô-đun thư viện chia sẻ như
- Với giao diện Native C, có thể nhúng như một thư viện vào mã hiện có; có ví dụ như Tasmota
- Cung cấp easy mapping tùy chọn để gọi mã C từ Berry
- Ví dụ cú pháp minh họa duyệt list, tạo map và duyệt khóa, khai báo
class, và kế thừa đơn qua toán tử: - Có thể xem thêm mã nguồn ví dụ trên GitHub
1 bình luận
Ý kiến trên Hacker News
Với một runtime 40KB, tính năng của nó phong phú đến mức đáng ngạc nhiên: một ngôn ngữ giống Python/Ruby chạy trên VM có garbage collection, hỗ trợ phong cách thủ tục, hướng đối tượng và hàm
Nhìn qua thôi cũng thấy khá dễ viết. Đặc biệt đáng chú ý là khả năng tạo sẵn các đối tượng hằng, đưa phần lớn vào ROM, còn RAM chỉ dùng cho dữ liệu thực sự có thể thay đổi. Theo tôi biết thì MicroPython hay Lua không có cách này, và trên các MCU có ROM/flash dư dả nhưng thiếu RAM thì khác biệt rất lớn
Nếu trong module có dữ liệu lưu trữ dưới dạng đối tượng bất biến như chuỗi hay
bytes(), chúng được đọc trực tiếp từ flash mà không cần chép vào RAM trước. Tuy nhiên để thực hiện freeze thì phải chạy mã một lần trên máy tính desktophttps://docs.micropython.org/en/latest/reference/constrained...
Vì vậy quy trình thuận tiện là triển khai lúc runtime cho đến khi nền tảng mã ổn định hoặc gần giai đoạn sản phẩm hóa, rồi đến lúc đó mới freeze mã vào firmware. Một mô hình tiện hơn là đề xuất hỗ trợ
mapfs: phân bổ một phần flash để lưu mã, biên dịch Python thành bytecode (mpy_cross), upload vào vùng đó và cho phép chạy lúc runtime. Bản chứng minh khái niệm đã có, nhưng vẫn còn vài chi tiết cần dọn dẹp trước khi vào mainlinehttps://github.com/micropython/micropython/pull/8381
Xem rotables tại https://eluaproject.net/doc/v0.9/en_arch_ltr.html
Berry được dùng trong Tasmota: https://tasmota.github.io/docs/Berry/
Thật sự trông rất hay. Cá nhân tôi nghĩ đây gần như là một trong những bộ tài liệu hàng đầu mà tôi từng thấy
Tôi đặc biệt thích “short manual”, giúp một lập trình viên có kinh nghiệm nhanh chóng nắm được cảm giác về ngôn ngữ. Trước đây tôi không biết Tasmota, nhưng có lẽ sẽ tìm cớ để dùng nó trong một dự án
Điều tôi tò mò nhất là hiệu năng và mức dùng bộ nhớ so với Lua ra sao, và khả năng sandbox đến mức nào
Tôi cũng muốn biết liệu có thể chạy mã không đáng tin cậy hay không
Nếu ngôn ngữ này là một lựa chọn thay thế hợp lệ với struct đơn giản và constructor mặc định, tôi nghĩ có thể khuyến nghị nó để loại bỏ các script Python cùng phụ thuộc của chúng
Sandbox là trách nhiệm của ứng dụng. WebAssembly là một lựa chọn tốt cho sandbox
async, nó có lẽ sẽ tạo khác biệt rõ ràng so với Lua trong các trường hợp dùng cho game engineNếu có thứ gần giống như thế này nhưng ít paradigm hơn và có kiểu tĩnh, nó sẽ rất tuyệt để dùng làm ngôn ngữ cấu hình
Ở vài dự án cần cấu hình phức tạp, thay vì bắt viết hàng trăm dòng YAML, có trường hợp cho dùng Lua hoặc Starlark/Python, và cảm giác tốt hơn nhiều. Nhưng lúc nào tôi cũng thấy thiếu tự động hoàn thành và reflection. Khó thấy ứng viên nào thật sự phù hợp cho mục đích này, còn các ngôn ngữ script nhỏ có thể nhúng hầu như đều là kiểu động
Tuy vậy, https://dhall-lang.org/ cho thấy nhiều cấu hình có thể được xử lý bằng kiểu tĩnh và lợi ích của nó cũng lớn. Có vẻ có thể nhúng theo cách lập trình vào nhiều ngôn ngữ
https://docs.dhall-lang.org/howtos/How-to-integrate-Dhall.ht...
Trông hay đấy. Dù vậy hiện tôi vẫn khá nghiêng về uLisp(http://www.ulisp.com), nhưng rất vui khi thấy những thứ như thế này xuất hiện
Nếu bạn có thói quen xem ví dụ mã trước để nắm cảm giác về ngôn ngữ, hãy xem thư mục ví dụ: https://github.com/berry-lang/berry/tree/master/examples
Sẽ rất tuyệt nếu cung cấp binding cho các ngôn ngữ khác. Chúng tôi đang dùng quickjs từ Rust và nó hoạt động khá tốt
Có thể chỉ cung cấp cho VM những gì mình muốn, nên cũng chạy được mã không đáng tin cậy
Trông giống một ngôn ngữ được tối ưu cho mục đích nhúng. Thiết kế và tài liệu tốt, dường như không có hành vi kỳ lạ hay ngoài dự đoán
Cú pháp cũng tối giản dễ chịu và hợp gu tôi. Chắc chắn tôi sẽ cân nhắc nó cho dự án ESP32 tiếp theo
Nó có vẻ rất phù hợp với ngách này, nhất là vì nó làm những việc mà tôi không nghĩ ra đối ứng tương tự trong các ngôn ngữ khác
Tôi tò mò liệu có cách tiếp cận chuẩn nào để hiển thị tên hàm script trong stack frame của stack trace native hay không
Khi xảy ra crash hoặc dùng CPU profiler, tôi muốn biết liệu có thể hiển thị trộn lẫn stack trace native với stack trace script hay không