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::{
22    BoundPath, CrateFacing, DeclaringBinding, DeliveryForm, SchemaId, SupportName,
23};
24use super::ShellName;
25use crate::bounded::Overflow;
26use crate::request::Door;
27use crate::token::{
28    GeneratedDelimiter, GeneratedToken, attribute, documentation, group, metavariable,
29    segmented_twin_path,
30};
31
32/// The gate a carrier's body invokes.
33pub const GATE_MACRO: &str = "generated_support";
34
35/// The gate's clause carrying the producer's own expectation.
36pub const EXPECTED_CLAUSE: &str = "expected";
37
38/// The suffix naming the repeated path-segment binding beside a crate-facing root binding.
39const PATH_SEGMENT_SUFFIX: &str = "_segment";
40
41/// The repeated path-segment binding belonging to one crate-facing root binding.
42fn segment_binding(facing: CrateFacing) -> String {
43    format!("{}{PATH_SEGMENT_SUFFIX}", facing.name())
44}
45
46/// One path rooted at the complete segmented path a carrier binds for this facing.
47#[must_use]
48pub(crate) fn rooted_path(facing: CrateFacing, segments: &[&str]) -> Vec<GeneratedToken> {
49    segmented_twin_path(facing.name(), &segment_binding(facing), segments)
50}
51
52/// One path a caller declared, spelled from the crate it was rooted at.
53#[must_use]
54pub fn rendered_path(path: &BoundPath) -> Vec<GeneratedToken> {
55    let segments: Vec<&str> = path.segments().iter().map(String::as_str).collect();
56    rooted_path(path.facing(), &segments)
57}
58
59/// The producer's expectation, as the bracketed roster of decimal byte values the gate's opening arm matches.
60///
61/// # Errors
62///
63/// Returns [`Overflow`] where the roster outgrows the declared token magnitude.
64pub fn expectation_roster(expectation: SchemaId) -> Result<GeneratedToken, Overflow> {
65    let mut bytes: Vec<GeneratedToken> = Vec::new();
66    for byte in expectation.as_bytes() {
67        bytes.push(GeneratedToken::number(u64::from(*byte)));
68        bytes.push(GeneratedToken::alone(','));
69    }
70    group(GeneratedDelimiter::Bracket, bytes)
71}
72
73/// One `<name>: $<name>:<fragment>,` clause of a carrier's matcher.
74#[must_use]
75pub fn matched_clause(name: &str, fragment: &str) -> Vec<GeneratedToken> {
76    let mut tokens = vec![GeneratedToken::word(name), GeneratedToken::alone(':')];
77    tokens.extend(metavariable(name));
78    tokens.push(GeneratedToken::alone(':'));
79    tokens.push(GeneratedToken::word(fragment));
80    tokens.push(GeneratedToken::alone(','));
81    tokens
82}
83
84/// A carrier's matcher: the binding every rendered path is rooted at, and exactly the clauses the declared cargo consumes.
85///
86/// 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.
87/// 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.
88#[must_use]
89pub fn matcher(declared: &AxisCargo<DeclaredCargo>) -> Vec<GeneratedToken> {
90    matcher_for(DeclaringBinding::Absent, declared)
91}
92
93pub(super) fn matcher_requiring_declaring(
94    declared: &AxisCargo<DeclaredCargo>,
95) -> Vec<GeneratedToken> {
96    matcher_for(DeclaringBinding::Required, declared)
97}
98
99fn matcher_for(
100    declaring: DeclaringBinding,
101    declared: &AxisCargo<DeclaredCargo>,
102) -> Vec<GeneratedToken> {
103    let mut tokens = Vec::new();
104    if declaring == DeclaringBinding::Required {
105        tokens.extend(path_matcher(CrateFacing::Declaring));
106    }
107    tokens.extend(path_matcher(CrateFacing::Harness));
108    if let AxisCargo::Carried(cargo) = declared {
109        tokens.extend(cargo.matched().tokens().iter().cloned());
110    }
111    tokens
112}
113
114fn path_matcher(facing: CrateFacing) -> Vec<GeneratedToken> {
115    let binding = facing.name();
116    let segment = segment_binding(facing);
117    let mut tokens = vec![GeneratedToken::word(binding), GeneratedToken::alone(':')];
118    tokens.extend(metavariable(binding));
119    tokens.push(GeneratedToken::alone(':'));
120    tokens.push(GeneratedToken::word("ident"));
121    tokens.push(GeneratedToken::joint('$'));
122    tokens.push(GeneratedToken::fixed_group(
123        GeneratedDelimiter::Parenthesis,
124        [
125            GeneratedToken::joint(':'),
126            GeneratedToken::alone(':'),
127            GeneratedToken::joint('$'),
128            GeneratedToken::word(&segment),
129            GeneratedToken::alone(':'),
130            GeneratedToken::word("ident"),
131        ],
132    ));
133    tokens.push(GeneratedToken::alone('*'));
134    tokens.push(GeneratedToken::alone(','));
135    tokens
136}
137
138/// The gate invocation a carrier's body IS: the producer's expectation, the binding, and the form's coupled pair of seats.
139///
140/// # Both seats, always
141///
142/// 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.
143/// 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.
144/// 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.
145///
146/// # Errors
147///
148/// Returns [`Overflow`] where either seat, or the invocation around them, outgrows the declared token magnitude.
149pub fn gate_invocation(
150    form: DeliveryForm,
151    expectation: GeneratedToken,
152    stamped: Vec<GeneratedToken>,
153    opaque: Vec<GeneratedToken>,
154) -> Result<Vec<GeneratedToken>, Overflow> {
155    let facing = CrateFacing::Harness;
156    let binding = facing.name();
157    let mut clauses = vec![
158        GeneratedToken::word(EXPECTED_CLAUSE),
159        GeneratedToken::alone(':'),
160        expectation,
161        GeneratedToken::alone(','),
162        GeneratedToken::word(binding),
163        GeneratedToken::alone(':'),
164    ];
165    clauses.extend(rooted_path(facing, &[]));
166    clauses.push(GeneratedToken::alone(','));
167    clauses.push(GeneratedToken::word(form.name()));
168    clauses.push(GeneratedToken::alone(':'));
169    clauses.push(group(GeneratedDelimiter::Brace, stamped)?);
170    clauses.push(GeneratedToken::alone(','));
171    clauses.push(GeneratedToken::word(form.opaque()));
172    clauses.push(GeneratedToken::alone(':'));
173    clauses.push(group(GeneratedDelimiter::Brace, opaque)?);
174    clauses.push(GeneratedToken::alone(','));
175    let mut tokens = rooted_path(facing, &[GATE_MACRO]);
176    tokens.push(GeneratedToken::alone('!'));
177    tokens.push(group(GeneratedDelimiter::Brace, clauses)?);
178    Ok(tokens)
179}
180
181/// 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.
182///
183/// # Errors
184///
185/// Returns [`Overflow`] where the definition outgrows the declared token magnitude.
186pub fn exported_shell(
187    name: &ShellName,
188    sentence: &str,
189    matched: Vec<GeneratedToken>,
190    body: Vec<GeneratedToken>,
191) -> Result<Vec<GeneratedToken>, Overflow> {
192    let mut tokens = documentation(sentence)?;
193    tokens.extend(attribute(vec![
194        GeneratedToken::word("doc"),
195        group(
196            GeneratedDelimiter::Parenthesis,
197            vec![GeneratedToken::word("hidden")],
198        )?,
199    ])?);
200    tokens.extend(attribute(vec![GeneratedToken::word("macro_export")])?);
201    tokens.push(GeneratedToken::word("macro_rules"));
202    tokens.push(GeneratedToken::alone('!'));
203    tokens.push(GeneratedToken::word(name.spelling()));
204    let mut rule = vec![group(GeneratedDelimiter::Parenthesis, matched)?];
205    rule.push(GeneratedToken::joint('='));
206    rule.push(GeneratedToken::alone('>'));
207    rule.push(group(GeneratedDelimiter::Brace, body)?);
208    rule.push(GeneratedToken::alone(';'));
209    tokens.push(group(GeneratedDelimiter::Brace, rule)?);
210    Ok(tokens)
211}
212
213/// The author-chosen address: an exported definition under the spelling a declaration chose, whose one rule forwards its whole input to the hidden carrier.
214///
215/// # Why an address exists at all
216///
217/// 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.
218/// 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.
219///
220/// # What it forwards
221///
222/// Every semantic token, unread.
223/// An ordinary address forwards through the defining crate's own root.
224/// Where generated cargo needs declaration-owned items across a target boundary, the address reads the explicitly supplied declaring path only to reach the hidden carrier and forwards that same binding beside every other token.
225/// The hidden carrier remains the sole owner of the complete matcher grammar.
226///
227/// # Errors
228///
229/// Returns [`Overflow`] where the definition outgrows the declared token magnitude.
230pub fn public_alias(
231    name: &ShellName,
232    address: &SupportName,
233    sentence: &str,
234) -> Result<Vec<GeneratedToken>, Overflow> {
235    public_alias_for(name, address, sentence, DeclaringBinding::Absent)
236}
237
238pub(super) fn public_alias_requiring_declaring(
239    name: &ShellName,
240    address: &SupportName,
241    sentence: &str,
242) -> Result<Vec<GeneratedToken>, Overflow> {
243    public_alias_for(name, address, sentence, DeclaringBinding::Required)
244}
245
246fn public_alias_for(
247    name: &ShellName,
248    address: &SupportName,
249    sentence: &str,
250    declaring: DeclaringBinding,
251) -> Result<Vec<GeneratedToken>, Overflow> {
252    let mut tokens = documentation(sentence)?;
253    tokens.extend(attribute(vec![GeneratedToken::word("macro_export")])?);
254    tokens.push(GeneratedToken::word("macro_rules"));
255    tokens.push(GeneratedToken::alone('!'));
256    tokens.push(GeneratedToken::word(address.spelling()));
257
258    let mut rules = Vec::new();
259    if declaring == DeclaringBinding::Required {
260        let matched = local_declaring_input()?;
261        let passed = local_forwarded_input()?;
262        let forwarded = alias_call(Vec::new(), name, passed)?;
263        rules.extend(alias_rule(matched, forwarded)?);
264    }
265
266    let (matched, forwarded) = match declaring {
267        DeclaringBinding::Absent => (repeated_input()?, metavariable("crate")),
268        DeclaringBinding::Required => {
269            let facing = CrateFacing::Declaring;
270            (declaring_input()?, rooted_path(facing, &[]))
271        }
272    };
273    let passed = forwarded_input(declaring)?;
274    let forwarded = alias_call(forwarded, name, passed)?;
275    rules.extend(alias_rule(matched, forwarded)?);
276    tokens.push(group(GeneratedDelimiter::Brace, rules)?);
277    Ok(tokens)
278}
279
280fn alias_call(
281    mut root: Vec<GeneratedToken>,
282    name: &ShellName,
283    passed: Vec<GeneratedToken>,
284) -> Result<Vec<GeneratedToken>, Overflow> {
285    if !root.is_empty() {
286        root.push(GeneratedToken::joint(':'));
287        root.push(GeneratedToken::alone(':'));
288    }
289    root.push(GeneratedToken::word(name.spelling()));
290    root.push(GeneratedToken::alone('!'));
291    root.push(group(GeneratedDelimiter::Brace, passed)?);
292    Ok(root)
293}
294
295fn alias_rule(
296    matched: Vec<GeneratedToken>,
297    forwarded: Vec<GeneratedToken>,
298) -> Result<Vec<GeneratedToken>, Overflow> {
299    let mut rule = vec![group(GeneratedDelimiter::Parenthesis, matched)?];
300    rule.push(GeneratedToken::joint('='));
301    rule.push(GeneratedToken::alone('>'));
302    rule.push(group(GeneratedDelimiter::Brace, forwarded)?);
303    rule.push(GeneratedToken::alone(';'));
304    Ok(rule)
305}
306
307fn repeated_input() -> Result<Vec<GeneratedToken>, Overflow> {
308    let mut taken = metavariable("input");
309    taken.push(GeneratedToken::alone(':'));
310    taken.push(GeneratedToken::word("tt"));
311    let mut repeated = vec![GeneratedToken::joint('$')];
312    repeated.push(group(GeneratedDelimiter::Parenthesis, taken)?);
313    repeated.push(GeneratedToken::alone('*'));
314    Ok(repeated)
315}
316
317fn declaring_input() -> Result<Vec<GeneratedToken>, Overflow> {
318    let mut matched = path_matcher(CrateFacing::Declaring);
319    matched.extend(repeated_input()?);
320    Ok(matched)
321}
322
323fn local_declaring_input() -> Result<Vec<GeneratedToken>, Overflow> {
324    let mut matched = vec![
325        GeneratedToken::word(CrateFacing::Declaring.name()),
326        GeneratedToken::alone(':'),
327        GeneratedToken::word("crate"),
328        GeneratedToken::alone(','),
329    ];
330    matched.extend(repeated_input()?);
331    Ok(matched)
332}
333
334fn forwarded_input(declaring: DeclaringBinding) -> Result<Vec<GeneratedToken>, Overflow> {
335    let mut passed = Vec::new();
336    if declaring == DeclaringBinding::Required {
337        passed.extend([
338            GeneratedToken::word(CrateFacing::Declaring.name()),
339            GeneratedToken::alone(':'),
340        ]);
341        passed.extend(rooted_path(CrateFacing::Declaring, &[]));
342        passed.push(GeneratedToken::alone(','));
343    }
344    passed.push(GeneratedToken::joint('$'));
345    passed.push(group(
346        GeneratedDelimiter::Parenthesis,
347        metavariable("input"),
348    )?);
349    passed.push(GeneratedToken::alone('*'));
350    Ok(passed)
351}
352
353fn local_forwarded_input() -> Result<Vec<GeneratedToken>, Overflow> {
354    let mut passed = vec![
355        GeneratedToken::word(CrateFacing::Declaring.name()),
356        GeneratedToken::alone(':'),
357        GeneratedToken::word("crate"),
358        GeneratedToken::alone(','),
359    ];
360    passed.push(GeneratedToken::joint('$'));
361    passed.push(group(
362        GeneratedDelimiter::Parenthesis,
363        metavariable("input"),
364    )?);
365    passed.push(GeneratedToken::alone('*'));
366    Ok(passed)
367}
368
369/// The sentence the exported carrier documents itself with.
370///
371/// 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.
372pub(super) fn shell_sentence(door: &Door) -> String {
373    let producer = door.producer();
374    let namespace = producer.namespace;
375    let name = producer.name;
376    format!(
377        "Generated support carrier from {namespace}/{name}: deferred tokens a consumption \
378         target invokes. Hidden and mangled because it is machinery. Its body is one gate \
379         invocation, and the gate compares this producer's expected schema identity against \
380         the published one before any constructor reaches type checking."
381    )
382}
383
384/// The sentence the author-chosen address documents itself with.
385///
386/// On [`shell_sentence`]'s terms.
387/// 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.
388pub(super) fn alias_sentence(door: &Door) -> String {
389    let producer = door.producer();
390    let namespace = producer.namespace;
391    let name = producer.name;
392    format!(
393        "Generated support from {namespace}/{name}: invoke this from a consumption target to \
394         receive what this declaration states. It forwards every token to the hidden plan-keyed \
395         carrier, whose matcher is the grammar and whose gate compares the producer's expected \
396         schema identity against the published one."
397    )
398}