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}