tex_engine/
engine.rs

1#![allow(clippy::module_name_repetitions)]
2/*! A TeX engine combines all the necessary components into a struct capable of compiling a TeX file into
3    some output format.
4*/
5use crate::commands::primitives::PRIMITIVES;
6use crate::commands::{ResolvedToken, TeXCommand};
7use crate::engine::filesystem::{File, FileSystem, VirtualFile};
8use crate::engine::fontsystem::{Font, FontSystem, TfmFont, TfmFontSystem};
9use crate::engine::gullet::{DefaultGullet, Gullet};
10use crate::engine::mouth::{DefaultMouth, Mouth};
11use crate::engine::state::State;
12use crate::engine::stomach::{DefaultStomach, Stomach};
13use crate::engine::utils::memory::MemoryManager;
14use crate::engine::utils::outputs::{LogOutputs, Outputs};
15use crate::tex;
16use crate::tex::catcodes::CommandCode;
17use crate::tex::characters::Character;
18use crate::tex::nodes::vertical::VNode;
19use crate::tex::nodes::CustomNodeTrait;
20use crate::tex::numerics::{Dim32, Mu, MuDim, NumSet, Numeric, TeXDimen, TeXInt};
21use crate::tex::tokens::control_sequences::{CSName, InternedCSName};
22use crate::tex::tokens::Token;
23use crate::utils::errors::{ErrorHandler, ErrorThrower, TeXError, TeXResult};
24use chrono::{Datelike, Timelike};
25use std::convert::Infallible;
26use std::fmt::Debug;
27
28pub mod filesystem;
29pub mod fontsystem;
30pub mod gullet;
31pub mod mouth;
32pub mod state;
33pub mod stomach;
34pub mod utils;
35
36/**
37    The types that an engine needs to implement. To reduce overhad in function signature,
38    we bundle all of them into a single trait and pass that around.
39*/
40pub trait EngineTypes: Sized + Copy + Clone + Debug + 'static {
41    type Char: Character;
42    type CSName: CSName<Self::Char>;
43    #[cfg(feature = "multithreaded")]
44    type Token: Token<Char = Self::Char, CS = Self::CSName> + Send + Sync;
45    #[cfg(not(feature = "multithreaded"))]
46    type Token: Token<Char = Self::Char, CS = Self::CSName>;
47    type Extension: EngineExtension<Self>;
48    #[cfg(feature = "multithreaded")]
49    type File: File<Char = Self::Char> + Send + Sync;
50    #[cfg(not(feature = "multithreaded"))]
51    type File: File<Char = Self::Char>;
52    type FileSystem: FileSystem<File = Self::File>;
53    type Int: TeXInt;
54    type Dim: TeXDimen + Numeric<Self::Int>;
55    type MuDim: MuDim + Numeric<Self::Int>;
56    type Num: crate::tex::numerics::NumSet<Int = Self::Int, Dim = Self::Dim, MuDim = Self::MuDim>;
57    type State: State<Self>;
58    type Outputs: Outputs;
59    type Mouth: Mouth<Self>;
60    type Gullet: Gullet<Self>;
61    type Stomach: Stomach<Self>;
62    type ErrorHandler: ErrorHandler<Self>;
63    type CustomNode: CustomNodeTrait<Self>;
64    type Font: Font<Char = Self::Char, Int = Self::Int, Dim = Self::Dim, CS = Self::CSName>;
65    type FontSystem: FontSystem<
66        Font = Self::Font,
67        Char = Self::Char,
68        Int = Self::Int,
69        Dim = Self::Dim,
70        CS = Self::CSName,
71    >;
72}
73/// Auxiliary components passed around to [`PrimitiveCommand`](crate::commands::PrimitiveCommand)s.
74pub struct EngineAux<ET: EngineTypes> {
75    /// memory management and interning of control sequence names
76    pub memory: MemoryManager<ET::Token>,
77    /// error handling
78    pub error_handler: ET::ErrorHandler,
79    /// printing to logs or the terminal
80    pub outputs: ET::Outputs,
81    /// start time of the current job
82    pub start_time: chrono::DateTime<chrono::Local>,
83    /// `\jobname`
84    pub jobname: String,
85    /// extension components
86    pub extension: ET::Extension,
87}
88
89struct Colon<'c, ET: EngineTypes> {
90    out: Box<dyn FnMut(&mut EngineReferences<ET>, VNode<ET>) -> TeXResult<(), ET> + 'c>,
91}
92impl<'c, ET: EngineTypes> Colon<'c, ET> {
93    fn new<F: FnMut(&mut EngineReferences<ET>, VNode<ET>) -> TeXResult<(), ET> + 'c>(f: F) -> Self {
94        Colon { out: Box::new(f) }
95    }
96    fn out(&mut self, engine: &mut EngineReferences<ET>, n: VNode<ET>) -> TeXResult<(), ET> {
97        (self.out)(engine, n)
98    }
99}
100impl<ET: EngineTypes> Default for Colon<'_, ET> {
101    fn default() -> Self {
102        Colon {
103            out: Box::new(|_, _| Ok(())),
104        }
105    }
106}
107
108impl<ET: EngineTypes> EngineReferences<'_, ET> {
109    /// ships out the [`VNode`], passing it on to the provided continuation.
110    /// #### Errors
111    /// On LaTeX errors in Whatsits (e.g. non-immediate `\write`s)
112    pub fn shipout(&mut self, n: VNode<ET>) -> TeXResult<(), ET> {
113        let mut colon = std::mem::take(&mut self.colon);
114        let r = colon.out(self, n);
115        self.colon = colon;
116        r
117    }
118}
119
120/**
121    This struct combines all the necessary components for use in [`PrimitiveCommand`](crate::commands::PrimitiveCommand)s.
122    We use public fields instead of accessor methods to convince the borrow checker
123    that all the components are *independent*, and avoid "Cannot borrow as mutable because already borrowed as
124    immutable" errors.
125*/
126pub struct EngineReferences<'et, ET: EngineTypes> {
127    pub state: &'et mut ET::State,
128    pub mouth: &'et mut ET::Mouth,
129    pub gullet: &'et mut ET::Gullet,
130    pub stomach: &'et mut ET::Stomach,
131    pub filesystem: &'et mut ET::FileSystem,
132    pub fontsystem: &'et mut ET::FontSystem,
133    colon: Colon<'et, ET>,
134    pub aux: &'et mut EngineAux<ET>,
135}
136
137/// Example implementation of [`EngineTypes`] for a plain TeX engine.
138#[derive(Copy, Clone, Debug)]
139pub struct DefaultPlainTeXEngineTypes;
140impl EngineTypes for DefaultPlainTeXEngineTypes {
141    type Char = u8;
142    type CSName = InternedCSName<u8>;
143    type Token = super::tex::tokens::CompactToken;
144    type Extension = ();
145    type Int = i32;
146    type Dim = Dim32;
147    type MuDim = Mu;
148    type Num = tex::numerics::DefaultNumSet;
149    type State = state::tex_state::DefaultState<Self>;
150    type File = VirtualFile<u8>;
151    type FileSystem = filesystem::NoOutputFileSystem<u8>;
152    type Outputs = LogOutputs;
153    type Mouth = DefaultMouth<Self>;
154    type Gullet = DefaultGullet<Self>;
155    type CustomNode = Infallible;
156    type ErrorHandler = ErrorThrower<Self>;
157    type Stomach = DefaultStomach<Self>;
158    type Font = TfmFont<i32, Dim32, InternedCSName<u8>>;
159    type FontSystem = TfmFontSystem<i32, Dim32, InternedCSName<u8>>;
160}
161
162/// A [`TeXEngine`] combines all necessary components (see [`EngineTypes`]) to compile a TeX file into some output format.
163pub trait TeXEngine: Sized {
164    type Types: EngineTypes;
165    /// Returns mutable references to the components of the engine.
166    fn get_engine_refs(&mut self) -> EngineReferences<Self::Types>;
167    /// Initializes the engine with a file, e.g. `latex.ltx` or `pdftex.cfg`.
168    /// #### Errors
169    /// On TeX errors in init files
170    #[allow(clippy::cast_possible_wrap)]
171    fn init_file(&mut self, s: &str) -> TeXResult<(), Self::Types> {
172        log::debug!("Initializing with file {}", s);
173        let mut comps = self.get_engine_refs();
174        comps.aux.start_time = chrono::Local::now();
175        comps.state.set_primitive_int(
176            comps.aux,
177            PRIMITIVES.year,
178            comps.aux.start_time.year().into(),
179            true,
180        );
181        comps.state.set_primitive_int(
182            comps.aux,
183            PRIMITIVES.month,
184            (comps.aux.start_time.month() as i32).into(),
185            true,
186        );
187        comps.state.set_primitive_int(
188            comps.aux,
189            PRIMITIVES.day,
190            (comps.aux.start_time.day() as i32).into(),
191            true,
192        );
193        comps.state.set_primitive_int(
194            comps.aux,
195            PRIMITIVES.time,
196            (((comps.aux.start_time.hour() * 60) + comps.aux.start_time.minute()) as i32).into(),
197            true,
198        );
199        let file = comps.filesystem.get(s);
200        let Some(filename) = file
201            .path()
202            .file_stem()
203            .and_then(|s| s.to_str().map(ToString::to_string))
204        else {
205            return Err(TeXError::General(format!("Invalid init file {s}")));
206        };
207        comps.aux.jobname = filename;
208        comps.push_file(file);
209        comps.top_loop()
210    }
211
212    /// #### Errors
213    /// On TeX errors in init files
214    #[allow(clippy::cast_possible_wrap)]
215    fn run<
216        F: FnMut(&mut EngineReferences<Self::Types>, VNode<Self::Types>) -> TeXResult<(), Self::Types>,
217    >(
218        &mut self,
219        f: F,
220    ) -> TeXResult<(), Self::Types> {
221        let mut comps = self.get_engine_refs();
222        comps.aux.start_time = chrono::Local::now();
223        comps.state.set_primitive_int(
224            comps.aux,
225            PRIMITIVES.year,
226            comps.aux.start_time.year().into(),
227            true,
228        );
229        comps.state.set_primitive_int(
230            comps.aux,
231            PRIMITIVES.month,
232            (comps.aux.start_time.month() as i32).into(),
233            true,
234        );
235        comps.state.set_primitive_int(
236            comps.aux,
237            PRIMITIVES.day,
238            (comps.aux.start_time.day() as i32).into(),
239            true,
240        );
241        comps.state.set_primitive_int(
242            comps.aux,
243            PRIMITIVES.time,
244            (((comps.aux.start_time.hour() * 60) + comps.aux.start_time.minute()) as i32).into(),
245            true,
246        );
247        comps.push_every(PRIMITIVES.everyjob);
248        comps.colon = Colon::new(f);
249        comps.top_loop()
250    }
251
252    /// Compile a `.tex` file. All finished pages are passed to the provided continuation.
253    ///
254    /// #### Errors
255    /// On TeX errors
256    fn do_file_default<
257        F: FnMut(&mut EngineReferences<Self::Types>, VNode<Self::Types>) -> TeXResult<(), Self::Types>,
258    >(
259        &mut self,
260        s: &str,
261        f: F,
262    ) -> TeXResult<(), Self::Types> {
263        log::debug!("Running file {}", s);
264        {
265            let mut comps = self.get_engine_refs();
266            let file = comps.filesystem.get(s);
267            let Some(parent) = file.path().parent() else {
268                return Err(TeXError::General(format!("Invalid file {s}")));
269            };
270            comps.filesystem.set_pwd(parent.to_path_buf());
271            let Some(filename) = file
272                .path()
273                .file_stem()
274                .and_then(|s| s.to_str().map(ToString::to_string))
275            else {
276                return Err(TeXError::General(format!("Invalid init file {s}")));
277            };
278            comps.aux.jobname = filename;
279            comps.push_file(file);
280        }
281        self.run(f)
282    }
283    /// Registers all primitives of plain TeX and sets the default variables.
284    fn initialize_tex_primitives(&mut self) {
285        super::commands::tex::register_tex_primitives(self);
286        let mag = PRIMITIVES.mag;
287        let fam = PRIMITIVES.fam;
288        let refs = self.get_engine_refs();
289        refs.state
290            .set_primitive_int(refs.aux, mag, (1000).into(), true);
291        refs.state
292            .set_primitive_int(refs.aux, fam, (-1).into(), true);
293    }
294
295    /// Initialize the engine by processing `plain.tex`.
296    /// #### Errors
297    /// On TeX errors
298    fn initialize_plain_tex(&mut self) -> TeXResult<(), Self::Types> {
299        self.initialize_tex_primitives();
300        self.init_file("plain.tex")
301    }
302
303    /// Registers all primitives of plain TeX, e-TeX and sets the default variables.
304    fn initialize_etex_primitives(&mut self) {
305        self.initialize_tex_primitives();
306        super::commands::etex::register_etex_primitives(self);
307    }
308
309    /// Initialize the engine by processing `eplain.tex`.
310    /// #### Errors
311    /// On TeX errors
312    fn initialize_eplain_tex(&mut self) -> TeXResult<(), Self::Types> {
313        self.initialize_etex_primitives();
314        self.init_file("eplain.tex")
315    }
316
317    /// Initialized the engine by processing `latex.ltx`. Only call this (for modern LaTeX setups)
318    /// after calling [`initialize_etex_primitives`](TeXEngine::initialize_etex_primitives) first.
319    /// #### Errors
320    /// On TeX errors
321    fn load_latex(&mut self) -> TeXResult<(), Self::Types> {
322        self.init_file("latex.ltx")
323    }
324}
325
326/// Default implementation of a [`TeXEngine`] for the provided [`EngineTypes`].
327pub struct DefaultEngine<ET: EngineTypes> {
328    pub aux: EngineAux<ET>,
329    pub state: ET::State,
330    pub filesystem: ET::FileSystem,
331    pub fontsystem: ET::FontSystem,
332    pub mouth: ET::Mouth,
333    pub gullet: ET::Gullet,
334    pub stomach: ET::Stomach,
335}
336impl<ET: EngineTypes> Default for DefaultEngine<ET> {
337    fn default() -> Self {
338        let mut memory = MemoryManager::default();
339        let mut aux = EngineAux {
340            outputs: ET::Outputs::new(),
341            error_handler: ET::ErrorHandler::new(),
342            start_time: chrono::Local::now(),
343            extension: ET::Extension::new(&mut memory),
344            memory,
345            jobname: String::new(),
346        };
347        let fontsystem = ET::FontSystem::new(&mut aux);
348        let mut state = ET::State::new(fontsystem.null(), &mut aux);
349        let mut mouth = ET::Mouth::new(&mut aux, &mut state);
350        let gullet = ET::Gullet::new(&mut aux, &mut state, &mut mouth);
351        let stomach = ET::Stomach::new(&mut aux, &mut state);
352        Self {
353            state,
354            aux,
355            fontsystem,
356            filesystem: ET::FileSystem::new(crate::utils::PWD.to_path_buf()),
357            mouth,
358            gullet,
359            stomach,
360        }
361    }
362}
363impl<ET: EngineTypes> TeXEngine for DefaultEngine<ET> {
364    type Types = ET;
365    fn get_engine_refs(&mut self) -> EngineReferences<ET> {
366        EngineReferences {
367            aux: &mut self.aux,
368            state: &mut self.state,
369            filesystem: &mut self.filesystem,
370            fontsystem: &mut self.fontsystem,
371            mouth: &mut self.mouth,
372            gullet: &mut self.gullet,
373            stomach: &mut self.stomach,
374            colon: Colon::default(),
375        }
376    }
377}
378/// A plain TeX engine with default components.
379pub type PlainTeXEngine = DefaultEngine<DefaultPlainTeXEngineTypes>;
380
381/** Additional components we want to add to a [`EngineReferences`] can be implemented here.
382   Notably, `()` extends this trait if we don't need any additional components.
383*/
384pub trait EngineExtension<ET: EngineTypes> {
385    fn new(memory: &mut MemoryManager<ET::Token>) -> Self;
386}
387impl<ET: EngineTypes<Extension = ()>> EngineExtension<ET> for () {
388    fn new(_memory: &mut MemoryManager<ET::Token>) -> Self {}
389}
390
391impl<ET: EngineTypes> EngineReferences<'_, ET> {
392    /// Runs the provided closure and prints the result to `\write-1` iff `\tracingcommands > 0`.
393    pub fn trace_command<D: std::fmt::Display, F: FnOnce(&mut Self) -> D>(&mut self, f: F) {
394        let trace = self.state.get_primitive_int(PRIMITIVES.tracingcommands)
395            > <ET::Num as NumSet>::Int::default();
396        if trace {
397            let d = f(self);
398            self.aux.outputs.write_neg1(format_args!("{{{d}}}"));
399        }
400    }
401    /// Entry point for compilation. This function is called by [`TeXEngine::do_file_default`].
402    /// #### Errors
403    /// On TeX errors
404    pub fn top_loop(&mut self) -> TeXResult<(), ET> {
405        crate::expand_loop!(ET::Stomach::every_top(self) => token => {
406            if token.is_primitive() == Some(PRIMITIVES.noexpand) {
407                let _ = self.get_next(false);
408                continue
409            }
410        }; self,
411            ResolvedToken::Tk { char, code } => ET::Stomach::do_char(self, token, char, code)?,
412            ResolvedToken::Cmd(Some(TeXCommand::Char {char, code})) => ET::Stomach::do_char(self, token, *char, *code)?,
413            ResolvedToken::Cmd(None) => TeXError::undefined(self.aux,self.state,self.mouth,&token)?,
414            ResolvedToken::Cmd(Some(cmd)) => crate::do_cmd!(self,token,cmd)
415        );
416        Ok(())
417    }
418}
419
420/// Expands tokens until a non-expandable Token is found, the [`ResolvedToken`] of which is then matched by the
421/// provided `$case` patterns.
422#[macro_export]
423macro_rules! expand_loop {
424    ($engine:ident,$tk:ident,$($case:tt)*) => {{
425        $crate::expand_loop!(ET;$engine,$tk,$($case)*)
426    }};
427    ($then:expr => $engine:ident,$tk:ident,$($case:tt)*) => {{
428        $then;
429        while let Some($tk) = $engine.get_next(false)? {
430            $crate::expand!($engine,$tk;$($case)*);
431            $then;
432        }
433    }};
434    ($then:expr => $tk:ident => $first:expr; $engine:ident,$($case:tt)*) => {{
435        $then;
436        while let Some($tk) = $engine.get_next(false)? {
437            $first;
438            $crate::expand!($engine,$tk;$($case)*);
439            $then;
440        }
441    }};
442    ($tk:ident => $first:expr; $engine:ident,$($case:tt)*) => {{
443        while let Some($tk) = $engine.get_next(false)? {
444            $first;
445            $crate::expand!($engine,$tk;$($case)*);
446        }
447    }};
448    ($ET:ty; $engine:ident,$tk:ident,$($case:tt)*) => {{
449        while let Some($tk) = $engine.get_next(false)? {
450            $crate::expand!($ET;$engine,$tk;$($case)*);
451        }
452    }};
453    ($ET:ty; $tk:ident => $first:expr; $engine:ident,$($case:tt)*) => {{
454        while let Some($tk) = $engine.get_next(false)? {
455            $first;
456            $crate::expand!($ET;$engine,$tk;$($case)*);
457        }
458    }}
459}
460
461/// Expands the provided token or, if not expandable, matches the [`ResolvedToken`] against the provided `$case` patterns.
462#[macro_export]
463macro_rules! expand {
464    ($engine:ident,$tk:expr;$($case:tt)*) => {
465        $crate::expand!(ET;$engine,$tk;$($case)*)
466    };
467    ($ET:ty; $engine:ident,$token:expr;$($case:tt)*) => {
468        let cmd = <<$ET as EngineTypes>::Gullet as $crate::engine::gullet::Gullet<$ET>>::resolve($engine.state,&$token);
469        match cmd {
470            $crate::commands::ResolvedToken::Cmd(Some($crate::commands::TeXCommand::Macro(m))) =>
471                <<$ET as EngineTypes>::Gullet as $crate::engine::gullet::Gullet<$ET>>::do_macro($engine,m.clone(),$token)?,
472            $crate::commands::ResolvedToken::Cmd(Some($crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Conditional(cond)})) =>
473                <<$ET as EngineTypes>::Gullet as $crate::engine::gullet::Gullet<$ET>>::do_conditional($engine,*name,$token,*cond,false)?,
474            $crate::commands::ResolvedToken::Cmd(Some($crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Expandable(e)})) =>
475                <<$ET as EngineTypes>::Gullet as $crate::engine::gullet::Gullet<$ET>>::do_expandable($engine,*name,$token,*e)?,
476            $crate::commands::ResolvedToken::Cmd(Some($crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::SimpleExpandable(e)})) =>
477                <<$ET as EngineTypes>::Gullet as $crate::engine::gullet::Gullet<$ET>>::do_simple_expandable($engine,*name,$token,*e)?,
478            $($case)*
479        }
480    }
481}
482
483/// Default treatment of unexpandable tokens, i.e. passed to the relevant [`Stomach`] method or throws
484/// [`ErrorHandler::not_allowed_in_mode`] errors.
485#[macro_export]
486macro_rules! do_cmd {
487    ($engine:ident,$token:expr,$cmd:ident) => {
488        $crate::do_cmd!(ET;$engine,$token,$cmd)
489    };
490    ($ET:ty;$engine:ident,$token:expr,$cmd:ident) => {
491        match $cmd {
492            /*$crate::commands::TeXCommand::CharDef(char) if <$ET as EngineTypes>::Stomach::data_mut($engine.stomach).mode().is_math() =>
493                <$ET as EngineTypes>::Stomach::do_char_in_math($engine, *char)?,*/
494            $crate::commands::TeXCommand::CharDef(char)  => <$ET as EngineTypes>::Stomach::do_char($engine, $token, *char, CommandCode::Other)?,
495            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Unexpandable { scope, apply }} =>
496                <$ET as EngineTypes>::Stomach::do_unexpandable($engine, *name, *scope,$token, *apply)?,
497            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Assignment(assign)} =>
498                <$ET as EngineTypes>::Stomach::do_assignment($engine, *name, $token, *assign,false)?,
499            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Int {  assign: Some(assign), .. }} =>
500                <$ET as EngineTypes>::Stomach::do_assignment($engine, *name, $token, *assign,false)?,
501            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Dim { assign: Some(assign), .. }} =>
502                <$ET as EngineTypes>::Stomach::do_assignment($engine, *name, $token, *assign,false)?,
503            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Skip { assign: Some(assign), .. }} =>
504                <$ET as EngineTypes>::Stomach::do_assignment($engine, *name, $token, *assign,false)?,
505            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::MuSkip { assign: Some(assign), .. }} =>
506                <$ET as EngineTypes>::Stomach::do_assignment($engine, *name, $token, *assign,false)?,
507            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::FontCmd { assign: Some(assign), .. }} =>
508                <$ET as EngineTypes>::Stomach::do_assignment($engine, *name, $token, *assign,false)?,
509            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Box(read)} =>
510                <$ET as EngineTypes>::Stomach::do_box($engine, *name, $token, *read)?,
511            $crate::commands::TeXCommand::Font(f) =>
512                <$ET as EngineTypes>::Stomach::assign_font($engine, $token, f.clone(),false)?,
513            $crate::commands::TeXCommand::IntRegister(u) =>
514                <$ET as EngineTypes>::Stomach::assign_int_register($engine, *u,false,$token)?,
515            $crate::commands::TeXCommand::DimRegister(u) =>
516                <$ET as EngineTypes>::Stomach::assign_dim_register($engine, *u,false,$token)?,
517            $crate::commands::TeXCommand::SkipRegister(u) =>
518                <$ET as EngineTypes>::Stomach::assign_skip_register($engine, *u,false,$token)?,
519            $crate::commands::TeXCommand::MuSkipRegister(u) =>
520               <$ET as EngineTypes>::Stomach::assign_muskip_register($engine, *u,false,$token)?,
521            $crate::commands::TeXCommand::ToksRegister(u) =>
522                <$ET as EngineTypes>::Stomach::assign_toks_register($engine,$token, *u,false)?,
523            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::Whatsit { get, .. }} =>
524                <$ET as EngineTypes>::Stomach::do_whatsit($engine, *name,$token, *get)?,
525            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::PrimitiveInt} =>
526                <$ET as EngineTypes>::Stomach::assign_primitive_int($engine,*name,false,$token)?,
527            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::PrimitiveDim} =>
528                <$ET as EngineTypes>::Stomach::assign_primitive_dim($engine,*name,false,$token)?,
529            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::PrimitiveSkip} =>
530                <$ET as EngineTypes>::Stomach::assign_primitive_skip($engine,*name,false,$token)?,
531            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::PrimitiveMuSkip} =>
532                <$ET as EngineTypes>::Stomach::assign_primitive_muskip($engine,*name,false,$token)?,
533            $crate::commands::TeXCommand::Primitive{name,cmd:$crate::commands::PrimitiveCommand::PrimitiveToks} =>
534                <$ET as EngineTypes>::Stomach::assign_primitive_toks($engine,$token,*name,false)?,
535            $crate::commands::TeXCommand::MathChar(u) if <$ET as EngineTypes>::Stomach::data_mut($engine.stomach).mode().is_math() =>
536                <$ET as EngineTypes>::Stomach::do_mathchar($engine,*u,Some($token)),
537            $crate::commands::TeXCommand::Primitive{cmd:$crate::commands::PrimitiveCommand::Relax,..} => (),
538            $crate::commands::TeXCommand::Primitive{
539                cmd:$crate::commands::PrimitiveCommand::Int { .. } |
540                    $crate::commands::PrimitiveCommand::Dim { .. } |
541                    $crate::commands::PrimitiveCommand::Skip { .. } |
542                    $crate::commands::PrimitiveCommand::MuSkip { .. } |
543                    $crate::commands::PrimitiveCommand::FontCmd { .. }
544                ,name
545            } =>
546                TeXError::not_allowed_in_mode($engine.aux,$engine.state,$engine.mouth,*name,
547                    <$ET as EngineTypes>::Stomach::data_mut($engine.stomach).mode()
548                )?,
549            $crate::commands::TeXCommand::MathChar(_) => 
550                TeXError::not_allowed_in_mode($engine.aux,$engine.state,$engine.mouth,
551                    $crate::commands::primitives::PRIMITIVES.mathchar,
552                    <$ET as EngineTypes>::Stomach::data_mut($engine.stomach).mode()
553                )?,
554            $crate::commands::TeXCommand::Macro(_) |
555            $crate::commands::TeXCommand::Primitive{ cmd:$crate::commands::PrimitiveCommand::Conditional { .. } |
556                $crate::commands::PrimitiveCommand::Expandable { .. } |
557                $crate::commands::PrimitiveCommand::SimpleExpandable { .. },..
558            } | TeXCommand::Char {..} => unreachable!(),
559        }
560    }
561}