1use text_scanner::{ext::ScssScannerExt, Scanner};
2
3use crate::{impl_lexer_from_scanner, CssToken, ScanToken, ScannerExt, TokenSpan};
4
5#[derive(PartialEq, Eq, Clone, Copy, Debug)]
6pub enum ScssToken {
7 Space,
8 LineComment,
9 BlockComment,
10 Ident,
11 AtKeyword,
12 Hash,
13 String,
14 Number,
15 Punct,
17 Delim,
19 Unknown,
25}
26
27impl ScanToken for ScssToken {
28 fn scan_token<'text>(scanner: &mut Scanner<'text>) -> Option<(Self, TokenSpan<'text>)> {
29 if let Ok((r, _s)) = scanner.scan_scss_line_comment() {
30 return Some((Self::LineComment, scanner.span(r)));
31 }
32
33 let (tok, span) = CssToken::scan_token(scanner)?;
34 match tok {
35 CssToken::Space => Some((ScssToken::Space, span)),
36 CssToken::BlockComment => Some((ScssToken::BlockComment, span)),
37 CssToken::Ident => Some((ScssToken::Ident, span)),
38 CssToken::AtKeyword => Some((ScssToken::AtKeyword, span)),
39 CssToken::Hash => Some((ScssToken::Hash, span)),
40 CssToken::String => Some((ScssToken::String, span)),
41 CssToken::Number => Some((ScssToken::Number, span)),
42 CssToken::Punct => Some((ScssToken::Punct, span)),
43 CssToken::Delim => Some((ScssToken::Delim, span)),
44 CssToken::Unknown => Some((ScssToken::Unknown, span)),
45 }
46 }
47}
48
49#[derive(Clone, Debug)]
59pub struct ScssLexer<'text> {
60 scanner: Scanner<'text>,
61}
62
63impl<'text> ScssLexer<'text> {
64 #[inline]
65 pub fn new(text: &'text str) -> Self {
66 Self {
67 scanner: Scanner::new(text),
68 }
69 }
70}
71
72impl_lexer_from_scanner!('text, ScssLexer<'text>, ScssToken, scanner);
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_scss_lexer_spans() {
80 let input = include_str!("../../../text-scanner/src/ext/rust.rs");
83 let mut output = String::new();
84
85 let lexer = ScssLexer::new(input);
86 for (_tok, span) in lexer {
87 output.push_str(span.as_str());
88 }
89
90 assert_eq!(input, output);
91 }
92}