clex/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod char;
4mod comment;
5mod float;
6mod int;
7mod keyword;
8mod lexer;
9mod string;
10
11pub use float::Float;
12pub use int::Int;
13pub use keyword::Keyword;
14pub use lexer::Token;
15
16/// C lexeme
17#[derive(Debug, Clone)]
18pub struct Lexeme<'l> {
19    /// Token kind
20    pub token: Token,
21    /* TODO:
22    /// Position in source code
23    pub location: Location,
24    */
25    pub span: core::ops::Range<usize>,
26    /// String slice
27    pub slice: &'l str,
28}
29
30impl<'l> core::ops::Deref for Lexeme<'l> {
31    type Target = Token;
32
33    fn deref(&self) -> &Self::Target {
34        &self.token
35    }
36}
37
38impl<'l> AsRef<str> for Lexeme<'l> {
39    fn as_ref(&self) -> &'l str {
40        self.slice
41    }
42}
43
44impl<'l> Lexeme<'l> {
45    /// Extract keyword
46    pub fn keyword(&self) -> Option<Keyword> {
47        if self.token == Token::Identifier {
48            self.slice.parse().ok()
49        } else {
50            None
51        }
52    }
53
54    /// Extract text from comment
55    pub fn comment(&self) -> Option<String> {
56        if self.token == Token::Comment {
57            comment::extract(self.slice)
58        } else {
59            None
60        }
61    }
62
63    /// Extract text from character literal
64    pub fn char(&self) -> Option<char> {
65        if self.token == Token::Char {
66            char::extract(self.slice)
67        } else {
68            None
69        }
70    }
71
72    /// Extract text from string literal
73    pub fn string(&self) -> Option<String> {
74        if self.token == Token::String {
75            string::extract(self.slice)
76        } else {
77            None
78        }
79    }
80
81    /// Extract number from integer literal
82    pub fn int<T: Int>(&self) -> Option<T> {
83        if self.token == Token::Int {
84            int::extract(self.slice)
85        } else {
86            None
87        }
88    }
89
90    /// Extract number from floating-point literal
91    pub fn float<T: Float>(&self) -> Option<T> {
92        if self.token == Token::Float {
93            float::extract(self.slice)
94        } else {
95            None
96        }
97    }
98}
99
100/* TODO:
101/// C token location
102#[derive(Debug, Clone)]
103pub struct Location {
104    /// Source code position
105    pub point: u32,
106    /// Source code line
107    pub line: u32,
108    /// Source code column
109    pub column: u32,
110}
111*/
112
113/// C Lexer
114pub struct Lexer<'l> {
115    inner: logos::Lexer<'l, Token>,
116}
117
118impl<'l> From<&'l str> for Lexer<'l> {
119    fn from(s: &'l str) -> Self {
120        Self {
121            inner: logos::Lexer::new(s),
122        }
123    }
124}
125
126impl<'l> Iterator for Lexer<'l> {
127    type Item = Lexeme<'l>;
128
129    fn next(&mut self) -> Option<Self::Item> {
130        self.inner.next().map(|token| {
131            let span = self.inner.span();
132            let slice = self.inner.slice();
133            Lexeme { token, span, slice }
134        })
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    #[test]
141    fn it_works() {
142        let result = 2 + 2;
143        assert_eq!(result, 4);
144    }
145}