macroonz_compiler/support/carrier/
render.rs1use 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
32pub const GATE_MACRO: &str = "generated_support";
34
35pub const EXPECTED_CLAUSE: &str = "expected";
37
38const PATH_SEGMENT_SUFFIX: &str = "_segment";
40
41fn segment_binding(facing: CrateFacing) -> String {
43 format!("{}{PATH_SEGMENT_SUFFIX}", facing.name())
44}
45
46#[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#[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
59pub 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#[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#[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
138pub 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
181pub 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
213pub 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
369pub(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
384pub(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}