1use arrayvec::ArrayVec;
4
5use crate::{
6 lexer::{PreLexer, PreTextToken, PreToken as InputToken},
7 util::LineMap,
8};
9
10mod token;
11use lang_util::TextRange;
12pub use token::Token;
13
14pub type TextToken = crate::util::TextToken<token::Token>;
15
16#[derive(Debug, Clone)]
22pub struct Lexer<'i> {
23 input: PreLexer<'i>,
24 buffer: ArrayVec<PreTextToken, 2>,
27}
28
29impl<'i> Lexer<'i> {
30 pub fn new(input: &'i str) -> Self {
31 Self {
32 input: PreLexer::new(input),
33 buffer: ArrayVec::new(),
34 }
35 }
36
37 pub fn input(&self) -> &'i str {
39 self.input.input()
40 }
41
42 pub fn line_map(&self) -> &LineMap {
44 self.input.line_map()
45 }
46
47 pub fn into_line_map(self) -> LineMap {
49 self.input.into_line_map()
50 }
51
52 pub fn set_expect_angle_string(&mut self, expect_angle_string: bool) {
59 self.input.set_expect_angle_string(expect_angle_string)
60 }
61
62 fn next(&mut self) -> Option<PreTextToken> {
63 self.buffer.pop().or_else(|| self.input.next())
64 }
65
66 fn maybe_concat(
67 &mut self,
68 token: PreTextToken,
69 next: impl FnOnce(InputToken) -> Option<Token>,
70 ) -> Option<TextToken> {
71 if let Some(next_token) = self.next() {
72 let result = next(*next_token);
73
74 if let Some(result) = result {
75 return Some(TextToken::new(
76 result,
77 TextRange::new(token.range.start(), next_token.range.end()),
78 ));
79 } else {
80 self.buffer.push(next_token);
82 }
83 }
84
85 Some(token.transmute())
86 }
87
88 fn maybe_concat2(
89 &mut self,
90 token: PreTextToken,
91 next: impl FnOnce(InputToken) -> Option<Token>,
92 after: impl FnOnce((InputToken, InputToken)) -> Option<Token>,
93 ) -> Option<TextToken> {
94 if let Some(next_token) = self.next() {
95 if let Some(after_token) = self.next() {
98 let result = after((*next_token, *after_token));
100
101 if let Some(result) = result {
102 return Some(TextToken::new(
104 result,
105 TextRange::new(token.range.start(), after_token.range.end()),
106 ));
107 } else {
108 self.buffer.push(after_token);
110 self.buffer.push(next_token);
111
112 return self.maybe_concat(token, next);
113 }
114 } else {
115 self.buffer.push(next_token);
118 return self.maybe_concat(token, next);
119 }
120 }
121
122 Some(token.transmute())
123 }
124}
125
126impl<'i> Iterator for Lexer<'i> {
127 type Item = TextToken;
128
129 fn next(&mut self) -> Option<Self::Item> {
130 use Token::*;
131
132 let token = self.next();
133 match token {
134 Some(token) => match *token {
135 InputToken::PLUS => self.maybe_concat(token, |input| match input {
136 InputToken::PLUS => Some(INC_OP),
137 InputToken::EQUAL => Some(ADD_ASSIGN),
138 _ => None,
139 }),
140 InputToken::DASH => self.maybe_concat(token, |input| match input {
141 InputToken::DASH => Some(DEC_OP),
142 InputToken::EQUAL => Some(SUB_ASSIGN),
143 _ => None,
144 }),
145 InputToken::SLASH => self.maybe_concat(token, |input| match input {
146 InputToken::EQUAL => Some(DIV_ASSIGN),
147 _ => None,
148 }),
149 InputToken::ASTERISK => self.maybe_concat(token, |input| match input {
150 InputToken::EQUAL => Some(MUL_ASSIGN),
151 _ => None,
152 }),
153 InputToken::PERCENT => self.maybe_concat(token, |input| match input {
154 InputToken::EQUAL => Some(MOD_ASSIGN),
155 _ => None,
156 }),
157 InputToken::LANGLE => self.maybe_concat2(
158 token,
159 |input| match input {
160 InputToken::LANGLE => Some(LEFT_OP),
161 InputToken::EQUAL => Some(LE_OP),
162 _ => None,
163 },
164 |input| match input {
165 (InputToken::LANGLE, InputToken::EQUAL) => Some(LEFT_ASSIGN),
166 _ => None,
167 },
168 ),
169 InputToken::RANGLE => self.maybe_concat2(
170 token,
171 |input| match input {
172 InputToken::RANGLE => Some(RIGHT_OP),
173 InputToken::EQUAL => Some(GE_OP),
174 _ => None,
175 },
176 |input| match input {
177 (InputToken::RANGLE, InputToken::EQUAL) => Some(RIGHT_ASSIGN),
178 _ => None,
179 },
180 ),
181 InputToken::CARET => self.maybe_concat(token, |input| match input {
182 InputToken::CARET => Some(XOR_OP),
183 InputToken::EQUAL => Some(XOR_ASSIGN),
184 _ => None,
185 }),
186 InputToken::BAR => self.maybe_concat(token, |input| match input {
187 InputToken::BAR => Some(OR_OP),
188 InputToken::EQUAL => Some(OR_ASSIGN),
189 _ => None,
190 }),
191 InputToken::AMPERSAND => self.maybe_concat(token, |input| match input {
192 InputToken::AMPERSAND => Some(AND_OP),
193 InputToken::EQUAL => Some(AND_ASSIGN),
194 _ => None,
195 }),
196 InputToken::EQUAL => self.maybe_concat(token, |input| match input {
197 InputToken::EQUAL => Some(EQ_OP),
198 _ => None,
199 }),
200 InputToken::BANG => self.maybe_concat(token, |input| match input {
201 InputToken::EQUAL => Some(NE_OP),
202 _ => None,
203 }),
204 InputToken::HASH => self.maybe_concat(token, |input| match input {
205 InputToken::HASH => Some(PP_CONCAT),
206 _ => None,
207 }),
208 InputToken::PERIOD => self.maybe_concat(token, |input| match input {
209 InputToken::DIGITS => Some(DIGITS),
210 _ => None,
211 }),
212 _ => Some(token.transmute()),
213 },
214 None => None,
215 }
216 }
217}