Lisp S-Expressions Parser (lispexp)
A pure-Rust reader (lexer + parser) for S-expression syntax across many Lisp-family dialects, producing a faithful, position-annotated, code-vs-data-aware parse tree.
lispexp is deliberately reader-only: it does not evaluate, expand macros, or interpret the numeric tower. It reads source text into data — the shape, positions, and reader-macro structure needed to statically analyze Lisp code.
Features
- One reader, many dialects. Scheme (R7RS-small), Guile, Racket, Common Lisp, Emacs Lisp, Clojure, Hy, Phel, Fennel, LFE (Lisp Flavoured Erlang), ISLisp, AutoLISP, Janet, and EDN — plus a tolerant
.scm"Scheme superset" — selected viaOptionspresets built from orthogonal, individually-toggleable syntax settings. - Position-annotated. Every datum carries a byte span and 1-based start line; a
LineIndexmaps offsets to 1-based (line, byte-column). - Code vs. data aware. Quote/quasiquote/unquote structure is preserved, and a pruning
walkclassifies each node asCodeorDataso consumers descend into code and skip quoted data. - Fault-tolerant. Malformed input never panics; the reader returns a partial tree plus structured diagnostics, resynchronizing at the next top-level form, with a bounded recursion depth.
- Zero-copy. The parse tree borrows
&strslices from the source; verbatim round-trip is lossless via source spans. - Two layers. A tree reader (
parse) and an independent token stream (lex) that tiles the input — for consumers such as a parinfer backend that need lexical state rather than a tree. - Definition-aware utilities. An opt-in
annotatemodule tags definition forms (name, arglist, docstring, body, method dispatch) across dialects, and anindentmodule harvests Emacs Lisp indent specs. - Pure Rust, no
unsafe, zero dependencies — cross-compiles cleanly. MSRV 1.70.
Install
Usage
use ;
let parsed = parse;
assert!;
assert_eq!;
assert_eq!;
Pick a dialect with a preset (Options::clojure(), Options::emacs_lisp(), Options::edn(), …) or Options::for_dialect(Dialect::Racket), then adjust individual fields by assignment. The reader is fault-tolerant, so always inspect parsed.errors alongside parsed.data.
Beyond the core reader, the crate exposes: lex / Lexer (the token layer), walk (a code-vs-data pruning visitor), parse_form_at (positioned single-form reparse for incremental validation), LineIndex (offset ↔ line/column), and the annotate and indent utility modules.
Documentation
API docs are on docs.rs. The design is recorded in docs/design.md, the domain vocabulary in CONTEXT.md, and the decisions behind it in the ADRs under docs/adr/.
Copyright
Copyright 2026 TypedDuck - USAMI Kenta <tadsan@zonu.me>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.