4P by GN⁺ | ★ favorite | 댓글 1개
  • 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를 제공함
  • 함수 기능은 지역 변수와 블록 스코프, 반환문, 중첩 함수 정의, 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에서 확인할 수 있음

댓글과 토론

Hacker News 의견들
  • 40KB 런타임치고 기능이 놀라울 만큼 풍부함: 가비지 컬렉션이 있는 VM에서 Python/Ruby와 비슷한 언어가 돌고, 절차형·객체지향·함수형 스타일을 지원함
    대충 봐도 작성하기 꽤 편해 보임. 특히 상수 객체를 미리 만들어 대부분 ROM에 넣고, RAM은 실제로 변경 가능한 데이터에만 쓰는 기능이 눈에 띔. 내가 알기로 MicroPython이나 Lua에는 없는 방식이고, ROM/플래시는 넉넉하지만 RAM이 부족한 MCU에서는 차이가 큼

    • MicroPython도 모듈을 freeze해서 플래시에 저장할 수 있고, 이때 플래시에는 미리 컴파일된 바이트코드만 들어감
      모듈에 문자열이나 bytes() 같은 불변 객체 형태의 저장 데이터가 있으면 RAM으로 먼저 복사하지 않고 플래시에서 바로 읽음. 다만 freeze를 수행하려면 데스크톱 컴퓨터에서 코드를 한 번 실행해야 함
      https://docs.micropython.org/en/latest/reference/constrained...
    • 설명을 읽고 다시 사이트에 가 봤는데, 홈페이지보다 훨씬 더 포괄적이고 매력적으로 느껴짐
    • @snops가 설명했듯이 MicroPython은 frozen code 형태로 플래시에서 코드를 실행할 수 있음. 그 결과 펌웨어 바이너리에 컴파일해 넣어야 해서 MicroPython의 일반적인 빠른 개발 사이클이 느려짐
      그래서 편한 흐름은 코드 기반이 안정되거나 제품화 단계에 가까워질 때까지는 런타임에 배포하고, 그 시점에 코드를 펌웨어에 freeze하는 방식임. 더 편한 모델로는 mapfs 지원 제안이 있어서, 플래시 일부를 코드 저장용으로 할당한 뒤 Python을 바이트코드로 컴파일(mpy_cross)해 그 영역에 업로드하고 런타임에 실행할 수 있게 함. 개념 증명은 이미 나왔지만 메인라인에 들어가기 전 정리할 세부 사항이 남아 있음
      https://github.com/micropython/micropython/pull/8381
    • 꽤 흥미로워 보이고 여러 면에서 Lua와 비슷해 보이지만, 눈에 띄는 차이도 있음. 참고로 eLua에서도 일부 데이터를 투명하게 ROM에 두는 작업이 있었음
      https://eluaproject.net/doc/v0.9/en_arch_ltr.html의 rotables를 보면 됨
  • Berry는 Tasmota에서 쓰임: https://tasmota.github.io/docs/Berry/

    • Tasmota가 흥미로워 보임. 써 봤거나 toit/jaguar와 비교해 봤다면 생각이 궁금함
  • 정말 좋아 보임. 개인적으로는 지금까지 본 문서 중에서도 최상급 문서에 가깝다고 생각함
    숙련된 개발자가 언어 감을 빠르게 잡을 수 있게 해 주는 “short manual”이 특히 좋음. Tasmota는 전에는 몰랐지만, 프로젝트에서 써 볼 핑계를 찾게 될 것 같음

  • 가장 궁금한 건 Lua 대비 성능과 메모리 사용량이 어떠냐는 것, 그리고 샌드박싱이 얼마나 가능한지임
    신뢰할 수 없는 코드를 실행할 수 있는지도 궁금함

    • Lua와의 비교가 제일 흥미로움. 내가 일했던 회사들은 대부분 Python을 조잡한 프록시나 CLI 도구처럼 썼지만, 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) 쪽에 꽤 마음이 가지만, 이런 것이 나오는 건 반가움

  • 언어 감을 잡으려고 코드 예제를 먼저 보는 편이라면, 예제 디렉터리를 보면 좋음: https://github.com/berry-lang/berry/tree/master/examples

  • 다른 언어용 바인딩을 제공하면 아주 좋겠음. 우리는 Rust에서 quickjs를 쓰고 있는데 꽤 잘 동작함
    VM에 원하는 것만 제공할 수 있어서 신뢰할 수 없는 코드도 실행할 수 있음

  • 임베디드 용도에 최적화된 언어처럼 보임. 설계와 문서가 잘 되어 있고, 이상하거나 예상 밖의 행동을 하지 않는 듯함
    문법도 기분 좋게 미니멀하고 취향에 맞음. 다음 ESP32 프로젝트에서 꼭 염두에 둘 것 같음

    • 바로 써 볼 예정임. 번쩍이는 핼러윈 장식을 만들려고 ESP-32 개발 키트를 만지작거리고 있었는데, 이걸 시험해 볼 생각에 기대됨
      이 틈새 영역에는 정말 잘 맞아 보이고, 특히 다른 언어에 비슷한 대응물이 딱히 떠오르지 않는 일들을 하고 있다는 점이 좋음
  • 네이티브 스택 추적에서 스택 프레임에 스크립트 함수 이름을 표시하는 표준적인 접근이 있는지 궁금함
    충돌이 나거나 CPU 프로파일러를 쓸 때, 네이티브 스택 추적과 스크립트 스택 추적을 섞어서 보여 줄 수 있는지 알고 싶음