Skip to main content

texlang/vm/
streams.rs

1use std::path::PathBuf;
2
3use super::TexlangState;
4use crate::token::trace;
5use crate::token::Token;
6use crate::*;
7
8/// A stream of tokens generated on demand.
9///
10/// This trait describes a general stream of tokens where the front of the stream may
11/// retrieved using [TokenStream::next] or peeked at using [TokenStream::peek].
12/// In practice, all [TokenStreams](TokenStream) in Texlang
13/// are either [ExecutionInput], [ExpansionInput] or [UnexpandedStream].
14/// This trait exists to allow a generic function to accept any of these types.
15///
16/// # Note on lazy loading
17///
18/// The simplest example of a stream is a vector of tokens. However, streams are more general
19/// than this and can encompass situations in which the full contents cannot be determined in
20/// advance. This can be thought of as "lazy loading" for the tokens.
21/// The classic example of this kind of stream comes from the following LaTeX
22/// snippet:
23/// ```tex
24/// \makeatletter \do@
25/// ```
26/// Assuming the default TeX catcode map, if we were to parse this input all at once we would
27/// get three tokens: the control sequence `makeatletter`, the control sequence `do`, and a
28/// single character token with value `@` and catcode "other". This is not the correct result,
29/// though: the first control sequence changes the tokenization rules such that `@` is now
30/// an admissible character in the name of a control sequence. The correct input is thus
31/// the control sequence `makeatletter` followed by the control sequence `do@`.
32pub trait TokenStream {
33    /// The type of the custom state in the VM.
34    type S;
35
36    /// Gets the next token in the stream.
37    ///
38    /// This method is almost the same
39    /// as the `next` method in Rust's iterator trait, except a stream can return an error.
40    ///
41    /// As with iterators, a result of `Ok(None)` indicates that the stream is exhausted.
42    fn next(&mut self) -> Result<Option<Token>, Box<error::Error>>;
43
44    /// Peeks at the next token in the stream without removing it.
45    ///
46    /// In many situations it is necessary to examine the next token without consuming it.
47    /// For example when reading an integer from a stream, one needs to peek at the next token
48    /// to see if it is a digit and thus extends the currently parsed integer.
49    /// Consuming the token with [TokenStream::next] is not
50    /// correct in this situation if the token is not a digit.
51    ///
52    /// For consumers, it is important to note that the peek method requires a mutable reference
53    /// to the stream. This is because some mutable processing may be needed in order to determine
54    /// what the next token is. For example:
55    ///
56    /// 1. When reading tokens from a file, peeking at the next token may involve reading more bytes
57    ///     from the file and thus mutating the file pointer. sThis mutations is easy to undo in
58    ///     general.
59    ///
60    /// 1. When performing expansion on a stream, the next token in the stream may need to be expanded
61    ///     rather than returned. The next token will be the first token in the expansion in this case,
62    ///     or the following token in the remaining stream if the expansion returns no tokens.
63    ///     This mutation is generally irreversible.
64    fn peek(&mut self) -> Result<Option<&Token>, Box<error::Error>>;
65
66    /// Consumes the next token in the stream without returning it.
67    ///
68    /// This method is mostly to make code self-documenting. It is typically used in
69    /// situations where a peek has already occurred, and the token itself is not needed.
70    fn consume(&mut self) -> Result<(), Box<error::Error>> {
71        self.next().map(|_| ())
72    }
73
74    /// Returns a reference to the VM.
75    fn vm(&self) -> &vm::VM<Self::S>;
76
77    /// Returns a reference to the commands map.
78    #[inline]
79    fn commands_map(&self) -> &command::Map<Self::S> {
80        &self.vm().commands_map
81    }
82
83    /// Returns a reference to the custom state.
84    #[inline]
85    fn state(&self) -> &Self::S {
86        &self.vm().state
87    }
88
89    fn trace(&self, token: Token) -> trace::SourceCodeTrace {
90        self.vm().trace(token)
91    }
92
93    fn trace_end_of_input(&self) -> trace::SourceCodeTrace {
94        self.vm().internal.tracer.trace_end_of_input()
95    }
96}
97
98/// A [TokenStream] that performs expansion.
99///
100/// The unexpanded tokens are retrieved from the unexpanded stream returned by the
101/// [unexpanded](ExpandedStream::unexpanded) method.
102#[repr(transparent)]
103pub struct ExpandedStream<S>(UnexpandedStream<S>);
104
105impl<S> std::convert::AsMut<ExpandedStream<S>> for ExpandedStream<S> {
106    fn as_mut(&mut self) -> &mut ExpandedStream<S> {
107        self
108    }
109}
110
111impl<S: TexlangState> ExpandedStream<S> {
112    /// Returns the underlying unexpanded stream.
113    pub fn unexpanded(&mut self) -> &mut UnexpandedStream<S> {
114        &mut self.0
115    }
116
117    /// Expand the next token in the input.
118    ///
119    /// This method only expands a single token. If, after the expansion, the next token
120    /// is expandable it will not be expanded.
121    pub fn expand_once(&mut self) -> Result<bool, Box<error::Error>> {
122        stream::expand_once(&mut self.unexpanded().0)
123    }
124}
125
126impl<S: TexlangState> TokenStream for ExpandedStream<S> {
127    type S = S;
128
129    #[inline]
130    fn next(&mut self) -> Result<Option<Token>, Box<error::Error>> {
131        stream::next_expanded(&mut self.unexpanded().0)
132    }
133
134    #[inline]
135    fn peek(&mut self) -> Result<Option<&Token>, Box<error::Error>> {
136        stream::peek_expanded(&mut self.unexpanded().0)
137    }
138
139    #[inline]
140    fn vm(&self) -> &vm::VM<Self::S> {
141        &self.0 .0
142    }
143}
144
145/// Stream that returns input tokens without performing expansion.
146///
147/// The unexpanded stream is used when reading tokens without performing expansion;
148/// e.g., when reading the replacement text for a macro defined using `\def`.
149///
150/// It be obtained from either the [ExecutionInput] or the [ExpansionInput]
151/// using the [ExpandedStream] trait methods.
152#[repr(transparent)]
153pub struct UnexpandedStream<S>(vm::VM<S>);
154
155impl<S: TexlangState> TokenStream for UnexpandedStream<S> {
156    type S = S;
157
158    #[inline]
159    fn next(&mut self) -> Result<Option<Token>, Box<error::Error>> {
160        stream::next_unexpanded(&mut self.0)
161    }
162
163    #[inline]
164    fn peek(&mut self) -> Result<Option<&Token>, Box<error::Error>> {
165        stream::peek_unexpanded(&mut self.0)
166    }
167
168    #[inline]
169    fn vm(&self) -> &vm::VM<S> {
170        &self.0
171    }
172}
173
174/// Input type for expansion primitives.
175///
176/// This type provides:
177///
178/// - Access to the input stream (with or without expansion). Its implementation of the [TokenStream]
179///     trait returns expanded tokens.
180///     To read the input stream without performing expansion, use the
181///     [unexpanded](ExpandedStream::unexpanded) method.
182///
183/// - Read only access to the VM.
184///
185/// - The ability to push source code or token expansions to the front of the input stream.
186///     For source code use [ExpansionInput::push_source];
187///     for tokens use [ExpansionInput::push_expansion] or [ExpansionInput::expansions_mut].
188///
189/// - Access to token buffers using the [ExpansionInput::checkout_token_buffer] and
190///     [ExpansionInput::return_token_buffer] methods.
191///
192/// This type is also used in the parsing code for situations where both an
193/// [ExpansionInput] or [ExecutionInput] is accepted. We use this type because
194/// it has only read access to the VM, and so casting does not escalate privileges.
195#[repr(transparent)]
196// TODO: shouldn't this be in the command module no vm module?
197// TODO: it should wrap the ExpandedStream
198pub struct ExpansionInput<S>(ExpandedStream<S>);
199
200impl<S> std::convert::AsMut<ExpandedStream<S>> for ExpansionInput<S> {
201    fn as_mut(&mut self) -> &mut ExpandedStream<S> {
202        &mut self.0
203    }
204}
205
206impl<S: TexlangState> TokenStream for ExpansionInput<S> {
207    type S = S;
208
209    fn next(&mut self) -> Result<Option<Token>, Box<error::Error>> {
210        self.0.next()
211    }
212
213    fn peek(&mut self) -> Result<Option<&Token>, Box<error::Error>> {
214        self.0.peek()
215    }
216
217    fn vm(&self) -> &vm::VM<Self::S> {
218        self.0.vm()
219    }
220}
221
222impl<S> ExpansionInput<S> {
223    /// Creates a mutable reference to this type from the [VM](vm::VM) type.
224    #[inline]
225    pub fn new(vm: &mut vm::VM<S>) -> &mut ExpansionInput<S> {
226        unsafe { &mut *(vm as *mut vm::VM<S> as *mut ExpansionInput<S>) }
227    }
228}
229
230impl<S: TexlangState> ExpansionInput<S> {
231    /// Push source code to the front of the input stream.
232    #[inline]
233    pub fn push_source(
234        &mut self,
235        token: Token,
236        file_name: PathBuf,
237        source_code: String,
238    ) -> Result<(), Box<error::Error>> {
239        self.0
240             .0
241             .0
242            .internal
243            .push_source(Some(token), file_name, source_code)
244    }
245
246    pub fn push_string_tokens(&mut self, token: Token, s: &str) {
247        let trace_key = token.trace_key();
248        for c in s.chars().rev() {
249            let token = match c {
250                ' ' => token::Token::new_space(' ', trace_key),
251                _ => token::Token::new_letter(c, trace_key),
252            };
253            self.expansions_mut().push(token);
254        }
255    }
256}
257
258impl<S> ExpansionInput<S> {
259    #[inline]
260    pub fn unexpanded(&mut self) -> &mut UnexpandedStream<S> {
261        &mut self.0 .0
262    }
263
264    #[inline]
265    pub fn expanded(&mut self) -> &mut ExpandedStream<S> {
266        &mut self.0
267    }
268
269    /// Push tokens to the front of the input stream.
270    ///
271    /// The first token in the provided slice will be the next token read.
272    #[inline]
273    pub fn push_expansion(&mut self, expansion: &[Token]) {
274        self.0 .0 .0.internal.push_expansion(expansion)
275    }
276
277    /// Returns a reference to the expanded tokens stack for the current input source.
278    ///
279    /// The tokens are a stack, so the next token is the last token in the vector.
280    ///
281    /// Adding tokens to the front of the input using this method can be more efficient
282    /// than using [ExpansionInput::push_expansion] because an allocation is avoided.
283    #[inline]
284    pub fn expansions(&self) -> &Vec<Token> {
285        self.0 .0 .0.internal.expansions()
286    }
287
288    /// Returns a mutable reference to the expanded tokens stack for the current input source.
289    ///
290    /// The tokens are a stack, so the next token is the last token in the vector.
291    ///
292    /// Adding tokens to the front of the input using this method can be more efficient
293    /// than using [ExpansionInput::push_expansion] because an allocation is avoided.
294    #[inline]
295    pub fn expansions_mut(&mut self) -> &mut Vec<Token> {
296        self.0 .0 .0.internal.expansions_mut()
297    }
298
299    /// Returns a vector than can be used as a token buffer, potentially without allocating memory.
300    ///
301    /// The returned vector is empty, but will generally have non-zero capacity from previous uses of the buffer.
302    /// Reusing the allocated memory results in fewer allocations overall.
303    /// This buffer mechanism was first introduced in a successful attempt to improve the performance of the
304    /// TeX macros implementation.
305    ///
306    /// When finished with the buffer, please return it using [return_token_buffer](ExpansionInput::return_token_buffer).
307    ///
308    /// This API may feel a bit awkward - it would seem nicer to return a mutable reference to a buffer instead.
309    /// Doing this while keeping the borrow checker happy is very difficult and (as is often the case) for good reason.
310    /// Token buffers are often used in macro expansion, and at any point in time multiple macros may be in
311    ///     the process of expansion.
312    /// This getting "the" token buffer to use for expansion would be incorrect, as the multiple expansions
313    /// would step on each other.
314    pub fn checkout_token_buffer(&mut self) -> Vec<Token> {
315        self.0
316             .0
317             .0
318            .internal
319            .token_buffers
320            .pop()
321            .unwrap_or_default()
322            .0
323    }
324
325    /// Return a token buffer, allowing it to be reused.
326    pub fn return_token_buffer(&mut self, mut token_buffer: Vec<Token>) {
327        token_buffer.clear();
328        self.0
329             .0
330             .0
331            .internal
332            .token_buffers
333            .push(super::TokenBuffer(token_buffer))
334    }
335}
336
337/// Input type for execution primitives.
338///
339/// This type provides:
340///
341/// - Access to the input stream (with or without expansion). Its implementation of the [TokenStream]
342///     trait returns expanded tokens.
343///     To read the input stream without performing expansion, use the
344///     [unexpanded](ExpandedStream::unexpanded) method.
345///
346/// - Mutable access to the state and the commands map
347///     the [ExecutionInput::state_mut]
348///     and [ExecutionInput::commands_map_mut] methods.
349#[repr(transparent)]
350pub struct ExecutionInput<S>(ExpandedStream<S>);
351
352impl<S> std::convert::AsMut<ExpandedStream<S>> for ExecutionInput<S> {
353    fn as_mut(&mut self) -> &mut ExpandedStream<S> {
354        &mut self.0
355    }
356}
357
358impl<S: TexlangState> TokenStream for ExecutionInput<S> {
359    type S = S;
360
361    fn next(&mut self) -> Result<Option<Token>, Box<error::Error>> {
362        self.0.next()
363    }
364
365    fn peek(&mut self) -> Result<Option<&Token>, Box<error::Error>> {
366        self.0.peek()
367    }
368
369    fn vm(&self) -> &vm::VM<Self::S> {
370        self.0.vm()
371    }
372}
373
374impl<S> ExecutionInput<S> {
375    /// Creates a mutable reference to this type from the [VM](vm::VM) type.
376    #[inline]
377    pub fn new(state: &mut vm::VM<S>) -> &mut ExecutionInput<S> {
378        unsafe { &mut *(state as *mut vm::VM<S> as *mut ExecutionInput<S>) }
379    }
380
381    #[inline]
382    pub fn unexpanded(&mut self) -> &mut UnexpandedStream<S> {
383        &mut self.0 .0
384    }
385
386    #[inline]
387    pub fn commands_map_mut(&mut self) -> &mut command::Map<S> {
388        &mut self.0 .0 .0.commands_map
389    }
390
391    /// Returns a mutable reference to the state.
392    #[inline]
393    pub fn state_mut(&mut self) -> &mut S {
394        &mut self.0 .0 .0.state
395    }
396
397    /// Returns a mutable reference to the custom state.
398    pub fn state_mut_and_cs_name_interner(&mut self) -> (&mut S, &token::CsNameInterner) {
399        (
400            &mut self.0 .0 .0.state,
401            &self.0 .0 .0.internal.cs_name_interner,
402        )
403    }
404
405    // TODO: pass in the token and keep it as a reference
406    pub fn begin_group(&mut self) {
407        self.0 .0 .0.begin_group()
408    }
409
410    pub fn end_group(&mut self, token: Token) -> Result<(), Box<error::Error>> {
411        self.0 .0 .0.end_group(token)
412    }
413
414    pub(crate) fn groups(&mut self) -> &mut [variable::SaveStackElement<S>] {
415        &mut self.0 .0 .0.internal.groups
416    }
417
418    pub(crate) fn current_group_mut(&mut self) -> Option<(&mut variable::SaveStackElement<S>, &S)> {
419        match self.0 .0 .0.internal.groups.last_mut() {
420            None => None,
421            Some(g) => Some((g, &self.0 .0 .0.state)),
422        }
423    }
424}
425
426/// Strips the lifetime from the token.
427///
428/// This function is intended to get around limitations of the borrow checker only. It
429/// should only be used when the code is actually fine but the borrow checker is being
430/// too conservative. Don't do anything fancy.
431///
432/// See this question for the type of code this function is designed for:
433/// https://stackoverflow.com/questions/69680201/is-this-use-of-unsafe-trivially-safe
434#[inline]
435unsafe fn launder<'a>(token: &Token) -> &'a Token {
436    &*(token as *const Token)
437}
438
439mod stream {
440    use super::*;
441    use crate::token::lexer;
442    use crate::token::CatCode;
443    use crate::token::{lexer::CatCodeFn, Value::ControlSequence};
444
445    impl<T: TexlangState> CatCodeFn for T {
446        #[inline]
447        fn cat_code(&self, c: char) -> crate::token::CatCode {
448            self.cat_code(c)
449        }
450    }
451
452    #[inline]
453    pub fn next_unexpanded<S: TexlangState>(
454        vm: &mut vm::VM<S>,
455    ) -> Result<Option<Token>, Box<error::Error>> {
456        if let Some(token) = vm.internal.current_source.expansions.pop() {
457            return Ok(Some(token));
458        }
459        match vm
460            .internal
461            .current_source
462            .root
463            .next(&vm.state, &mut vm.internal.cs_name_interner)
464        {
465            Ok(None) => {}
466            Ok(Some(token)) => {
467                return Ok(Some(token));
468            }
469            Err(err) => return Err(LexerError::new(vm, err).into()),
470        }
471        next_unexpanded_recurse(vm)
472    }
473
474    fn next_unexpanded_recurse<S: TexlangState>(
475        vm: &mut vm::VM<S>,
476    ) -> Result<Option<Token>, Box<error::Error>> {
477        if vm.internal.pop_source() {
478            next_unexpanded(vm)
479        } else {
480            Ok(None)
481        }
482    }
483
484    #[inline]
485    pub fn peek_unexpanded<S: TexlangState>(
486        vm: &mut vm::VM<S>,
487    ) -> Result<Option<&Token>, Box<error::Error>> {
488        if let Some(token) = vm.internal.current_source.expansions.last() {
489            return Ok(Some(unsafe { launder(token) }));
490        }
491        match vm
492            .internal
493            .current_source
494            .root
495            .next(&vm.state, &mut vm.internal.cs_name_interner)
496        {
497            Ok(None) => {}
498            Ok(Some(token)) => {
499                vm.internal.current_source.expansions.push(token);
500                return Ok(vm.internal.current_source.expansions.last());
501            }
502            Err(err) => return Err(LexerError::new(vm, err).into()),
503        }
504        peek_unexpanded_recurse(vm)
505    }
506
507    fn peek_unexpanded_recurse<S: TexlangState>(
508        vm: &mut vm::VM<S>,
509    ) -> Result<Option<&Token>, Box<error::Error>> {
510        if vm.internal.pop_source() {
511            peek_unexpanded(vm)
512        } else {
513            Ok(None)
514        }
515    }
516
517    pub fn next_expanded<S: TexlangState>(
518        vm: &mut vm::VM<S>,
519    ) -> Result<Option<Token>, Box<error::Error>> {
520        let (token, command) = match next_unexpanded(vm)? {
521            None => return Ok(None),
522            Some(token) => match token.value() {
523                ControlSequence(name) => (token, vm.commands_map.get_command(&name)),
524                _ => return Ok(Some(token)),
525            },
526        };
527        match command {
528            Some(command::Command::Expansion(command, tag)) => {
529                let command = *command;
530                let tag = *tag;
531                match S::expansion_override_hook(token, ExpansionInput::new(vm), tag) {
532                    Ok(None) => (),
533                    Ok(Some(override_expansion)) => {
534                        return Ok(Some(override_expansion));
535                    }
536                    Err(err) => return Err(convert_command_error(vm, token, err)),
537                };
538                let output = match command(token, ExpansionInput::new(vm)) {
539                    Ok(output) => output,
540                    Err(err) => return Err(convert_command_error(vm, token, err)),
541                };
542                vm.internal.push_expansion(&output);
543                next_expanded(vm)
544            }
545            Some(command::Command::Macro(command)) => {
546                let command = command.clone();
547                if let Err(err) = command.call(token, ExpansionInput::new(vm)) {
548                    return Err(convert_command_error(vm, token, err));
549                }
550                next_expanded(vm)
551            }
552            _ => Ok(Some(token)),
553        }
554    }
555
556    pub fn peek_expanded<S: TexlangState>(
557        vm: &mut vm::VM<S>,
558    ) -> Result<Option<&Token>, Box<error::Error>> {
559        let (token, command) = match peek_unexpanded(vm)? {
560            None => return Ok(None),
561            Some(token) => match token.value() {
562                ControlSequence(name) => (
563                    unsafe { launder(token) },
564                    vm.commands_map.get_command(&name),
565                ),
566                _ => return Ok(Some(unsafe { launder(token) })),
567            },
568        };
569        match command {
570            Some(command::Command::Expansion(command, tag)) => {
571                let command = *command;
572                let token = *token;
573                let tag = *tag;
574                consume_peek(vm);
575                match S::expansion_override_hook(token, ExpansionInput::new(vm), tag) {
576                    Ok(None) => (),
577                    Ok(Some(override_expansion)) => {
578                        vm.internal.expansions_mut().push(override_expansion);
579                        return Ok(vm.internal.expansions().last());
580                    }
581                    Err(err) => return Err(convert_command_error(vm, token, err)),
582                };
583                let output = match command(token, ExpansionInput::new(vm)) {
584                    Ok(output) => output,
585                    Err(err) => return Err(convert_command_error(vm, token, err)),
586                };
587                vm.internal.push_expansion(&output);
588                peek_expanded(vm)
589            }
590            Some(command::Command::Macro(command)) => {
591                let command = command.clone();
592                let token = *token;
593                consume_peek(vm);
594                if let Err(err) = command.call(token, ExpansionInput::new(vm)) {
595                    return Err(convert_command_error(vm, token, err));
596                }
597                peek_expanded(vm)
598            }
599            _ => Ok(Some(unsafe { launder(token) })),
600        }
601    }
602
603    pub fn expand_once<S: TexlangState>(vm: &mut vm::VM<S>) -> Result<bool, Box<error::Error>> {
604        let (token, command) = match peek_unexpanded(vm)? {
605            None => return Ok(false),
606            Some(token) => match token.value() {
607                ControlSequence(name) => (
608                    unsafe { launder(token) },
609                    vm.commands_map.get_command(&name),
610                ),
611                _ => return Ok(false),
612            },
613        };
614        match command {
615            Some(command::Command::Expansion(command, tag)) => {
616                let command = *command;
617                let token = *token;
618                let tag = *tag;
619                consume_peek(vm);
620                match S::expansion_override_hook(token, ExpansionInput::new(vm), tag) {
621                    Ok(None) => (),
622                    Ok(Some(override_expansion)) => {
623                        vm.internal.expansions_mut().push(override_expansion);
624                        return Ok(true);
625                    }
626                    Err(err) => return Err(convert_command_error(vm, token, err)),
627                };
628                let output = match command(token, ExpansionInput::new(vm)) {
629                    Ok(output) => output,
630                    Err(err) => return Err(convert_command_error(vm, token, err)),
631                };
632                vm.internal.push_expansion(&output);
633                Ok(true)
634            }
635            Some(command::Command::Macro(command)) => {
636                let command = command.clone();
637                let token = *token;
638                consume_peek(vm);
639                if let Err(err) = command.call(token, ExpansionInput::new(vm)) {
640                    return Err(convert_command_error(vm, token, err));
641                }
642                Ok(true)
643            }
644            _ => Ok(false),
645        }
646    }
647
648    #[inline]
649    pub fn consume_peek<S>(vm: &mut vm::VM<S>) {
650        // When we peek at a token, it is placed on top of the expansions stack.
651        // So to consume the token, we just need to remove it from the stack.
652        vm.internal.current_source.expansions.pop();
653    }
654
655    use crate::error::Error;
656
657    fn convert_command_error<S: TexlangState>(
658        vm: &mut vm::VM<S>,
659        token: Token,
660        err: Box<error::Error>,
661    ) -> Box<Error> {
662        Error::new_propagated(vm, error::PropagationContext::Expansion, token, err)
663    }
664
665    #[derive(Debug)]
666    enum LexerError {
667        InvalidCharacter(char, trace::SourceCodeTrace),
668        EmptyControlSequence(trace::SourceCodeTrace),
669    }
670
671    impl LexerError {
672        fn new<S>(vm: &vm::VM<S>, err: lexer::Error) -> LexerError {
673            match err {
674                lexer::Error::InvalidCharacter(c, key) => {
675                    LexerError::InvalidCharacter(c, vm.trace(Token::new_other(c, key)))
676                }
677                lexer::Error::EmptyControlSequence(key) => {
678                    LexerError::EmptyControlSequence(vm.trace(Token::new_other(' ', key)))
679                }
680            }
681        }
682    }
683
684    impl error::TexError for LexerError {
685        fn kind(&self) -> error::Kind {
686            match self {
687                LexerError::InvalidCharacter(_, key) => error::Kind::Token(key),
688                LexerError::EmptyControlSequence(key) => error::Kind::EndOfInput(key),
689            }
690        }
691
692        fn title(&self) -> String {
693            match self {
694                LexerError::InvalidCharacter(c, _) => {
695                    format!["input contains a character {} (Unicode code point {}) with category code {}", *c, *c as u32, CatCode::Invalid]
696                }
697                LexerError::EmptyControlSequence(_) => {
698                    format![
699                        "unexpected end of file after a token with category code {}",
700                        CatCode::Escape
701                    ]
702                }
703            }
704        }
705
706        fn source_annotation(&self) -> String {
707            match self {
708                LexerError::InvalidCharacter(_, _) => "invalid character",
709                LexerError::EmptyControlSequence(_) => "file ended after this token",
710            }
711            .into()
712        }
713
714        fn notes(&self) -> Vec<error::display::Note> {
715            match self {
716                LexerError::InvalidCharacter(_, _) => vec![
717                  format!["characters with category code {} cannot appear in the input", CatCode::Invalid].into()
718                ],
719                LexerError::EmptyControlSequence(_) => vec![
720                  "escape tokens start a control sequence and must be followed by at least one character".into(),
721                ],
722            }
723        }
724    }
725}