4 điểm bởi GN⁺ 2023-10-09 | 1 bình luận | Chia sẻ qua WhatsApp
  • 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
  • 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

 
GN⁺ 2023-10-09
Ý 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

    • MicroPython cũng có thể freeze module để lưu vào flash, khi đó trong flash chỉ có bytecode đã biên dịch sẵ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 desktop
      https://docs.micropython.org/en/latest/reference/constrained...
    • Đọc phần giải thích rồi quay lại trang web, tôi thấy nó toàn diện và hấp dẫn hơn trang chủ rất nhiều
    • Như @snops đã giải thích, MicroPython có thể chạy mã từ flash dưới dạng frozen code. Hệ quả là phải biên dịch và đưa nó vào binary firmware, làm chậm chu trình phát triển nhanh thường thấy của MicroPython
      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 mainline
      https://github.com/micropython/micropython/pull/8381
    • Trông khá thú vị và ở nhiều mặt giống Lua, nhưng cũng có khác biệt đáng chú ý. Nhân tiện, eLua cũng từng có công việc đặt một phần dữ liệu vào ROM một cách trong suốt
      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/

    • Tasmota trông có vẻ thú vị. Nếu ai đã dùng hoặc đã so sánh với toit/jaguar thì tôi muốn nghe ý kiến
  • 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

    • So sánh với Lua là phần thú vị nhất. Hầu hết các công ty tôi từng làm đều dùng Python như các proxy thô sơ hoặc công cụ CLI, nhưng Lua thì khó khuyến nghị vì hướng đối tượng dựa trên metatable dễ gây nhầm lẫn
      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
    • Về cơ bản, mã có thể mở và ghi vào hệ thống tệp, nên không thể cứ thế chạy mã không đáng tin cậy
      Sandbox là trách nhiệm của ứng dụng. WebAssembly là một lựa chọn tốt cho sandbox
    • Nếu có thêm quản lý luồng native với từ khóa 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 engine
  • Nế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

    • Tôi cũng từng nghĩ theo hướng tương tự, nhưng gần với cấu hình được kiểm chứng mạnh hơn là kiểu tĩnh. Sẽ tốt hơn nếu có thể tải toàn bộ cấu hình rồi tạo ra danh sách vấn đề; nếu làm đúng thì cũng phải có khả năng hỗ trợ editor tốt
      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

    • Tôi định sẽ thử ngay. Tôi đang vọc một bộ dev kit ESP-32 để làm đồ trang trí Halloween nhấp nháy, và rất háo hức thử thứ này
      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