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                    match r.read(
294                        aux.memory.cs_interner_mut(),
295                        state.get_catcode_scheme(),
296                        state.get_endline_char(),
297                        |t| ret.push(t),
298                    ) {
299                        Ok(_) => (),
300                        Err(e) => e.recover(aux, state, self)?,
301                    }
302                    self.with_list(|ls| ls.extend(ret.into_iter().rev()));
303                }
304                return Ok(());
305            }
306        }
307        Ok(())
308    }
309
310    fn line_number(&self) -> usize {
311        for s in self.inputs.iter().rev() {
312            if let TokenSource::File(s, _) = s {
313                return s.line();
314            }
315        }
316        0
317    }
318
319    fn push_macro_exp(&mut self, mut exp: MacroExpansion<ET::Token>) {
320        self.with_list(|v| exp.consume_rev(v));
321        self.return_args(exp.args);
322    }
323
324    fn push_exp(&mut self, exp: &TokenList<ET::Token>) {
325        self.with_list(|v| v.extend(exp.0.iter().rev().cloned()));
326    }
327
328    fn push_vec(&mut self, exp: Vec<ET::Token>) {
329        self.with_list(|v| v.extend(exp.into_iter().rev()));
330    }
331    fn push_slice_rev(&mut self, exp: &[ET::Token]) {
332        self.with_list(|v| v.extend(exp.iter().cloned()));
333    }
334
335    fn push_string(&mut self, s: StringLineSource<ET::Char>) {
336        self.inputs
337            .push(TokenSource::String(InputTokenizer::new(s)));
338    }
339
340    fn requeue(&mut self, t: ET::Token) {
341        self.with_list(|v| v.push(t));
342    }
343
344    fn push_file(&mut self, f: ET::File) {
345        //self.clean();
346        let id = f.sourceref();
347        let s = match f.line_source() {
348            Ok(s) => s,
349            Err(p) => panic!("File {} has no line source",p.display())
350        };
351        let rf = SourceReference {
352            file: id,
353            line: 0,
354            column: 0,
355        };
356        self.inputs
357            .push(TokenSource::File(InputTokenizer::new(s), id));
358        self.start_ref.push(rf);
359    }
360
361    fn get_next(
362        &mut self,
363        aux: &mut EngineAux<ET>,
364        state: &ET::State,
365    ) -> Result<Option<ET::Token>, InvalidCharacter<ET::Char>> {
366        while let Some(src) = self.inputs.last_mut() {
367            match src {
368                TokenSource::Vec(v) => match v.pop() {
369                    Some(t) => return Ok(Some(t)),
370                    _ => {
371                        if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
372                            self.vecs.push(v);
373                        }
374                    }
375                },
376                TokenSource::String(s) => {
377                    match s.get_next(
378                        aux.memory.cs_interner_mut(),
379                        state.get_catcode_scheme(),
380                        state.get_endline_char(),
381                    ) {
382                        Ok(Some(t)) => return Ok(Some(t)),
383                        Ok(None) => return Ok(Some(self.end_file(aux, state))),
384                        Err(c) => {
385                            c.recover::<_, InvalidCharacter<_>>(aux, state, self)?;
386                            continue;
387                        }
388                    }
389                }
390                TokenSource::File(s, _) => {
391                    let cc: &CategoryCodeScheme<ET::Char> = state.get_catcode_scheme();
392                    let endline: Option<ET::Char> = state.get_endline_char();
393                    match s.get_next(aux.memory.cs_interner_mut(), cc, endline) {
394                        Ok(Some(t)) => return Ok(Some(t)),
395                        Ok(None) => return Ok(Some(self.end_file(aux, state))),
396                        Err(c) => {
397                            c.recover::<_, InvalidCharacter<_>>(aux, state, self)?;
398                            continue;
399                        }
400                    }
401                }
402            }
403        }
404        Ok(None)
405    }
406
407    fn iterate<R, E, F: FnMut(&mut EngineAux<ET>, ET::Token) -> TeXResult<Option<R>, ET>>(
408        &mut self,
409        aux: &mut EngineAux<ET>,
410        state: &ET::State,
411        mut cont: F,
412        eof: E,
413    ) -> TeXResult<R, ET>
414    where
415        E: Fn(&EngineAux<ET>, &ET::State, &mut Self) -> TeXResult<(), ET>,
416    {
417        'top: loop {
418            match self.inputs.last_mut() {
419                Some(TokenSource::Vec(v)) => {
420                    while let Some(t) = v.pop() {
421                        if let Some(r) = cont(aux, t)? {
422                            return Ok(r);
423                        }
424                    }
425                    if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
426                        self.vecs.push(v);
427                    } else {
428                        unreachable!()
429                    }
430                }
431                Some(TokenSource::String(s)) => {
432                    let cc = state.get_catcode_scheme();
433                    let endline = state.get_endline_char();
434                    loop {
435                        match s.get_next(aux.memory.cs_interner_mut(), cc, endline) {
436                            Ok(Some(t)) => {
437                                if let Some(r) = cont(aux, t)? {
438                                    return Ok(r);
439                                }
440                            }
441                            Err(c) => {
442                                c.recover::<_, TeXError<_>>(aux, state, self)?;
443                                continue 'top;
444                            }
445                            Ok(None) => {
446                                eof(aux, state, self)?;
447                                continue 'top;
448                            }
449                        }
450                    }
451                }
452                Some(TokenSource::File(s, _)) => {
453                    let cc = state.get_catcode_scheme();
454                    let endline = state.get_endline_char();
455                    loop {
456                        match s.get_next(aux.memory.cs_interner_mut(), cc, endline) {
457                            Ok(Some(t)) => {
458                                if let Some(r) = cont(aux, t)? {
459                                    return Ok(r);
460                                }
461                            }
462                            Err(c) => {
463                                c.recover::<_, TeXError<_>>(aux, state, self)?;
464                                continue 'top;
465                            }
466                            Ok(None) => {
467                                eof(aux, state, self)?;
468                                continue 'top;
469                            }
470                        }
471                    }
472                }
473                None => eof(aux, state, self)?,
474            }
475        }
476    }
477
478    fn preview(
479        &self,
480        int: &<ET::CSName as CSName<ET::Char>>::Handler,
481        cc: &CategoryCodeScheme<ET::Char>,
482        esc: Option<ET::Char>,
483    ) -> String {
484        let mut str = String::new();
485        for src in self.inputs.iter().rev() {
486            match src {
487                //TokenSource::TokenList(s) => s.preview(int,cc,esc,&mut str),
488                TokenSource::String(s) => s.preview(&mut 1000, &mut str).unwrap(),
489                //TokenSource::Expansion(s) => s.preview(int,cc,esc,&mut str),
490                TokenSource::File(s, _) => {
491                    s.preview(&mut 1000, &mut str).unwrap();
492                    break;
493                }
494                TokenSource::Vec(v) => {
495                    for t in v.iter().rev().take(1000) {
496                        t.display_fmt(int, cc, esc, &mut str).unwrap()
497                    }
498                } /*TokenSource::Requeued(t) => {
499                      t.display_fmt(int,cc,esc,&mut str).unwrap()
500                  }*/
501            }
502        }
503        str
504    }
505}
506
507impl<ET: EngineTypes> DefaultMouth<ET> {
508    /// Trivial conversion between different compatible [`EngineTypes`].
509    pub fn into<ET2: EngineTypes<Token = ET::Token, File = ET::File>>(self) -> DefaultMouth<ET2> {
510        DefaultMouth {
511            inputs: self.inputs,
512            args: self.args,
513            start_ref: self.start_ref,
514            vecs: self.vecs,
515        }
516    }
517    /// Less trivial conversion between different [`EngineTypes`] with compatible [`Token`]s.
518    pub fn into_tokens<
519        ET2: EngineTypes<Char = ET::Char, File = ET::File>,
520        F: FnMut(ET::Token) -> ET2::Token,
521    >(
522        self,
523        mut token: F,
524    ) -> DefaultMouth<ET2> {
525        DefaultMouth {
526            inputs: self
527                .inputs
528                .into_iter()
529                .map(|s| match s {
530                    TokenSource::String(s) => TokenSource::String(s),
531                    TokenSource::File(s, id) => TokenSource::File(s, id),
532                    TokenSource::Vec(v) => {
533                        TokenSource::Vec(v.into_iter().map(&mut token).collect())
534                    }
535                })
536                .collect(),
537            args: self.args.map(|[a0, a1, a2, a3, a4, a5, a6, a7, a8]| {
538                [
539                    a0.into_iter().map(&mut token).collect(),
540                    a1.into_iter().map(&mut token).collect(),
541                    a2.into_iter().map(&mut token).collect(),
542                    a3.into_iter().map(&mut token).collect(),
543                    a4.into_iter().map(&mut token).collect(),
544                    a5.into_iter().map(&mut token).collect(),
545                    a6.into_iter().map(&mut token).collect(),
546                    a7.into_iter().map(&mut token).collect(),
547                    a8.into_iter().map(&mut token).collect(),
548                ]
549            }),
550            start_ref: self.start_ref,
551            vecs: self
552                .vecs
553                .into_iter()
554                .map(|v| v.into_iter().map(&mut token).collect())
555                .collect(),
556        }
557    }
558    fn with_list<Fn: FnOnce(&mut Vec<ET::Token>)>(&mut self, f: Fn) {
559        match self.inputs.last_mut() {
560            Some(TokenSource::Vec(v)) => f(v),
561            _ => {
562                let v = match self.vecs.pop() {
563                    Some(mut v) => {
564                        f(&mut v);
565                        v
566                    }
567                    None => {
568                        let mut v = Vec::new();
569                        f(&mut v);
570                        v
571                    }
572                };
573                self.inputs.push(TokenSource::Vec(v));
574            }
575        };
576    }
577    fn end_file(&mut self, aux: &mut EngineAux<ET>, state: &ET::State) -> ET::Token {
578        match self.inputs.pop() {
579            Some(TokenSource::File(f, _)) => {
580                self.start_ref.pop();
581                aux.outputs.file_close(f.source.path().display());
582            }
583            Some(TokenSource::String(_)) => (), //aux.outputs.file_close(""),
584            _ => unreachable!(),
585        };
586        let everyeof = state.get_primitive_tokens(PRIMITIVES.everyeof);
587        if everyeof.is_empty() {
588            ET::Token::eof()
589        } else {
590            self.requeue(ET::Token::eof());
591            self.push_exp(everyeof);
592            if let Some(TokenSource::Vec(v)) = self.inputs.last_mut() {
593                v.pop().unwrap()
594            } else {
595                unreachable!()
596            }
597        }
598    }
599}
600
601impl<ET: EngineTypes> EngineReferences<'_, ET> {
602    /// Push a file to the [`Mouth`] (see [`Mouth::push_file`]).
603    pub fn push_file(&mut self, f: ET::File) {
604        self.mouth.push_file(f);
605    }
606    /// Insert the value of a primitive token list (e.g. `\everypar`) into the [`Mouth`].
607    pub fn push_every(&mut self, every: PrimitiveIdentifier) {
608        let tks = self.state.get_primitive_tokens(every);
609        self.mouth.push_exp(tks);
610    }
611    /// Useful for debugging (see [`Mouth::preview`]).
612    pub fn preview(&self) -> String {
613        self.mouth.preview(
614            self.aux.memory.cs_interner(),
615            self.state.get_catcode_scheme(),
616            self.state.get_escape_char(),
617        )
618    }
619}