1use std::collections::VecDeque;
2
3use glsl_lang_pp::{
4 last::{self, LocatedIterator, MaybeToken, TokenState, Tokenizer},
5 processor::event::{self, Error, EventDirective, OutputToken},
6 types,
7};
8
9use glsl_lang_types::ast;
10
11use lang_util::{located::Located, position::NodeSpan, FileId, NodeContent, TextRange};
12
13use crate::{ParseContext, ParseOptions};
14
15use super::{Directives, LexerPosition, LexicalError, Token};
16
17pub type Item<E> = Result<(LexerPosition, Token, LexerPosition), LexicalError<E>>;
18
19pub struct LexerCore {
20 pub ctx: ParseContext,
21 file_id: FileId,
22 opts: ParseOptions,
23 directives: Vec<EventDirective>,
24}
25
26pub enum HandleTokenResult<E: std::error::Error + 'static> {
27 None,
28 Item(Item<E>),
29 Pending(VecDeque<Item<E>>, VecDeque<Result<last::Event, Located<E>>>),
30}
31
32impl<E: std::error::Error + 'static> HandleTokenResult<E> {
33 pub fn push_item(&mut self, item: Item<E>) {
34 match std::mem::take(self) {
35 HandleTokenResult::None => {
36 *self = HandleTokenResult::Item(item);
37 }
38 HandleTokenResult::Item(old_item) => {
39 let mut pending_items = VecDeque::with_capacity(2);
40 pending_items.push_back(old_item);
41 pending_items.push_back(item);
42 *self = HandleTokenResult::Pending(pending_items, VecDeque::new());
43 }
44 HandleTokenResult::Pending(mut items, events) => {
45 items.push_back(item);
46 *self = HandleTokenResult::Pending(items, events);
47 }
48 }
49 }
50
51 pub fn pop_item(&mut self) -> Option<Item<E>> {
52 match std::mem::take(self) {
53 HandleTokenResult::None => None,
54 HandleTokenResult::Item(item) => Some(item),
55 HandleTokenResult::Pending(mut items, events) => {
56 let item = items.pop_front();
57 if !items.is_empty() || !events.is_empty() {
58 *self = Self::Pending(items, events);
59 }
60 item
61 }
62 }
63 }
64
65 pub fn pop_event(&mut self) -> Option<Result<last::Event, Located<E>>> {
66 match std::mem::take(self) {
67 HandleTokenResult::None => None,
68 HandleTokenResult::Item(item) => {
69 *self = Self::Item(item);
70 None
71 }
72 HandleTokenResult::Pending(items, mut events) => {
73 let event = events.pop_front();
74 if !items.is_empty() || !events.is_empty() {
75 *self = Self::Pending(items, events);
76 }
77 event
78 }
79 }
80 }
81
82 pub fn push_errors(&mut self, errors: impl IntoIterator<Item = Error>) {
83 let items = errors.into_iter().map(|error| Err(error.into()));
84
85 match std::mem::take(self) {
86 HandleTokenResult::None => {
87 *self = HandleTokenResult::Pending(items.collect(), Default::default());
88 }
89 HandleTokenResult::Item(old_item) => {
90 let mut pending_items = VecDeque::with_capacity(items.size_hint().0 + 1);
91 pending_items.push_back(old_item);
92 pending_items.extend(items);
93 *self = HandleTokenResult::Pending(pending_items, Default::default());
94 }
95 HandleTokenResult::Pending(mut old_items, events) => {
96 old_items.extend(items);
97 *self = HandleTokenResult::Pending(old_items, events);
98 }
99 }
100 }
101}
102
103impl<E: std::error::Error + 'static> Default for HandleTokenResult<E> {
104 fn default() -> Self {
105 Self::None
106 }
107}
108
109impl LexerCore {
110 pub fn new(opts: &ParseOptions, ctx: ParseContext) -> Self {
111 let file_id = opts.source_id;
112 Self {
113 ctx,
114 file_id,
115 opts: *opts,
116 directives: Vec::with_capacity(2),
117 }
118 }
119
120 fn lang_token(
121 &self,
122 source_token: &OutputToken,
123 token_kind: types::Token,
124 ) -> Result<(LexerPosition, Token, LexerPosition), (types::Token, types::token::ErrorKind)>
125 {
126 crate::lang_token::lang_token(
127 &self.ctx,
128 source_token.text(),
129 source_token.text_range(),
130 token_kind,
131 )
132 }
133
134 pub fn handle_file_id(&mut self, file_id: FileId) {
135 self.file_id = file_id;
136 }
137
138 pub fn handle_token<'r, I, E>(
139 &self,
140 source_token: OutputToken,
141 token_kind: types::Token,
142 state: TokenState,
143 tokenizer: &mut Tokenizer<'r, I>,
144 token_state: &mut HandleTokenResult<E>,
145 ) where
146 E: std::error::Error + 'static,
147 I: Iterator<Item = Result<event::Event, Located<E>>> + LocatedIterator,
148 <Tokenizer<'r, I> as Iterator>::Item: MaybeToken,
149 {
150 if state.active() {
151 match self.lang_token(&source_token, token_kind) {
152 Ok(token) => {
153 match token.1 {
155 Token::Whitespace => {}
156 Token::SingleLineComment | Token::MultiLineComment => {
157 if self.ctx.has_comments() {
158 let mut text = source_token.text().split_at(2).1.to_string();
159
160 let comment = match token.1 {
161 Token::SingleLineComment => ast::CommentData::Single(text),
162 Token::MultiLineComment => {
163 text.pop();
164 text.pop();
165 ast::CommentData::Multi(text)
166 }
167 _ => unreachable!(),
168 }
169 .spanned(token.0, token.2);
170
171 self.ctx.add_comment(comment);
172 }
173 }
174 _ => {
175 if token.1 == Token::LeftBrace {
176 self.ctx.push_scope();
177 } else if token.1 == Token::RightBrace {
178 self.ctx.pop_scope();
179 }
180
181 token_state.push_item(Ok(token));
182 }
183 }
184 }
185
186 Err((token_kind, error)) => {
187 if !(self.opts.allow_rs_ident
188 && error == types::token::ErrorKind::InvalidToken
189 && token_kind == types::Token::HASH)
190 {
191 token_state.push_item(Err(LexicalError::Token {
192 kind: error,
193 pos: source_token.text_range(),
194 }));
195 } else {
196 let start = source_token.text_range().start();
198 let mut end = start;
199
200 let mut pending_items = VecDeque::new();
201 let mut pending_events = VecDeque::new();
202
203 pending_items.push_back(Err(LexicalError::Token {
204 kind: types::token::ErrorKind::InvalidToken,
205 pos: NodeSpan::new(
206 start.source_id,
207 TextRange::new(start.offset, end.offset),
208 ),
209 }));
210
211 while let Some(maybe_lparen_result) = tokenizer.next() {
212 if let Some(types::Token::WS) = maybe_lparen_result.as_token_kind() {
214 pending_events.push_back(maybe_lparen_result);
215 continue;
216 }
217
218 if let Some(types::Token::LPAREN) = maybe_lparen_result.as_token_kind()
219 {
220 let mut level = 1;
224 let mut quoted = "#(".to_owned();
225
226 while level > 0 {
227 match tokenizer.next() {
228 Some(result) => {
229 if let Some((source_token, token_kind, _)) =
230 result.as_token()
231 {
232 match token_kind {
233 types::Token::LPAREN => level += 1,
234 types::Token::RPAREN => level -= 1,
235 _ => {}
236 }
237
238 if level > 0 {
239 quoted.push_str(source_token.text());
240 } else {
241 end = source_token.text_range().start();
242 }
243 }
244 }
245 None => {
246 *token_state = HandleTokenResult::Pending(
250 pending_items,
251 pending_events,
252 );
253 return;
254 }
255 }
256 }
257
258 quoted.push(')');
259 token_state.push_item(Ok((
260 start,
261 Token::Identifier(quoted.into()),
262 end,
263 )));
264 } else {
265 pending_events.push_back(maybe_lparen_result);
266 *token_state =
267 HandleTokenResult::Pending(pending_items, pending_events);
268 }
269
270 return;
271 }
272 }
273 }
274 };
275 }
276 }
277
278 pub fn into_directives(self) -> Directives {
279 self.directives.into()
280 }
281
282 pub fn handle_directive(
283 &mut self,
284 directive: EventDirective,
285 masked: bool,
286 ) -> Result<(), Vec<Error>> {
287 if masked {
288 return Ok(());
289 }
290
291 let errors = directive.errors().to_vec();
292
293 self.directives.push(directive);
294
295 if errors.is_empty() {
296 Ok(())
297 } else {
298 Err(errors)
299 }
300 }
301}