sphinx/lexer/rules/
comments.rs

1use crate::lexer::Token;
2use crate::lexer::rules::{MatchResult, LexerRule, TokenError};
3use crate::lexer::rules::strmatcher::StrMatcher;
4
5// Special-Purpose Rules
6
7#[derive(Clone)]
8pub struct LineCommentRule {
9    // (start, end)
10    // start -> if the comment has started
11    // end   -> if the comment has ended
12    state: (bool, bool),
13    comment: char
14}
15
16impl LineCommentRule {
17    pub fn new(comment: char) -> Self {
18        LineCommentRule { comment, state: (false, false) }
19    }
20    
21    fn match_state(&self, state: (bool, bool)) -> MatchResult {
22        match state {
23            (_, false) => MatchResult::CompleteMatch,
24            (true, _)  => MatchResult::CompleteMatch,
25            (false, true) => MatchResult::NoMatch,
26        }
27    }
28    
29    fn next_state(&self, state: (bool, bool), next: char) -> (bool, bool) {
30        let (start, end) = state;
31        
32        // looking for initial comment char
33        if !start {
34            if next != self.comment {
35                return (false, true);
36            }
37            return (true, false);
38        }
39        
40        // looking for end of comment
41        if start && !end {
42            if next == '\n' {
43                return (true, true);
44            }
45            return (true, false);
46        }
47        
48        // complete comment - anything else will not match
49        (false, true)
50    }
51}
52
53impl LexerRule for LineCommentRule {
54    fn reset(&mut self) {
55        self.state = (false, false);
56    }
57    
58    fn current_state(&self) -> MatchResult {
59        self.match_state(self.state)
60    }
61    
62    fn try_match(&mut self, _prev: Option<char>, next: char) -> MatchResult {
63        let state = self.next_state(self.state, next);
64        let match_result = self.match_state(state);
65        
66        if match_result.is_match() {
67            self.state = state;
68        }
69        
70        match_result
71    }
72    
73    // produce Some(Token) if current state is CompleteMatch, otherwise None
74    fn get_token(&self) -> Result<Token, TokenError> {
75        debug_assert!(self.current_state().is_complete_match());
76        Ok(Token::Comment)
77    }
78}
79
80#[derive(Clone)]
81pub struct BlockCommentRule {
82    nestlevel: u32,
83    start: StrMatcher<'static>,
84    end: StrMatcher<'static>,
85}
86
87impl BlockCommentRule {
88    pub fn new(start: &'static str, end: &'static str) -> Self {
89        BlockCommentRule {
90            nestlevel: 0,
91            start: StrMatcher::case_sensitive(start),
92            end: StrMatcher::case_sensitive(end),
93        }
94    }
95}
96
97impl LexerRule for BlockCommentRule {
98    fn reset(&mut self) {
99        self.nestlevel = 0;
100        self.start.reset();
101        self.end.reset();
102    }
103    
104    fn current_state(&self) -> MatchResult {
105        if self.nestlevel > 0 {
106            return MatchResult::IncompleteMatch;
107        }
108        
109        if self.end.last_match_result().is_complete_match() {
110            return MatchResult::CompleteMatch;
111        }
112        
113        self.start.last_match_result()
114    }
115    
116    fn try_match(&mut self, _prev: Option<char>, next: char) -> MatchResult {
117
118        let start_result = self.start.try_match(next);
119        if start_result.is_complete_match() {
120            self.nestlevel += 1;
121            self.start.reset();
122            return MatchResult::IncompleteMatch;
123        }
124        
125        if self.nestlevel > 0 {
126            let end_result = self.end.try_match(next);
127            if end_result.is_complete_match() {
128                self.nestlevel -= 1;
129                
130                if self.nestlevel > 0 {
131                    self.end.reset();
132                } else {
133                    return MatchResult::CompleteMatch;
134                }
135            }
136            
137            if !start_result.is_match() {
138                self.start.reset();
139            }
140            if !end_result.is_match() {
141                self.end.reset();
142            }
143            
144            return MatchResult::IncompleteMatch;
145        }
146        
147        start_result
148    }
149    
150    // produce Some(Token) if current state is CompleteMatch, otherwise None
151    fn get_token(&self) -> Result<Token, TokenError> {
152        debug_assert!(self.current_state().is_complete_match());
153        Ok(Token::Comment)
154    }
155}