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;
10use common::font;
11pub use mathcode::MathCode;
12
13impl Parsable for font::Id {
14    fn parse_impl<S: TexlangState>(input: &mut crate::vm::ExpandedStream<S>) -> txl::Result<Self> {
15        // Corresponds to scan_font_ident in TeX.2021.577.
16        match parse_font_or(input)? {
17            None => {
18                let token_or = input.peek()?;
19                input.error(
20                    parse::Error::new(
21                    "a font reference",
22                    token_or,
23                    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)",
24                    )
25                )?;
26                Ok(font::Id::NULL)
27            }
28            Some(font) => Ok(font),
29        }
30    }
31}
32
33fn parse_font_or<S: TexlangState>(
34    input: &mut crate::vm::ExpandedStream<S>,
35) -> txl::Result<Option<font::Id>> {
36    let Some(token) = input.next()? else {
37        return Ok(None);
38    };
39    let crate::token::Value::CommandRef(command_ref) = token.value() else {
40        input.back(token);
41        return Ok(None);
42    };
43    match input.commands_map().get_command(&command_ref) {
44        Some(command::Command::Font(f)) => {
45            let f = *f;
46            Ok(Some(f))
47        }
48        Some(command::Command::Variable(var)) => {
49            let var = var.clone();
50            match var.resolve_type::<font::Id>(token, input)? {
51                None => {
52                    input.back(token);
53                    Ok(None)
54                }
55                Some(typed_variable) => Ok(Some(*typed_variable.get(input.state()))),
56            }
57        }
58        Some(command::Command::Execution(_, Some(tag))) => {
59            if input.state().is_current_font_command(*tag) {
60                Ok(Some(input.vm().current_font()))
61            } else {
62                input.back(token);
63                Ok(None)
64            }
65        }
66        _ => {
67            input.back(token);
68            Ok(None)
69        }
70    }
71}