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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! Defines Carlo language tokens.

use std::fmt;

#[derive(Clone, Debug)]
/// A Carlo language token.
pub struct Token {
    pub class: TokenClass,
    pub value: String,
}

impl Token {
    /// Constructs a new token.
    pub fn new(class: TokenClass, value: String) -> Self {
        Self {
            class,
            value,
        }
    }

    /// Checks if this token is of a given class.
    pub fn check(&self, class: TokenClass) -> bool {
        self.class == class
    }

    /// Gets the precedence of this token.
    pub fn precedence(&self) -> u8 {
        self.class.into()
    }
}

impl fmt::Display for Token {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({}, \"{}\")", self.class, self.value)
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
/// Enumerates the classes of Carlo langauge tokens.
pub enum TokenClass {
    /// Let
    Let,

    /// Identifier
    Identifier,

    /// Assignment operator
    Assignment,

    /// Addition
    Plus,

    /// Subtraction
    Minus,

    /// Multiplication
    Times,

    /// Division
    Divide,

    /// Number
    Number,

    /// Symbolic
    Symbolic,

    /// Opening parenthesis
    OpenParen,

    /// Closing parenthesis
    CloseParen,

    /// Newline
    Newline,

    /// Unknown
    Unknown,
}

impl From<TokenClass> for u8 {
    fn from(class: TokenClass) -> Self {
        use TokenClass::*;

        match class {
            Let         => 1,
            Identifier  => 0,
            Assignment  => 2,
            Number      => 0,
            Unknown     => 0,
            Plus        => 3,
            Minus       => 3,
            Times       => 4,
            Divide      => 4,
            Symbolic    => 1,
            OpenParen   => 2,
            CloseParen  => 2,
            Newline     => 0,
        }
    }
}

/// Maps characters to classes of tokens that may
/// begin with this character.
impl From<char> for TokenClass {
    fn from(c: char) -> Self {
        use TokenClass::*;

        match c {
            'a'..='z' | 'A'..='Z' | '_' => Identifier,
            '=' => Assignment,
            '+' => Plus,
            '-' => Minus,
            '*' => Times,
            '/' => Divide,
            '!' => Symbolic,
            '(' => OpenParen,
            ')' => CloseParen,
            '0'..='9' => Number,
            '\n' => Newline,
            _ => Unknown,
        }
    }
}

impl fmt::Display for TokenClass {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TokenClass::*;

        let string = match self {
            Let         => "Let",
            Identifier  => "Identifier",
            Assignment  => "Assignment",
            Number      => "Number",
            Unknown     => "Unknown",
            Plus        => "Plus",
            Minus       => "Minus",
            Times       => "Times",
            Divide      => "Divide",
            Symbolic    => "Symbolic",
            Newline     => "Newline",
            OpenParen   => "OpenParen",
            CloseParen  => "CloseParen",
        };

        write!(f, "{}", string)
    }
}