TL;DR

  • DummyScheme은 Lua에서 영감을 받은 레지스터 기반 바이트코드 가상 머신(VM)을 사용하는 이식형·임베디드 Scheme 구현으로, C/C++ 호스트 프로그램에 통합할 수 있음.
  • 꼬리 호출 최적화, call/cc 기반 다중 샷 무제한 연속(continuation), dynamic-wind, 값 다중 반환을 지원함.
  • syntax-rules 위생적 매크로, 사용자 정의 생략 부호, 큰 정수(bignum)를 포함한 숫자 타워, 소스 위치 추적을 지원함.
  • r4rstest와 r5rs-tests 테스트를 통과하며, 기본 설정에서 R5RS를 준수하고 SCHEME_STD_R4RS=1 설정으로 R4RS를 지원함.
  • 일부 구현만 완료되고 현재 사용되지 않는 세대별 증분 가비지 컬렉터(GC)를 포함하며, Lua식 해시 테이블과 C/C++ 연동 인터페이스를 제공함.

DummyScheme

  • 레지스터 기반 바이트코드 VM을 사용하는 이식형 임베디드 Scheme 구현임.

개발 배경

  • 게임 프로그래밍, 특히 백엔드 분야에서 다년간 경험을 쌓았으며, 게임 업계와 다른 여러 분야에서 Lua가 널리 사용되는 점에 주목함.
  • SICP를 매우 좋아하고, 「The Roots Of Lisp」 글과 『Hackers and Painters』를 읽었으며, Lisp를 높이 평가함.
  • Lua처럼 레지스터와 바이트코드 기반 VM을 사용하고 줄 단위 디버그 정보를 제공하는 Scheme 구현을 원함.
  • .h와 .cpp 파일을 복사해 호스트 프로그램과 함께 컴파일하고 스텁을 작성하는 방식으로 쉽게 임베드할 수 있음.

기능

  • 레지스터 기반 명령어 집합을 사용하는 바이트코드 컴파일러
  • 꼬리 호출 최적화
  • 일급 연속(first-class continuation): call/cc 기반 다중 샷, 무제한 연속이며 호출 프레임에 쓰기 시 복사(copy-on-write) 방식을 사용함. 구분 연속(delimited continuation)은 가까운 시일 내 지원 예정임.
  • Lua에서 영감을 받은 평탄화 박스 값(flatten box value): 체인을 만들지 않고, 내부 람다에 의해 캡처되는 스택 값은 박싱함.
  • Chez Scheme에서 영감을 받은 연속 캡처 및 체인 순회용 스택 세그먼트 기법
  • 두 구간(two-halves) 증분 세대별 가비지 컬렉터: 일부 구현됐으나 현재 사용되지 않음.
  • 사용자 정의 생략 부호도 지원하는 syntax-rules 위생적 매크로
  • 큰 정수(bignum)를 지원하는 숫자 타워
  • 소스 위치 추적을 포함한 줄 단위 디버그 정보
  • Lua식 임베딩 및 이식성: 플랫폼에 독립적이며 C/C++ 호스트 애플리케이션에 쉽게 통합 가능함. Windows, Linux, macOS, iOS, Android를 비롯해 C99/C++98 호환 컴파일러가 있는 모든 플랫폼을 대상으로 함.
  • SCHEME_STD_R4RS=1 설정을 적용한 r4rstest와 r5rs-tests 전체 테스트 통과
  • call/cc와 중첩된 dynamic-wind 지원. dynamic-wind의 썽크나 본문에서 바깥으로 이동해 before와 after를 건너뛸 수 있으며, 안으로 이동하는 것은 금지되지 않음.
  • values와 call-with-values

추가 항목

  • transcript-on 및 transcript-off 없음
  • eval은 없지만 vm->evalstr 제공
  • Lua에서 영감을 받은 해시 테이블: make-hash-table, hash-table-ref table key, hash-table-set! table key val, hash-table-for-each 제공

사용 방법

  • Scheme 코드를 테스트할 때 프로젝트의 r4rstest.scm, r5rs-tests.scm, aftertest.scm 참조
  • main.cpp를 제외한 *.cpp 및 *.h 파일을 프로젝트에 복사
  • 헤더 vm.h를 포함하고 Scheme 네임스페이스 사용
  • 기본 malloc과 free를 사용하려면 VM vm으로 VM 초기화
  • 사용자 지정 메모리 할당·재할당·해제를 사용하려면 사용자 지정 할당 함수를 전달해 VM vm(myalloc)으로 초기화
  • vm.loadfile("filename.scm")로 파일 로드
  • RegCProc 항목 배열에 스텁 함수를 등록해 Scheme에서 호출할 C 함수를 연결함. 고정 인자 함수와 나머지 인자 함수 모두 등록 가능하며, regcfunc(vm, myext)로 등록함.
  • Scheme에서 (my-add 2 3), (my-sum 1 2 3 4)처럼 등록된 스텁 호출
  • C/C++에서 vm->evalstr("(+ 1 2)")로 Scheme 코드를 평가하고, scm_get_int로 결과 정수 추출
  • C/C++에서 vm->call("f", argv, n)으로 람다 호출

호환성

  • 별도 설정이 없으면 R5RS 준수
  • SCHEME_STD_R4RS 매크로 설정 시 R4RS 준수. 주된 차이는 심벌의 대문자 변환임.

향후 계획

  • 최적화와 기능 추가는 계속될 수 있음.

라이선스

  • MIT