Skip to main content

Module cst_v1

Module cst_v1 

Source
Expand description

The SATySFi 0.1.0 (dev-0-1-0) surface grammar — a fork of crate::cst, not a version-gate of it (gating one shared cst.rs would mean hand-writing Parse for nearly every node, destroying the derive idiom and risking 0.0.6 on every 0.1 edit). crate::cst stays frozen: this module imports only its token-Atom-generic, non-recursive helpers (crate::cst::Header, crate::cst::ParseFileError) and re-declares everything else — including its own *ErasedV1 eraser leaves and its own copy of render_parse_error — so that touching cst_v1.rs never touches cst.rs.

Scope. SATySFi 0.1’s grammar adds a whole ML-style module system (bind/modexpr/sigexpr/decl) on top of an expr/pattern/type layer that is structurally close to 0.0.6’s, plus five surface deltas: ,-separated lists/records (not ;), EXACT_EQ for both definitional and record = (reusing DefEqTok — no new = leaf), mandatory match … with … end, per-binding staging instead of a whole-file @stage: header, and no when/while/before at all. This module builds:

  • FileV1header* expr EOI or header* module Name option(sig_annot) = struct bind* end EOI.
  • Bind — every arm of upstream bind: val/val inline/val block, val math (math-split — see Bind::ValueMath), val rec … and …/val mutable/type … and …, module … = modexpr/signature … = sigexpr/include modexpr.
  • ast::ModExpr/ast::SigExpr/ast::Decl — the full module/signature grammar: functor literals/ application, module paths/aliases, :> coercion, sig … end with every decl form, with type refinement, include.
  • A copy of crate::cst::ast’s expr/pattern/type layer with the 0.1 deltas applied (see each type’s doc comment for the exact delta), including the full let rec … and … in/let mutable … in expression forms, a widened TypeExpr grammar (products, prefix application), inline […]/block […]/math […] command types (parser_v1.mly:730-735) and LONG_LOWER qualified type paths (:720-728,742-743; TypeApp::AppliedLong/TypeAtom::LongName).

Grammar shipped with placeholder semantics only. Every module/signature construct beyond the struct-literal ModExpr::Struct body PARSES and round-trips, but lowers to a precise LowerError (v1/lower.rs) rather than real semantics — see that module’s doc comment for the placeholder set and the seal rule.

Deliberately NOT built: macro binds/decls and row quantifiers (rowquant). Staging DOES parse — the operand prefixes &e/~e (ast::StagePrefix, parser_v1.mly:870-873) and the per-binding qualifier of val ~x/val persistent ~x (BindStageV1, :417-421 and the decl form :600-603), with persistent a 0.1-only keyword token.

The #[recurse] SCC story (five roots). Five singleton, directly self-referential roots — the same shape crate::cst::ast uses, for the same reason (see its module doc comment for the measured compile-time blowup a naive transcription hits):

  • ast::Expr (its variants’ own Box<Expr> children);
  • ast::PatBot (CtorApplied’s Box<PatBot> argument);
  • ast::TypeExpr (Fun’s right-recursive Box<TypeExpr> codomain);
  • ast::ModExpr (Functor.body’s Box<ModExpr> self-loop);
  • ast::SigExpr (Functor.dom/Functor.cod’s Box<SigExpr> self-loop — encoded left-recursion-safe, with is bot+suffix, never With { base: Box<SigExpr> }; see ast::SigExpr’s own doc comment).

Every other recursion edge is routed through the erasers declared below (ExprErasedV1, PatErasedV1, PatBotErasedV1, TyErasedV1, MathErasedV1, ModExprErasedV1, SigExprErasedV1, TypeBindsErasedV1), keeping each SCC a singleton and the wrapped grammar’s recursion reborrowing one stream type (syan pins it, not us). ast::Decl is a satellite, not a root: it has no Box<Self> anywhere and no type inside the #[recurse] module ever names it — it is reached only through the hand-written StructDeclV1 connector (an opaque leaf to the SCC analysis, mirroring StructBindV1), so SigExpr ↔ Decl never forms a rootless static sub-cycle.

Re-exports§

pub use crate::cst::Header;
pub use crate::cst::BindName;
pub use ast::AscribedInnerV1;
pub use ast::OptParamEntryV1;
pub use ast::OptParamsV1;
pub use ast::Param;
pub use ast::ParamBody;

Modules§

ast
The recursive expression/pattern/type/text grammar for SATySFi 0.1. A copy of crate::cst::ast with the deltas documented on each type; see the module doc comment for the SCC/root story.

Structs§

BarVariantDefV1
A | UPPER [OF typ] continuation (variantsseparated_nonempty_ list(BAR, variant), parser_v1.mly:545-548).
BindStageV1
The stage qualifier of a val bind or val decl: ~ alone is stage 0, persistent ~ is the persistent stage (parser_v1.mly:417-421 for binds, :600-603 for decls). No prefix at all is stage 1 — the document stage, where an ordinary val lives — which is why the field holding this is an Option.
ExprErasedV1
An ast::Expr behind a stream-erasing parse (see above).
MathErasedV1
An ast::MathElemCst behind a stream-erasing parse (see above).
ModExprErasedV1
An ast::ModExpr behind a stream-erasing parse. Carries the OUTSIDE→INSIDE edge Bind::Module.body → ModExpr — the one edge of the Bind → ModExpr → StructBindV1 → Bind runtime cycle not already erased by the connector (the erasers are for the INSIDE types, not for Bind).
OfTypeV1
The of typ payload suffix.
PatBotErasedV1
An ast::PatBot behind a stream-erasing parse (see above). Kept separate from PatErasedV1 for the same reason crate::cst’s PatErased/PatBotErased split exists: a constructor pattern’s argument is a patbot, not a full patas.
PatErasedV1
An ast::Pattern behind a stream-erasing parse (see above).
PatNonVarErasedV1
An ast::Pattern that is not a bare variable — upstream 0.1’s own pattern_non_var (parser_v1.mly:796), and the 0.1 twin of crate::cst::PatNonVarErased, whose doc comment carries the whole story.
ScriptsParamV1
scripts_param (parser_v1.mly:532-534): WITH sub=LOWER sup=LOWERval math’s optional with sub sup suffix, binding the two script-callback parameters directly rather than synthesizing the hidden %math-attach-scripts wrapper.
SigAnnotV1
COERCE sigexpr — a signature annotation :> S (sig_annot, parser_v1.mly:555-557). 0.1’s annotation sigil is :> (COERCE, lexer_v1.mll:280), NOT 0.0.6’s : sig … end (crate::cst::SigAnnot, cst.rs:295-303) — module M : S = … is a 0.1 parse error (pinned in tests). The signature body goes through SigExprErasedV1: SigAnnotV1 lives outside the #[recurse] module, so this is a cross-boundary edge into the SigExpr root (see the module doc comment’s SCC story).
SigExprErasedV1
An ast::SigExpr behind a stream-erasing parse. Used by SigAnnotV1 and Bind::Signature (outside → the SigExpr root).
StructBindV1
One declaration inside a module … = struct … end body. Bind’s own alternatives are exactly what a struct body may contain (bind*), so this simply re-parses a Bind — but not by naming Bind as a field type directly: Bind lives outside the #[recurse] module (below), so Bind -> ModExpr -> Vec<StructBindV1> -> Bind would be a self-recursive cycle through a plain #[derive(Parse)], which (without the #[recurse] engine to back it) is an E0275 hazard (an unbounded recursive trait-bound obligation) — exactly crate::cst::StructDecl’s own rationale (cst.rs:262-269). Hand-writing Parse/Unparse here — the same trick as the erased_leaf_v1! macro below — sidesteps that: the impl has no recursive where-bound for the compiler to try to satisfy, it just calls Bind::parse through the stream-erasing adapter at runtime.
StructDeclV1
One declaration inside a sig … end body (list(decl), parser_v1.mly:591) — StructBindV1’s twin, hand-written Parse/ Unparse for the same E0275 reason. ast::Decl lives INSIDE the #[recurse] module and SigExpr → SigBotV1 → StructDeclV1 → Decl → SigExpr is a runtime cycle; naming ast::Decl as a plain derived field of ast::SigBotV1 would re-enter the module’s own SCC analysis. As an opaque leaf it closes that cycle at RUNTIME while keeping both SCCs singletons. NOTE: named after crate::cst::StructDecl (the mechanism), even though it carries a sig-decl, not a struct binding.
TyErasedV1
An ast::TypeExpr behind a stream-erasing parse (see above).
TypeAndV1
An and bind_type_single continuation (bind_type’s separated_nonempty_list(AND, …), parser_v1.mly:535-537).
TypeBindSingleV1
One bind_type_single (parser_v1.mly:539-544). 0.1 delta from crate::cst::TypeDecl: the type parameters come AFTER the name (type t 'a = …, tyident LOWER; tyvars list(TYPEVAR)), where 0.0.6 writes them before (type 'a t = …, cst.rs:401-408) — the lowering reorders the fields. No constraint suffix exists in 0.1’s production.
TypeBindsErasedV1
A TypeBindsV1 behind a stream-erasing parse. Unlike every other eraser this one targets an OUTSIDE type: SigExpr::WithType / Decl::Type (inside) must reach bind_type, whose TypeBindSingleV1 re-enters the module through plain-derived ast::TypeExpr fields — an inside→outside-plain-derive→inside-root chain with no precedent in cst.rs’s discipline. Erasing at the boundary keeps the re-entry cheap (one stream type, monomorphized once), exactly like every other cross-boundary edge.
TypeBindsV1
One whole bind_type chain — bind_type_single (AND bind_type_single)* (parser_v1.mly:535-537) — grouped into a single struct so the sig layer (ast::SigExpr::WithType, ast::Decl::Type) can reference the chain through ONE eraser (TypeBindsErasedV1). Bind::Type keeps its flattened first/ands fields unchanged (avoiding call-site churn); the two spellings are the same grammar.
VariantDefV1
One UPPER [OF typ] variant (parser_v1.mly:549-553).

Enums§

Bind
Every arm of bind (parser_v1.mly:415-440) — upstream’s own nonterminal name (helper types like StructBindV1/ TypeBindSingleV1 keep a V1 suffix). Every value arm’s = is EXACT_EQ (DefEqTok) and body is an ast::Expr. name is a crate::cst::BindName wherever upstream’s bound_identifier reaches it (Value, and the rec clauses inside ast::RecClauseV1); ValueMutable and ValueInline/ValueBlock’s ctx stay plain VarToks — upstream’s MUTABLE LOWER …/ctx-variable productions are a plain LOWER, not bound_identifier (see crate::cst::BindName’s doc comment for the ordered-choice-safety argument).
FileV1
A whole 0.1 .saty/.satyh file (main, upstream parser_v1.mly:364- 368): a header list followed by either a library (main_lib) or a document expression. Unlike 0.0.6’s crate::cst::File (a flat prelude of top-level lets with an optional trailing in body), 0.1 has no flat top-level binding sequence at all: a document body is just an ast::Expr (every let chains its own in), and a library is exactly one module … = struct … end.
HeaderV1
A 0.1 header element — the UNION of BOTH packaging generations’ header forms (Axis B). Legacy is dev-0-1-0’s @require:/@import: (byte-identical to 0.0.6’s, reusing Header); the three Use* forms are saphe-split’s headerelem (parser.mly:371-380 @ b836d512). Which family is legal is a LoadMode question the loader answers (rustyfi_loader), not a grammar question — this ONE V0_1 grammar accepts both so the mode error can be raised at load time with a better message than a lex error would give.
TypeBodyV1
The right-hand side of one type bind: a variant’s constructor list (EXACT_EQ BAR? variants, parser_v1.mly:540-541,545-553) or a transparent synonym (EXACT_EQ typ, :542-543). Variant-first is unambiguous for the same reason as crate::cst::TypeDeclBody (cst.rs:410-418): a variant list is BarTok/CtorTok-headed and no ast::TypeExpr can start with either.

Functions§

parse_file_v1
Lex (crate::lexer::lex_with_version under crate::version::RustyfiVersion::V0_1) and parse a whole 0.1 .saty/.satyh source file. Mirrors crate::cst::parse_file’s two-step shape exactly, sharing its crate::cst::ParseFileError (no new error type).