Skip to main content

macroonz_compiler/support/carrier/
render.rs

1//! The token half: the pin roster, the one gate invocation a carrier's body is, the exported definition around it, and the forwarding address beside it.
2//!
3//! # Tokens, not text
4//!
5//! Every path is spelled as segments, every literal is a typed literal whose quoting the tree owns, and every brace is a group.
6//! No function here composes Rust source; the Rust a person reads is the generated tree's own projection.
7//!
8//! # The crate a path is rooted at is never spelled
9//!
10//! Every path a carrier writes begins with the carrier's own root-and-segments METAVARIABLES for the crate it is rooted at, and the consumption target supplies the path once, at the invocation.
11//! A consumer that reaches the harness through a facade or renamed dependency gets its own path back, and this home never learns what that path is.
12//! The gate's own binding clause receives the very same metavariables, which is what makes that binding load-bearing rather than decorative: the gate proves the path the consumer passed reaches the same declaration the gate's own crate reaches, so a wrong path refuses at the door instead of as an unresolved path somewhere inside a seat.
13//!
14//! # The pin is a roster of canonical tokens
15//!
16//! The gate matches TOKENS.
17//! A byte string has many spellings of one value and the spelling on this side is a literal writer's choice rather than a declaration anybody made, so a byte string here would be a producer hostage to an escaping convention nobody controls.
18//! An unsuffixed integer has exactly one rendering, so the two sides are one token by construction.
19
20use super::super::cargo::{AxisCargo, DeclaredCargo};
21use super::super::types::{BoundPath, CrateFacing, DeliveryForm, SchemaId, SupportName};
22use super::ShellName;
23use crate::bounded::Overflow;
24use crate::request::Door;
25use crate::token::{
26    GeneratedDelimiter, GeneratedToken, attribute, documentation, group, metavariable,
27    segmented_twin_path,
28};
29
30/// The gate a carrier's body invokes.
31pub const GATE_MACRO: &str = "generated_support";
32
33/// The gate's clause carrying the producer's own expectation.
34pub const EXPECTED_CLAUSE: &str = "expected";
35
36/// The suffix naming the repeated path-segment binding beside a crate-facing root binding.
37const PATH_SEGMENT_SUFFIX: &str = "_segment";
38
39/// The repeated path-segment binding belonging to one crate-facing root binding.
40fn segment_binding(facing: CrateFacing) -> String {
41    format!("{}{PATH_SEGMENT_SUFFIX}", facing.name())
42}
43
44/// One path rooted at the complete segmented path a carrier binds for this facing.
45#[must_use]
46pub(crate) fn rooted_path(facing: CrateFacing, segments: &[&str]) -> Vec<GeneratedToken> {
47    segmented_twin_path(facing.name(), &segment_binding(facing), segments)
48}
49
50/// One path a caller declared, spelled from the crate it was rooted at.
51#[must_use]
52pub fn rendered_path(path: &BoundPath) -> Vec<GeneratedToken> {
53    let segments: Vec<&str> = path.segments().iter().map(String::as_str).collect();
54    rooted_path(path.facing(), &segments)
55}
56
57/// The producer's expectation, as the bracketed roster of decimal byte values the gate's opening arm matches.
58///
59/// # Errors
60///
61/// Returns [`Overflow`] where the roster outgrows the declared token magnitude.
62pub fn expectation_roster(expectation: SchemaId) -> Result<GeneratedToken, Overflow> {
63    let mut bytes: Vec<GeneratedToken> = Vec::new();
64    for byte in expectation.as_bytes() {
65        bytes.push(GeneratedToken::number(u64::from(*byte)));
66        bytes.push(GeneratedToken::alone(','));
67    }
68    group(GeneratedDelimiter::Bracket, bytes)
69}
70
71/// One `<name>: $<name>:<fragment>,` clause of a carrier's matcher.
72#[must_use]
73pub fn matched_clause(name: &str, fragment: &str) -> Vec<GeneratedToken> {
74    let mut tokens = vec![GeneratedToken::word(name), GeneratedToken::alone(':')];
75    tokens.extend(metavariable(name));
76    tokens.push(GeneratedToken::alone(':'));
77    tokens.push(GeneratedToken::word(fragment));
78    tokens.push(GeneratedToken::alone(','));
79    tokens
80}
81
82/// A carrier's matcher: the binding every rendered path is rooted at, and exactly the clauses the declared cargo consumes.
83///
84/// The binding is asked for always, because every expression a carrier renders is rooted at it and the gate's own clause is what proves the path the consumer passed reaches the right crate.
85/// The rest is the declared cargo's own, carried beside the body that spells it — an argument a consumer supplies that nothing spells is a value the plan decided and nothing read.
86#[must_use]
87pub fn matcher(declared: &AxisCargo<DeclaredCargo>) -> Vec<GeneratedToken> {
88    let facing = CrateFacing::Harness;
89    let binding = facing.name();
90    let segment = segment_binding(facing);
91    let mut tokens = vec![GeneratedToken::word(binding), GeneratedToken::alone(':')];
92    tokens.extend(metavariable(binding));
93    tokens.push(GeneratedToken::alone(':'));
94    tokens.push(GeneratedToken::word("ident"));
95    tokens.push(GeneratedToken::joint('$'));
96    tokens.push(GeneratedToken::fixed_group(
97        GeneratedDelimiter::Parenthesis,
98        [
99            GeneratedToken::joint(':'),
100            GeneratedToken::alone(':'),
101            GeneratedToken::joint('$'),
102            GeneratedToken::word(&segment),
103            GeneratedToken::alone(':'),
104            GeneratedToken::word("ident"),
105        ],
106    ));
107    tokens.push(GeneratedToken::alone('*'));
108    tokens.push(GeneratedToken::alone(','));
109    if let AxisCargo::Carried(cargo) = declared {
110        tokens.extend(cargo.matched().tokens().iter().cloned());
111    }
112    tokens
113}
114
115/// The gate invocation a carrier's body IS: the producer's expectation, the binding, and the form's coupled pair of seats.
116///
117/// # Both seats, always
118///
119/// A seat may be EMPTY and it is still written, because a gate arm that had to match two clause shapes would be two arms and one pin would open two doors.
120/// The stamped seat carries material under the address's own grammar, which the gate forwards to its stamp; the opaque seat carries token trees the gate never parses and emits verbatim.
121/// They are separate seats because they are two vocabularies: folding the opaque trees in beside the stamped body would hand the stamp items it has no clause for, and standing them outside the invocation would release them on a pin MISMATCH.
122///
123/// # Errors
124///
125/// Returns [`Overflow`] where either seat, or the invocation around them, outgrows the declared token magnitude.
126pub fn gate_invocation(
127    form: DeliveryForm,
128    expectation: GeneratedToken,
129    stamped: Vec<GeneratedToken>,
130    opaque: Vec<GeneratedToken>,
131) -> Result<Vec<GeneratedToken>, Overflow> {
132    let facing = CrateFacing::Harness;
133    let binding = facing.name();
134    let mut clauses = vec![
135        GeneratedToken::word(EXPECTED_CLAUSE),
136        GeneratedToken::alone(':'),
137        expectation,
138        GeneratedToken::alone(','),
139        GeneratedToken::word(binding),
140        GeneratedToken::alone(':'),
141    ];
142    clauses.extend(rooted_path(facing, &[]));
143    clauses.push(GeneratedToken::alone(','));
144    clauses.push(GeneratedToken::word(form.name()));
145    clauses.push(GeneratedToken::alone(':'));
146    clauses.push(group(GeneratedDelimiter::Brace, stamped)?);
147    clauses.push(GeneratedToken::alone(','));
148    clauses.push(GeneratedToken::word(form.opaque()));
149    clauses.push(GeneratedToken::alone(':'));
150    clauses.push(group(GeneratedDelimiter::Brace, opaque)?);
151    clauses.push(GeneratedToken::alone(','));
152    let mut tokens = rooted_path(facing, &[GATE_MACRO]);
153    tokens.push(GeneratedToken::alone('!'));
154    tokens.push(group(GeneratedDelimiter::Brace, clauses)?);
155    Ok(tokens)
156}
157
158/// The exported carrier: a hidden definition under the mangled name, with one rule matching what the delivery consumes and expanding to the body it guards.
159///
160/// # Errors
161///
162/// Returns [`Overflow`] where the definition outgrows the declared token magnitude.
163pub fn exported_shell(
164    name: &ShellName,
165    sentence: &str,
166    matched: Vec<GeneratedToken>,
167    body: Vec<GeneratedToken>,
168) -> Result<Vec<GeneratedToken>, Overflow> {
169    let mut tokens = documentation(sentence)?;
170    tokens.extend(attribute(vec![
171        GeneratedToken::word("doc"),
172        group(
173            GeneratedDelimiter::Parenthesis,
174            vec![GeneratedToken::word("hidden")],
175        )?,
176    ])?);
177    tokens.extend(attribute(vec![GeneratedToken::word("macro_export")])?);
178    tokens.push(GeneratedToken::word("macro_rules"));
179    tokens.push(GeneratedToken::alone('!'));
180    tokens.push(GeneratedToken::word(name.spelling()));
181    let mut rule = vec![group(GeneratedDelimiter::Parenthesis, matched)?];
182    rule.push(GeneratedToken::joint('='));
183    rule.push(GeneratedToken::alone('>'));
184    rule.push(group(GeneratedDelimiter::Brace, body)?);
185    rule.push(GeneratedToken::alone(';'));
186    tokens.push(group(GeneratedDelimiter::Brace, rule)?);
187    Ok(tokens)
188}
189
190/// The author-chosen address: an exported definition under the spelling a declaration chose, whose one rule forwards its whole input to the hidden carrier.
191///
192/// # Why an address exists at all
193///
194/// The carrier is exported under the plan's identity at full width, so two declarations in one crate can never mint one exported name — and no person can know that spelling before the expansion runs.
195/// There is no road from a runtime string to a macro invocation, so a carrier with no second name is a carrier nobody can invoke.
196///
197/// # What it forwards
198///
199/// Every token, unread.
200/// The address declares no grammar of its own — the hidden carrier's matcher is the grammar, and a second matcher here would be a second shape a caller has to satisfy and a second place for it to drift.
201/// The forward is spelled through the defining crate's own root, so it resolves inside whatever crate the declaration site sits in whatever that crate is called.
202///
203/// # Errors
204///
205/// Returns [`Overflow`] where the definition outgrows the declared token magnitude.
206pub fn public_alias(
207    name: &ShellName,
208    address: &SupportName,
209    sentence: &str,
210) -> Result<Vec<GeneratedToken>, Overflow> {
211    let mut tokens = documentation(sentence)?;
212    tokens.extend(attribute(vec![GeneratedToken::word("macro_export")])?);
213    tokens.push(GeneratedToken::word("macro_rules"));
214    tokens.push(GeneratedToken::alone('!'));
215    tokens.push(GeneratedToken::word(address.spelling()));
216
217    let mut taken = metavariable("input");
218    taken.push(GeneratedToken::alone(':'));
219    taken.push(GeneratedToken::word("tt"));
220    let mut repeated = vec![GeneratedToken::joint('$')];
221    repeated.push(group(GeneratedDelimiter::Parenthesis, taken)?);
222    repeated.push(GeneratedToken::alone('*'));
223
224    let mut forwarded = metavariable("crate");
225    forwarded.push(GeneratedToken::joint(':'));
226    forwarded.push(GeneratedToken::alone(':'));
227    forwarded.push(GeneratedToken::word(name.spelling()));
228    forwarded.push(GeneratedToken::alone('!'));
229    let mut passed = vec![GeneratedToken::joint('$')];
230    passed.push(group(
231        GeneratedDelimiter::Parenthesis,
232        metavariable("input"),
233    )?);
234    passed.push(GeneratedToken::alone('*'));
235    forwarded.push(group(GeneratedDelimiter::Brace, passed)?);
236
237    let mut rule = vec![group(GeneratedDelimiter::Parenthesis, repeated)?];
238    rule.push(GeneratedToken::joint('='));
239    rule.push(GeneratedToken::alone('>'));
240    rule.push(group(GeneratedDelimiter::Brace, forwarded)?);
241    rule.push(GeneratedToken::alone(';'));
242    tokens.push(group(GeneratedDelimiter::Brace, rule)?);
243    Ok(tokens)
244}
245
246/// The sentence the exported carrier documents itself with.
247///
248/// Composed from the DOOR's producer and from nothing a declaration wrote: the item lands at the root of a consumer's crate, so a sentence carrying owner material would put a declaration's own words somewhere nobody asked for them, and a reader who trips over a mangled name there is owed the name of whoever put it there.
249pub(super) fn shell_sentence(door: &Door) -> String {
250    let producer = door.producer();
251    let namespace = producer.namespace;
252    let name = producer.name;
253    format!(
254        "Generated support carrier from {namespace}/{name}: deferred tokens a consumption \
255         target invokes. Hidden and mangled because it is machinery. Its body is one gate \
256         invocation, and the gate compares this producer's expected schema identity against \
257         the published one before any constructor reaches type checking."
258    )
259}
260
261/// The sentence the author-chosen address documents itself with.
262///
263/// On [`shell_sentence`]'s terms.
264/// The address's own NAME is owner material — the author chose it — and the sentence beside it says what the item is rather than restating what the author called it.
265pub(super) fn alias_sentence(door: &Door) -> String {
266    let producer = door.producer();
267    let namespace = producer.namespace;
268    let name = producer.name;
269    format!(
270        "Generated support from {namespace}/{name}: invoke this from a consumption target to \
271         receive what this declaration states. It forwards every token to the hidden plan-keyed \
272         carrier, whose matcher is the grammar and whose gate compares the producer's expected \
273         schema identity against the published one."
274    )
275}