Skip to main content

tex_engine/engine/
mouth.rs

1/*! A [`Mouth`] provides a stream of [`Token`]s to be processed by an engine; either by tokenizing
2   a file or by returning the [`Token`]s expanded by a macro
3*/
4
5use crate::commands::primitives::{PrimitiveIdentifier, PRIMITIVES};
6use crate::engine::filesystem::SourceReference;
7use crate::engine::filesystem::{File, FileLineSource};
8use crate::engine::mouth::strings::{InputTokenizer, MouthState};
9use crate::engine::state::State;
10use crate::engine::utils::outputs::Outputs;
11use crate::engine::{EngineAux, EngineReferences, EngineTypes};
12use crate::prelude::{CommandCode, TokenList};
13use crate::tex::catcodes::CategoryCodeScheme;
14use crate::tex::characters::StringLineSource;
15use crate::tex::tokens::control_sequences::CSName;
16use crate::tex::tokens::token_lists::MacroExpansion;
17use crate::tex::tokens::Token;
18use crate::utils::errors::{InvalidCharacter, RecoverableError, TeXError, TeXResult};
19
20pub mod strings;
21
22/// A [`Mouth`] provides a stream of [`Token`]s to be processed by an engine; either by tokenizing
23/// a file or by returning the [`Token`]s expanded by a macro. Since a TeX engine spends most of its
24/// time processing and expanding [`Token`]s, the [`Mouth`] is likely the most performance critical component of the engine.
25///
26/// [`DefaultMouth`] is the default implementation of [`Mouth`] that has been quite well optimized.
27///
28/// During a run, most methods provided by the [`Mouth`] should *not* be called directly, since they circumvent the [Gullet](crate::engine::Gullet),
29/// which needs to occasionally do some bookkeeping (e.g. counting braces in an `\halign`).
30/// Instead, the [`Mouth`] should if possible be accessed through the [`EngineReferences`]
31/// or the [`Gullet`](crate::engine::gullet::Gullet) only.
32///
33/// Note that we do not require `ET:`[`EngineTypes`]`<`[`Mouth`](EngineTypes::Mouth)`=Self>` - this allows for
34/// implementing your own Mouth by just wrapping an existing implementation in a new wrapper struct and pass on functionality
35/// to the inner Mouth, which would otherwise
36/// fail since `ET::Mouth` would be the outer wrapper struct, not the inner one.
37pub trait Mouth<ET: EngineTypes> {
38    /// Create a new [`Mouth`]. May use [`EngineAux`] and [`State`], although in practice, the default implementation doesn't.
39    fn new(aux: &mut EngineAux<ET>, state: &mut ET::State) -> Self;
40    /// Push a file to the [`Mouth`]. The [`Mouth`] will tokenize the file contents and return the [`Token`]s lazily.
41    fn push_file(&mut self, f: ET::File);
42    /// Push a string to the [`Mouth`]. The [`Mouth`] will tokenize the string and return the [`Token`]s lazily.
43    fn push_string(&mut self, s: StringLineSource<ET::Char>);
44    /// Push a [`TokenList`] to the [`Mouth`] - e.g. from a token register or `\everypar`.
45    fn push_exp(&mut self, exp: &TokenList<ET::Token>);
46    /// Push a [`Vec`] of [`Token`]s to the [`Mouth`]. This is occasionally useful for things like `\write`.
47    fn push_vec(&mut self, exp: Vec<ET::Token>);
48    /// Push a slice of [`Token`]s to the [`Mouth`], assumed to be in reverse order (i.e. the first
49    /// token to return is the last one in the slice).
50    fn push_slice_rev(&mut self, exp: &[ET::Token]);
51    /// Push a [`MacroExpansion`] (with arguments already read) to the [`Mouth`]. The [`Mouth`] will return the [`Token`]s lazily,
52    /// resolving the parameter tokens in the expansion in the process.
53    fn push_macro_exp(&mut self, exp: MacroExpansion<ET::Token>);
54    /// Push a [`Token`] back to the [`Mouth`]. This is useful for e.g. `\futurelet`, `\expandafter`, or when
55    /// reading keywords, numbers, dimensions, etc. that often read "too far ahead" and need to back up.
56    /// This method should not be called directly, but rather through [`EngineReferences::requeue`]
57    /// or [`Gullet::requeue`](crate::engine::gullet::Gullet::requeue).
58    fn requeue(&mut self, t: ET::Token);
59    /// Get the next [`Token`] from the [`Mouth`].
60    /// This method should not be called directly, but rather through [`EngineReferences::get_next`]
61    /// or [`Gullet::get_next_opt`](crate::engine::gullet::Gullet::get_next).
62    /// #### Errors
63    fn get_next(
64        &mut self,
65        aux: &mut EngineAux<ET>,
66        state: &ET::State,
67    ) -> Result<Option<ET::Token>, InvalidCharacter<ET::Char>>;
68    /// Iterate over the [`Token`]s in the [`Mouth`] until `cont` returns `false`. Can be faster than repeatedly calling
69    /// [`get_next_opt`](Self::get_next), but
70    /// blocking both state changes and expanding macros. Useful for e.g. reading macro arguments or the expansion list
71    /// in `\def`.
72    /// This method should not be called directly, but rather through [`EngineReferences::iterate`]
73    /// or [`Gullet::iterate`](crate::engine::gullet::Gullet::iterate).
74    /// #### Errors
75    fn iterate<R, E, F: FnMut(&mut EngineAux<ET>, ET::Token) -> TeXResult<Option<R>, ET>>(
76        &mut self,
77        aux: &mut EngineAux<ET>,
78        state: &ET::State,
79        cont: F,
80        eof: E,
81    ) -> TeXResult<R, ET>
82    where
83        E: Fn(&EngineAux<ET>, &ET::State, &mut Self) -> TeXResult<(), ET>;
84    /// `\endinput` - removes the last file from the [`Mouth`] without inserting `\everyeof` or an [`EOF`](crate::tex::catcodes::CommandCode::EOF)
85    /// [`Token`].
86    /// #### Errors
87    fn endinput(
88        &mut self,
89        aux: &mut EngineAux<ET>,
90        state: &ET::State,
91    ) -> Result<(), InvalidCharacter<ET::Char>>;
92    /// clears the mouth at the end of a run, if desired.
93    fn finish(&mut self);
94
95    /// Get the current [`SourceReference`] of the [`Mouth`] (file/line/column).
96    fn current_sourceref(&self) -> SourceReference<<ET::File as File>::SourceRefID>;
97    /// The mouth (can) track(s) two [`SourceReference`]s: the current one (see [`current_sourceref`](Self::current_sourceref))
98    /// and the position
99    /// of the last [`Token`] encountered in the top-loop of an engine run that was not the result of an expansion.
100    /// The latter is returned by this function. The intuition being that this one indicates the start of the macro
101    ///responsible for what is currently happening, even if the Mouth is already further along because more [`Token`]s
102    ///have been eaten as arguments to a macro etc.
103    fn start_ref(&self) -> SourceReference<<ET::File as File>::SourceRefID>;
104    /// Tells the mouth to update the start reference to the current [`SourceReference`] (see [`start_ref`](Self::start_ref)).
105    fn update_start_ref(&mut self);
106    /// The current line number in the top-most file in the [`Mouth`].
107    fn line_number(&self) -> usize;
108    /// We (can) reuse an array of Token vectors for macro arguments and reuse it to avoid frequent memory allocations.
109    /// This method provides such an array. If it is not pushed to the mouth using [`push_macro_exp`](Self::push_macro_exp),
110    /// later, it should be given back to the mouth using [`return_args`](Self::return_args) later.
111    fn get_args(&mut self) -> [Vec<ET::Token>; 9];
112    /// Return the array of Token vectors to the mouth. Should only be called with an array that was previously obtained
113    /// using [`get_args`](Self::get_args).
114    fn return_args(&mut self, args: [Vec<ET::Token>; 9]);
115
116    /// Convenience method reading [`Token`]s in the [`Mouth`] until the next [EndGroup](crate::tex::catcodes::CommandCode::EndGroup)
117    ///[`Token`] is encountered and returns that. Useful whenever a group is to be taken; e.g. when reading macro arguments.
118    /// This method should not be called directly, but rather through [`EngineReferences::read_until_endgroup`]
119    /// or [`Gullet::read_until_endgroup`](crate::engine::gullet::Gullet::read_until_endgroup).
120    /// #### Errors
121    fn read_until_endgroup<E, F: FnMut(&mut EngineAux<ET>, ET::Token) -> TeXResult<(), ET>>(
122        &mut self,
123        aux: &mut EngineAux<ET>,
124        state: &ET::State,
125        mut cont: F,
126        eof: E,
127    ) -> TeXResult<ET::Token, ET>
128    where
129        E: Fn(&EngineAux<ET>, &ET::State, &mut Self) -> TeXResult<(), ET>,
130    {
131        let mut ingroups = 0;
132        self.iterate(
133            aux,
134            state,
135            |a, t| {
136                match t.command_code() {
137                    CommandCode::BeginGroup => ingroups += 1,
138                    CommandCode::EndGroup => {
139                        if ingroups == 0 {
140                            return Ok(Some(t));
141                        }
142                        ingroups -= 1;
143                    }
144                    CommandCode::Primitive if t.is_primitive() == Some(PRIMITIVES.noexpand) => {
145                        return Ok(None)
146                    }
147                    _ => (),
148                }
149                cont(a, t)?;
150                Ok(None)
151            },
152            eof,
153        )
154    }
155
156    /// For debugging purposes, this method returns a string representation of the upcoming stuff in the [`Mouth`].
157    fn preview(
158        &self,
159        int: &<ET::CSName as CSName<ET::Char>>::Handler,
160        cc: &CategoryCodeScheme<ET::Char>,
161        esc: Option<ET::Char>,
162    ) -> String;
163
164    fn file_trace(
165        &self,
166    ) -> impl Iterator<Item = SourceReference<<ET::File as File>::SourceRefID>> + '_;
167}
168
169enum TokenSource<T: Token, F: File<Char = T::Char>> {
170    String(InputTokenizer<T::Char, StringLineSource<T::Char>>),
171    File(InputTokenizer<T::Char, F::LineSource>, F::SourceRefID),
172    Vec(Vec<T>),
173}
174
175/// The default implementation of [`Mouth`]. Well optimized to be fast, but at the cost of not keeping track
176/// of "the depth of current macro expansions" - I found that to be an acceptable loss, since afaict, the only thing that
177/// is done with that information
178/// is to print a corresponding number of `.`s if `\tracingcommands` is set. By omitting that and just concatenating
179/// all expansions into a single Vec from which to `pop()`, we gain a massive speedup.
180/// #### Errors
181pub struct DefaultMouth<ET: EngineTypes> {
182    inputs: Vec<TokenSource<ET::Token, ET::File>>,
183    args: Option<[Vec<ET::Token>; 9]>,
184    start_ref: Vec<SourceReference<<ET::File as File>::SourceRefID>>,
185    vecs: Vec<Vec<ET::Token>>,
186}
187
188impl<ET: EngineTypes> Mouth<ET> for DefaultMouth<ET> {
189    fn new(_aux: &mut EngineAux<ET>, _state: &mut ET::State) -> Self {
190        Self {
191            inputs: Vec::new(),
192            args: Some(array_init::array_init(|_| Vec::new())),
193            start_ref: vec![],
194            vecs: vec![],
195        }
196    }
197
198    fn finish(&mut self) {
199        for s in self.inputs.drain(..) {
200            if let TokenSource::Vec(mut v) = s {
201                v.clear();
202                self.vecs.push(v);
203            }
204        }
205        self.start_ref.clear();
206    }
207
208    fn file_trace(
209        &self,
210    ) -> impl Iterator<Item = SourceReference<<ET::File as File>::SourceRefID>> + '_ {
211        self.inputs.iter().rev().filter_map(|s| {
212            if let TokenSource::File(f, id) = s {
213                Some(SourceReference {
214                    file: *id,
215                    line: f.line(),
216                    column: f.column(),
217                })
218            } else {
219                None
220            }
221        })
222    }
223
224    fn current_sourceref(&self) -> SourceReference<<ET::File as File>::SourceRefID> {
225        for s in self.inputs.iter().rev() {
226            if let TokenSource::File(f, id) = s {
227                return SourceReference {
228                    file: *id,
229                    line: f.line(),
230                    column: f.column(),
231                };
232            }
233        }
234        self.start_ref.last().copied().unwrap_or_default()
235    }
236    fn start_ref(&self) -> SourceReference<<ET::File as File>::SourceRefID> {
237        self.start_ref.last().copied().unwrap_or_default()
238    }
239    fn update_start_ref(&mut self) {
240        match self.inputs.last() {
241            Some(TokenSource::File(f, id)) => {
242                let rf = SourceReference {
243                    file: *id,
244                    line: f.line(),
245                    column: f.column(),
246                };
247                match self.start_ref.last_mut() {
248                    None => self.start_ref.push(rf),
249                    Some(s) => *s = rf,
250                }
251            }
252            Some(TokenSource::Vec(v)) if v.is_empty() => {
253                if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
254                    self.vecs.push(v);
255                } else {
256                    unreachable!()
257                }
258                self.update_start_ref();
259            }
260            _ => (),
261        }
262    }
263
264    fn get_args(&mut self) -> [Vec<ET::Token>; 9] {
265        match std::mem::take(&mut self.args) {
266            Some(a) => a,
267            None => unreachable!(), //array_init::array_init(|_| Vec::new())
268        }
269        //array_init::array_init(|_| Vec::new())
270    }
271
272    fn return_args(&mut self, mut exp: [Vec<ET::Token>; 9]) {
273        for a in &mut exp {
274            a.clear();
275        }
276        self.args = Some(exp);
277    }
278
279    fn endinput(
280        &mut self,
281        aux: &mut EngineAux<ET>,
282        state: &ET::State,
283    ) -> Result<(), InvalidCharacter<ET::Char>> {
284        for (i, s) in self.inputs.iter().enumerate().rev() {
285            if let TokenSource::File(f, _) = s {
286                aux.outputs.file_close(f.source.path().display());
287                let TokenSource::File(mut r, _) = self.inputs.remove(i) else {
288                    unreachable!()
289                };
290                self.start_ref.pop();
291                if r.state != MouthState::NewLine {
292                    let mut ret = Vec::new();
293                    let par = state.get_par_token();
294                    match r.read(
295                        aux.memory.cs_interner_mut(),
296                        state.get_catcode_scheme(),
297                        state.get_endline_char(),
298                        &par,
299                        |t| ret.push(t),
300                    ) {
301                        Ok(_) => (),
302                        Err(e) => e.recover(aux, state, self)?,
303                    }
304                    self.with_list(|ls| ls.extend(ret.into_iter().rev()));
305                }
306                return Ok(());
307            }
308        }
309        Ok(())
310    }
311
312    fn line_number(&self) -> usize {
313        for s in self.inputs.iter().rev() {
314            if let TokenSource::File(s, _) = s {
315                return s.line();
316            }
317        }
318        0
319    }
320
321    fn push_macro_exp(&mut self, mut exp: MacroExpansion<ET::Token>) {
322        self.with_list(|v| exp.consume_rev(v));
323        self.return_args(exp.args);
324    }
325
326    fn push_exp(&mut self, exp: &TokenList<ET::Token>) {
327        self.with_list(|v| v.extend(exp.0.iter().rev().cloned()));
328    }
329
330    fn push_vec(&mut self, exp: Vec<ET::Token>) {
331        self.with_list(|v| v.extend(exp.into_iter().rev()));
332    }
333    fn push_slice_rev(&mut self, exp: &[ET::Token]) {
334        self.with_list(|v| v.extend(exp.iter().cloned()));
335    }
336
337    fn push_string(&mut self, s: StringLineSource<ET::Char>) {
338        self.inputs
339            .push(TokenSource::String(InputTokenizer::new(s)));
340    }
341
342    fn requeue(&mut self, t: ET::Token) {
343        self.with_list(|v| v.push(t));
344    }
345
346    fn push_file(&mut self, f: ET::File) {
347        //self.clean();
348        let id = f.sourceref();
349        let s = match f.line_source() {
350            Ok(s) => s,
351            Err(p) => panic!("File {} has no line source", p.display()),
352        };
353        let rf = SourceReference {
354            file: id,
355            line: 0,
356            column: 0,
357        };
358        self.inputs
359            .push(TokenSource::File(InputTokenizer::new(s), id));
360        self.start_ref.push(rf);
361    }
362
363    fn get_next(
364        &mut self,
365        aux: &mut EngineAux<ET>,
366        state: &ET::State,
367    ) -> Result<Option<ET::Token>, InvalidCharacter<ET::Char>> {
368        while let Some(src) = self.inputs.last_mut() {
369            match src {
370                TokenSource::Vec(v) => match v.pop() {
371                    Some(t) => return Ok(Some(t)),
372                    _ => {
373                        if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
374                            self.vecs.push(v);
375                        }
376                    }
377                },
378                TokenSource::String(s) => {
379                    let par = state.get_par_token();
380                    match s.get_next(
381                        aux.memory.cs_interner_mut(),
382                        state.get_catcode_scheme(),
383                        state.get_endline_char(),
384                        &par,
385                    ) {
386                        Ok(Some(t)) => return Ok(Some(t)),
387                        Ok(None) => return Ok(Some(self.end_file(aux, state))),
388                        Err(c) => {
389                            c.recover::<_, InvalidCharacter<_>>(aux, state, self)?;
390                            continue;
391                        }
392                    }
393                }
394                TokenSource::File(s, _) => {
395                    let cc: &CategoryCodeScheme<ET::Char> = state.get_catcode_scheme();
396                    let endline: Option<ET::Char> = state.get_endline_char();
397                    let par = state.get_par_token();
398                    match s.get_next(aux.memory.cs_interner_mut(), cc, endline, &par) {
399                        Ok(Some(t)) => return Ok(Some(t)),
400                        Ok(None) => return Ok(Some(self.end_file(aux, state))),
401                        Err(c) => {
402                            c.recover::<_, InvalidCharacter<_>>(aux, state, self)?;
403                            continue;
404                        }
405                    }
406                }
407            }
408        }
409        Ok(None)
410    }
411
412    fn iterate<R, E, F: FnMut(&mut EngineAux<ET>, ET::Token) -> TeXResult<Option<R>, ET>>(
413        &mut self,
414        aux: &mut EngineAux<ET>,
415        state: &ET::State,
416        mut cont: F,
417        eof: E,
418    ) -> TeXResult<R, ET>
419    where
420        E: Fn(&EngineAux<ET>, &ET::State, &mut Self) -> TeXResult<(), ET>,
421    {
422        'top: loop {
423            match self.inputs.last_mut() {
424                Some(TokenSource::Vec(v)) => {
425                    while let Some(t) = v.pop() {
426                        if let Some(r) = cont(aux, t)? {
427                            return Ok(r);
428                        }
429                    }
430                    if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
431                        self.vecs.push(v);
432                    } else {
433                        unreachable!()
434                    }
435                }
436                Some(TokenSource::String(s)) => {
437                    let cc = state.get_catcode_scheme();
438                    let endline = state.get_endline_char();
439                    let par = state.get_par_token();
440                    loop {
441                        match s.get_next(aux.memory.cs_interner_mut(), cc, endline, &par) {
442                            Ok(Some(t)) => {
443                                if let Some(r) = cont(aux, t)? {
444                                    return Ok(r);
445                                }
446                            }
447                            Err(c) => {
448                                c.recover::<_, TeXError<_>>(aux, state, self)?;
449                                continue 'top;
450                            }
451                            Ok(None) => {
452                                eof(aux, state, self)?;
453                                continue 'top;
454                            }
455                        }
456                    }
457                }
458                Some(TokenSource::File(s, _)) => {
459                    let cc = state.get_catcode_scheme();
460                    let endline = state.get_endline_char();
461                    let par = state.get_par_token();
462                    loop {
463                        match s.get_next(aux.memory.cs_interner_mut(), cc, endline, &par) {
464                            Ok(Some(t)) => {
465                                if let Some(r) = cont(aux, t)? {
466                                    return Ok(r);
467                                }
468                            }
469                            Err(c) => {
470                                c.recover::<_, TeXError<_>>(aux, state, self)?;
471                                continue 'top;
472                            }
473                            Ok(None) => {
474                                eof(aux, state, self)?;
475                                continue 'top;
476                            }
477                        }
478                    }
479                }
480                None => eof(aux, state, self)?,
481            }
482        }
483    }
484
485    fn preview(
486        &self,
487        int: &<ET::CSName as CSName<ET::Char>>::Handler,
488        cc: &CategoryCodeScheme<ET::Char>,
489        esc: Option<ET::Char>,
490    ) -> String {
491        let mut str = String::new();
492        for src in self.inputs.iter().rev() {
493            match src {
494                //TokenSource::TokenList(s) => s.preview(int,cc,esc,&mut str),
495                TokenSource::String(s) => s.preview(&mut 1000, &mut str).unwrap(),
496                //TokenSource::Expansion(s) => s.preview(int,cc,esc,&mut str),
497                TokenSource::File(s, _) => {
498                    s.preview(&mut 1000, &mut str).unwrap();
499                    break;
500                }
501                TokenSource::Vec(v) => {
502                    for t in v.iter().rev().take(1000) {
503                        t.display_fmt(int, cc, esc, &mut str).unwrap()
504                    }
505                } /*TokenSource::Requeued(t) => {
506                      t.display_fmt(int,cc,esc,&mut str).unwrap()
507                  }*/
508            }
509        }
510        str
511    }
512}
513
514impl<ET: EngineTypes> DefaultMouth<ET> {
515    /// Trivial conversion between different compatible [`EngineTypes`].
516    pub fn into<ET2: EngineTypes<Token = ET::Token, File = ET::File>>(self) -> DefaultMouth<ET2> {
517        DefaultMouth {
518            inputs: self.inputs,
519            args: self.args,
520            start_ref: self.start_ref,
521            vecs: self.vecs,
522        }
523    }
524    /// Less trivial conversion between different [`EngineTypes`] with compatible [`Token`]s.
525    pub fn into_tokens<
526        ET2: EngineTypes<Char = ET::Char, File = ET::File>,
527        F: FnMut(ET::Token) -> ET2::Token,
528    >(
529        self,
530        mut token: F,
531    ) -> DefaultMouth<ET2> {
532        DefaultMouth {
533            inputs: self
534                .inputs
535                .into_iter()
536                .map(|s| match s {
537                    TokenSource::String(s) => TokenSource::String(s),
538                    TokenSource::File(s, id) => TokenSource::File(s, id),
539                    TokenSource::Vec(v) => {
540                        TokenSource::Vec(v.into_iter().map(&mut token).collect())
541                    }
542                })
543                .collect(),
544            args: self.args.map(|[a0, a1, a2, a3, a4, a5, a6, a7, a8]| {
545                [
546                    a0.into_iter().map(&mut token).collect(),
547                    a1.into_iter().map(&mut token).collect(),
548                    a2.into_iter().map(&mut token).collect(),
549                    a3.into_iter().map(&mut token).collect(),
550                    a4.into_iter().map(&mut token).collect(),
551                    a5.into_iter().map(&mut token).collect(),
552                    a6.into_iter().map(&mut token).collect(),
553                    a7.into_iter().map(&mut token).collect(),
554                    a8.into_iter().map(&mut token).collect(),
555                ]
556            }),
557            start_ref: self.start_ref,
558            vecs: self
559                .vecs
560                .into_iter()
561                .map(|v| v.into_iter().map(&mut token).collect())
562                .collect(),
563        }
564    }
565    fn with_list<Fn: FnOnce(&mut Vec<ET::Token>)>(&mut self, f: Fn) {
566        match self.inputs.last_mut() {
567            Some(TokenSource::Vec(v)) => f(v),
568            _ => {
569                let v = match self.vecs.pop() {
570                    Some(mut v) => {
571                        f(&mut v);
572                        v
573                    }
574                    None => {
575                        let mut v = Vec::new();
576                        f(&mut v);
577                        v
578                    }
579                };
580                self.inputs.push(TokenSource::Vec(v));
581            }
582        };
583    }
584    fn end_file(&mut self, aux: &mut EngineAux<ET>, state: &ET::State) -> ET::Token {
585        match self.inputs.pop() {
586            Some(TokenSource::File(f, _)) => {
587                self.start_ref.pop();
588                aux.outputs.file_close(f.source.path().display());
589            }
590            Some(TokenSource::String(_)) => (), //aux.outputs.file_close(""),
591            _ => unreachable!(),
592        };
593        let everyeof = state.get_primitive_tokens(PRIMITIVES.everyeof);
594        if everyeof.is_empty() {
595            ET::Token::eof()
596        } else {
597            self.requeue(ET::Token::eof());
598            self.push_exp(everyeof);
599            if let Some(TokenSource::Vec(v)) = self.inputs.last_mut() {
600                v.pop().unwrap()
601            } else {
602                unreachable!()
603            }
604        }
605    }
606}
607
608impl<ET: EngineTypes> EngineReferences<'_, ET> {
609    /// Push a file to the [`Mouth`] (see [`Mouth::push_file`]).
610    pub fn push_file(&mut self, f: ET::File) {
611        self.mouth.push_file(f);
612    }
613    /// Insert the value of a primitive token list (e.g. `\everypar`) into the [`Mouth`].
614    pub fn push_every(&mut self, every: PrimitiveIdentifier) {
615        let tks = self.state.get_primitive_tokens(every);
616        self.mouth.push_exp(tks);
617    }
618    /// Useful for debugging (see [`Mouth::preview`]).
619    pub fn preview(&self) -> String {
620        self.mouth.preview(
621            self.aux.memory.cs_interner(),
622            self.state.get_catcode_scheme(),
623            self.state.get_escape_char(),
624        )
625    }
626}