1mod catcode;
4mod mathcode;
5use crate::command;
6use crate::parse;
7use crate::prelude as txl;
8use crate::traits::*;
9pub use catcode::CatCode;
10pub use mathcode::MathCode;
11
12#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
15pub struct Font(pub u16);
16
17impl Font {
18 pub const NULL_FONT: Font = Font(0);
20}
21
22impl Parsable for Font {
23 fn parse_impl<S: TexlangState>(input: &mut crate::vm::ExpandedStream<S>) -> txl::Result<Self> {
24 match Option::<Font>::parse(input)? {
25 None => {
26 let token_or = input.peek()?;
27 input.error(
28 parse::Error::new(
29 "a font reference",
30 token_or,
31 r"a font reference can either be the current font (e.g. \font), a font variable (e.g. \textfont 1) or the result of loading a font (e.g. \a after \font \a path/to/font)",
32 )
33 )?;
34 Ok(Font::NULL_FONT)
35 }
36 Some(font) => Ok(font),
37 }
38 }
39}
40
41impl Parsable for Option<Font> {
42 fn parse_impl<S: TexlangState>(input: &mut crate::vm::ExpandedStream<S>) -> txl::Result<Self> {
43 let Some(token) = input.next()? else {
44 return Ok(None);
45 };
46 let crate::token::Value::CommandRef(command_ref) = token.value() else {
47 input.back(token);
48 return Ok(None);
49 };
50 match input.commands_map().get_command(&command_ref) {
51 Some(command::Command::Font(f)) => {
52 let f = *f;
53 Ok(Some(f))
54 }
55 Some(command::Command::Variable(var)) => {
56 let var = var.clone();
57 match var.resolve_type::<Font>(token, input)? {
58 None => {
59 input.back(token);
60 Ok(None)
61 }
62 Some(typed_variable) => Ok(Some(*typed_variable.get(input.state()))),
63 }
64 }
65 Some(command::Command::Execution(_, Some(tag))) => {
66 if input.state().is_current_font_command(*tag) {
67 Ok(Some(input.vm().current_font()))
68 } else {
69 input.back(token);
70 Ok(None)
71 }
72 }
73 _ => {
74 input.back(token);
75 Ok(None)
76 }
77 }
78 }
79}