use super::super::cargo::{AxisCargo, DeclaredCargo};
use super::super::types::{
BoundPath, CrateFacing, DeclaringBinding, DeliveryForm, SchemaId, SupportName,
};
use super::ShellName;
use crate::bounded::Overflow;
use crate::request::Door;
use crate::token::{
GeneratedDelimiter, GeneratedToken, attribute, documentation, group, metavariable,
segmented_twin_path,
};
pub const GATE_MACRO: &str = "generated_support";
pub const EXPECTED_CLAUSE: &str = "expected";
const PATH_SEGMENT_SUFFIX: &str = "_segment";
fn segment_binding(facing: CrateFacing) -> String {
format!("{}{PATH_SEGMENT_SUFFIX}", facing.name())
}
#[must_use]
pub(crate) fn rooted_path(facing: CrateFacing, segments: &[&str]) -> Vec<GeneratedToken> {
segmented_twin_path(facing.name(), &segment_binding(facing), segments)
}
#[must_use]
pub fn rendered_path(path: &BoundPath) -> Vec<GeneratedToken> {
let segments: Vec<&str> = path.segments().iter().map(String::as_str).collect();
rooted_path(path.facing(), &segments)
}
pub fn expectation_roster(expectation: SchemaId) -> Result<GeneratedToken, Overflow> {
let mut bytes: Vec<GeneratedToken> = Vec::new();
for byte in expectation.as_bytes() {
bytes.push(GeneratedToken::number(u64::from(*byte)));
bytes.push(GeneratedToken::alone(','));
}
group(GeneratedDelimiter::Bracket, bytes)
}
#[must_use]
pub fn matched_clause(name: &str, fragment: &str) -> Vec<GeneratedToken> {
let mut tokens = vec![GeneratedToken::word(name), GeneratedToken::alone(':')];
tokens.extend(metavariable(name));
tokens.push(GeneratedToken::alone(':'));
tokens.push(GeneratedToken::word(fragment));
tokens.push(GeneratedToken::alone(','));
tokens
}
#[must_use]
pub fn matcher(declared: &AxisCargo<DeclaredCargo>) -> Vec<GeneratedToken> {
matcher_for(DeclaringBinding::Absent, declared)
}
pub(super) fn matcher_requiring_declaring(
declared: &AxisCargo<DeclaredCargo>,
) -> Vec<GeneratedToken> {
matcher_for(DeclaringBinding::Required, declared)
}
fn matcher_for(
declaring: DeclaringBinding,
declared: &AxisCargo<DeclaredCargo>,
) -> Vec<GeneratedToken> {
let mut tokens = Vec::new();
if declaring == DeclaringBinding::Required {
tokens.extend(path_matcher(CrateFacing::Declaring));
}
tokens.extend(path_matcher(CrateFacing::Harness));
if let AxisCargo::Carried(cargo) = declared {
tokens.extend(cargo.matched().tokens().iter().cloned());
}
tokens
}
fn path_matcher(facing: CrateFacing) -> Vec<GeneratedToken> {
let binding = facing.name();
let segment = segment_binding(facing);
let mut tokens = vec![GeneratedToken::word(binding), GeneratedToken::alone(':')];
tokens.extend(metavariable(binding));
tokens.push(GeneratedToken::alone(':'));
tokens.push(GeneratedToken::word("ident"));
tokens.push(GeneratedToken::joint('$'));
tokens.push(GeneratedToken::fixed_group(
GeneratedDelimiter::Parenthesis,
[
GeneratedToken::joint(':'),
GeneratedToken::alone(':'),
GeneratedToken::joint('$'),
GeneratedToken::word(&segment),
GeneratedToken::alone(':'),
GeneratedToken::word("ident"),
],
));
tokens.push(GeneratedToken::alone('*'));
tokens.push(GeneratedToken::alone(','));
tokens
}
pub fn gate_invocation(
form: DeliveryForm,
expectation: GeneratedToken,
stamped: Vec<GeneratedToken>,
opaque: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
let facing = CrateFacing::Harness;
let binding = facing.name();
let mut clauses = vec![
GeneratedToken::word(EXPECTED_CLAUSE),
GeneratedToken::alone(':'),
expectation,
GeneratedToken::alone(','),
GeneratedToken::word(binding),
GeneratedToken::alone(':'),
];
clauses.extend(rooted_path(facing, &[]));
clauses.push(GeneratedToken::alone(','));
clauses.push(GeneratedToken::word(form.name()));
clauses.push(GeneratedToken::alone(':'));
clauses.push(group(GeneratedDelimiter::Brace, stamped)?);
clauses.push(GeneratedToken::alone(','));
clauses.push(GeneratedToken::word(form.opaque()));
clauses.push(GeneratedToken::alone(':'));
clauses.push(group(GeneratedDelimiter::Brace, opaque)?);
clauses.push(GeneratedToken::alone(','));
let mut tokens = rooted_path(facing, &[GATE_MACRO]);
tokens.push(GeneratedToken::alone('!'));
tokens.push(group(GeneratedDelimiter::Brace, clauses)?);
Ok(tokens)
}
pub fn exported_shell(
name: &ShellName,
sentence: &str,
matched: Vec<GeneratedToken>,
body: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
let mut tokens = documentation(sentence)?;
tokens.extend(attribute(vec![
GeneratedToken::word("doc"),
group(
GeneratedDelimiter::Parenthesis,
vec![GeneratedToken::word("hidden")],
)?,
])?);
tokens.extend(attribute(vec![GeneratedToken::word("macro_export")])?);
tokens.push(GeneratedToken::word("macro_rules"));
tokens.push(GeneratedToken::alone('!'));
tokens.push(GeneratedToken::word(name.spelling()));
let mut rule = vec![group(GeneratedDelimiter::Parenthesis, matched)?];
rule.push(GeneratedToken::joint('='));
rule.push(GeneratedToken::alone('>'));
rule.push(group(GeneratedDelimiter::Brace, body)?);
rule.push(GeneratedToken::alone(';'));
tokens.push(group(GeneratedDelimiter::Brace, rule)?);
Ok(tokens)
}
pub fn public_alias(
name: &ShellName,
address: &SupportName,
sentence: &str,
) -> Result<Vec<GeneratedToken>, Overflow> {
public_alias_for(name, address, sentence, DeclaringBinding::Absent)
}
pub(super) fn public_alias_requiring_declaring(
name: &ShellName,
address: &SupportName,
sentence: &str,
) -> Result<Vec<GeneratedToken>, Overflow> {
public_alias_for(name, address, sentence, DeclaringBinding::Required)
}
fn public_alias_for(
name: &ShellName,
address: &SupportName,
sentence: &str,
declaring: DeclaringBinding,
) -> Result<Vec<GeneratedToken>, Overflow> {
let mut tokens = documentation(sentence)?;
tokens.extend(attribute(vec![GeneratedToken::word("macro_export")])?);
tokens.push(GeneratedToken::word("macro_rules"));
tokens.push(GeneratedToken::alone('!'));
tokens.push(GeneratedToken::word(address.spelling()));
let mut rules = Vec::new();
if declaring == DeclaringBinding::Required {
let matched = local_declaring_input()?;
let passed = local_forwarded_input()?;
let forwarded = alias_call(Vec::new(), name, passed)?;
rules.extend(alias_rule(matched, forwarded)?);
}
let (matched, forwarded) = match declaring {
DeclaringBinding::Absent => (repeated_input()?, metavariable("crate")),
DeclaringBinding::Required => {
let facing = CrateFacing::Declaring;
(declaring_input()?, rooted_path(facing, &[]))
}
};
let passed = forwarded_input(declaring)?;
let forwarded = alias_call(forwarded, name, passed)?;
rules.extend(alias_rule(matched, forwarded)?);
tokens.push(group(GeneratedDelimiter::Brace, rules)?);
Ok(tokens)
}
fn alias_call(
mut root: Vec<GeneratedToken>,
name: &ShellName,
passed: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
if !root.is_empty() {
root.push(GeneratedToken::joint(':'));
root.push(GeneratedToken::alone(':'));
}
root.push(GeneratedToken::word(name.spelling()));
root.push(GeneratedToken::alone('!'));
root.push(group(GeneratedDelimiter::Brace, passed)?);
Ok(root)
}
fn alias_rule(
matched: Vec<GeneratedToken>,
forwarded: Vec<GeneratedToken>,
) -> Result<Vec<GeneratedToken>, Overflow> {
let mut rule = vec![group(GeneratedDelimiter::Parenthesis, matched)?];
rule.push(GeneratedToken::joint('='));
rule.push(GeneratedToken::alone('>'));
rule.push(group(GeneratedDelimiter::Brace, forwarded)?);
rule.push(GeneratedToken::alone(';'));
Ok(rule)
}
fn repeated_input() -> Result<Vec<GeneratedToken>, Overflow> {
let mut taken = metavariable("input");
taken.push(GeneratedToken::alone(':'));
taken.push(GeneratedToken::word("tt"));
let mut repeated = vec![GeneratedToken::joint('$')];
repeated.push(group(GeneratedDelimiter::Parenthesis, taken)?);
repeated.push(GeneratedToken::alone('*'));
Ok(repeated)
}
fn declaring_input() -> Result<Vec<GeneratedToken>, Overflow> {
let mut matched = path_matcher(CrateFacing::Declaring);
matched.extend(repeated_input()?);
Ok(matched)
}
fn local_declaring_input() -> Result<Vec<GeneratedToken>, Overflow> {
let mut matched = vec![
GeneratedToken::word(CrateFacing::Declaring.name()),
GeneratedToken::alone(':'),
GeneratedToken::word("crate"),
GeneratedToken::alone(','),
];
matched.extend(repeated_input()?);
Ok(matched)
}
fn forwarded_input(declaring: DeclaringBinding) -> Result<Vec<GeneratedToken>, Overflow> {
let mut passed = Vec::new();
if declaring == DeclaringBinding::Required {
passed.extend([
GeneratedToken::word(CrateFacing::Declaring.name()),
GeneratedToken::alone(':'),
]);
passed.extend(rooted_path(CrateFacing::Declaring, &[]));
passed.push(GeneratedToken::alone(','));
}
passed.push(GeneratedToken::joint('$'));
passed.push(group(
GeneratedDelimiter::Parenthesis,
metavariable("input"),
)?);
passed.push(GeneratedToken::alone('*'));
Ok(passed)
}
fn local_forwarded_input() -> Result<Vec<GeneratedToken>, Overflow> {
let mut passed = vec![
GeneratedToken::word(CrateFacing::Declaring.name()),
GeneratedToken::alone(':'),
GeneratedToken::word("crate"),
GeneratedToken::alone(','),
];
passed.push(GeneratedToken::joint('$'));
passed.push(group(
GeneratedDelimiter::Parenthesis,
metavariable("input"),
)?);
passed.push(GeneratedToken::alone('*'));
Ok(passed)
}
pub(super) fn shell_sentence(door: &Door) -> String {
let producer = door.producer();
let namespace = producer.namespace;
let name = producer.name;
format!(
"Generated support carrier from {namespace}/{name}: deferred tokens a consumption \
target invokes. Hidden and mangled because it is machinery. Its body is one gate \
invocation, and the gate compares this producer's expected schema identity against \
the published one before any constructor reaches type checking."
)
}
pub(super) fn alias_sentence(door: &Door) -> String {
let producer = door.producer();
let namespace = producer.namespace;
let name = producer.name;
format!(
"Generated support from {namespace}/{name}: invoke this from a consumption target to \
receive what this declaration states. It forwards every token to the hidden plan-keyed \
carrier, whose matcher is the grammar and whose gate compares the producer's expected \
schema identity against the published one."
)
}