oak_core/lexer/
scan_comment.rs

1use super::LexerState;
2use crate::{Language, source::Source};
3
4/// Configuration for comment scanning.
5pub struct CommentConfig {
6    /// Marker for line comments (e.g., "//").
7    pub line_marker: &'static str,
8    /// Marker for block comment start (e.g., "/*").
9    pub block_start: &'static str,
10    /// Marker for block comment end (e.g., "*/").
11    pub block_end: &'static str,
12    /// Whether block comments can be nested.
13    pub nested_blocks: bool,
14}
15
16impl CommentConfig {
17    /// Scans for a comment at the current position in the lexer state.
18    pub fn scan<S: Source + ?Sized, L: Language>(&self, state: &mut LexerState<S, L>, line_kind: L::TokenType, block_kind: L::TokenType) -> bool {
19        let start = state.get_position();
20
21        // Try line comment
22        if !self.line_marker.is_empty() && state.starts_with(self.line_marker) {
23            state.advance(self.line_marker.len());
24            state.take_while_byte(|b| b != b'\n');
25            state.add_token(line_kind, start, state.get_position());
26            return true;
27        }
28
29        // Try block comment
30        if !self.block_start.is_empty() && state.starts_with(self.block_start) {
31            state.advance(self.block_start.len());
32            let mut depth = 1;
33            while depth > 0 && state.not_at_end() {
34                if self.nested_blocks && !self.block_start.is_empty() && state.starts_with(self.block_start) {
35                    depth += 1;
36                    state.advance(self.block_start.len());
37                }
38                else if !self.block_end.is_empty() && state.starts_with(self.block_end) {
39                    depth -= 1;
40                    state.advance(self.block_end.len());
41                }
42                else if let Some(ch) = state.current() {
43                    state.advance(ch.len_utf8());
44                }
45            }
46            state.add_token(block_kind, start, state.get_position());
47            return true;
48        }
49
50        false
51    }
52}
53
54/// Checks if the given byte slice starts with a line comment marker ("//").
55#[inline]
56pub fn starts_with_line_comment(bytes: &[u8]) -> bool {
57    bytes.starts_with(b"//")
58}
59
60/// Checks if the given byte slice starts with a block comment marker ("/*").
61#[inline]
62pub fn starts_with_block_comment(bytes: &[u8]) -> bool {
63    bytes.starts_with(b"/*")
64}