use super::{GeneratedDelimiter, GeneratedLiteralForm, GeneratedSpacing, GeneratedToken};
pub(super) fn inspect_token(token: &GeneratedToken, into: &mut String) {
match token {
GeneratedToken::Word(word) => {
into.push_str(word);
into.push(' ');
}
GeneratedToken::RawIdentifier(name) => {
into.push_str("r#");
into.push_str(name);
into.push(' ');
}
GeneratedToken::Punct { mark, spacing } => {
into.push(*mark);
if *spacing == GeneratedSpacing::Alone {
into.push(' ');
}
}
GeneratedToken::Text(text) => {
into.push('"');
for character in text.chars() {
inspect_string_character(character, into);
}
into.push('"');
into.push(' ');
}
GeneratedToken::Group { delimiter, tokens } => {
let written = match delimiter {
GeneratedDelimiter::Parenthesis => Some(('(', ')')),
GeneratedDelimiter::Brace => Some(('{', '}')),
GeneratedDelimiter::Bracket => Some(('[', ']')),
GeneratedDelimiter::Bare => None,
};
if let Some((open, _)) = written {
into.push(open);
into.push(' ');
}
for inner in tokens.as_slice() {
inspect_token(inner, into);
}
if let Some((_, close)) = written {
into.push(close);
into.push(' ');
}
}
GeneratedToken::ByteText(material) => {
into.push('b');
into.push('"');
for byte in material {
inspect_byte(*byte, into);
}
into.push('"');
into.push(' ');
}
GeneratedToken::Number(value) => {
into.push_str(&value.to_string());
into.push(' ');
}
GeneratedToken::Literal(literal) => inspect_literal(literal.form(), into),
}
}
fn inspect_literal(literal: GeneratedLiteralForm<'_>, into: &mut String) {
match literal {
GeneratedLiteralForm::Number(spelling) => into.push_str(spelling),
GeneratedLiteralForm::Character(character) => {
into.push('\'');
inspect_quoted_character(character, into);
into.push('\'');
}
GeneratedLiteralForm::Byte(byte) => {
into.push('b');
into.push('\'');
inspect_quoted_byte(byte, into);
into.push('\'');
}
GeneratedLiteralForm::NulTerminatedText(material) => {
into.push('c');
into.push('"');
for byte in material {
inspect_byte(*byte, into);
}
into.push('"');
}
}
into.push(' ');
}
fn inspect_string_character(character: char, into: &mut String) {
for escaped in character.escape_default() {
into.push(escaped);
}
}
fn inspect_quoted_character(character: char, into: &mut String) {
if character == '\'' {
into.push('\\');
into.push('\'');
} else {
inspect_string_character(character, into);
}
}
fn inspect_quoted_byte(byte: u8, into: &mut String) {
if byte == b'\'' || byte == b'\\' {
into.push('\\');
into.push(char::from(byte));
} else if byte.is_ascii_graphic() || byte == b' ' {
into.push(char::from(byte));
} else {
inspect_hex_byte(byte, into);
}
}
fn inspect_byte(byte: u8, into: &mut String) {
match byte {
b'"' | b'\\' => {
into.push('\\');
into.push(char::from(byte));
}
0x20..=0x7E => into.push(char::from(byte)),
_ => {
inspect_hex_byte(byte, into);
}
}
}
fn inspect_hex_byte(byte: u8, into: &mut String) {
into.push('\\');
into.push('x');
into.push(hex_digit(byte >> 4));
into.push(hex_digit(byte & 0x0F));
}
const fn hex_digit(nibble: u8) -> char {
match nibble {
0 => '0',
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
6 => '6',
7 => '7',
8 => '8',
9 => '9',
10 => 'A',
11 => 'B',
12 => 'C',
13 => 'D',
14 => 'E',
_ => 'F',
}
}