use crate::tex::characters::Character;
use crate::tex::tokens::control_sequences::CSName;
use crate::tex::tokens::token_lists::CharWrite;
use const_for::const_for;
use std::fmt::Formatter;
#[derive(Copy, PartialEq, Eq, Clone, Default)]
pub enum CategoryCode {
Escape = 0,
BeginGroup = 1,
EndGroup = 2,
MathShift = 3,
AlignmentTab = 4,
EOL = 5,
Parameter = 6,
Superscript = 7,
Subscript = 8,
Ignored = 9,
Space = 10,
Letter = 11,
#[default]
Other = 12,
Active = 13,
Comment = 14,
Invalid = 15,
}
impl std::fmt::Debug for CategoryCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}
impl std::fmt::Display for CategoryCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
use CategoryCode as CC;
write!(
f,
"{}",
match self {
CC::Escape => "escape",
CC::BeginGroup => "begin group",
CC::EndGroup => "end group",
CC::MathShift => "math shift",
CC::AlignmentTab => "alignment",
CC::EOL => "end of line",
CC::Parameter => "parameter",
CC::Superscript => "superscript",
CC::Subscript => "subscript",
CC::Ignored => "ignored",
CC::Space => "space",
CC::Letter => "letter",
CC::Other => "other",
CC::Active => "active",
CC::Comment => "comment",
CC::Invalid => "invalid",
}
)
}
}
impl From<CategoryCode> for u8 {
fn from(cc: CategoryCode) -> Self {
use CategoryCode as CC;
match cc {
CC::Escape => 0,
CC::BeginGroup => 1,
CC::EndGroup => 2,
CC::MathShift => 3,
CC::AlignmentTab => 4,
CC::EOL => 5,
CC::Parameter => 6,
CC::Superscript => 7,
CC::Subscript => 8,
CC::Ignored => 9,
CC::Space => 10,
CC::Letter => 11,
CC::Other => 12,
CC::Active => 13,
CC::Comment => 14,
CC::Invalid => 15,
}
}
}
impl TryFrom<u8> for CategoryCode {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
use CategoryCode as CC;
Ok(match value {
0 => CC::Escape,
1 => CC::BeginGroup,
2 => CC::EndGroup,
3 => CC::MathShift,
4 => CC::AlignmentTab,
5 => CC::EOL,
6 => CC::Parameter,
7 => CC::Superscript,
8 => CC::Subscript,
9 => CC::Ignored,
10 => CC::Space,
11 => CC::Letter,
12 => CC::Other,
13 => CC::Active,
14 => CC::Comment,
15 => CC::Invalid,
_ => return Err(()),
})
}
}
pub type CategoryCodeScheme<Char> = <Char as Character>::CharMap<CategoryCode>;
pub static OTHER_SCHEME_U8: CategoryCodeScheme<u8> = {
let mut catcodes = [CategoryCode::Other; 256];
catcodes[32] = CategoryCode::Space;
catcodes
};
pub static STARTING_SCHEME_U8: CategoryCodeScheme<u8> = {
let mut catcodes = [CategoryCode::Other; 256];
catcodes[92] = CategoryCode::Escape;
catcodes[32] = CategoryCode::Space;
catcodes[13] = CategoryCode::EOL;
catcodes[37] = CategoryCode::Comment;
const_for!(i in 65..91 => catcodes[i] = CategoryCode::Letter);
const_for!(i in 97..123 => catcodes[i] = CategoryCode::Letter);
catcodes[126] = CategoryCode::Active;
catcodes
};
pub static DEFAULT_SCHEME_U8: CategoryCodeScheme<u8> = {
let mut catcodes = [CategoryCode::Other; 256];
catcodes[123] = CategoryCode::BeginGroup;
catcodes[125] = CategoryCode::EndGroup;
catcodes[36] = CategoryCode::MathShift;
catcodes[38] = CategoryCode::AlignmentTab;
catcodes[35] = CategoryCode::Parameter;
catcodes[94] = CategoryCode::Superscript;
catcodes[95] = CategoryCode::Subscript;
catcodes[126] = CategoryCode::Active;
catcodes[92] = CategoryCode::Escape;
catcodes[32] = CategoryCode::Space;
catcodes[13] = CategoryCode::EOL;
catcodes[37] = CategoryCode::Comment;
const_for!(i in 65..91 => catcodes[i] = CategoryCode::Letter);
const_for!(i in 97..123 => catcodes[i] = CategoryCode::Letter);
catcodes
};
pub static AT_LETTER_SCHEME: CategoryCodeScheme<u8> = {
let mut catcodes = [CategoryCode::Other; 256];
catcodes[123] = CategoryCode::BeginGroup;
catcodes[125] = CategoryCode::EndGroup;
catcodes[36] = CategoryCode::MathShift;
catcodes[38] = CategoryCode::AlignmentTab;
catcodes[35] = CategoryCode::Parameter;
catcodes[94] = CategoryCode::Superscript;
catcodes[95] = CategoryCode::Subscript;
catcodes[126] = CategoryCode::Active;
catcodes[92] = CategoryCode::Escape;
catcodes[32] = CategoryCode::Space;
catcodes[13] = CategoryCode::EOL;
catcodes[37] = CategoryCode::Comment;
const_for!(i in 64..91 => catcodes[i] = CategoryCode::Letter);
const_for!(i in 97..123 => catcodes[i] = CategoryCode::Letter);
catcodes
};
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum CommandCode {
Escape = 0,
BeginGroup = 1,
EndGroup = 2,
MathShift = 3,
AlignmentTab = 4,
EOF = 5,
Parameter = 6,
Superscript = 7,
Subscript = 8,
Primitive = 9,
Space = 10,
Letter = 11,
Other = 12,
Active = 13,
Argument = 14,
}
impl CommandCode {
pub fn meaning<C: Character, CS: CSName<C>, W: CharWrite<C, CS>>(
&self,
c: C,
mut f: W,
) -> std::fmt::Result {
match self {
CommandCode::BeginGroup => write!(f, "begin-group character "),
CommandCode::EndGroup => write!(f, "end-group character "),
CommandCode::MathShift => write!(f, "math shift character "),
CommandCode::Parameter => write!(f, "macro parameter character "),
CommandCode::Superscript => write!(f, "superscript character "),
CommandCode::Subscript => write!(f, "subscript character "),
CommandCode::Space => {
write!(f, "blank space ")?;
return Ok(());
}
CommandCode::Letter => write!(f, "the letter "),
_ => write!(f, "the character "),
}?;
f.push_char(c);
Ok(())
}
pub const fn as_byte(self) -> u8 {
use CommandCode::*;
match self {
Escape => 0,
BeginGroup => 1,
EndGroup => 2,
MathShift => 3,
AlignmentTab => 4,
EOF => 5,
Parameter => 6,
Superscript => 7,
Subscript => 8,
Primitive => 9,
Space => 10,
Letter => 11,
Other => 12,
Active => 13,
Argument => 14,
}
}
}
impl From<CategoryCode> for CommandCode {
fn from(value: CategoryCode) -> Self {
match value {
CategoryCode::Escape => CommandCode::Escape,
CategoryCode::BeginGroup => CommandCode::BeginGroup,
CategoryCode::EndGroup => CommandCode::EndGroup,
CategoryCode::MathShift => CommandCode::MathShift,
CategoryCode::AlignmentTab => CommandCode::AlignmentTab,
CategoryCode::EOL => CommandCode::EOF,
CategoryCode::Parameter => CommandCode::Parameter,
CategoryCode::Superscript => CommandCode::Superscript,
CategoryCode::Subscript => CommandCode::Subscript,
CategoryCode::Space => CommandCode::Space,
CategoryCode::Letter => CommandCode::Letter,
CategoryCode::Other => CommandCode::Other,
CategoryCode::Active => CommandCode::Active,
_ => panic!("Invalid category code for command code: {:?}\n This is an implementation error and should not happen",value)
}
}
}
impl TryFrom<u8> for CommandCode {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
use CommandCode::*;
Ok(match value {
0 => Escape,
1 => BeginGroup,
2 => EndGroup,
3 => MathShift,
4 => AlignmentTab,
5 => EOF,
6 => Parameter,
7 => Superscript,
8 => Subscript,
9 => Primitive,
10 => Space,
11 => Letter,
12 => Other,
13 => Active,
14 => Argument,
_ => return Err(()),
})
}
}