1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! lispexp — a pure-Rust reader (lexer + parser) for S-expression syntax across
//! many Lisp dialects.
//!
//! The crate 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 — and accepts a superset of what any one implementation's reader
//! would, so it is a substrate for tools (linters, indexers, formatters), not a
//! validator (ADR-0030). See `docs/design.md` and `docs/adr/` for the design and
//! the decisions behind it.
//!
//! # Quick start
//!
//! ```
//! use lispexp::{parse, Options};
//!
//! let parsed = parse("(define (square x) (* x x))", &Options::scheme());
//! assert!(parsed.errors.is_empty());
//! assert_eq!(parsed.data[0].head_symbol(), Some("define"));
//! assert_eq!(parsed.data[0].items().unwrap().len(), 3);
//! ```
//!
//! The reader is fault-tolerant — a malformed form loses only itself and
//! recovery resumes at the next top-level form (ADR-0004) — so always inspect
//! [`Parsed::errors`] alongside [`Parsed::data`]. `parsed.errors.is_empty()` is a
//! usable "structurally clean" check.
//!
//! # Choosing a dialect
//!
//! There is one reader; a [`Dialect`] selects a preset of [`Options`] (ADR-0003).
//! lispexp never infers a dialect across files — pick one per input, e.g. by file
//! extension:
//!
//! ```
//! use lispexp::{Dialect, Options};
//!
//! let options = match "core.clj".rsplit('.').next() {
//! Some("clj" | "cljs" | "cljc" | "edn") => Options::clojure(),
//! Some("scm" | "ss") => Options::scheme_superset(),
//! Some("el") => Options::emacs_lisp(),
//! _ => Options::for_dialect(Dialect::Scheme),
//! };
//! # let _ = options;
//! ```
//!
//! Presets are a starting point: adjust individual fields by assignment
//! afterwards (the settings are orthogonal, ADR-0006).
//!
//! # Two layers
//!
//! Both layers sit over the same [`Options`] (ADR-0015):
//!
//! - [`parse`] — builds the [`Parsed`] datum tree. The common entry point.
//! - [`lex`] / [`Lexer`] — a linear token stream that *tiles* the input (every
//! byte is covered), for consumers like a parinfer backend that need lexical
//! state, not a tree. The tree drops comments and whitespace, so a
//! trivia-sensitive tool reads those here and correlates by byte [`Span`].
//!
//! The lexer's EOF contract: tokens always tile the input, and an unterminated
//! construct at end-of-input is reported as one [`TokenKind::Unterminated`] token
//! carrying the lexical state it was in, rather than an error or a truncated
//! token stream.
//!
//! # Static-analysis utilities
//!
//! Built on the tree, each opt-in and reader-only:
//!
//! - [`walk`] — a pruning visitor that classifies each node as [`Class::Code`]
//! or [`Class::Data`], so a tool descends into code and skips quoted data;
//! [`walk_regions`] refines `Data` into prunable [`Region::SealedData`] vs.
//! porous [`Region::PorousData`] so a `Skip` never drops quasiquoted code,
//! and [`code_nodes`] is a fixed-policy pre-order iterator over just the code
//! nodes (ADR-0026).
//! - [`annotate`] — tags definition forms (name, arglist, docstring, body,
//! method dispatch) across dialects, from a bundled per-dialect core plus a
//! spec harvester that learns a project's own def-macros (ADR-0019/0020,
//! ADR-0031/0032).
//! - [`indent`] — harvests Emacs Lisp indent specs into a `symbol → IndentSpec`
//! table (ADR-0022).
//! - [`detect`] — opt-in, content-aware dialect detection (extension registry +
//! `#lang`/shebang/structural signals) that *picks* an `Options` for you; the
//! reader itself stays passive (ADR-0034, ADR-0012).
//! - [`parse_form_at`] — reads exactly one top-level form at a byte offset, for
//! incremental re-validation after an edit (ADR-0023).
//! - [`LineIndex`] — maps byte offsets to 1-based (line, byte-column) (ADR-0024).
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use Span;
pub use ;
pub use ;