use super::types::Emittable;
use crate::closure::PartitionCargo;
use crate::token::{GeneratedDelimiter, GeneratedSpacing, GeneratedToken, GeneratedTree};
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
#[must_use]
pub fn emit(emittable: &impl Emittable) -> TokenStream {
let mut emitted = TokenStream::new();
for cargo in emittable.cargos() {
emitted.extend(emit_cargo(cargo));
}
emitted
}
fn emit_cargo(cargo: &PartitionCargo) -> TokenStream {
cargo.tokens().map_or_else(TokenStream::new, emit_tree)
}
fn emit_tree(tree: &GeneratedTree) -> TokenStream {
tree.tokens().iter().map(emit_token).collect()
}
fn emit_token(token: &GeneratedToken) -> TokenTree {
match token {
GeneratedToken::Word(word) => TokenTree::Ident(Ident::new(word, Span::call_site())),
GeneratedToken::RawIdentifier(name) => {
TokenTree::Ident(Ident::new_raw(name, Span::call_site()))
}
GeneratedToken::Punct { mark, spacing } => {
TokenTree::Punct(Punct::new(*mark, written_spacing(*spacing)))
}
GeneratedToken::Text(text) => TokenTree::Literal(Literal::string(text)),
GeneratedToken::Group { delimiter, tokens } => TokenTree::Group(Group::new(
written_delimiter(*delimiter),
tokens.iter().map(emit_token).collect(),
)),
GeneratedToken::ByteText(material) => TokenTree::Literal(Literal::byte_string(material)),
GeneratedToken::Number(value) => TokenTree::Literal(Literal::u64_unsuffixed(*value)),
}
}
const fn written_spacing(spacing: GeneratedSpacing) -> Spacing {
match spacing {
GeneratedSpacing::Joint => Spacing::Joint,
GeneratedSpacing::Alone => Spacing::Alone,
}
}
const fn written_delimiter(delimiter: GeneratedDelimiter) -> Delimiter {
match delimiter {
GeneratedDelimiter::Parenthesis => Delimiter::Parenthesis,
GeneratedDelimiter::Brace => Delimiter::Brace,
GeneratedDelimiter::Bracket => Delimiter::Bracket,
}
}