rocks_lang/
token.rs

1use std::fmt::{self, Display};
2use std::hash::Hash;
3
4use crate::literal::Literal;
5
6/// Represents a token type in the language.
7#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
8pub enum Type {
9    // Single-character tokens.
10    LeftParen, RightParen, LeftBrace, RightBrace,
11    Comma, Dot, Minus, Plus, Semicolon, Slash, Star,
12
13    // One or two character tokens.
14    Bang, BangEqual,
15    Equal, EqualEqual,
16    Greater, GreaterEqual,
17    Less, LessEqual,
18
19    // Literals.
20    Identifier, String, Number,
21
22    // Keywords.
23    And, Class, Else, False, Fun, For, If, Null, Or,
24    Print, Return, Break, Super, This, True, Var, While,
25
26    EOF
27}
28
29/// Represents a location in the source code.
30#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
31pub struct Location {
32    pub line: usize,
33    pub column: usize,
34}
35
36impl Location {
37    /// Creates a new location.
38    pub fn new(line: usize, column: usize) -> Self {
39        Location { line, column }
40    }
41}
42
43impl Display for Location {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        write!(f, "{}:{}", self.line, self.column)
46    }
47}
48
49/// Represents a token in the language.
50#[derive(Debug, Eq, PartialEq, Clone)]
51pub struct Token {
52    /// Type of the token.
53    pub r#type: Type,
54    /// String representation of the token.
55    pub lexeme: String,
56    /// Literal value of the token (if any).
57    pub literal: Option<Literal>,
58    /// Location of the token in the source code.
59    pub location: Location,
60}
61
62impl Token {
63    /// Creates a new token.
64    pub fn new(
65        r#type: Type,
66        lexeme: String,
67        literal: Option<Literal>,
68        location: Location,
69    ) -> Token {
70        Token { r#type, lexeme, literal, location }
71    }
72}
73
74/// Convenience methods for creating dummy tokens.
75impl From<&str> for Token {
76    fn from(token: &str) -> Self {
77        Token::new(Type::Identifier, token.to_string(), None, Location::new(0, 0))
78    }
79}
80
81impl Display for Token {
82    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83        write!(f, "{:#?} {} {:#?} @ [{}]", self.r#type, self.lexeme, self.literal, self.location)
84    }
85}
86
87/// This is required for the `HashMap` to work for [`Interpreter::locals`](crate::interpreter::Interpreter).
88/// Since no two tokens can have the same type, lexeme, and location, we can use them as the key for
89/// the `HashMap`.
90impl Hash for Token {
91    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
92        self.r#type.hash(state);
93        self.lexeme.hash(state);
94        self.location.hash(state);
95    }
96}