1mod token;
2use crate::node::Span;
3use fe_common::files::SourceFileId;
4use logos::Logos;
5pub use token::{Token, TokenKind};
6
7#[derive(Clone)]
8pub struct Lexer<'a> {
9 file_id: SourceFileId,
10 inner: logos::Lexer<'a, TokenKind>,
11}
12
13impl<'a> Lexer<'a> {
14 pub fn new(file_id: SourceFileId, src: &'a str) -> Lexer {
16 Lexer {
17 file_id,
18 inner: TokenKind::lexer(src),
19 }
20 }
21
22 pub fn source(&self) -> &'a str {
24 self.inner.source()
25 }
26}
27
28impl<'a> Iterator for Lexer<'a> {
29 type Item = Token<'a>;
30
31 fn next(&mut self) -> Option<Self::Item> {
32 let kind = self.inner.next()?;
33 let text = self.inner.slice();
34 let span = self.inner.span();
35 Some(Token {
36 kind,
37 text,
38 span: Span {
39 file_id: self.file_id,
40 start: span.start,
41 end: span.end,
42 },
43 })
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use crate::lexer::{Lexer, TokenKind};
50 use fe_common::files::SourceFileId;
51 use TokenKind::*;
52
53 fn check(input: &str, expected: &[TokenKind]) {
54 let lex = Lexer::new(SourceFileId::dummy_file(), input);
55
56 let actual = lex.map(|t| t.kind).collect::<Vec<_>>();
57
58 assert!(
59 actual.iter().eq(expected.iter()),
60 "\nexpected: {expected:?}\n actual: {actual:?}"
61 );
62 }
63
64 #[test]
65 fn basic() {
66 check(
67 "contract Foo:\n x: u32\n fn f() -> u32: not x",
68 &[
69 Contract, Name, Colon, Newline, Name, Colon, Name, Newline, Fn, Name, ParenOpen,
70 ParenClose, Arrow, Name, Colon, Not, Name,
71 ],
72 );
73 }
74
75 #[test]
76 fn strings() {
77 let rawstr = r#""string \t with \n escapes \" \"""#;
78 let mut lex = Lexer::new(SourceFileId::dummy_file(), rawstr);
79 let lexedstr = lex.next().unwrap();
80 assert!(lexedstr.kind == Text);
81 assert!(lexedstr.text == rawstr);
82 assert!(lex.next().is_none());
83 }
84
85 #[test]
86 fn errors() {
87 check(
88 "contract Foo@ 5u8 \n self.bar",
89 &[
90 Contract, Name, Error, Int, Name, Newline, SelfValue, Dot, Name,
91 ],
92 );
93 }
94
95 #[test]
96 fn tabs_and_comment() {
97 check(
98 "\n\t \tcontract\n\tFoo // hi mom!\n ",
99 &[Newline, Contract, Newline, Name, Newline],
100 );
101 }
102}