A new command-line tool called rlisp lets you write Rust programs using Lisp-style s-expressions. It is a transparent frontend: you write .lisp files, and rlisp transpiles them to .rs files, which are then compiled by rustc. There is no runtime, no garbage collector, and no semantic gap — the generated Rust code uses ownership, borrowing, lifetimes, generics, traits, and pattern matching exactly as you would write them by hand.
What it does
rlisp maps Lisp syntax directly to Rust constructs. For example:
(fn add ((x i32) (y i32)) i32 (+ x y))becomesfn add(x: i32, y: i32) -> i32 { (x + y) }(struct Point (x f64) (y f64))becomesstruct Point { x: f64, y: f64 }(let x i32 42)becomeslet x: i32 = 42;(if (> x 0) (println! "yes") (println! "no"))becomesif (x > 0) { println!("yes") } else { println!("no") }
Binary operators like +, -, *, /, ==, !=, <, > are emitted infix: (+ a b) → (a + b).
The tool supports all major Rust features: closures (typed and untyped, move closures), modules with visibility (pub, pub(crate), pub(super)), use imports with renaming, match expressions, loop/while/for loops (including destructuring in for), and inline raw Rust via (rust "...") for anything the s-expression syntax does not express natively.
Macros without proc_macro
A key feature is the macro system. rlisp macros are compile-time s-expression transformers — no proc_macro crate, no token streaming, no syn/quote. A macro is simply a function from s-expressions to s-expressions. It uses three special forms:
(quasiquote template)— quote a template but allow unquotes inside(unquote name)— insert the value ofnameinto the template(unquote-splicing name)— splice a list into the surrounding form
Example: a when macro:
(defmacro when (condition &rest body)
(quasiquote (if (unquote condition)
(do (unquote-splicing body)))))
(when (> x 10) (print "big") (print "huge")) expands to (if (> x 10) (do (print "big") (print "huge"))), which compiles to if x > 10 { print("big"); print("huge") }.
How to install and use
git clone https://github.com/ThatXliner/rlisp.git
cd rlisp
cargo install --path .
Three commands:
rlisp compile file.lisp— transpile tofile.rsrlisp build file.lisp— transpile and compile withrustcrlisp run file.lisp— transpile, compile, and run
Tradeoffs
rlisp is a syntax layer only. It does not change Rust's semantics, type system, or borrow checker. The generated .rs file is what rustc sees, so all Rust rules apply. The main tradeoff is readability for teams unfamiliar with s-expressions. The author describes the project as "mostly for fun — an exploration of what Rust looks like when you strip away the syntax and keep the semantics." Practical benefits include trivial macros (no proc_macro ceremony) and structural editing (slurp, barf, transpose, wrap — every operation is balanced by construction).
When to use it
This is not a production tool for most teams. It is useful for:
- Experimenting with Lisp-style metaprogramming in a Rust context
- Teaching or demonstrating Rust semantics without syntax distractions
- Projects where macro simplicity outweighs the s-expression learning curve
- Anyone who wants to write Rust with parentheses
Bottom line
rlisp is a well-executed syntax experiment that compiles Lisp to Rust with zero runtime overhead. The macro system is genuinely simpler than Rust's proc_macro. If you are comfortable with s-expressions and want to explore what Rust looks like in that form, it is worth a look. For most Rust work, the standard syntax remains the practical choice.