본문으로 건너뛰기
피드

러스트를 리스프 문법으로 쓰면 이런 느낌이라는 주말 프로젝트

open-source 약 8분

러스트의 소유권, 빌림, 라이프타임, 제네릭, 트레이트 같은 의미론은 그대로 두고, 겉 문법만 리스프의 에스표현식으로 바꾼 실험 프로젝트가 나왔다. 완성형 컴파일러라기보다는 리스프 매크로를 러스트 세계에 붙이면 어떤 맛이 나는지 보여주는 트랜스파일러에 가깝다.

  • 1

    에스표현식으로 작성한 코드를 러스트 소스 파일로 변환한 뒤 rustc가 타입 검사와 빌림 검사를 그대로 수행함

  • 2

    매크로는 proc_macro나 토큰 스트리밍 없이 에스표현식을 받아 에스표현식을 반환하는 함수처럼 동작함

  • 3

    제네릭, 라이프타임, 모듈, match guard, where 절, associated type, turbofish 같은 러스트 기능 상당수를 문법 레퍼런스에 포함함

  • 4

    표현 불가능한 부분은 raw Rust 블록으로 빠져나갈 수 있게 설계함

  • 한 줄로 말하면, 러스트의 속은 그대로 두고 겉문법만 리스프로 갈아끼운 프로젝트임

    • 작성자는 대놓고 “프로덕션 컴파일러 아님, 주말 프로젝트임”이라고 선을 그음
    • 목표도 러스트 완전 대체가 아니라, 러스트 의미론에 리스프 매크로를 붙이면 어떤 느낌이 나는지 보는 실험에 가까움
  • 동작 방식은 꽤 단순함: 에스표현식으로 코드를 쓰면 .rs 파일로 변환하고, 그다음은 rustc가 처리함

    • 파이프라인은 (s-expr -> .rs -> binary) 구조
    • 타입 검사, 빌림 검사, 최적화는 전부 기존 러스트 컴파일러가 맡음
    • rlisp는 “문법만 바꿔주는 앞단” 역할을 하는 셈
  • 예시를 보면 러스트의 구조체, 메서드, 참조, 필드 접근이 전부 괄호 문법으로 표현됨

    • (struct Point (x f64) (y f64))처럼 구조체를 선언함
    • (&self), (other &Point) 같은 식으로 참조와 인자를 적음
    • (. self x)self.x처럼 필드 접근으로 변환되고, (. p1 distance (& p2))는 메서드 호출로 이어짐
  • 러스트의 핵심 기능을 꽤 많이 덮고 있다는 게 의외의 포인트임

    • 소유권, 빌림, 라이프타임, 제네릭, 트레이트, 패턴 매칭을 에스표현식으로 표현함
    • 문법 문서에는 visibility, module, turbofish, inline Rust, const/static, if-let, while-let, match guard, derive, where 절, supertrait, associated type, type alias까지 들어가 있음
    • 아직 빠진 문법도 있고, lifetime bound 같은 건 작업 목록에 남아 있음

중요

> 이 프로젝트가 직접 러스트의 타입 시스템을 재구현하는 건 아님. 변환 결과를 rustc에 넘기기 때문에 “문법 실험”과 “언어 의미론”이 깔끔하게 분리됨.

  • 연산자는 리스프식으로 쓰되, 결과물은 러스트다운 중위 표기법으로 나감

    • (+ a b)(a + b)로 변환됨
    • (+ a b c)(a + b + c)처럼 여러 항을 이어 붙임
    • -, *, /, == 같은 이항 연산자도 같은 식으로 처리함
  • 식별자 처리에는 러스트와 리스프 문법 사이의 충돌을 피하려는 장치가 있음

    • page-header 같은 케밥 케이스 식별자는 page__header처럼 이중 밑줄로 변환됨
    • 문제는 foo-barfoo__bar가 둘 다 foo__bar가 될 수 있다는 점
    • 이런 충돌은 경고를 띄우는 방식으로 처리함
  • 가장 실용적인 재미는 매크로 쪽임

    • rlisp 매크로는 컴파일 타임에 에스표현식을 받아 에스표현식을 돌려주는 함수처럼 동작함
    • 러스트의 proc_macro 크레이트, 토큰 스트리밍, syn/quote 조합 없이 defmacro로 끝남
    • quasiquote, unquote, unquote-splicing을 써서 리스프식 코드 생성 패턴을 그대로 가져옴
  • 예를 들어 when 매크로는 조건과 여러 본문 표현식을 받아 ifdo 형태로 확장됨

    • (when (> x 10) ...)(if (> x 10) (do ...))로 바뀜
    • 최종적으로는 if x > 10 { ... } 형태의 러스트 코드가 생성됨
    • &rest는 남은 인자를 리스트로 모으고, unquote-splicing은 그 리스트를 주변 표현식에 펼쳐 넣음
  • 반복문, 클로저, 모듈, 가시성 같은 일상적인 러스트 코드도 대부분 괄호 세계로 들어옴

    • while, loop, for, destructuring이 있는 for까지 예시가 있음
    • 타입 없는 람다, 타입 명시 람다, move 클로저도 지원함
    • pub, pub(crate), pub(super), 공개 필드와 비공개 필드도 표현 가능함
  • 빠져나갈 구멍도 있음: (rust "...")로 원시 러스트 코드를 그대로 박을 수 있음

    • rlisp가 아직 표현하지 못하는 문법은 문자열로 넣으면 생성된 .rs 파일에 그대로 들어감
    • 예시에서는 let x: i32 = 42; x * 2 같은 코드를 raw Rust로 삽입함
    • 실험 프로젝트에서는 이런 escape hatch가 없으면 금방 막히기 때문에 꽤 현실적인 선택임
  • 작성자가 강조하는 장점은 “문법이 균일해진다”는 쪽에 있음

    • 표현식, 타입, 패턴, 문장이 모두 비슷한 모양을 갖게 됨
    • 구조 편집도 쉬워짐. 에스표현식은 괄호 균형이 명확해서 중괄호 하나 날려먹는 류의 실수가 줄어듦
    • 함수 시그니처와 match arm이 같은 문법 체계 안에 들어오는 느낌이 리스프 쪽 감성 포인트임
  • 물론 이걸 당장 업무 코드에 쓰자는 얘기는 아님

    • 작성자도 “mostly for fun”이라고 못 박음
    • 그래도 러스트의 어려움이 문법인지, 타입 시스템인지, 매크로 모델인지 분해해서 생각하게 만드는 데는 꽤 좋은 장난감임
    • 특히 언어 설계나 DSL, 매크로 시스템에 관심 있는 개발자라면 구경할 만함

기술 맥락

  • 이 프로젝트의 선택은 “새 언어를 만들자”가 아니라 “러스트 앞에 다른 문법층을 얹자”에 가까워요. 그래서 타입 검사와 빌림 검사를 직접 구현하지 않아도 되고, 이미 검증된 rustc의 안전성 모델을 그대로 가져갈 수 있거든요.

  • 매크로를 에스표현식 변환 함수로 둔 것도 중요한 선택이에요. 러스트의 proc_macro는 강력하지만 토큰 단위 처리와 별도 생태계가 필요해서 진입 장벽이 높은 편인데, 리스프식 모델은 코드가 곧 데이터라는 전제 덕분에 매크로 작성이 훨씬 직접적이에요.

  • 대신 트레이드오프도 분명해요. 러스트의 모든 문법과 에디터 도구, 포매터, 생태계 관습은 기본적으로 .rs 소스를 중심으로 돌아가니까, rlisp는 변환 전 코드와 변환 후 코드 사이의 디버깅 경험을 계속 신경 써야 해요.

  • raw Rust escape hatch를 둔 이유도 여기서 나와요. 실험용 문법층이 러스트 전체를 한 번에 덮으려 하면 금방 막히기 때문에, 부족한 부분은 원문 러스트로 빠져나가게 해두는 편이 실제로 더 오래 굴러가요.

이 프로젝트의 재미는 러스트를 대체하려는 데 있지 않고, 러스트에서 가장 무거운 부분인 문법 표면을 걷어내면 타입 시스템과 빌림 검사기가 얼마나 독립적으로 남는지 보여준다는 점에 있음. 특히 매크로 쪽은 러스트의 proc_macro가 얼마나 복잡한 모델인지 새삼 비교하게 만듦.

댓글

댓글

댓글을 불러오는 중...

open-source

뱀부랩, 오픈소스 슬라이서 개발자에게 법적 압박 걸었다가 역풍 맞음

3D 프린터 제조사 뱀부랩이 OrcaSlicer-BambuLab 개발자에게 중단 요구서를 보내면서 오픈소스와 수리권 커뮤니티의 반발을 샀다. GamersNexus와 Louis Rossmann은 개발자의 허락을 받아 소프트웨어를 다시 호스팅하고, 소송이 걸리면 각각 1만 달러씩 법률 지원을 하겠다고 나섰다.

open-source

OrcaSlicer 포크, Bambu Lab 프린터의 인터넷 연결 기능 되살림

FULU Foundation의 OrcaSlicer-bambulab 포크가 Bambu Lab 프린터에서 LAN 전용 제한 없이 BambuNetwork 기반 인터넷 연결을 다시 지원한다고 밝힘. Windows에서는 WSL 2 설정이 필요하고, Linux에서는 일반 설치만으로 충분하다고 안내함.

open-source

코넬대가 공개한 정확히 2,000줄짜리 교육용 운영체제

코넬대 기반 프로젝트인 egos-2000은 학생이 교육용 운영체제 전체 코드를 직접 읽을 수 있게 만드는 걸 목표로 한다. C, 헤더, 어셈블리, make 파일을 합쳐 정확히 2,000줄이며, QEMU와 RISC-V 보드에서 동작하고 9개 코스 프로젝트가 붙어 있다. 운영체제 수업에서 ‘작지만 전체 구조가 보이는 코드베이스’가 필요했던 사람에게 꽤 반가운 자료다.

open-source

이맥스가 Git 대신 Bazaar를 붙잡았던 6년짜리 오픈소스 드라마

이맥스는 2008년 CVS에서 벗어나면서 Git 대신 GNU 프로젝트인 Bazaar를 선택했고, 이 결정은 성능 벤치마크와 개발자 반발을 압도한 정치적 판단에 가까웠다. Bazaar는 느리고 유지보수도 흔들렸지만, GNU 패키지는 GNU 도구를 써야 한다는 원칙 때문에 전환은 2014년까지 미뤄졌다. 결국 ELPA 브랜치 문제와 Bazaar 개발 중단, 변환 스크립트 준비 끝에 이맥스는 Git으로 옮겨갔다.

open-source

현대차·기아, 오픈소스 특허 방어망 넓혀 소프트웨어 중심 차량 전환 준비

현대차·기아가 오픈소스 소프트웨어 특허 분쟁을 줄이기 위해 글로벌 특허 네트워크 OIN 2.0에 가입했다. 소프트웨어 중심 차량, 클라우드, 커넥티드 서비스처럼 오픈소스 의존도가 큰 영역에서 법적 리스크를 미리 관리하려는 움직임이다.