Question: Duncan offered the
oxurproject (Lisp Flavoured Rust;git@github.com:oxur/oxur.git, mountoxur) as a source of reusable Rust code, especially its S-expression parsing and AST. What, concretely, transfers totyped-check? Status: assessed against mounted source; verdict below. Verdict: Yes — high-value reuse of thesexp/reader + Position/error + CLI output + testing patterns; it collapses most of M0's reader work. The large Rust-AST↔sexp semantic layer is oxur's mission, not ours, and is not directly reused (its patterns are).
The Rust checker's front-end must read the macro-expanded, pre-codegen LFE
forms (the lfe_comp:file(File, [to_expand]) output) into a position-tracked
Rust data structure, so it can check contracts/exhaustiveness and emit
span-anchored diagnostics. So we need: an S-expr lexer + parser, a node type that
carries source positions, and a clean error type. That is exactly the shape of
oxur's sexp/ module.
types.rs— theSExpenum (Symbol | Keyword | String | Number | Nil | List). Every node carries aPosition; there's aHasPositiontrait (sexp/types.rs:87-102). It already has a first-classKeywordvariant for:foo(sexp/types.rs:20-24) — precisely what our Lykn-style:args/:returnscontracts and LFE keywords need. This type is ~90% the shape we'd design anyway.parser.rs—Parserwithparse_str(&str)/parse_file(path)(sexp/parser.rs:16-54), recursive-descent over tokens, cleanParseErrorvariants (EmptyInput,UnexpectedCloseParen,UnterminatedList,FileReadError), unit-tested.lexer.rs—Lexertrackingoffset/line/column→Position::new(offset, line, column)(sexp/lexer.rs:282-284); handles parens,:keyword,"string"with escapes, integers, symbols (symbol charset already includes/,*,+,<,>,=,!,?,&,'),nil, and;line comments.printer.rs— an S-expr printer (252 LOC), reusable for round-trip tests and for echoing forms in diagnostics.error::Position+ParseError/LexError— line/column/offset positions (diagnostic-friendly), the exact substrate a Gleam-grade renderer wants.
oxur-cli/src/common/output.rs(152 LOC) — coloredsuccess/error/info/warninghelpers for the checker CLI.oxur-smap— a dedicated span-map crate; candidate for diagnostic span bookkeeping.oxur-pretty— pretty-printer (+ its own parser) for formatting output.oxur-testing+ oxur-ast'stests/+examples/+ fixtures-by-complexity organization and round-trip testing discipline — a ready template for our backend-matrix and diagnostics-snapshot suites.
The bulk of oxur-ast (~10k LOC: ast/, builder/, gen_sexp/, gen_rs/,
rust_gen.rs) converts Rust's AST ↔ canonical S-expressions via syn
(Item/Expr/Stmt/generics ⇄ sexpr). typed-check models LFE forms +
Erlang/BEAM types, not Rust's AST, so this layer is not directly reused. Its
patterns do transfer: the Position{offset,line,column} + ParseError-with-
position convention, the builder pattern for AST construction, and the round-trip
test methodology.
- Lexer needs LFE-literal coverage. oxur's lexer is tuned to its restricted
canonical-sexp dialect, not the full LFE reader. Verified gaps: numbers are
integer-only (no floats
2.3, based ints16#ff,$char, scientific); no#-syntax (#(...)tuples,#"..."/#B(...)binaries,#M(...)maps,#\char);mod:funcwould mis-lex because:starts a keyword; no|quoted symbols|. Two ways to handle it: (a) extend the lexer for the LFE lexemes that actually appear into_expandoutput, or (b) have the rebar3 provider serialize the expanded forms into a Rust-friendly sexp subset. Leaning (a) for fidelity, scoped to "whatto_expandemits." - Multi-form parsing.
Parser::parsereads a single top-level S-expr; a module is many top-level forms. Add aparse_allreturningVec<SExp>. Trivial.
The sexp/ module depends only on the crate's error module — no syn
dependency — so it factors out cleanly. Options:
- Factor
oxur-sexpinto its own crate that bothoxurandtyped-checkdepend on. Cleanest; a nice shared-ecosystem outcome; Duncan owns oxur and offered to release code. Recommended. - Vendor/copy the ~857 LOC into
typed-check. Faster to start, diverges over time.
M0 shrinks. "Rust sexpr reader" stops being from-scratch work and becomes
"adopt oxur-sexp (factored or vendored) + extend the lexer for LFE lexemes +
add parse_all." The position/error infrastructure, the keyword-aware node type,
the printer, and the test scaffolding all come for free. Net: the front-end is
mostly solved; M0's real remaining work is the provider plumbing
(to_expand → serialize → invoke) and the lexer extension.
Sources (mount oxur): crates/oxur-ast/src/sexp/{types,parser,lexer,printer}.rs,
crates/oxur-ast/src/error.rs (Position/ParseError), crates/oxur-ast/src/ast/span.rs,
crates/oxur-cli/src/common/output.rs, crates/oxur-smap/, crates/oxur-pretty/,
crates/oxur-testing/. Cross-references the v0 design doc (M0).