linkrs_query/parser/lexing/
lexer.rs1use crate::parser::lexing::LexError;
11use crate::parser::{Token, TokenKind as Tk};
12use linkrs_core::types::Position;
13use std::iter::Peekable;
14
15mod scanner;
16mod token;
17
18#[derive(Clone)]
19pub struct Lexer<'a> {
20 input: std::borrow::Cow<'a, str>,
21 chars: Peekable<std::vec::IntoIter<char>>,
22 position: usize,
23 line: usize,
24 column: usize,
25 current_token: Token,
26 errors: Vec<LexError>,
27}
28
29pub struct LexerCheckpoint {
30 position: usize,
31 line: usize,
32 column: usize,
33 current_token: Token,
34 chars: Vec<char>,
35}
36
37impl<'a> Lexer<'a> {
38 pub fn new(input: &'a str) -> Self {
39 let chars: Vec<char> = input.chars().collect();
40 let mut lexer = Lexer {
41 input: std::borrow::Cow::Borrowed(input),
42 chars: chars.into_iter().peekable(),
43 position: 0,
44 line: 1,
45 column: 0,
46 current_token: Token::new(Tk::Eof, String::new(), 0, 0),
47 errors: Vec::new(),
48 };
49 lexer.current_token = lexer.next_token();
50 lexer
51 }
52
53 pub fn from_string(input: String) -> Self {
54 let chars: Vec<char> = input.chars().collect();
55 let mut lexer = Lexer {
56 input: std::borrow::Cow::Owned(input),
57 chars: chars.into_iter().peekable(),
58 position: 0,
59 line: 1,
60 column: 0,
61 current_token: Token::new(Tk::Eof, String::new(), 0, 0),
62 errors: Vec::new(),
63 };
64 lexer.read_char();
65 lexer.current_token = lexer.next_token();
66 lexer
67 }
68
69 fn read_char(&mut self) -> Option<char> {
70 let ch = self.chars.next();
71 if let Some(c) = ch {
72 self.position += c.len_utf8();
73 if c == '\n' {
74 self.line += 1;
75 self.column = 0;
76 } else {
77 self.column += 1;
78 }
79 }
80 ch
81 }
82
83 fn peek_char(&mut self) -> Option<&char> {
84 self.chars.peek()
85 }
86
87 fn add_error(&mut self, error: LexError) {
88 self.errors.push(error);
89 }
90
91 pub fn has_errors(&self) -> bool {
92 !self.errors.is_empty()
93 }
94
95 pub fn take_errors(&mut self) -> Vec<LexError> {
96 std::mem::take(&mut self.errors)
97 }
98
99 pub fn errors(&self) -> &[LexError] {
100 &self.errors
101 }
102
103 pub fn checkpoint(&self) -> LexerCheckpoint {
104 LexerCheckpoint {
105 position: self.position,
106 line: self.line,
107 column: self.column,
108 current_token: self.current_token.clone(),
109 chars: self.chars.clone().collect(),
110 }
111 }
112
113 pub fn restore(&mut self, ckpt: LexerCheckpoint) {
114 self.position = ckpt.position;
115 self.line = ckpt.line;
116 self.column = ckpt.column;
117 self.current_token = ckpt.current_token;
118 self.chars = ckpt.chars.into_iter().peekable();
119 }
120
121 pub fn current_token(&self) -> &Token {
122 &self.current_token
123 }
124
125 pub fn current_position(&self) -> Position {
126 Position::new(self.line, self.column)
127 }
128
129 pub fn is_at_end(&mut self) -> bool {
130 self.chars.peek().is_none()
131 }
132
133 pub fn peek(&mut self) -> Result<Token, String> {
134 Ok(self.current_token.clone())
135 }
136
137 pub fn advance(&mut self) {
138 self.current_token = self.next_token();
139 }
140
141 pub fn check(&mut self, kind: Tk) -> bool {
142 self.current_token.kind == kind
143 }
144}
145
146#[cfg(test)]
147mod tests;