texlang/types/
mod.rs

1//! TeX types supported by Texlang
2
3mod 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/// A reference to a font that has been loaded.
13#[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    /// The null font.
19    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}