# A tolerant `.scm` "Scheme superset" preset, not a widened `scheme()` nor a per-project dialect switch

Real-world `.scm` files are frequently not strict R7RS-small: the `.scm` extension is shared by Gauche, Mosh (R6RS), and Gambit, each of which extends the reader. Auditing a full Gauche checkout under `Options::scheme()` produced 288 parse errors across 40 files — almost all from two token shapes whose payload contains raw delimiter bytes the strict reader tries to tokenize as code, losing sync: Gauche/Mosh **`#/regexp/`** literals and Gauche **`#[char-set]`** literals (the rest of each dialect's surface — `#!optional` markers, `#*bitvectors`, `#s32(…)` uniform vectors, `#,(…)` SRFI-10 constructors, `#!fold-case` directives — already survives as opaque atoms without losing sync). We fix this with a new **`Options::scheme_superset()` preset** (`Dialect::SchemeSuperset`) rather than either alternative that was considered. We **do not widen `Options::scheme()` itself**, because keeping the base preset exact R7RS-small preserves its value as a conformance signal (the chibi-scheme reference implementation still parses with zero errors) and still flags a genuinely malformed `#/` in code that really is R7RS; the tolerance is opt-in, chosen by the consumer per file extension. We **do not attempt per-project dialect inference** (detect Gauche in one file, re-read the rest in a Gauche mode): that needs cross-file, order-dependent state that does not fit lispexp's stateless, per-input `parse(&str, &Options)` contract (ADR-0003) — and, crucially, is unnecessary, because the fix is a pure per-file *widening*. The superset unions only the non-conflicting reader extensions of the `.scm`-using implementations: `#[...]` char-sets and `#/.../` regexps (consumed as opaque `Str` leaves, following ADR-0011's "capture verbatim, do not model" philosophy and the existing Clojure/LFE `#"..."`-regex→`Str` precedent — chosen over dedicated `Regex`/`CharSet` `DatumKind` variants to avoid growing the public enum and the walker/annotator for a distinction no current consumer needs), `#"..."` interpolated strings (a string leaf), `#vu8(...)` bytevectors (R6RS/Mosh), and both leading-colon `:foo` (Gauche/Guile) and trailing-colon `foo:` (Gambit/Gerbil, DSSSL/SRFI-88) keywords. Every member is a strict widening: each only affects input the strict reader would have rejected or split, and none reclassifies valid R7RS in a way that changes tree shape — a mis-guessed keyword-vs-symbol is still a leaf, never a sync loss. The Lexer mirrors Gauche's own reader for these payloads: the char-set follows `Scm_CharSetRead`'s `]`-member rules (`#[]` is the empty set, a literal `]` is `\]`, and a complete, bounded POSIX class `[:name:]` — optionally negated `[:^name:]` — holds a non-closing `]`, while any other `[` is an ordinary member so a malformed `[:` can never consume unbounded input); the regexp ends at the first unescaped `/` like Mosh's reader and then consumes at most the single `i` (case-fold) flag Gauche's `read_regexp` honors, without tracking `[...]` classes. Gerbil is intentionally out of scope: its files are `.ss` (not `.scm`), and its distinctive `[]`→`(@list …)` / `{}`→`(@method …)` conventions are macro-level meanings over ordinary bracket tokens, so `{` `}` stay ordinary in the superset. Result on the same Gauche checkout: 288 errors across 40 files drop to 3 errors in 1 file — `src/srfis.scm`, which reads its own trailing text as runtime data after `(exit 0)` (a `__DATA__`/`__END__`-style idiom no static full-file reader can model), confirming the shim resynchronizes cleanly everywhere else.
