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