glsl_lang_pp/processor/
expand.rs

1use std::{
2    collections::{hash_map::Entry, VecDeque},
3    convert::TryInto,
4    iter::FusedIterator,
5};
6
7use arrayvec::ArrayVec;
8use derive_more::From;
9use rowan::{NodeOrToken, SyntaxElementChildren, TextSize};
10
11use lang_util::{
12    located::{HasFileNumber, Resolver},
13    position::NodeSpan,
14    FileId,
15};
16
17use crate::{
18    parser::{self, Ast, PreprocessorLang, SyntaxKind::*, SyntaxNode, SyntaxToken},
19    types::path::ParsedPath,
20    util::{LineMap, Unescaped},
21};
22
23use super::{
24    definition::{Definition, MacroInvocation},
25    event::{ErrorKind, Event, ProcessingErrorKind},
26    nodes::{
27        Define, Directive, DirectiveResult, Elif, Else, Empty, EndIf, Error as ErrorDirective,
28        Extension, If, IfDef, IfNDef, Include, Invalid, Line, ParsedLine, Pragma, Undef, Version,
29    },
30    IncludeMode, ProcessorState,
31};
32
33mod if_stack;
34use if_stack::IfStack;
35
36pub struct ExpandLocation {
37    current_file: FileId,
38    line_map: LineMap,
39    line_override: Option<(u32, ParsedLine)>,
40}
41
42impl Resolver for ExpandLocation {
43    fn resolve(&self, offset: TextSize) -> (u32, u32) {
44        self.offset_to_line_and_col(offset)
45    }
46}
47
48impl HasFileNumber for ExpandLocation {
49    fn current_file(&self) -> FileId {
50        self.current_file
51    }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum LocationString<'p> {
56    Number(u32),
57    String(&'p str),
58}
59
60impl LocationString<'_> {
61    pub fn is_number(&self) -> bool {
62        matches!(self, Self::Number(_))
63    }
64}
65
66impl std::fmt::Display for LocationString<'_> {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        match self {
69            LocationString::Number(num) => write!(f, "{}", num),
70            LocationString::String(path) => write!(f, "{}", path),
71        }
72    }
73}
74
75impl ExpandLocation {
76    pub fn new(current_file: FileId) -> Self {
77        Self {
78            current_file,
79            line_map: Default::default(),
80            line_override: Default::default(),
81        }
82    }
83
84    pub fn current_file(&self) -> FileId {
85        self.current_file
86    }
87
88    pub fn line_override(&self) -> Option<&(u32, ParsedLine)> {
89        self.line_override.as_ref()
90    }
91
92    pub fn offset_to_raw_line_and_col(&self, offset: TextSize) -> (u32, u32) {
93        self.line_map.get_line_and_col(offset.into())
94    }
95
96    pub fn offset_to_line_and_col(&self, offset: TextSize) -> (u32, u32) {
97        let line_and_col = self.offset_to_raw_line_and_col(offset);
98        (self.line_to_line_number(line_and_col.0), line_and_col.1)
99    }
100
101    pub fn line_to_line_number(&self, raw_line: u32) -> u32 {
102        if let Some((origin, line_override)) = &self.line_override {
103            let offset = line_override.line_number() as i64 - *origin as i64 - 2;
104            (raw_line as i64 + offset) as u32
105        } else {
106            raw_line
107        }
108    }
109
110    pub fn add_override(&mut self, current_offset: TextSize, line: ParsedLine) {
111        let raw_line = self.line_map.get_line_and_col(current_offset.into()).0;
112
113        // Combine the previous and the new override
114        self.line_override = match self.line_override.take() {
115            Some((_, prev_override)) => match line {
116                ParsedLine::Line(line_number) => Some(match prev_override {
117                    ParsedLine::Line(_) => line,
118                    ParsedLine::LineAndFileNumber(_, file_number) => {
119                        ParsedLine::LineAndFileNumber(line_number, file_number)
120                    }
121                    ParsedLine::LineAndPath(_, path) => ParsedLine::LineAndPath(line_number, path),
122                }),
123                ParsedLine::LineAndFileNumber(_, _) | ParsedLine::LineAndPath(_, _) => Some(line),
124            },
125            None => Some(line),
126        }
127        .map(|ov| (raw_line, ov));
128    }
129
130    pub fn string(&self) -> LocationString {
131        if let Some(line_override) = &self.line_override {
132            match &line_override.1 {
133                ParsedLine::LineAndFileNumber(_, number) => {
134                    return LocationString::Number(*number);
135                }
136                ParsedLine::LineAndPath(_, path) => {
137                    return LocationString::String(path.as_str());
138                }
139                _ => {}
140            }
141        }
142
143        LocationString::Number(self.current_file.number())
144    }
145}
146
147pub(crate) struct ExpandOne {
148    if_stack: IfStack,
149    location: ExpandLocation,
150    state: ExpandState,
151}
152
153#[allow(clippy::large_enum_variant)]
154enum ExpandState {
155    Init {
156        ast: Ast,
157        current_state: ProcessorState,
158    },
159    Iterate {
160        iterator: SyntaxElementChildren<PreprocessorLang>,
161        errors: Vec<parser::Error>,
162        current_state: ProcessorState,
163    },
164    EnterNewFile {
165        iterator: SyntaxElementChildren<PreprocessorLang>,
166        errors: Vec<parser::Error>,
167        current_state: ProcessorState,
168        path: ParsedPath,
169        node: SyntaxNode,
170    },
171    PendingOne {
172        iterator: SyntaxElementChildren<PreprocessorLang>,
173        errors: Vec<parser::Error>,
174        node_or_token: NodeOrToken<SyntaxNode, SyntaxToken>,
175        current_state: ProcessorState,
176    },
177    PendingEvents {
178        iterator: SyntaxElementChildren<PreprocessorLang>,
179        errors: Vec<parser::Error>,
180        events: ArrayVec<Event, 3>,
181        current_state: ProcessorState,
182    },
183    ExpandedTokens {
184        iterator: SyntaxElementChildren<PreprocessorLang>,
185        errors: Vec<parser::Error>,
186        events: VecDeque<Event>,
187        current_state: ProcessorState,
188    },
189    Complete,
190}
191
192#[derive(From)]
193enum HandleNodeResult {
194    Event(Event),
195    EnterFile(Event, SyntaxNode, ParsedPath),
196}
197
198impl ExpandOne {
199    pub fn new(parsed_file: impl Into<(FileId, Ast)>, current_state: ProcessorState) -> Self {
200        let (file_id, ast) = parsed_file.into();
201
202        Self {
203            if_stack: IfStack::new(),
204            location: ExpandLocation::new(file_id),
205            state: ExpandState::Init { ast, current_state },
206        }
207    }
208
209    pub fn state(&self) -> Option<&ProcessorState> {
210        match &self.state {
211            ExpandState::Init { current_state, .. }
212            | ExpandState::Iterate { current_state, .. }
213            | ExpandState::EnterNewFile { current_state, .. }
214            | ExpandState::PendingOne { current_state, .. }
215            | ExpandState::PendingEvents { current_state, .. }
216            | ExpandState::ExpandedTokens { current_state, .. } => Some(current_state),
217            ExpandState::Complete => None,
218        }
219    }
220
221    pub fn set_state(&mut self, new_state: ProcessorState) {
222        match &mut self.state {
223            ExpandState::Init { current_state, .. }
224            | ExpandState::Iterate { current_state, .. }
225            | ExpandState::EnterNewFile { current_state, .. }
226            | ExpandState::PendingOne { current_state, .. }
227            | ExpandState::PendingEvents { current_state, .. }
228            | ExpandState::ExpandedTokens { current_state, .. } => {
229                *current_state = new_state;
230            }
231            ExpandState::Complete => {
232                panic!("cannot update the state on a completed expand");
233            }
234        }
235    }
236
237    pub fn location(&self) -> &ExpandLocation {
238        &self.location
239    }
240
241    fn handle_node(
242        &mut self,
243        current_state: &mut ProcessorState,
244        node: SyntaxNode,
245    ) -> HandleNodeResult {
246        match node.kind() {
247            PP_EMPTY => Event::directive(
248                Directive::new(self.location.current_file(), node, Empty),
249                !self.if_stack.active(),
250            ),
251            PP_VERSION => {
252                let active = self.if_stack.active();
253                let directive: DirectiveResult<Version> =
254                    (self.location.current_file(), node).try_into();
255
256                match directive {
257                    Ok(directive) => {
258                        // TODO: Check that the version is the first thing in the file?
259                        if active {
260                            current_state.version = *directive;
261                        }
262
263                        Event::directive(directive, !active)
264                    }
265                    Err(error) => Event::directive_error(error, &self.location, !active),
266                }
267            }
268            PP_EXTENSION => {
269                let active = self.if_stack.active();
270                let directive: DirectiveResult<Extension> =
271                    (self.location.current_file(), node).try_into();
272
273                match directive {
274                    Ok(directive) => {
275                        if active {
276                            current_state.extension(&directive);
277                        }
278
279                        Event::directive(directive, !active)
280                    }
281                    Err(error) => Event::directive_error(error, &self.location, !active),
282                }
283            }
284            PP_DEFINE => {
285                let active = self.if_stack.active();
286                let directive: DirectiveResult<Define> =
287                    (self.location.current_file(), node).try_into();
288
289                match directive {
290                    Ok(define) => {
291                        let error = if active {
292                            if define.name().starts_with("GL_") {
293                                Some(ProcessingErrorKind::ProtectedDefine {
294                                    ident: define.name().into(),
295                                    is_undef: false,
296                                })
297                            } else {
298                                let definition = Definition::Regular(
299                                    (*define).clone().into(),
300                                    self.location.current_file(),
301                                );
302
303                                match current_state.definitions.entry(define.name().into()) {
304                                    Entry::Occupied(mut entry) => {
305                                        if entry.get().protected() {
306                                            Some(ProcessingErrorKind::ProtectedDefine {
307                                                ident: define.name().into(),
308                                                is_undef: false,
309                                            })
310                                        } else {
311                                            // TODO: Check that we are not overwriting an incompatible definition
312                                            *entry.get_mut() = definition;
313
314                                            None
315                                        }
316                                    }
317                                    Entry::Vacant(entry) => {
318                                        entry.insert(definition);
319                                        None
320                                    }
321                                }
322                            }
323                        } else {
324                            None
325                        };
326
327                        Event::directive_errors(define, !active, error, &self.location)
328                    }
329                    Err(error) => Event::directive_error(error, &self.location, !active),
330                }
331            }
332            PP_IFDEF => {
333                let active = self.if_stack.active();
334                let directive: DirectiveResult<IfDef> =
335                    (self.location.current_file(), node).try_into();
336
337                let (result, ret) = match directive {
338                    Ok(ifdef) => {
339                        let is_defined = current_state.definitions.contains_key(&ifdef.ident);
340                        (is_defined, Event::directive(ifdef, !active))
341                    }
342                    Err(error) => (true, Event::directive_error(error, &self.location, !active)),
343                };
344
345                self.if_stack.on_if_like(result);
346                ret
347            }
348            PP_IFNDEF => {
349                let active = self.if_stack.active();
350                let directive: DirectiveResult<IfNDef> =
351                    (self.location.current_file(), node).try_into();
352
353                let (result, ret) = match directive {
354                    Ok(ifndef) => {
355                        // Update masking state
356                        let is_defined = current_state.definitions.contains_key(&ifndef.ident);
357                        (!is_defined, Event::directive(ifndef, !active))
358                    }
359                    Err((error, node)) => (
360                        true,
361                        Event::directive_error(
362                            (ProcessingErrorKind::DirectiveIfNDef(error), node),
363                            &self.location,
364                            !active,
365                        ),
366                    ),
367                };
368
369                self.if_stack.on_if_like(result);
370                ret
371            }
372            PP_IF => {
373                let active = self.if_stack.active();
374                let directive: DirectiveResult<If> =
375                    (self.location.current_file(), node).try_into();
376
377                let (result, ret) = match directive {
378                    Ok(if_) => {
379                        let (value, error) = if active {
380                            if_.eval(current_state, &self.location)
381                        } else {
382                            (true, None)
383                        };
384
385                        (
386                            value,
387                            Event::directive_errors(
388                                if_,
389                                !active,
390                                error.map(ProcessingErrorKind::DirectiveIf),
391                                &self.location,
392                            ),
393                        )
394                    }
395                    Err(error) => (true, Event::directive_error(error, &self.location, !active)),
396                };
397
398                self.if_stack.on_if_like(result);
399                ret
400            }
401            PP_ELIF => {
402                let active = self.if_stack.if_group_active();
403                let directive: DirectiveResult<Elif> =
404                    (self.location.current_file(), node).try_into();
405                let mut errors: ArrayVec<_, 2> = ArrayVec::new();
406
407                let expr = match &directive {
408                    Ok(elif_) => {
409                        if self.if_stack.if_group_active() {
410                            let (value, error) = if active {
411                                elif_.eval(current_state, &self.location)
412                            } else {
413                                (true, None)
414                            };
415
416                            if let Some(error) = error {
417                                errors.push(ProcessingErrorKind::DirectiveElif(error));
418                            }
419
420                            value
421                        } else {
422                            // Do not evaluate if the group is not active
423                            true
424                        }
425                    }
426                    Err(_) => true,
427                };
428
429                // Update the if stack, which may fail
430                if let Err(error) = self.if_stack.on_elif(expr) {
431                    errors.push(ProcessingErrorKind::from(error));
432                }
433
434                match directive {
435                    Ok(elif_) => Event::directive_errors(elif_, !active, errors, &self.location),
436                    Err(error) => Event::directive_error(error, &self.location, !active),
437                }
438            }
439            PP_ELSE => {
440                let active = self.if_stack.if_group_active();
441                let directive: DirectiveResult<Else> =
442                    (self.location.current_file(), node).try_into();
443
444                // Update the if stack, which may fail
445                let error = self.if_stack.on_else().err().map(ProcessingErrorKind::from);
446
447                match directive {
448                    Ok(else_) => Event::directive_errors(else_, !active, error, &self.location),
449                    Err(error) => Event::directive_error(error, &self.location, !active),
450                }
451            }
452            PP_ENDIF => {
453                let active = self.if_stack.if_group_active();
454                let directive: DirectiveResult<EndIf> =
455                    (self.location.current_file(), node).try_into();
456
457                // Update the if stack, which may fail
458                let error = self
459                    .if_stack
460                    .on_endif()
461                    .err()
462                    .map(ProcessingErrorKind::from);
463
464                match directive {
465                    Ok(endif) => Event::directive_errors(endif, !active, error, &self.location),
466                    Err(error) => Event::directive_error(error, &self.location, !active),
467                }
468            }
469            PP_UNDEF => {
470                let active = self.if_stack.active();
471                let directive: DirectiveResult<Undef> =
472                    (self.location.current_file(), node).try_into();
473
474                match directive {
475                    Ok(undef) => {
476                        let protected_ident = if active {
477                            if undef.ident.starts_with("GL_") {
478                                Some(undef.ident.clone())
479                            } else if let Some(def) = current_state.definitions.get(&undef.ident) {
480                                if def.protected() {
481                                    Some(undef.ident.clone())
482                                } else {
483                                    current_state.definitions.remove(&undef.ident);
484                                    None
485                                }
486                            } else {
487                                None
488                            }
489                        } else {
490                            None
491                        };
492
493                        Event::directive_errors(
494                            undef,
495                            !active,
496                            protected_ident.map(|ident| ProcessingErrorKind::ProtectedDefine {
497                                ident,
498                                is_undef: true,
499                            }),
500                            &self.location,
501                        )
502                    }
503                    Err((error, node)) => Event::directive_error(
504                        (ProcessingErrorKind::DirectiveUndef(error), node),
505                        &self.location,
506                        !active,
507                    ),
508                }
509            }
510            PP_ERROR => {
511                let active = self.if_stack.active();
512                let directive: DirectiveResult<ErrorDirective> =
513                    (self.location.current_file(), node).try_into();
514
515                match directive {
516                    Ok(error) => {
517                        let user_error = ProcessingErrorKind::ErrorDirective {
518                            message: error.message.clone(),
519                        };
520
521                        Event::directive_errors(
522                            error,
523                            !active,
524                            std::iter::once(user_error),
525                            &self.location,
526                        )
527                    }
528                    Err(error) => Event::directive_error(error, &self.location, !active),
529                }
530            }
531            PP_INCLUDE => {
532                let active = self.if_stack.active();
533                // Parse the directive itself
534                let directive: DirectiveResult<Include> =
535                    (self.location.current_file(), node.clone()).try_into();
536
537                // Perform macro substitution to get the path. If this fails, the directive is
538                // malformed and shouldn't be processed.
539                let (directive, path) = match directive {
540                    Ok(directive) => match directive.path(current_state, &self.location) {
541                        Ok(path) => (Ok(directive), Some(path)),
542                        Err(err) => (Err((err, directive.node().clone())), None),
543                    },
544                    err => (err, None),
545                };
546
547                match directive {
548                    Ok(include) => {
549                        let error = match (path, current_state.include_mode) {
550                            (_, IncludeMode::None) if active => {
551                                // No include mode requested, thus we are not expecting include
552                                // directives and this is a parsing error
553                                Some(ErrorKind::Processing(
554                                    ProcessingErrorKind::IncludeNotSupported,
555                                ))
556                            }
557                            (Some(path), IncludeMode::GoogleInclude { warn }) if active => {
558                                // Compile-time include, enter nested file
559                                let node = include.node().clone();
560                                return HandleNodeResult::EnterFile(
561                                    Event::directive_errors(
562                                        include,
563                                        !active,
564                                        if warn {
565                                            Some(ErrorKind::warn_ext_use(
566                                                ext_name!("GL_GOOGLE_include_directive"),
567                                                None,
568                                                NodeSpan::new(
569                                                    self.location.current_file(),
570                                                    node.text_range(),
571                                                ),
572                                                &self.location,
573                                            ))
574                                        } else {
575                                            None
576                                        },
577                                        &self.location,
578                                    ),
579                                    node,
580                                    path,
581                                );
582                            }
583                            // Run-time ArbInclude or inactive if group
584                            (_, other) => {
585                                if other.warn() {
586                                    if matches!(other, IncludeMode::GoogleInclude { .. }) {
587                                        Some(ErrorKind::warn_ext_use(
588                                            ext_name!("GL_GOOGLE_include_directive"),
589                                            None,
590                                            NodeSpan::new(
591                                                self.location.current_file(),
592                                                node.text_range(),
593                                            ),
594                                            &self.location,
595                                        ))
596                                    } else if matches!(other, IncludeMode::ArbInclude { .. }) {
597                                        Some(ErrorKind::warn_ext_use(
598                                            ext_name!("GL_ARB_shading_language_include"),
599                                            None,
600                                            NodeSpan::new(
601                                                self.location.current_file(),
602                                                node.text_range(),
603                                            ),
604                                            &self.location,
605                                        ))
606                                    } else {
607                                        None
608                                    }
609                                } else {
610                                    None
611                                }
612                            }
613                        };
614
615                        // Forward the directive
616                        Event::directive_errors(include, !active, error, &self.location)
617                    }
618                    Err(error) => {
619                        if current_state.include_mode == IncludeMode::None {
620                            // If includes are not enabled, the proper error we need to report is
621                            // IncludeNotSupported, ignoring any errors inside the directive body
622                            Event::directive_error(
623                                (ProcessingErrorKind::IncludeNotSupported, node),
624                                &self.location,
625                                !active,
626                            )
627                        } else {
628                            Event::directive_error(error, &self.location, !active)
629                        }
630                    }
631                }
632            }
633            PP_LINE => {
634                let active = self.if_stack.active();
635                // Parse the directive itself
636                let directive: DirectiveResult<Line> =
637                    (self.location.current_file(), node).try_into();
638
639                // Perform macro substitution to get the path. If this fails, the directive is
640                // malformed and shouldn't be processed.
641                let (directive, line) = match directive {
642                    Ok(directive) => match directive.parse(current_state, &self.location) {
643                        Ok(path) => (Ok(directive), Some(path)),
644                        Err(err) => (Err((err, directive.node().clone())), None),
645                    },
646                    err => (err, None),
647                };
648
649                match directive {
650                    Ok(ld) => {
651                        let error = if active {
652                            if let Some(line) = line {
653                                // Check that we support cpp style line
654                                let (line, error) = match line {
655                                    ParsedLine::Line(_) | ParsedLine::LineAndFileNumber(_, _) => {
656                                        (line, None)
657                                    }
658                                    ParsedLine::LineAndPath(_, _)
659                                        if current_state.cpp_style_line() =>
660                                    {
661                                        (line, None)
662                                    }
663                                    ParsedLine::LineAndPath(line, _) => (
664                                        ParsedLine::Line(line),
665                                        Some(ProcessingErrorKind::CppStyleLineNotSupported),
666                                    ),
667                                };
668
669                                self.location
670                                    .add_override(ld.node().text_range().start(), line);
671                                error
672                            } else {
673                                None
674                            }
675                        } else {
676                            None
677                        };
678
679                        Event::directive_errors(ld, !active, error, &self.location)
680                    }
681                    Err(error) => Event::directive_error(error, &self.location, !active),
682                }
683            }
684            PP_PRAGMA => {
685                let active = self.if_stack.active();
686                let directive: DirectiveResult<Pragma> =
687                    (self.location.current_file(), node).try_into();
688
689                match directive {
690                    Ok(pragma) => Event::directive(pragma, !active),
691                    Err(error) => Event::directive_error(error, &self.location, !active),
692                }
693            }
694            ERROR => {
695                // Unknown preprocessor directive, these are already reported as parse errors
696                Event::directive(
697                    Directive::new(self.location.current_file(), node, Invalid),
698                    !self.if_stack.active(),
699                )
700            }
701            _ => {
702                // Should never happen if all preprocessor directives are implemented
703                panic!("unhandled node type: {:?}", node.kind());
704            }
705        }
706        .into()
707    }
708
709    fn handle_token(
710        &mut self,
711        current_state: ProcessorState,
712        token: SyntaxToken,
713        iterator: SyntaxElementChildren<PreprocessorLang>,
714        errors: Vec<parser::Error>,
715    ) -> Option<Event> {
716        // Look for macro substitutions unless the current group is masked
717        if let Some(definition) = (if self.if_stack.active() && token.kind() == IDENT_KW {
718            Some(Unescaped::new(token.text()).to_string())
719        } else {
720            None
721        })
722        .and_then(|ident| current_state.definitions.get(ident.as_ref()))
723        {
724            // We matched a defined identifier
725
726            match MacroInvocation::parse_raw(
727                definition,
728                token.clone(),
729                iterator.clone(),
730                &self.location,
731            ) {
732                Ok(Some((invocation, new_iterator))) => {
733                    // We successfully parsed a macro invocation
734                    self.state = ExpandState::ExpandedTokens {
735                        iterator: new_iterator,
736                        errors,
737                        events: invocation.substitute(&current_state, &self.location).into(),
738                        current_state,
739                    };
740                }
741                Ok(None) => {
742                    // Could not parse a macro invocation starting at the current token, so just
743                    // resume iterating normally
744                    self.state = ExpandState::Iterate {
745                        iterator,
746                        errors,
747                        current_state,
748                    };
749
750                    return Some(Event::token((token, self.location.current_file()), false));
751                }
752                Err(err) => {
753                    let mut events = ArrayVec::new();
754                    let pos = err.pos();
755                    events.push(Event::error(err.into_inner(), pos, &self.location, false));
756                    events.push(Event::token((token, self.location.current_file()), false));
757
758                    self.state = ExpandState::PendingEvents {
759                        iterator,
760                        errors,
761                        events,
762                        current_state,
763                    };
764                }
765            }
766
767            None
768        } else {
769            // No matching definition for this identifier or current if group is inactive, just keep iterating
770            self.state = ExpandState::Iterate {
771                iterator,
772                errors,
773                current_state,
774            };
775
776            Some(Event::token(
777                (token, self.location.current_file()),
778                !self.if_stack.active(),
779            ))
780        }
781    }
782
783    fn handle_node_or_token(
784        &mut self,
785        mut current_state: ProcessorState,
786        iterator: SyntaxElementChildren<PreprocessorLang>,
787        errors: Vec<parser::Error>,
788        node_or_token: NodeOrToken<SyntaxNode, SyntaxToken>,
789    ) -> Option<Event> {
790        match node_or_token {
791            rowan::NodeOrToken::Node(node) => match self.handle_node(&mut current_state, node) {
792                HandleNodeResult::Event(event) => {
793                    self.state = ExpandState::Iterate {
794                        iterator,
795                        errors,
796                        current_state,
797                    };
798
799                    Some(event)
800                }
801
802                HandleNodeResult::EnterFile(event, node, path) => {
803                    self.state = ExpandState::EnterNewFile {
804                        iterator,
805                        errors,
806                        current_state,
807                        path,
808                        node,
809                    };
810
811                    Some(event)
812                }
813            },
814            rowan::NodeOrToken::Token(token) => {
815                self.handle_token(current_state, token, iterator, errors)
816            }
817        }
818    }
819}
820
821pub(crate) enum ExpandEvent {
822    Event(Event),
823    EnterFile(SyntaxNode, ParsedPath),
824    Completed(ProcessorState),
825}
826
827impl From<Event> for ExpandEvent {
828    fn from(event: Event) -> Self {
829        Self::Event(event)
830    }
831}
832
833impl Iterator for ExpandOne {
834    type Item = ExpandEvent;
835
836    fn next(&mut self) -> Option<Self::Item> {
837        loop {
838            match std::mem::replace(&mut self.state, ExpandState::Complete) {
839                ExpandState::Init { ast, current_state } => {
840                    let (root, errors, line_map) = ast.into_inner();
841
842                    // Store the current line map
843                    self.location.line_map = line_map;
844
845                    self.state = ExpandState::Iterate {
846                        iterator: root.children_with_tokens(),
847                        errors,
848                        current_state,
849                    };
850
851                    return Some(Event::enter_file(self.location.current_file).into());
852                }
853                ExpandState::Iterate {
854                    mut iterator,
855                    mut errors,
856                    current_state,
857                } => {
858                    if let Some(node_or_token) = iterator.next() {
859                        if let Some(first) = errors.first() {
860                            if node_or_token.text_range().end() >= first.pos().start() {
861                                let error = errors.pop().unwrap();
862                                let pos = node_or_token.text_range();
863
864                                self.state = ExpandState::PendingOne {
865                                    iterator,
866                                    errors,
867                                    node_or_token,
868                                    current_state,
869                                };
870
871                                return Some(
872                                    Event::error(
873                                        error.into_inner(),
874                                        pos,
875                                        &self.location,
876                                        !self.if_stack.active(),
877                                    )
878                                    .into(),
879                                );
880                            }
881                        }
882
883                        if let Some(result) = self.handle_node_or_token(
884                            current_state,
885                            iterator,
886                            errors,
887                            node_or_token,
888                        ) {
889                            return Some(result.into());
890                        }
891                    } else {
892                        // Iteration completed, return the updated state
893                        return Some(ExpandEvent::Completed(current_state));
894                    }
895                }
896
897                ExpandState::EnterNewFile {
898                    iterator,
899                    errors,
900                    current_state,
901                    path,
902                    node,
903                } => {
904                    self.state = ExpandState::Iterate {
905                        iterator,
906                        errors,
907                        current_state,
908                    };
909
910                    return Some(ExpandEvent::EnterFile(node, path));
911                }
912
913                ExpandState::PendingOne {
914                    iterator,
915                    errors,
916                    node_or_token,
917                    current_state,
918                } => {
919                    if let Some(result) =
920                        self.handle_node_or_token(current_state, iterator, errors, node_or_token)
921                    {
922                        return Some(result.into());
923                    }
924                }
925                ExpandState::PendingEvents {
926                    iterator,
927                    errors,
928                    mut events,
929                    current_state,
930                } => {
931                    if let Some(event) = events.swap_pop(0) {
932                        self.state = ExpandState::PendingEvents {
933                            iterator,
934                            errors,
935                            events,
936                            current_state,
937                        };
938
939                        return Some(event.into());
940                    } else {
941                        self.state = ExpandState::Iterate {
942                            iterator,
943                            errors,
944                            current_state,
945                        };
946                    }
947                }
948
949                ExpandState::ExpandedTokens {
950                    iterator,
951                    errors,
952                    mut events,
953                    current_state,
954                } => {
955                    if let Some(event) = events.pop_front() {
956                        self.state = ExpandState::ExpandedTokens {
957                            iterator,
958                            errors,
959                            events,
960                            current_state,
961                        };
962
963                        return Some(event.into());
964                    } else {
965                        self.state = ExpandState::Iterate {
966                            iterator,
967                            errors,
968                            current_state,
969                        };
970                    }
971                }
972
973                ExpandState::Complete => {
974                    return None;
975                }
976            }
977        }
978    }
979}
980
981impl FusedIterator for ExpandOne {}