概要
rlisp は、 LISP風S式 で Rustコード を書くための週末プロジェクト。 Rustの型・所有権システム を維持しつつ、 LISPのマクロ や構文を利用可能。 rlisp は構文変換のみ担当し、 rustc が型・所有権・最適化を担当。 Ariadne によるエラーダイアグノスティクス、 インストール・利用方法 も簡単。 SYNTAX.md で全機能を網羅、 MITライセンス で公開。
rlisp:RustセマンティクスをLISP構文で
- rlisp はLISPの S式 でRustプログラムを記述し、Rustソースコードへ変換するツール
- 例:(struct Point (x f64) (y f64)) → struct Point { x: f64, y: f64 }
- 所有権・借用・ライフタイム・ジェネリクス・トレイト・パターンマッチ など、Rustの主要機能をS式で表現
- rustc による型チェック・借用チェック・最適化を活用、 rlisp は構文変換に特化
- Ariadne による分かりやすいエラー出力
インストール・使い方
- インストール手順
- git clone https://github.com/ThatXliner/rlisp.git
- cd rlisp
- cargo install --path .
- コマンド例
- rlisp compile file.lisp # Rustソース生成
- rlisp build file.lisp # Rustソース生成&コンパイル
- rlisp run file.lisp # 生成・コンパイル・実行
LISP→Rust 構文変換クイックリファレンス
- 関数定義:(fn add ((x i32) (y i32)) i32 (+ x y)) ⇒ fn add(x: i32, y: i32) -> i32 { x + y }
- 変数定義:(let x i32 42) ⇒ let x: i32 = 42;
- 構造体:(struct Point (x f64) (y f64)) ⇒ struct Point { x: f64, y: f64 }
- 列挙型:(enum Option (generic T) (Some T) None) ⇒ enum Option<T> { Some(T), None }
- パターンマッチ:(match val ((Some x) (handle x)) (None ())) ⇒ match val { Some(x) => handle(x), None => {} }
- if文:(if (> x 0) (println! "yes") (println! "no")) ⇒ if x > 0 { println!("yes") } else { println!("no") }
- 実装ブロック:(impl Point (fn new (...) ...)) ⇒ impl Point { fn new(...) ... }
- トレイト:(trait Display (fn fmt (...) Result)) ⇒ trait Display { fn fmt(...) -> Result; }
- フィールド・メソッドアクセス:(. obj field) / (. obj method arg) ⇒ obj.field / obj.method(arg)
- 構造体初期化:(new Point (x 1.0) (y 2.0)) ⇒ Point { x: 1.0, y: 2.0 }
- ループ:(loop (body)) / (while cond (body)) / (for x in iter (body)) ⇒ loop { body } / while cond { body } / for x in iter { body }
- クロージャ:(lambda (x y) (+ x y)) ⇒ |x, y| { x + y }
- マクロ・プリント:(foo! args) / (println! "{}" x) ⇒ foo!(args) / println!("{}", x)
- 公開関数:(pub fn foo () i32 42) ⇒ pub fn foo() -> i32 { 42 }
- インラインRust:(rust "let x: i32 = 42; x") ⇒ let x: i32 = 42; x
詳細仕様と注意点
- SYNTAX.md にて、 ジェネリクス・ライフタイム・可視性・モジュール・turbofish・if-let・unsafe など全構文を解説
- 二項演算子 は自動で中置記法に変換:(+ a b) → (a + b)
- ケバブケース識別子 はRust用に自動変換:page-header → page__header
- 名前衝突時はコンパイル警告
マクロ機能
- rlispマクロ は、 S式→S式 のコンパイル時変換関数
- Rustの proc_macro や syn/quote 不要
- マクロ定義はLISP同様、 quasiquote/unquote/unquote-splicing を使用
- (quasiquote template):テンプレート全体をクオート、unquote箇所のみ展開
- (unquote name):テンプレート内の穴埋め
- (unquote-splicing name):リストを展開して挿入
- 可変長引数 は&restで受け取り、unquote-splicingで展開
- 例:(defmacro when (condition &rest body) (quasiquote (if (unquote condition) (do (unquote-splicing body)))))
- (when (> x 10) (print "big") (print "huge")) ⇒ if x > 10 { print("big"); print("huge") }
ループ・クロージャ・モジュール
- ループ例
- (while (> x 0) (println! "{}" x) (-= x 1))
- (loop (println! "tick"))
- (for x in 0..10 (println! "{}" x))
- クロージャ例
- 型なし:(let add (lambda (x y) (+ x y)))
- 型あり:(let mul (lambda ((x i32) (y i32)) i32 (* x y)))
- move:(let s "hello") (let greet (lambda move () (println! "{}" s)))
- モジュール・可視性・import
- (pub fn public_api () i32 42)
- (pub (crate) fn internal () i32 0)
- (pub struct Config (pub host String) (port u16))
- (mod external_lib)
- (use std::collections::HashMap)
インラインRust・高度な構文
- rlispで表現困難な場合、(rust "...")で生のRustコード挿入可能
- ライフタイム・turbofish・制御フローもS式で表現
- (fn longest (generic 'a) ((x &'a str) (y &'a str)) (&'a str) ...)
- (let nums ((:: (. (0..10) collect) Vec<i32>)))
- (if-let (Some v) (. map get key) (println! "found: {}" v) (println! "missing"))
- (unsafe (rust "let ptr: *const i32 = &42;") (rust "*ptr"))
rlispの目的とメリット
- 目的 :Rustの型・所有権システムを維持しつつ、LISPの 柔軟なマクロ や 均一なS式構文 を楽しむ
- LISPマクロ の強み:proc_macro不要、S式を返すだけで強力な構文拡張が可能
- 構造的編集 :S式は括弧が常に対応し、構造化編集が容易
- 統一構文 :関数シグネチャもmatchアームも同じS式で記述、理解負荷が低減
ライセンス
- MITライセンス で公開、誰でも自由に利用・改変可能