Skip to main content

macroonz_compiler/stamp/
types.rs

1//! The stamp home's declarations: the pattern a caller authors, the sites that adopt it, the artifact both are rendered into, and how stamping refuses.
2//!
3//! Declarations only.
4//! Every road that reaches a private field lives in `type_guard.rs`, this file's own child, which is what makes the identifier alphabet and the two closed namespaces structural rather than remembered.
5
6use crate::bounded::{Bounded, NonEmpty, Overflow};
7use crate::identity::{self, Identity};
8use crate::plan::DigestContract;
9use crate::token::GeneratedTree;
10
11#[path = "type_guard.rs"]
12mod guard;
13
14/// Segments one spelled path may carry.
15///
16/// A path reaching deeper than eight segments has stopped naming an item and started describing a tree, and the repair is a re-export at the address rather than a longer spelling at this end.
17pub const PATH_SEGMENT_LIMIT: usize = 8;
18
19/// Parts one pattern may declare, and therefore the most arguments one site can carry.
20pub const PART_LIMIT: usize = 64;
21
22/// Sites one published stamp may cover.
23///
24/// One publication unit is one artifact landed at one address, and past sixty-four the unit has stopped being one migration and become two.
25pub const SITE_LIMIT: usize = 64;
26
27crate::roster! {
28    /// Which fragment of Rust one seat matches.
29    ///
30    /// The language's own roster, minus a visibility: a reach is declared at a coordinate rather than captured as a fragment, because a captured one cannot be transported one module deeper.
31    pub enum Fragment {
32        /// A whole item.
33        Item = "item",
34        /// A braced block.
35        Block = "block",
36        /// One statement.
37        Statement = "stmt",
38        /// One expression.
39        Expression = "expr",
40        /// One match pattern.
41        MatchPattern = "pat",
42        /// One type.
43        Type = "ty",
44        /// One identifier.
45        Identifier = "ident",
46        /// One path.
47        Path = "path",
48        /// One lifetime.
49        Lifetime = "lifetime",
50        /// One literal.
51        Literal = "literal",
52        /// The body of one attribute.
53        Attribute = "meta",
54        /// One token tree, whatever it is.
55        Tokens = "tt",
56    }
57}
58
59crate::roster! {
60    /// The reach one stamped item is written at, as the site spells it.
61    ///
62    /// The five non-parameterized forms and no more: a front door spells every reach it admits as literal syntax, so a parameterized reach is a change to that grammar rather than a value this roster can carry.
63    pub enum Visibility {
64        /// No visibility token: private to the module the site sits in.
65        Private = "private",
66        /// `pub(self)` — the same reach, spelled.
67        Module = "module",
68        /// `pub(super)`.
69        Parent = "parent",
70        /// `pub(crate)`.
71        Crate = "crate",
72        /// `pub`.
73        Public = "public",
74    }
75}
76
77crate::roster! {
78    /// The reach one stamped item carries inside the module a pattern seats it in.
79    ///
80    /// A separate roster from [`Visibility`] because it answers a different question at a different coordinate: one is what the site wrote, one module out, and this is what the stamped item wears one module in.
81    /// Nothing transports to a private reach — an item that landed private inside the seat module could not be re-exported out of it, and the site's own coordinate would name nothing.
82    pub enum TransportedReach {
83        /// `pub(super)` — out of the seat module to the module the site sits in.
84        Enclosing = "enclosing",
85        /// `pub(in super::super)` — out to the parent of the module the site sits in.
86        Ancestor = "ancestor",
87        /// `pub(crate)` — absolute, and unmoved by the extra module.
88        Crate = "crate",
89        /// `pub` — absolute, and unmoved by the extra module.
90        Public = "public",
91    }
92}
93
94crate::roster! {
95    /// Why neither a splice at the declaration nor a hand-written definition expresses one requested output.
96    ///
97    /// A publication road is lawful only where the output requires one of these two, and a rendering that names neither has not earned the road.
98    pub enum PublicationGround {
99        /// The output is one definition several files must reach.
100        CrossFileArtifact = "cross-file-artifact",
101        /// The output mints identifiers other files name.
102        IdentifierMinting = "identifier-minting",
103    }
104}
105
106/// How one seat is matched, and how an expansion writes it back.
107///
108/// Three shapes, because three is what a matcher can express about one metavariable: one of something, any number of them, or any number of attributes written over the item.
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
110pub enum Seating {
111    /// One fragment of the declared kind.
112    One(Fragment),
113    /// Any number of fragments of the declared kind, separated by commas.
114    Many(Fragment),
115    /// Any number of attributes, each written over the stamped item.
116    Attributes,
117}
118
119/// One metavariable seat: the name material travels under, and the shape it travels in.
120///
121/// The name is the caller's and is never composed from another: a matcher cannot build an identifier out of an identifier, and a derived name would be this home deciding a spelling law nobody gave it.
122#[derive(Debug, Clone, PartialEq, Eq, Hash)]
123pub struct Seat {
124    name: String,
125    seating: Seating,
126}
127
128/// One part of a pattern's declared shape.
129///
130/// A pattern is a sequence of these, and both halves of the grammar are walks over it: a matcher reads a seat as a metavariable and a site writes its own material there, while literal parts are the same tokens on both sides.
131#[derive(Debug, Clone, PartialEq, Eq, Hash)]
132pub enum Part {
133    /// Token material every matcher reads and every site writes unchanged.
134    Literal(GeneratedTree),
135    /// One seat.
136    Seat(Seat),
137    /// The coordinate the site's visibility is written at, which a pattern seating nothing behind a module of its own declares none of.
138    Reach,
139}
140
141/// One authored pattern: what the definition is documented with, the shape it is invoked in, and the body that shape expands into.
142///
143/// # Authority
144///
145/// **The body is the caller's token material and nothing here reads it.**
146/// It names seats by the names the shape declares them under, and the two reaches by the names this home publishes.
147/// A body naming anything else is a defect the consumer's own compiler reports at the site that adopted it, because a producer that checked it would be legislating a meaning it does not own.
148#[derive(Debug, Clone, PartialEq, Eq, Hash)]
149pub struct Pattern {
150    note: String,
151    parts: NonEmpty<Part, PART_LIMIT>,
152    body: GeneratedTree,
153}
154
155/// The name one published stamp is exported under.
156///
157/// The spelling is the caller's and is never mangled: a published artifact is visible source a person commits and other files invoke by name, so the uniqueness an exported macro namespace needs is the caller's to keep.
158#[derive(Debug, Clone, PartialEq, Eq, Hash)]
159pub struct StampName {
160    spelling: String,
161}
162
163/// The path one site reaches its published stamp by.
164///
165/// Structurally non-empty, and read the way the language reads a path: qualifiers only at the root — `crate`, `self`, or a leading run of `super` — and an item name at every later step, so a root the consumer's compiler would read as something else is not a value anybody can hold.
166/// Usually one segment: the crate the stamp is published in names its own root, and a site elsewhere names that crate.
167#[derive(Debug, Clone, PartialEq, Eq, Hash)]
168pub struct SiteRoot {
169    segments: NonEmpty<String, PATH_SEGMENT_LIMIT>,
170}
171
172/// One site that adopts a stamp: what the manifest calls it, how it reaches the definition, the reach it writes, and one argument per declared seat.
173///
174/// The arguments are as many as the pattern declares seats, settled where the site meets the pattern rather than counted a second time here.
175#[derive(Debug, Clone, PartialEq, Eq, Hash)]
176pub struct Site {
177    name: String,
178    root: SiteRoot,
179    reach: Visibility,
180    arguments: Bounded<GeneratedTree, PART_LIMIT>,
181}
182
183/// The complete declared payload one published stamp is rendered from: the name it is exported under, the pattern it stamps, and every site that adopts it.
184///
185/// # Bounds
186///
187/// Structurally non-empty — a definition nobody invokes is an artifact with no reader — and the site namespace is closed at declaration, because two rows naming one site is a manifest that says one thing twice.
188/// Every site's arguments are settled against the pattern here rather than left to the consumer's compiler, which would report a mismatch inside an expansion nobody wrote.
189#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190pub struct Stamp {
191    name: StampName,
192    pattern: Pattern,
193    sites: NonEmpty<Site, SITE_LIMIT>,
194}
195
196/// What a plan decided about the artifact one stamp publishes, read off the plan's own surface.
197///
198/// Holding one says nothing about whether anything was rendered, staged, or landed — but it does say the reading happened: the only mint is [`planned`](crate::stamp::planned), which is where the seat's existence and its publication destination are checked, so a value of this type cannot state a decision no plan made.
199#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
200pub struct StampedPlan {
201    unit: Identity<identity::GeneratedUnit>,
202    staged: DigestContract,
203}
204
205/// This side's record of one publication act.
206///
207/// # Authority
208///
209/// **It is a statement and never a receipt.**
210/// It answers which unit the artifact materializes, what its staged bytes must satisfy, why the road is lawful at all, and what the unit contains — so a publication step compares its own independently built answers against these rather than a value with itself.
211///
212/// The manifest is read off the stamp the artifact was rendered from, never kept as a second list that agrees with it until it does not.
213#[must_use = "the record is what a publication road's admission rule is satisfied from"]
214#[derive(Debug, Clone, PartialEq, Eq, Hash)]
215pub struct PublicationRecord {
216    ground: PublicationGround,
217    unit: Identity<identity::GeneratedUnit>,
218    staged: DigestContract,
219    stamp: Stamp,
220}
221
222/// One covered site's landing: the site, and the invocation written there.
223///
224/// The two travel together because they are one fact about one site.
225/// An invocation without the site it stands for cannot be placed, and a site without its invocation is a file the published stamp never reaches.
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct Landing {
228    site: String,
229    invocation: GeneratedTree,
230}
231
232/// The published stamp: the definition a publication road lands as visible source, and every landing it is landed for.
233///
234/// # Authority
235///
236/// **What is emitted is declarative and calls nothing.**
237/// The definition's body is the caller's self-contained token material and this compiler is named nowhere in it, which is why a stamp can stand in a crate that carries no edge back here.
238///
239/// # Bounds
240///
241/// Nothing here writes to disk: these are rendered trees and the record that pairs with them.
242/// The landings are as many as the record's stamp declares sites, because the one road that builds them walks that stamp, and the exported name is read out of the record rather than kept beside it.
243#[must_use = "a published stamp is the artifact a publication road lands under a record"]
244#[derive(Debug, Clone, PartialEq, Eq, Hash)]
245pub struct PublishedStamp {
246    definition: GeneratedTree,
247    landings: Vec<Landing>,
248    record: PublicationRecord,
249}
250
251/// How stamping says no.
252///
253/// One cause per refusal: every road here settles one question, and the road that settles several settles them in a declared order, so exactly one row is true of any refused value.
254#[must_use = "a stamping refusal names the exact thing the declaration did not settle"]
255#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
256pub enum StampError {
257    /// A spelling cannot stand where its seat needs it: outside the identifier alphabet, or — at a name seat — a keyword the language already took.
258    NotAnIdentifier,
259    /// A path names no segment, so it names nothing.
260    PathEmpty,
261    /// A path carries more segments than the declared magnitude.
262    PathUnbounded {
263        /// The magnitude and what was offered.
264        overflow: Overflow,
265    },
266    /// A pattern declares no part, so it declares no shape.
267    PatternEmpty,
268    /// A pattern declares more parts than the declared magnitude.
269    PatternUnbounded {
270        /// The magnitude and what was offered.
271        overflow: Overflow,
272    },
273    /// Two seats of one pattern carry one name, which binds one metavariable twice.
274    SeatNameDoubled {
275        /// The doubling part's position in the pattern.
276        at: u32,
277    },
278    /// A stamp covers no site, and a definition nobody invokes has no reader.
279    SitesAbsent,
280    /// A stamp covers more sites than the declared magnitude.
281    SitesUnbounded {
282        /// The magnitude and what was offered.
283        overflow: Overflow,
284    },
285    /// Two sites of one stamp carry one name, which is a manifest row written twice.
286    SiteNameDoubled {
287        /// The doubling site's position in the stamp.
288        at: u32,
289    },
290    /// One site carries more arguments than the declared magnitude.
291    ArgumentsUnbounded {
292        /// The magnitude and what was offered.
293        overflow: Overflow,
294    },
295    /// One site supplies a different number of arguments than the pattern declares seats.
296    ArgumentsUnmatched {
297        /// The site's position in the stamp.
298        at: u32,
299        /// How many seats the pattern declares.
300        seats: u32,
301        /// How many arguments the site supplied.
302        supplied: u32,
303    },
304    /// One site declares a reach the pattern gives no coordinate to, which is a visibility with nowhere to be written rather than a narrower one.
305    ReachUnseated {
306        /// The site's position in the stamp.
307        at: u32,
308    },
309    /// The plan declares no member under the seat this artifact stands for.
310    SeatNotPlanned {
311        /// The seat's position in its kind's roster.
312        role_slot: u16,
313    },
314    /// The planned member lands somewhere other than a standalone artifact, and a published stamp is bytes at an address the other three deliveries do not name.
315    DestinationNotArtifact {
316        /// The seat's position in its kind's roster.
317        role_slot: u16,
318    },
319    /// A rendered tree outgrows the declared token magnitude, and the artifact refuses whole rather than materializing the sites that happened to fit.
320    TokensUnbounded {
321        /// The magnitude and what was offered.
322        overflow: Overflow,
323    },
324}