1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use std::fmt::{Display, Error, Formatter};

use Kind::*;

/// Represents a kind of lexical token.
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub enum Kind {
    /// A sequence of non US-ASCII chars. (code points above 127)
    NonAscii,

    /// A single line-ending. (CR, LF, or CRLF)
    LineEnding,

    /// A sequence of US-ASCII whitespace chars. (spaces and tabs)
    Whitespace,

    /// A sequence of US-ASCII control chars. (0-31 & 127, excluding CR, LF, and TAB)
    Controls,

    /// A sequence of US-ASCII letters, numbers, and underscores.
    Symbol,

    /// A single special US-ASCII char not mentioned above.
    Special(u8),
}

impl Kind {
    //! Formatting

    /// Formats the value of this kind with the formatter.
    pub fn fmt_value(&self, value: &str, f: &mut Formatter<'_>) -> Result<(), Error> {
        match self {
            NonAscii | Controls => {
                for _ in value.as_bytes().iter() {
                    write!(f, "?")?;
                }
            }
            LineEnding => {
                for c in value.as_bytes().iter() {
                    match c {
                        b'\r' => write!(f, "r")?,
                        b'\n' => write!(f, "n")?,
                        _ => write!(f, "?")?,
                    }
                }
            }
            Whitespace => {
                for c in value.as_bytes().iter() {
                    match c {
                        b' ' => write!(f, "s")?,
                        b'\t' => write!(f, "t")?,
                        _ => write!(f, "?")?,
                    }
                }
            }
            Symbol | Special(_) => write!(f, "{}", value)?,
        }
        Ok(())
    }
}

impl Display for Kind {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        let s: &str = match self {
            NonAscii => "non-ascii",
            LineEnding => "line-ending",
            Whitespace => "whitespace",
            Controls => "controls",
            Symbol => "symbol",
            Special(_) => "special",
        };
        write!(f, "{}", s)
    }
}