Berry, ultra hafif dinamik tipli gömülü betikleme dili
(berry-lang.github.io)- Berry, düşük performanslı gömülü cihazlar için dinamik tipli bir betikleme dilidir; ARM Cortex M4 temelinde yorumlayıcı çekirdeği 40KiB’den küçüktür ve 4KiB’den küçük heap ile de çalışabilir
- Çalışma zamanı, tek geçişli derleyici ve register tabanlı VM’den oluşur; tüm kod ANSI C99 ile yazıldığı için mevcut gömülü koda eklenmesi kolaydır
- Performans için int, real, boolean, string sınıf nesnesi olarak oluşturulmaz; yalnızca list, map, range sınıf nesnesi olarak ele alınır
- Dil özellikleri, imperatif, nesne yönelimli ve fonksiyonel programlamayı birlikte destekler; GC, FFI, exception handling, bytecode dosyaları ve genişletme modüllerini içerir
- Derleme zamanı nesne oluşturma ve flash’a sabitleme özellikleri, kod, sınıf ve modüllerin RAM kullanımını azaltabildiğinden bellek kısıtı yüksek ortamlar için uygundur
Gömülü ortamları hedefleyen çalışma zamanı
- Berry, mikroişlemci gibi düşük performanslı gömülü cihazlarda kullanılmak üzere tasarlanmış dinamik tipli bir betikleme dilidir
- ARM Cortex M4 CPU, Thumb ISA, ARMCC compiler temelinde yorumlayıcı çekirdek kod boyutu 40KiB’den küçüktür
- Aynı koşullarda 4KiB’den küçük heap ile çalışabilir
- Yorumlayıcı ANSI C99 ile yazılmıştır; tek geçişli bytecode derleyici ve register tabanlı sanal makine içerir
- Tip tasarımı, çalışma performansını önceliklendirmek için değer tipleri ile nesne tiplerini ayırır
- Sınıf nesnesi olmayan tipler: int, real, boolean, string
- Sınıf nesnesi olan tipler: list, map, range
- Derleme zamanı nesne oluşturma, çoğu sabit nesneyi salt okunur kod veri segmentinde saklayarak yorumlayıcı başlatıldığında RAM kullanımını düşürür
Dil özellikleri ve yürütme modeli
- Temel tipler nil, boolean, integer, real, string, class, instance, module, list, map, range içerir
- İfadeler ve operatörler; atama, karşılaştırma, mantıksal, aritmetik, bit, alan, indis, string birleştirme, koşul operatörü, parantez ve bytes buffer desteği sunar
- Kontrol yapıları
if elif else end,while,for,break,continuesağlar - Fonksiyon özellikleri; yerel değişkenler ve blok kapsamı, return ifadeleri, iç içe fonksiyon tanımları, Upvalue tabanlı closure’lar, anonim fonksiyonlar ve lambda ifadelerine kadar uzanır
- Sınıflar yalnızca public single inheritance destekler; metotlar ve operatör overloading, constructor metodu ve destructor metodu sunar
- GC, Mark-Sweep GC kullanır
- Exception handling,
raiseifadesiyle herhangi bir exception değerinin fırlatılmasına izin verir ve birden fazla catch modunu destekler - Bytecode dosyası özelliğiyle fonksiyonlar bytecode dosyası olarak dışa aktarılıp tekrar yüklenerek çalıştırılabilir
Modüller, C entegrasyonu, örnekler
- Modül yönetimi, yerleşik modüller ve genişletme modüllerini birlikte destekler
- Genişletme modülleri; betik modülleri, bytecode dosyası modülleri ve
*.so·*.dllgibi paylaşımlı kütüphane modüllerini içerir - Kod, sınıf ve modüller flash’a sabitlenerek RAM kullanımı azaltılabilir
- İsteğe bağlı Regex desteği ve isteğe bağlı LVGL mapping sağlar
- Genişletme modülleri; betik modülleri, bytecode dosyası modülleri ve
- Native C arayüzü sayesinde mevcut koda bir kütüphane gibi gömülebilir; Tasmota gibi kodlar örnek olarak gösterilir
- Berry’den C kodu çağırmak için isteğe bağlı easy mapping sağlar
- Söz dizimi örnekleri; liste üzerinde dolaşma, map oluşturma ve anahtarlar üzerinde dolaşma,
classbildirimi ve:operatörüyle single inheritance kullanımını gösterir - Ek örnek kaynaklar GitHub üzerinde görülebilir
1 yorum
Hacker News yorumları
40 KB runtime için şaşırtıcı derecede zengin özellikli: çöp toplama özelliği olan bir VM üzerinde Python/Ruby benzeri bir dil çalışıyor; prosedürel, nesne yönelimli ve fonksiyonel stilleri destekliyor.
Üstünkörü bakınca bile yazması oldukça rahat görünüyor. Özellikle sabit nesneleri önceden oluşturup büyük ölçüde ROM’a koyması, RAM’i ise yalnızca gerçekten değiştirilebilir veriler için kullanması dikkat çekiyor. Bildiğim kadarıyla MicroPython veya Lua’da olmayan bir yaklaşım; ROM/flash bol ama RAM’i sınırlı MCU’larda büyük fark yaratır.
Modülde string veya
bytes()gibi değişmez nesneler biçiminde saklanan veri varsa, önce RAM’e kopyalanmadan doğrudan flash’tan okunuyor. Ancak freeze işlemini yapmak için kodu bir kez masaüstü bilgisayarda çalıştırmak gerekiyor.https://docs.micropython.org/en/latest/reference/constrained...
Bu yüzden rahat akış, kod tabanı kararlı hale gelene veya ürünleştirme aşamasına yaklaşana kadar runtime’da dağıtmak, o noktada kodu firmware’e freeze etmek. Daha kullanışlı bir model olarak
mapfsdesteği önerisi var; flash’ın bir kısmını kod depolama için ayırıp Python’u bayt koduna derleyerek (mpy_cross) bu alana yüklemeyi ve runtime’da çalıştırmayı sağlıyor. Kavram kanıtı şimdiden çıktı, ancak mainline’a girmeden önce temizlenmesi gereken ayrıntılar var.https://github.com/micropython/micropython/pull/8381
https://eluaproject.net/doc/v0.9/en_arch_ltr.html adresindeki rotables’a bakılabilir.
Berry, Tasmota içinde kullanılıyor: https://tasmota.github.io/docs/Berry/
Gerçekten iyi görünüyor. Kişisel olarak şimdiye kadar gördüğüm belgeler arasında en üst düzeye yakın olduğunu düşünüyorum.
Deneyimli bir geliştiricinin dili hızlıca kavramasını sağlayan “short manual” özellikle iyi. Tasmota’yı daha önce bilmiyordum, ama bir projede denemek için bahane arayacak gibiyim.
En çok merak ettiğim şey, Lua’ya kıyasla performansı ve bellek kullanımı nasıl, ayrıca sandboxing’in ne kadar mümkün olduğu.
Güvenilmeyen kodu çalıştırmanın mümkün olup olmadığını da merak ediyorum.
Bu dil basit struct’lar ve temel constructor’larla geçerli bir alternatifse, Python script’lerini ve bağımlılıklarını söküp atmak için önerebilirim gibi görünüyor.
Sandboxing uygulamanın sorumluluğunda olmalı. Sandboxing için WebAssembly iyi bir alternatif.
asyncanahtar sözcüğüyle yerel thread yönetimi eklenirse oyun motoru kullanımları için Lua’dan net biçimde ayrışacak gibi.Buna neredeyse aynı ama daha az paradigma içeren ve statik tipli bir şey olsaydı, yapılandırma dili olarak kullanmak gerçekten iyi olurdu.
Karmaşık yapılandırma gerektiren birçok projede yüzlerce satır YAML yazdırmak yerine Lua veya Starlark/Python kullandıran örnekler vardı; çok daha iyi hissettirmişti. Yine de her zaman otomatik tamamlama ve reflection eksikliği hissediliyor. Bu kullanım için tam uygun bir aday pek görünmüyor; küçük, gömülebilir script dillerinin neredeyse tamamı dinamik tipli.
Yine de https://dhall-lang.org/ pek çok yapılandırmanın statik tiplerle ele alınabileceğini ve bunun büyük faydası olduğunu gösteriyor. Birçok dile programatik olarak gömülebiliyor gibi görünüyor.
https://docs.dhall-lang.org/howtos/How-to-integrate-Dhall.ht...
İyi görünüyor. Yine de şimdilik uLisp(http://www.ulisp.com) tarafına epey sıcak bakıyorum; ama böyle şeylerin çıkması sevindirici.
Dili anlamak için önce kod örneklerine bakanlardansanız, örnekler dizinine bakmak iyi olur: https://github.com/berry-lang/berry/tree/master/examples
Diğer diller için binding sağlansa çok iyi olurdu. Biz Rust’ta quickjs kullanıyoruz ve oldukça iyi çalışıyor.
VM’e yalnızca istediğiniz şeyleri sunabildiğiniz için güvenilmeyen kodu da çalıştırabiliyorsunuz.
Gömülü kullanım için optimize edilmiş bir dil gibi görünüyor. Tasarımı ve belgeleri iyi; garip ya da beklenmedik davranışlar sergilemiyor gibi.
Sözdizimi de hoş biçimde minimal ve zevkime uygun. Bir sonraki ESP32 projemde kesinlikle aklımda tutacağım.
Bu niş alana gerçekten iyi uyuyor gibi görünüyor; özellikle de başka dillerde birebir karşılığı aklıma gelmeyen şeyler yapıyor olması hoşuma gitti.
Yerel stack trace’lerde stack frame’lerde script fonksiyon adlarını göstermenin standart bir yaklaşımı var mı merak ediyorum.
Bir çökme olduğunda veya CPU profiler kullanırken, yerel stack trace ile script stack trace’i karışık biçimde göstermek mümkün mü bilmek isterim.