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                            if !self.if_stack.none() {
421                                // Always false if the last if state was activated once
422                                false
423                            } else {
424                                value
425                            }
426                        } else {
427                            // Do not evaluate if the group is not active
428                            true
429                        }
430                    }
431                    Err(_) => true,
432                };
433
434                // Update the if stack, which may fail
435                if let Err(error) = self.if_stack.on_elif(expr) {
436                    errors.push(ProcessingErrorKind::from(error));
437                }
438
439                match directive {
440                    Ok(elif_) => Event::directive_errors(elif_, !active, errors, &self.location),
441                    Err(error) => Event::directive_error(error, &self.location, !active),
442                }
443            }
444            PP_ELSE => {
445                let active = self.if_stack.if_group_active();
446                let directive: DirectiveResult<Else> =
447                    (self.location.current_file(), node).try_into();
448
449                // Update the if stack, which may fail
450                let error = self.if_stack.on_else().err().map(ProcessingErrorKind::from);
451
452                match directive {
453                    Ok(else_) => Event::directive_errors(else_, !active, error, &self.location),
454                    Err(error) => Event::directive_error(error, &self.location, !active),
455                }
456            }
457            PP_ENDIF => {
458                let active = self.if_stack.if_group_active();
459                let directive: DirectiveResult<EndIf> =
460                    (self.location.current_file(), node).try_into();
461
462                // Update the if stack, which may fail
463                let error = self
464                    .if_stack
465                    .on_endif()
466                    .err()
467                    .map(ProcessingErrorKind::from);
468
469                match directive {
470                    Ok(endif) => Event::directive_errors(endif, !active, error, &self.location),
471                    Err(error) => Event::directive_error(error, &self.location, !active),
472                }
473            }
474            PP_UNDEF => {
475                let active = self.if_stack.active();
476                let directive: DirectiveResult<Undef> =
477                    (self.location.current_file(), node).try_into();
478
479                match directive {
480                    Ok(undef) => {
481                        let protected_ident = if active {
482                            if undef.ident.starts_with("GL_") {
483                                Some(undef.ident.clone())
484                            } else if let Some(def) = current_state.definitions.get(&undef.ident) {
485                                if def.protected() {
486                                    Some(undef.ident.clone())
487                                } else {
488                                    current_state.definitions.remove(&undef.ident);
489                                    None
490                                }
491                            } else {
492                                None
493                            }
494                        } else {
495                            None
496                        };
497
498                        Event::directive_errors(
499                            undef,
500                            !active,
501                            protected_ident.map(|ident| ProcessingErrorKind::ProtectedDefine {
502                                ident,
503                                is_undef: true,
504                            }),
505                            &self.location,
506                        )
507                    }
508                    Err((error, node)) => Event::directive_error(
509                        (ProcessingErrorKind::DirectiveUndef(error), node),
510                        &self.location,
511                        !active,
512                    ),
513                }
514            }
515            PP_ERROR => {
516                let active = self.if_stack.active();
517                let directive: DirectiveResult<ErrorDirective> =
518                    (self.location.current_file(), node).try_into();
519
520                match directive {
521                    Ok(error) => {
522                        let user_error = ProcessingErrorKind::ErrorDirective {
523                            message: error.message.clone(),
524                        };
525
526                        Event::directive_errors(
527                            error,
528                            !active,
529                            std::iter::once(user_error),
530                            &self.location,
531                        )
532                    }
533                    Err(error) => Event::directive_error(error, &self.location, !active),
534                }
535            }
536            PP_INCLUDE => {
537                let active = self.if_stack.active();
538                // Parse the directive itself
539                let directive: DirectiveResult<Include> =
540                    (self.location.current_file(), node.clone()).try_into();
541
542                // Perform macro substitution to get the path. If this fails, the directive is
543                // malformed and shouldn't be processed.
544                let (directive, path) = match directive {
545                    Ok(directive) => match directive.path(current_state, &self.location) {
546                        Ok(path) => (Ok(directive), Some(path)),
547                        Err(err) => (Err((err, directive.node().clone())), None),
548                    },
549                    err => (err, None),
550                };
551
552                match directive {
553                    Ok(include) => {
554                        let error = match (path, current_state.include_mode) {
555                            (_, IncludeMode::None) if active => {
556                                // No include mode requested, thus we are not expecting include
557                                // directives and this is a parsing error
558                                Some(ErrorKind::Processing(
559                                    ProcessingErrorKind::IncludeNotSupported,
560                                ))
561                            }
562                            (Some(path), IncludeMode::GoogleInclude { warn }) if active => {
563                                // Compile-time include, enter nested file
564                                let node = include.node().clone();
565                                return HandleNodeResult::EnterFile(
566                                    Event::directive_errors(
567                                        include,
568                                        !active,
569                                        if warn {
570                                            Some(ErrorKind::warn_ext_use(
571                                                ext_name!("GL_GOOGLE_include_directive"),
572                                                None,
573                                                NodeSpan::new(
574                                                    self.location.current_file(),
575                                                    node.text_range(),
576                                                ),
577                                                &self.location,
578                                            ))
579                                        } else {
580                                            None
581                                        },
582                                        &self.location,
583                                    ),
584                                    node,
585                                    path,
586                                );
587                            }
588                            // Run-time ArbInclude or inactive if group
589                            (_, other) => {
590                                if other.warn() {
591                                    if matches!(other, IncludeMode::GoogleInclude { .. }) {
592                                        Some(ErrorKind::warn_ext_use(
593                                            ext_name!("GL_GOOGLE_include_directive"),
594                                            None,
595                                            NodeSpan::new(
596                                                self.location.current_file(),
597                                                node.text_range(),
598                                            ),
599                                            &self.location,
600                                        ))
601                                    } else if matches!(other, IncludeMode::ArbInclude { .. }) {
602                                        Some(ErrorKind::warn_ext_use(
603                                            ext_name!("GL_ARB_shading_language_include"),
604                                            None,
605                                            NodeSpan::new(
606                                                self.location.current_file(),
607                                                node.text_range(),
608                                            ),
609                                            &self.location,
610                                        ))
611                                    } else {
612                                        None
613                                    }
614                                } else {
615                                    None
616                                }
617                            }
618                        };
619
620                        // Forward the directive
621                        Event::directive_errors(include, !active, error, &self.location)
622                    }
623                    Err(error) => {
624                        if current_state.include_mode == IncludeMode::None {
625                            // If includes are not enabled, the proper error we need to report is
626                            // IncludeNotSupported, ignoring any errors inside the directive body
627                            Event::directive_error(
628                                (ProcessingErrorKind::IncludeNotSupported, node),
629                                &self.location,
630                                !active,
631                            )
632                        } else {
633                            Event::directive_error(error, &self.location, !active)
634                        }
635                    }
636                }
637            }
638            PP_LINE => {
639                let active = self.if_stack.active();
640                // Parse the directive itself
641                let directive: DirectiveResult<Line> =
642                    (self.location.current_file(), node).try_into();
643
644                // Perform macro substitution to get the path. If this fails, the directive is
645                // malformed and shouldn't be processed.
646                let (directive, line) = match directive {
647                    Ok(directive) => match directive.parse(current_state, &self.location) {
648                        Ok(path) => (Ok(directive), Some(path)),
649                        Err(err) => (Err((err, directive.node().clone())), None),
650                    },
651                    err => (err, None),
652                };
653
654                match directive {
655                    Ok(ld) => {
656                        let error = if active {
657                            if let Some(line) = line {
658                                // Check that we support cpp style line
659                                let (line, error) = match line {
660                                    ParsedLine::Line(_) | ParsedLine::LineAndFileNumber(_, _) => {
661                                        (line, None)
662                                    }
663                                    ParsedLine::LineAndPath(_, _)
664                                        if current_state.cpp_style_line() =>
665                                    {
666                                        (line, None)
667                                    }
668                                    ParsedLine::LineAndPath(line, _) => (
669                                        ParsedLine::Line(line),
670                                        Some(ProcessingErrorKind::CppStyleLineNotSupported),
671                                    ),
672                                };
673
674                                self.location
675                                    .add_override(ld.node().text_range().start(), line);
676                                error
677                            } else {
678                                None
679                            }
680                        } else {
681                            None
682                        };
683
684                        Event::directive_errors(ld, !active, error, &self.location)
685                    }
686                    Err(error) => Event::directive_error(error, &self.location, !active),
687                }
688            }
689            PP_PRAGMA => {
690                let active = self.if_stack.active();
691                let directive: DirectiveResult<Pragma> =
692                    (self.location.current_file(), node).try_into();
693
694                match directive {
695                    Ok(pragma) => Event::directive(pragma, !active),
696                    Err(error) => Event::directive_error(error, &self.location, !active),
697                }
698            }
699            ERROR => {
700                // Unknown preprocessor directive, these are already reported as parse errors
701                Event::directive(
702                    Directive::new(self.location.current_file(), node, Invalid),
703                    !self.if_stack.active(),
704                )
705            }
706            _ => {
707                // Should never happen if all preprocessor directives are implemented
708                panic!("unhandled node type: {:?}", node.kind());
709            }
710        }
711        .into()
712    }
713
714    fn handle_token(
715        &mut self,
716        current_state: ProcessorState,
717        token: SyntaxToken,
718        iterator: SyntaxElementChildren<PreprocessorLang>,
719        errors: Vec<parser::Error>,
720    ) -> Option<Event> {
721        // Look for macro substitutions unless the current group is masked
722        if let Some(definition) = (if self.if_stack.active() && token.kind() == IDENT_KW {
723            Some(Unescaped::new(token.text()).to_string())
724        } else {
725            None
726        })
727        .and_then(|ident| current_state.definitions.get(ident.as_ref()))
728        {
729            // We matched a defined identifier
730
731            match MacroInvocation::parse_raw(
732                definition,
733                token.clone(),
734                iterator.clone(),
735                &self.location,
736            ) {
737                Ok(Some((invocation, new_iterator))) => {
738                    // We successfully parsed a macro invocation
739                    self.state = ExpandState::ExpandedTokens {
740                        iterator: new_iterator,
741                        errors,
742                        events: invocation.substitute(&current_state, &self.location).into(),
743                        current_state,
744                    };
745                }
746                Ok(None) => {
747                    // Could not parse a macro invocation starting at the current token, so just
748                    // resume iterating normally
749                    self.state = ExpandState::Iterate {
750                        iterator,
751                        errors,
752                        current_state,
753                    };
754
755                    return Some(Event::token((token, self.location.current_file()), false));
756                }
757                Err(err) => {
758                    let mut events = ArrayVec::new();
759                    let pos = err.pos();
760                    events.push(Event::error(err.into_inner(), pos, &self.location, false));
761                    events.push(Event::token((token, self.location.current_file()), false));
762
763                    self.state = ExpandState::PendingEvents {
764                        iterator,
765                        errors,
766                        events,
767                        current_state,
768                    };
769                }
770            }
771
772            None
773        } else {
774            // No matching definition for this identifier or current if group is inactive, just keep iterating
775            self.state = ExpandState::Iterate {
776                iterator,
777                errors,
778                current_state,
779            };
780
781            Some(Event::token(
782                (token, self.location.current_file()),
783                !self.if_stack.active(),
784            ))
785        }
786    }
787
788    fn handle_node_or_token(
789        &mut self,
790        mut current_state: ProcessorState,
791        iterator: SyntaxElementChildren<PreprocessorLang>,
792        errors: Vec<parser::Error>,
793        node_or_token: NodeOrToken<SyntaxNode, SyntaxToken>,
794    ) -> Option<Event> {
795        match node_or_token {
796            rowan::NodeOrToken::Node(node) => match self.handle_node(&mut current_state, node) {
797                HandleNodeResult::Event(event) => {
798                    self.state = ExpandState::Iterate {
799                        iterator,
800                        errors,
801                        current_state,
802                    };
803
804                    Some(event)
805                }
806
807                HandleNodeResult::EnterFile(event, node, path) => {
808                    self.state = ExpandState::EnterNewFile {
809                        iterator,
810                        errors,
811                        current_state,
812                        path,
813                        node,
814                    };
815
816                    Some(event)
817                }
818            },
819            rowan::NodeOrToken::Token(token) => {
820                self.handle_token(current_state, token, iterator, errors)
821            }
822        }
823    }
824}
825
826pub(crate) enum ExpandEvent {
827    Event(Event),
828    EnterFile(SyntaxNode, ParsedPath),
829    Completed(ProcessorState),
830}
831
832impl From<Event> for ExpandEvent {
833    fn from(event: Event) -> Self {
834        Self::Event(event)
835    }
836}
837
838impl Iterator for ExpandOne {
839    type Item = ExpandEvent;
840
841    fn next(&mut self) -> Option<Self::Item> {
842        loop {
843            match std::mem::replace(&mut self.state, ExpandState::Complete) {
844                ExpandState::Init { ast, current_state } => {
845                    let (root, errors, line_map) = ast.into_inner();
846
847                    // Store the current line map
848                    self.location.line_map = line_map;
849
850                    self.state = ExpandState::Iterate {
851                        iterator: root.children_with_tokens(),
852                        errors,
853                        current_state,
854                    };
855
856                    return Some(Event::enter_file(self.location.current_file).into());
857                }
858                ExpandState::Iterate {
859                    mut iterator,
860                    mut errors,
861                    current_state,
862                } => {
863                    if let Some(node_or_token) = iterator.next() {
864                        if let Some(first) = errors.first() {
865                            if node_or_token.text_range().end() >= first.pos().start() {
866                                let error = errors.pop().unwrap();
867                                let pos = node_or_token.text_range();
868
869                                self.state = ExpandState::PendingOne {
870                                    iterator,
871                                    errors,
872                                    node_or_token,
873                                    current_state,
874                                };
875
876                                return Some(
877                                    Event::error(
878                                        error.into_inner(),
879                                        pos,
880                                        &self.location,
881                                        !self.if_stack.active(),
882                                    )
883                                    .into(),
884                                );
885                            }
886                        }
887
888                        if let Some(result) = self.handle_node_or_token(
889                            current_state,
890                            iterator,
891                            errors,
892                            node_or_token,
893                        ) {
894                            return Some(result.into());
895                        }
896                    } else {
897                        // Iteration completed, return the updated state
898                        return Some(ExpandEvent::Completed(current_state));
899                    }
900                }
901
902                ExpandState::EnterNewFile {
903                    iterator,
904                    errors,
905                    current_state,
906                    path,
907                    node,
908                } => {
909                    self.state = ExpandState::Iterate {
910                        iterator,
911                        errors,
912                        current_state,
913                    };
914
915                    return Some(ExpandEvent::EnterFile(node, path));
916                }
917
918                ExpandState::PendingOne {
919                    iterator,
920                    errors,
921                    node_or_token,
922                    current_state,
923                } => {
924                    if let Some(result) =
925                        self.handle_node_or_token(current_state, iterator, errors, node_or_token)
926                    {
927                        return Some(result.into());
928                    }
929                }
930                ExpandState::PendingEvents {
931                    iterator,
932                    errors,
933                    mut events,
934                    current_state,
935                } => {
936                    if let Some(event) = events.swap_pop(0) {
937                        self.state = ExpandState::PendingEvents {
938                            iterator,
939                            errors,
940                            events,
941                            current_state,
942                        };
943
944                        return Some(event.into());
945                    } else {
946                        self.state = ExpandState::Iterate {
947                            iterator,
948                            errors,
949                            current_state,
950                        };
951                    }
952                }
953
954                ExpandState::ExpandedTokens {
955                    iterator,
956                    errors,
957                    mut events,
958                    current_state,
959                } => {
960                    if let Some(event) = events.pop_front() {
961                        self.state = ExpandState::ExpandedTokens {
962                            iterator,
963                            errors,
964                            events,
965                            current_state,
966                        };
967
968                        return Some(event.into());
969                    } else {
970                        self.state = ExpandState::Iterate {
971                            iterator,
972                            errors,
973                            current_state,
974                        };
975                    }
976                }
977
978                ExpandState::Complete => {
979                    return None;
980                }
981            }
982        }
983    }
984}
985
986impl FusedIterator for ExpandOne {}