Berryは超軽量な動的型付き組み込みスクリプト言語
(berry-lang.github.io)- Berryは低性能な組み込みデバイス向けの動的型付きスクリプト言語で、ARM Cortex M4基準でインタープリタコアは40KiB未満、4KiB未満のヒープでも実行可能
- ランタイムはワンパスコンパイラとレジスタベースVMで構成され、コード全体はANSI C99で書かれているため既存の組み込みコードに組み込みやすい
- 性能のために int、real、boolean、string はクラスオブジェクトにせず、list、map、range のみをクラスオブジェクトとして扱う
- 言語機能は命令型・オブジェクト指向・関数型プログラミングをあわせてサポートし、GC、FFI、例外処理、バイトコードファイル、拡張モジュールを含む
- コンパイル時のオブジェクト構成とflash固定機能により、コード・クラス・モジュールのRAM使用量を削減でき、メモリ制約の大きい環境に適している
組み込み環境を狙ったランタイム
- Berryはマイクロプロセッサのような低性能の組み込みデバイスで使うための動的型付きスクリプト言語
- ARM Cortex M4 CPU、Thumb ISA、ARMCC compiler 基準でインタープリタコアのコードサイズは40KiB未満
- 同じ条件で4KiB未満のヒープで実行可能
- インタープリタはANSI C99で書かれており、ワンパスのバイトコードコンパイラとレジスタベースの仮想マシンを含む
- 型設計は実行性能を優先し、値型とオブジェクト型を区別する
- クラスオブジェクトではない型: int、real、boolean、string
- クラスオブジェクトである型: list、map、range
- コンパイル時のオブジェクト構成では、ほとんどの定数オブジェクトを読み取り専用のコードデータセグメントに保存し、インタープリタ起動時のRAM使用量を抑える
言語機能と実行モデル
- 基本型には nil、boolean、integer、real、string、class、instance、module、list、map、range が含まれる
- 式と演算子は代入、関係、論理、算術、ビット、フィールド、添字、文字列連結、条件演算子、括弧、bytes buffer をサポートする
- 制御構造は
if elif else end、while、for、break、continueを提供する - 関数機能にはローカル変数とブロックスコープ、return文、入れ子関数定義、Upvalue ベースのクロージャ、無名関数、ラムダ式まで含まれる
- クラスは公開単一継承のみをサポートし、メソッドと演算子オーバーロード、コンストラクタメソッド、デストラクタメソッドを提供する
- GCはMark-Sweep GCを使用する
- 例外処理では
raise文で任意の例外値を投げられ、複数の catch モードをサポートする - バイトコードファイル機能により、関数をバイトコードファイルとしてエクスポートして再ロードし、実行できる
モジュール、C連携、例
- モジュール管理は組み込みモジュールと拡張モジュールの両方をサポートする
- 拡張モジュールにはスクリプトモジュール、バイトコードファイルモジュール、
*.so・*.dllのような共有ライブラリモジュールが含まれる - コード、クラス、モジュールを flash に固定して RAM 使用量を削減できる
- オプションの Regex サポートとオプションの LVGL mapping を提供する
- 拡張モジュールにはスクリプトモジュール、バイトコードファイルモジュール、
- Native C インターフェースにより既存コードへライブラリのように組み込め、Tasmota のようなコードが例として挙げられている
- Berry から C コードを呼び出すためのオプションの easy mapping を提供する
- 文法例ではリスト走査、map 作成とキー走査、
class宣言、:演算子による単一継承を示している - 追加のサンプルコードは GitHub で確認できる
1件のコメント
Hacker News のコメント
40KB のランタイムにしては機能が驚くほど豊富。ガベージコレクション付きの VM 上で Python/Ruby に似た言語が動き、手続き型・オブジェクト指向・関数型スタイルをサポートしている
ざっと見ただけでも、かなり書きやすそうに見える。特に定数オブジェクトを事前に作って大部分を ROM に置き、RAM は実際に変更可能なデータだけに使う機能が目を引く。私の知る限り MicroPython や Lua にはない方式で、ROM/フラッシュは十分あるが RAM が不足しがちな MCU では大きな差になる
モジュールに文字列や
bytes()のような不変オブジェクト形式の保存データがある場合、RAM に先にコピーせずフラッシュから直接読み出す。ただし freeze を行うには、デスクトップコンピューター上でコードを一度実行する必要があるhttps://docs.micropython.org/en/latest/reference/constrained...
そのため便利な流れとしては、コードベースが安定するか製品化段階に近づくまではランタイムにデプロイし、その時点でコードをファームウェアに freeze する、という方法になる。より便利なモデルとして
mapfsサポートの提案があり、フラッシュの一部をコード保存用に割り当てたうえで Python をバイトコードにコンパイル(mpy_cross)し、その領域へアップロードしてランタイムに実行できるようにする。概念実証はすでに出ているが、メインラインに入る前に整理すべき細部が残っているhttps://github.com/micropython/micropython/pull/8381
https://eluaproject.net/doc/v0.9/en_arch_ltr.html の rotables を見るとよい
Berry は Tasmota で使われている: https://tasmota.github.io/docs/Berry/
本当に良さそう。個人的には、これまで見たドキュメントの中でも最上級のドキュメントに近いと思う
熟練した開発者が言語の感覚をすばやくつかめるようにしてくれる「short manual」が特に良い。Tasmota は以前は知らなかったが、プロジェクトで試す口実を探すことになりそう
いちばん気になるのは、Lua と比べた性能とメモリ使用量がどうなのか、そしてサンドボックス化がどの程度可能なのかという点
信頼できないコードを実行できるのかも気になる
この言語が単純な構造体と基本的なコンストラクターを備えた有効な代替になるなら、Python スクリプトとその依存関係を取り除く用途で勧められそう
サンドボックス化はアプリケーション側が責任を持つ必要がある。サンドボックス化には WebAssembly が良い代替案になる
asyncキーワードのあるネイティブスレッド管理が入れば、ゲームエンジン用途では Lua と明確に差別化できそうこれとほぼ同じようなものだが、パラダイムはもっと少なく、静的型付けなら、設定言語として本当に良さそう
複雑な設定が必要な複数のプロジェクトで、数百行の YAML を書かせる代わりに Lua や Starlark/Python を使わせるケースがあったが、ずっと良く感じた。ただ、いつも自動補完とリフレクションが物足りない。この用途にぴったりの候補はなかなか見当たらず、小さく組み込めるスクリプト言語はほとんどが動的型付けだ
ただし https://dhall-lang.org/ は、多くの設定を静的型で扱えることと、その利点が大きいことを示している。複数の言語にプログラム的に埋め込めるようだ
https://docs.dhall-lang.org/howtos/How-to-integrate-Dhall.ht...
良さそう。それでも今のところはまだ uLisp(http://www.ulisp.com)のほうにかなり心が傾いているが、こういうものが出てくるのはうれしい
言語の雰囲気をつかむためにまずコード例を見るタイプなら、examples ディレクトリを見るとよい: https://github.com/berry-lang/berry/tree/master/examples
他言語向けのバインディングを提供してくれるととても良い。私たちは Rust から quickjs を使っているが、かなりうまく動いている
VM に必要なものだけを提供できるので、信頼できないコードも実行できる
組み込み用途に最適化された言語のように見える。設計とドキュメントがよくできていて、奇妙だったり予想外だったりする挙動はしないようだ
文法も心地よいほどミニマルで好みに合う。次の ESP32 プロジェクトでは必ず念頭に置くと思う
このニッチ領域には本当に合っていそうで、特に他の言語には対応物がすぐには思い浮かばないようなことをしている点が良い
ネイティブのスタックトレースで、スタックフレームにスクリプト関数名を表示する標準的なアプローチがあるのか気になる
クラッシュしたときや CPU プロファイラーを使うときに、ネイティブのスタックトレースとスクリプトのスタックトレースを混ぜて表示できるのか知りたい