rust_yaml/parser/
mod.rs

1//! YAML parser for converting tokens to events
2
3use crate::{
4    error::ErrorContext, tag::TagResolver, BasicScanner, Error, Limits, Position, Result, Scanner,
5    Token, TokenType,
6};
7
8pub mod events;
9pub mod streaming;
10// pub mod optimizations; // Temporarily disabled
11pub use events::*;
12pub use streaming::*;
13// pub use optimizations::*;
14
15/// Trait for YAML parsers that convert token streams to events
16pub trait Parser {
17    /// Check if there are more events available
18    fn check_event(&self) -> bool;
19
20    /// Peek at the next event without consuming it
21    fn peek_event(&self) -> Result<Option<&Event>>;
22
23    /// Get the next event, consuming it
24    fn get_event(&mut self) -> Result<Option<Event>>;
25
26    /// Reset the parser state
27    fn reset(&mut self);
28
29    /// Get the current position in the input
30    fn position(&self) -> Position;
31}
32
33/// Basic parser implementation that converts tokens to events
34#[derive(Debug)]
35pub struct BasicParser {
36    scanner: BasicScanner,
37    events: Vec<Event>,
38    event_index: usize,
39    state: ParserState,
40    state_stack: Vec<ParserState>,
41    position: Position,
42    pending_anchor: Option<String>,
43    pending_tag: Option<String>,
44    last_token_type: Option<TokenType>,
45    scanning_error: Option<Error>,
46    yaml_version: Option<(u8, u8)>,
47    tag_directives: Vec<(String, String)>,
48    tag_resolver: TagResolver,
49}
50
51/// Parser state for tracking context
52#[derive(Debug, Clone, Copy, PartialEq)]
53#[allow(dead_code)]
54enum ParserState {
55    StreamStart,
56    StreamEnd,
57    ImplicitDocumentStart,
58    DocumentStart,
59    DocumentContent,
60    DocumentEnd,
61    BlockNode,
62    BlockMapping,
63    BlockMappingKey,
64    BlockMappingValue,
65    BlockSequence,
66    FlowMapping,
67    FlowMappingKey,
68    FlowMappingValue,
69    FlowSequence,
70    BlockEnd,
71}
72
73impl BasicParser {
74    /// Create a new streaming parser (lazy parsing)
75    pub fn new(input: String) -> Self {
76        Self::with_limits(input, Limits::default())
77    }
78
79    /// Create a new streaming parser with custom limits
80    pub fn with_limits(input: String, limits: Limits) -> Self {
81        let scanner = BasicScanner::with_limits(input, limits);
82        let position = scanner.position();
83
84        Self {
85            scanner,
86            events: Vec::new(),
87            event_index: 0,
88            state: ParserState::StreamStart,
89            state_stack: Vec::new(),
90            position,
91            pending_anchor: None,
92            pending_tag: None,
93            last_token_type: None,
94            scanning_error: None,
95            yaml_version: None,
96            tag_directives: Vec::new(),
97            tag_resolver: TagResolver::new(),
98        }
99    }
100
101    /// Create a new parser with eager parsing (for compatibility)
102    pub fn new_eager(input: String) -> Self {
103        Self::new_eager_with_limits(input, Limits::default())
104    }
105
106    /// Create a new parser with eager parsing and custom limits
107    pub fn new_eager_with_limits(input: String, limits: Limits) -> Self {
108        let mut scanner = BasicScanner::new_eager_with_limits(input, limits);
109        let position = scanner.position();
110
111        // Check if there were any scanning errors and store them
112        let scanning_error = scanner.take_scanning_error();
113
114        let mut parser = Self {
115            scanner,
116            events: Vec::new(),
117            event_index: 0,
118            state: ParserState::StreamStart,
119            state_stack: Vec::new(),
120            position,
121            pending_anchor: None,
122            pending_tag: None,
123            last_token_type: None,
124            scanning_error: None,
125            yaml_version: None,
126            tag_directives: Vec::new(),
127            tag_resolver: TagResolver::new(),
128        };
129
130        // If there was a scanning error, store it for later propagation
131        if let Some(error) = scanning_error {
132            parser.scanning_error = Some(error);
133        } else {
134            // Parse all events immediately only if there were no scanning errors
135            parser.parse_all().unwrap_or(());
136        }
137
138        parser
139    }
140
141    /// Create parser from existing scanner
142    pub fn from_scanner(scanner: BasicScanner) -> Self {
143        let position = scanner.position();
144
145        let mut parser = Self {
146            scanner,
147            events: Vec::new(),
148            event_index: 0,
149            state: ParserState::StreamStart,
150            state_stack: Vec::new(),
151            position,
152            pending_anchor: None,
153            pending_tag: None,
154            last_token_type: None,
155            scanning_error: None,
156            yaml_version: None,
157            tag_directives: Vec::new(),
158            tag_resolver: TagResolver::new(),
159        };
160
161        parser.parse_all().unwrap_or(());
162        parser
163    }
164
165    /// Parse all tokens into events
166    fn parse_all(&mut self) -> Result<()> {
167        while self.scanner.check_token() {
168            let token = match self.scanner.get_token()? {
169                Some(token) => token,
170                None => break,
171            };
172
173            self.position = token.end_position;
174            self.process_token(token)?;
175        }
176
177        // Check for unclosed structures
178        self.validate_final_state()?;
179
180        // Ensure stream end
181        if !self
182            .events
183            .iter()
184            .any(|e| matches!(e.event_type, EventType::StreamEnd))
185        {
186            self.events.push(Event::stream_end(self.position));
187        }
188
189        Ok(())
190    }
191
192    /// Create implicit document start event with directives
193    fn create_implicit_document_start(&mut self, position: Position) -> Event {
194        let event = Event::document_start(
195            position,
196            self.yaml_version.take(),
197            self.tag_directives.clone(),
198            true,
199        );
200        self.tag_directives.clear();
201        event
202    }
203
204    /// Validate that the parser is in a valid final state
205    fn validate_final_state(&self) -> Result<()> {
206        match self.state {
207            ParserState::StreamEnd | ParserState::DocumentEnd | ParserState::DocumentContent => {
208                // These are valid final states
209                Ok(())
210            }
211            ParserState::BlockSequence | ParserState::FlowSequence => {
212                let context = ErrorContext::from_input(self.scanner.input(), &self.position, 2)
213                    .with_suggestion(
214                        "Close the sequence with proper indentation or closing bracket".to_string(),
215                    );
216                Err(Error::unclosed_delimiter_with_context(
217                    self.position,
218                    self.position,
219                    "sequence",
220                    context,
221                ))
222            }
223            ParserState::BlockMapping | ParserState::FlowMapping => {
224                let context = ErrorContext::from_input(self.scanner.input(), &self.position, 2)
225                    .with_suggestion(
226                        "Close the mapping with proper indentation or closing brace".to_string(),
227                    );
228                Err(Error::unclosed_delimiter_with_context(
229                    self.position,
230                    self.position,
231                    "mapping",
232                    context,
233                ))
234            }
235            _ => {
236                let context = ErrorContext::from_input(self.scanner.input(), &self.position, 2)
237                    .with_suggestion("Complete the YAML document structure".to_string());
238                Err(Error::parse_with_context(
239                    self.position,
240                    format!("Document ended in unexpected state: {:?}", self.state),
241                    context,
242                ))
243            }
244        }
245    }
246
247    /// Generate the next event by processing the next token
248    fn generate_next_event(&mut self) -> Result<()> {
249        if let Some(token) = self.scanner.get_token()? {
250            self.position = token.end_position;
251            self.process_token(token)?;
252        }
253        Ok(())
254    }
255
256    /// Process a single token and generate appropriate events
257    #[allow(clippy::cognitive_complexity)]
258    fn process_token(&mut self, token: Token) -> Result<()> {
259        // Store the token type for later use without cloning
260        let token_type_for_tracking = match &token.token_type {
261            TokenType::Scalar(..) => Some(TokenType::Scalar(
262                String::new(),
263                crate::scanner::QuoteStyle::Plain,
264            )),
265            TokenType::BlockScalarLiteral(..) => Some(TokenType::BlockScalarLiteral(String::new())),
266            TokenType::BlockScalarFolded(..) => Some(TokenType::BlockScalarFolded(String::new())),
267            TokenType::Alias(..) => Some(TokenType::Alias(String::new())),
268            TokenType::Anchor(..) => Some(TokenType::Anchor(String::new())),
269            TokenType::Tag(..) => Some(TokenType::Tag(String::new())),
270            TokenType::Comment(..) => Some(TokenType::Comment(String::new())),
271            other => {
272                // For simple token types without data, we can safely clone
273                match other {
274                    TokenType::StreamStart => Some(TokenType::StreamStart),
275                    TokenType::StreamEnd => Some(TokenType::StreamEnd),
276                    TokenType::DocumentStart => Some(TokenType::DocumentStart),
277                    TokenType::DocumentEnd => Some(TokenType::DocumentEnd),
278                    TokenType::BlockSequenceStart => Some(TokenType::BlockSequenceStart),
279                    TokenType::BlockMappingStart => Some(TokenType::BlockMappingStart),
280                    TokenType::BlockEnd => Some(TokenType::BlockEnd),
281                    TokenType::FlowSequenceStart => Some(TokenType::FlowSequenceStart),
282                    TokenType::FlowSequenceEnd => Some(TokenType::FlowSequenceEnd),
283                    TokenType::FlowMappingStart => Some(TokenType::FlowMappingStart),
284                    TokenType::FlowMappingEnd => Some(TokenType::FlowMappingEnd),
285                    TokenType::BlockEntry => Some(TokenType::BlockEntry),
286                    TokenType::FlowEntry => Some(TokenType::FlowEntry),
287                    TokenType::Key => Some(TokenType::Key),
288                    TokenType::Value => Some(TokenType::Value),
289                    TokenType::YamlDirective(_, _) => Some(TokenType::YamlDirective(0, 0)),
290                    TokenType::TagDirective(_, _) => {
291                        Some(TokenType::TagDirective(String::new(), String::new()))
292                    }
293                    _ => None,
294                }
295            }
296        };
297
298        match &token.token_type {
299            TokenType::StreamStart => {
300                self.events.push(Event::stream_start(token.start_position));
301                self.state = ParserState::ImplicitDocumentStart;
302            }
303
304            TokenType::StreamEnd => {
305                // Close any open document
306                if matches!(
307                    self.state,
308                    ParserState::DocumentContent | ParserState::BlockNode
309                ) {
310                    self.events
311                        .push(Event::document_end(token.start_position, true));
312                }
313                self.events.push(Event::stream_end(token.start_position));
314                self.state = ParserState::StreamEnd;
315            }
316
317            TokenType::YamlDirective(major, minor) => {
318                // Store YAML version directive
319                self.yaml_version = Some((*major, *minor));
320                // Stay in stream state waiting for document
321            }
322
323            TokenType::TagDirective(handle, prefix) => {
324                // Store tag directive and update tag resolver
325                self.tag_directives.push((handle.clone(), prefix.clone()));
326                self.tag_resolver
327                    .add_directive(handle.clone(), prefix.clone());
328                // Stay in stream state waiting for document
329            }
330
331            TokenType::DocumentStart => {
332                // Close previous document if needed
333                if matches!(
334                    self.state,
335                    ParserState::DocumentContent | ParserState::BlockNode
336                ) {
337                    self.events
338                        .push(Event::document_end(token.start_position, true));
339                }
340
341                // Create document start with directives
342                self.events.push(Event::document_start(
343                    token.start_position,
344                    self.yaml_version.take(),
345                    self.tag_directives.clone(),
346                    false,
347                ));
348
349                // Clear tag directives after using them (YAML version persists across documents)
350                // But keep them in the tag resolver for this document
351                self.tag_directives.clear();
352
353                self.state = ParserState::DocumentStart;
354            }
355
356            TokenType::DocumentEnd => {
357                self.events
358                    .push(Event::document_end(token.start_position, false));
359                self.state = ParserState::DocumentEnd;
360            }
361
362            TokenType::BlockSequenceStart => {
363                if matches!(self.state, ParserState::ImplicitDocumentStart) {
364                    let event = self.create_implicit_document_start(token.start_position);
365                    self.events.push(event);
366                }
367
368                // If we're starting a sequence within a mapping context, push the current state
369                if matches!(
370                    self.state,
371                    ParserState::BlockMappingValue | ParserState::BlockMappingKey
372                ) {
373                    self.state_stack.push(self.state);
374                }
375
376                self.events.push(Event::sequence_start(
377                    token.start_position,
378                    self.pending_anchor.take(),
379                    self.pending_tag.take(),
380                    false,
381                ));
382                self.state = ParserState::BlockSequence;
383            }
384
385            TokenType::BlockMappingStart => {
386                // Determine whether to create a new mapping or continue existing one
387                // This token is generated when we encounter a key at the start of a line with nested content
388                // It doesn't always mean we need to create a new mapping - sometimes we're just continuing
389
390                let should_create_new_mapping = match self.state {
391                    ParserState::ImplicitDocumentStart => {
392                        // At document start, we need a new mapping
393                        true
394                    }
395                    ParserState::DocumentStart => {
396                        // After explicit document start (---), we need a new mapping
397                        true
398                    }
399                    ParserState::DocumentContent => {
400                        // This is a tricky case - we could be:
401                        // 1. Starting a new root mapping
402                        // 2. Continuing an existing root mapping
403                        // The key is to check if we have an unclosed root mapping
404
405                        // Count mapping depth from the end
406                        let mut mapping_depth = 0;
407                        let mut has_unclosed_mapping = false;
408
409                        for event in self.events.iter().rev() {
410                            match &event.event_type {
411                                EventType::MappingEnd => mapping_depth += 1,
412                                EventType::MappingStart { .. } => {
413                                    if mapping_depth == 0 {
414                                        has_unclosed_mapping = true;
415                                        break;
416                                    }
417                                    mapping_depth -= 1;
418                                }
419                                EventType::DocumentStart { .. } => break,
420                                _ => {}
421                            }
422                        }
423
424                        // Don't create a new mapping if we have an unclosed one
425                        !has_unclosed_mapping
426                    }
427                    ParserState::BlockMappingValue => {
428                        // If we're expecting a value and see BlockMappingStart, it's a nested mapping
429                        true
430                    }
431                    ParserState::BlockMappingKey => {
432                        // We're already in a mapping key context
433                        // BlockMappingStart here means we're continuing the mapping unless:
434                        // - After a Key token (complex key)
435                        // - After a Value token (nested mapping as value)
436                        matches!(
437                            &self.last_token_type,
438                            Some(TokenType::Key | TokenType::Value)
439                        )
440                    }
441                    ParserState::BlockSequence => {
442                        // In a sequence context, BlockMappingStart means we're starting
443                        // a nested mapping as a sequence item
444                        true
445                    }
446                    _ => {
447                        // For other states, check last token
448                        matches!(
449                            &self.last_token_type,
450                            Some(TokenType::Key | TokenType::Value)
451                        )
452                    }
453                };
454
455                if should_create_new_mapping {
456                    // Create a new nested mapping
457                    if matches!(self.state, ParserState::ImplicitDocumentStart) {
458                        let event = self.create_implicit_document_start(token.start_position);
459                        self.events.push(event);
460                    }
461
462                    // If we're in a mapping value or sequence context, push state to stack
463                    if matches!(
464                        self.state,
465                        ParserState::BlockMappingValue | ParserState::BlockSequence
466                    ) {
467                        self.state_stack.push(self.state);
468                    }
469
470                    self.events.push(Event::mapping_start(
471                        token.start_position,
472                        self.pending_anchor.take(),
473                        self.pending_tag.take(),
474                        false,
475                    ));
476                    self.state = ParserState::BlockMappingKey;
477                } else {
478                    // Continue existing mapping
479                    // Ensure we're in the right state to handle the next key-value pair
480                    match self.state {
481                        ParserState::DocumentContent => {
482                            // We should be continuing a mapping, so transition to BlockMappingKey
483                            self.state = ParserState::BlockMappingKey;
484                        }
485                        ParserState::BlockMappingValue => {
486                            // We just processed a value, now ready for next key
487                            self.state = ParserState::BlockMappingKey;
488                        }
489                        ParserState::BlockMappingKey => {
490                            // Already ready for next key, no state change needed
491                        }
492                        _ => {
493                            // For other states, check if we can restore from state stack
494                            if let Some(prev_state) = self.state_stack.last() {
495                                if matches!(prev_state, ParserState::BlockMappingValue) {
496                                    if let Some(mapping_state) = self.state_stack.pop() {
497                                        self.state = mapping_state;
498                                        self.handle_node_completion();
499                                    }
500                                }
501                            }
502                        }
503                    }
504                }
505            }
506
507            TokenType::FlowSequenceStart => {
508                if matches!(self.state, ParserState::ImplicitDocumentStart) {
509                    self.events.push(Event::document_start(
510                        token.start_position,
511                        None,
512                        vec![],
513                        true,
514                    ));
515                }
516                self.events.push(Event::sequence_start(
517                    token.start_position,
518                    self.pending_anchor.take(),
519                    self.pending_tag.take(),
520                    true,
521                ));
522                self.state = ParserState::FlowSequence;
523            }
524
525            TokenType::FlowMappingStart => {
526                if matches!(self.state, ParserState::ImplicitDocumentStart) {
527                    self.events.push(Event::document_start(
528                        token.start_position,
529                        None,
530                        vec![],
531                        true,
532                    ));
533                }
534                self.events.push(Event::mapping_start(
535                    token.start_position,
536                    self.pending_anchor.take(),
537                    self.pending_tag.take(),
538                    true,
539                ));
540                self.state = ParserState::FlowMapping;
541            }
542
543            TokenType::FlowSequenceEnd => {
544                self.events.push(Event::sequence_end(token.start_position));
545                self.state = ParserState::DocumentContent;
546
547                // Handle state transitions for mapping key/value processing
548                self.handle_node_completion();
549            }
550
551            TokenType::FlowMappingEnd => {
552                self.events.push(Event::mapping_end(token.start_position));
553                self.state = ParserState::DocumentContent;
554
555                // Handle state transitions for mapping key/value processing
556                self.handle_node_completion();
557            }
558
559            TokenType::BlockEnd => {
560                // Determine what we're ending based on current state
561                match self.state {
562                    ParserState::BlockSequence => {
563                        self.events.push(Event::sequence_end(token.start_position));
564                        // Pop previous state from stack if available
565                        if let Some(prev_state) = self.state_stack.pop() {
566                            self.state = prev_state;
567                            // Handle state transitions for mapping key/value processing
568                            self.handle_node_completion();
569                        } else {
570                            self.state = ParserState::DocumentContent;
571                        }
572                    }
573                    ParserState::BlockMapping
574                    | ParserState::BlockMappingKey
575                    | ParserState::BlockMappingValue => {
576                        self.events.push(Event::mapping_end(token.start_position));
577                        // Pop previous state from stack if available
578                        if let Some(prev_state) = self.state_stack.pop() {
579                            self.state = prev_state;
580                            // If we popped back to a mapping value state, complete it
581                            if matches!(self.state, ParserState::BlockMappingValue) {
582                                self.handle_node_completion();
583                            }
584                        } else {
585                            // No state on stack - check if we're still in a root mapping
586                            // Count the mapping depth including the one we just closed
587                            let mut mapping_depth = 0;
588
589                            for event in self.events.iter().rev() {
590                                match &event.event_type {
591                                    EventType::MappingEnd => {
592                                        mapping_depth += 1;
593                                    }
594                                    EventType::MappingStart { .. } => {
595                                        if mapping_depth > 0 {
596                                            mapping_depth -= 1;
597                                        } else {
598                                            // Found an unclosed mapping - we're still in the root mapping
599                                            self.state = ParserState::BlockMappingKey;
600                                            return Ok(());
601                                        }
602                                    }
603                                    EventType::DocumentStart { .. } => break,
604                                    _ => {}
605                                }
606                            }
607
608                            // All mappings are closed
609                            self.state = ParserState::DocumentContent;
610                        }
611                    }
612                    _ => {}
613                }
614            }
615
616            TokenType::Scalar(value, quote_style) => {
617                if matches!(self.state, ParserState::ImplicitDocumentStart) {
618                    self.events.push(Event::document_start(
619                        token.start_position,
620                        None,
621                        vec![],
622                        true,
623                    ));
624                    self.state = ParserState::DocumentContent;
625                }
626
627                // Check if we're in a sequence and the next token is Value (indicating a mapping key)
628                if matches!(self.state, ParserState::BlockSequence) {
629                    if let Ok(Some(next_token)) = self.scanner.peek_token() {
630                        if matches!(next_token.token_type, TokenType::Value) {
631                            // This scalar is a mapping key within a sequence item
632                            // Push current state to stack and start a new mapping
633                            self.state_stack.push(self.state);
634                            self.events.push(Event::mapping_start(
635                                token.start_position,
636                                self.pending_anchor.take(),
637                                self.pending_tag.take(),
638                                false,
639                            ));
640                            self.state = ParserState::BlockMappingKey;
641                        }
642                    }
643                }
644
645                // Convert QuoteStyle to ScalarStyle
646                let style = match quote_style {
647                    crate::scanner::QuoteStyle::Plain => ScalarStyle::Plain,
648                    crate::scanner::QuoteStyle::Single => ScalarStyle::SingleQuoted,
649                    crate::scanner::QuoteStyle::Double => ScalarStyle::DoubleQuoted,
650                };
651
652                self.events.push(Event::scalar(
653                    token.start_position,
654                    self.pending_anchor.take(), // Use pending anchor
655                    self.pending_tag.take(),    // Use pending tag
656                    value.clone(),
657                    style == ScalarStyle::Plain,
658                    style != ScalarStyle::Plain,
659                    style,
660                ));
661
662                // Handle state transitions for mapping key/value processing
663                self.handle_node_completion();
664            }
665
666            TokenType::BlockScalarLiteral(value) => {
667                if matches!(self.state, ParserState::ImplicitDocumentStart) {
668                    self.events.push(Event::document_start(
669                        token.start_position,
670                        None,
671                        vec![],
672                        true,
673                    ));
674                    self.state = ParserState::DocumentContent;
675                }
676
677                self.events.push(Event::scalar(
678                    token.start_position,
679                    self.pending_anchor.take(), // Use pending anchor
680                    self.pending_tag.take(),    // Use pending tag
681                    value.clone(),
682                    false, // Not plain
683                    true,  // Quoted style
684                    ScalarStyle::Literal,
685                ));
686
687                // Handle state transitions for mapping key/value processing
688                self.handle_node_completion();
689            }
690
691            TokenType::BlockScalarFolded(value) => {
692                if matches!(self.state, ParserState::ImplicitDocumentStart) {
693                    self.events.push(Event::document_start(
694                        token.start_position,
695                        None,
696                        vec![],
697                        true,
698                    ));
699                    self.state = ParserState::DocumentContent;
700                }
701
702                self.events.push(Event::scalar(
703                    token.start_position,
704                    self.pending_anchor.take(), // Use pending anchor
705                    self.pending_tag.take(),    // Use pending tag
706                    value.clone(),
707                    false, // Not plain
708                    true,  // Quoted style
709                    ScalarStyle::Folded,
710                ));
711
712                // Handle state transitions for mapping key/value processing
713                self.handle_node_completion();
714            }
715
716            TokenType::BlockEntry => {
717                // Block sequence entry - this indicates a new item in a sequence
718                // We need to ensure proper state management for nested structures
719                match self.state {
720                    ParserState::BlockSequence => {
721                        // We're already in a sequence, this is a new item
722                        // No event needed, but we should be ready for the next item
723                    }
724                    ParserState::BlockMapping | ParserState::BlockMappingValue => {
725                        // If we encounter a BlockEntry while in a mapping,
726                        // we need to close the mapping and continue the sequence
727                        self.events.push(Event::mapping_end(token.start_position));
728                        self.state = ParserState::BlockSequence;
729                    }
730                    _ => {
731                        // BlockEntry in other contexts might indicate we need to start a sequence
732                        // This handles implicit sequence starts
733                        if matches!(self.state, ParserState::ImplicitDocumentStart) {
734                            self.events.push(Event::document_start(
735                                token.start_position,
736                                None,
737                                vec![],
738                                true,
739                            ));
740                        }
741
742                        // Start an implicit sequence if we're not already in one
743                        self.events.push(Event::sequence_start(
744                            token.start_position,
745                            self.pending_anchor.take(),
746                            self.pending_tag.take(),
747                            false,
748                        ));
749                        self.state = ParserState::BlockSequence;
750                    }
751                }
752            }
753
754            TokenType::Value => {
755                // Key-value separator in mappings
756                match self.state {
757                    ParserState::BlockMappingKey => {
758                        self.state = ParserState::BlockMappingValue;
759                    }
760                    ParserState::FlowMappingKey => {
761                        self.state = ParserState::FlowMappingValue;
762                    }
763                    _ => {
764                        // In other contexts, Value token doesn't change state
765                        // It's handled by the scanner's mapping detection logic
766                    }
767                }
768            }
769
770            TokenType::FlowEntry => {
771                // Flow collection separator, no specific event needed
772            }
773
774            TokenType::Anchor(name) => {
775                // Store the anchor name to be used with the next node
776                self.pending_anchor = Some(name.clone());
777            }
778
779            TokenType::Alias(name) => {
780                if matches!(self.state, ParserState::ImplicitDocumentStart) {
781                    self.events.push(Event::document_start(
782                        token.start_position,
783                        None,
784                        vec![],
785                        true,
786                    ));
787                    self.state = ParserState::DocumentContent;
788                }
789
790                // Generate alias event
791                self.events
792                    .push(Event::alias(token.start_position, name.clone()));
793
794                // Handle state transitions for mapping key/value processing
795                self.handle_node_completion();
796            }
797
798            TokenType::Tag(tag) => {
799                // Resolve and normalize the tag before storing
800                match self.tag_resolver.resolve(&tag) {
801                    Ok(resolved_tag) => {
802                        self.pending_tag = Some(resolved_tag.uri);
803                    }
804                    Err(_) => {
805                        // If tag resolution fails, store the original tag
806                        self.pending_tag = Some(tag.clone());
807                    }
808                }
809            }
810
811            // TODO: Implement these when we add support for advanced features
812            TokenType::Comment(_) => {
813                // Not implemented in basic version
814            }
815
816            // Complex key marker
817            TokenType::Key => {
818                match self.state {
819                    ParserState::ImplicitDocumentStart => {
820                        // Start implicit document and mapping
821                        let event = self.create_implicit_document_start(token.start_position);
822                        self.events.push(event);
823                        self.events.push(Event::mapping_start(
824                            token.start_position,
825                            self.pending_anchor.take(),
826                            self.pending_tag.take(),
827                            false,
828                        ));
829                        self.state = ParserState::BlockMappingKey;
830                    }
831                    ParserState::DocumentContent => {
832                        // Check if we just finished a mapping - if so, continue it instead of starting new one
833                        // This happens when the previous mapping key-value pair was processed but no BlockEnd was generated
834                        if !self.events.is_empty() {
835                            if let Some(last_event) = self.events.last() {
836                                // If the last event was a scalar and we have a MappingStart before it,
837                                // we're probably continuing an existing mapping
838                                if matches!(last_event.event_type, EventType::Scalar { .. }) {
839                                    // Look for a recent MappingStart without a corresponding MappingEnd
840                                    let mut mapping_depth = 0;
841                                    let mut has_unfinished_mapping = false;
842
843                                    for event in self.events.iter().rev() {
844                                        match &event.event_type {
845                                            EventType::MappingEnd => mapping_depth += 1,
846                                            EventType::MappingStart { .. } => {
847                                                if mapping_depth == 0 {
848                                                    has_unfinished_mapping = true;
849                                                    break;
850                                                }
851                                                mapping_depth -= 1;
852                                            }
853                                            _ => {}
854                                        }
855                                    }
856
857                                    if has_unfinished_mapping {
858                                        // Continue the existing mapping instead of starting a new one
859                                        self.state = ParserState::BlockMappingKey;
860                                        return Ok(());
861                                    }
862                                }
863                            }
864                        }
865
866                        // Start new mapping
867                        self.events.push(Event::mapping_start(
868                            token.start_position,
869                            self.pending_anchor.take(),
870                            self.pending_tag.take(),
871                            false,
872                        ));
873                        self.state = ParserState::BlockMappingKey;
874                    }
875                    ParserState::BlockMapping | ParserState::FlowMapping => {
876                        // Already in a mapping, now we have a complex key
877                        self.state = if matches!(self.state, ParserState::BlockMapping) {
878                            ParserState::BlockMappingKey
879                        } else {
880                            ParserState::FlowMappingKey
881                        };
882                    }
883                    ParserState::BlockMappingKey | ParserState::FlowMappingKey => {
884                        // Already in a mapping and expecting a key, this is another complex key
885                        // Don't start a new mapping, just continue with the current state
886                        // The state is already correct for expecting a key
887                    }
888                    _ => {
889                        let context =
890                            ErrorContext::from_input(self.scanner.input(), &self.position, 2)
891                                .with_suggestion(
892                                    "Complex keys must be used in mapping contexts".to_string(),
893                                );
894                        return Err(Error::parse_with_context(
895                            self.position,
896                            "Complex key marker (?) in invalid context",
897                            context,
898                        ));
899                    }
900                }
901            }
902        }
903
904        // Update the last token type for next iteration
905        self.last_token_type = token_type_for_tracking;
906
907        Ok(())
908    }
909
910    /// Handle completion of a node (scalar or collection) and manage mapping state transitions
911    #[allow(clippy::missing_const_for_fn)]
912    fn handle_node_completion(&mut self) {
913        match self.state {
914            ParserState::BlockMappingKey => {
915                // After processing a key, we stay in BlockMappingKey state
916                // The Value token (:) will transition us to BlockMappingValue
917                // No state change needed here
918            }
919            ParserState::FlowMappingKey => {
920                // After processing a key in flow mapping, we stay in FlowMappingKey state
921                // The Value token (:) will transition us to FlowMappingValue
922                // No state change needed here
923            }
924            ParserState::BlockMappingValue => {
925                // After processing a value, we go back to waiting for the next key
926                self.state = ParserState::BlockMappingKey;
927            }
928            ParserState::FlowMappingValue => {
929                // After processing a value in flow mapping, we go back to waiting for the next key
930                self.state = ParserState::FlowMapping;
931            }
932            _ => {
933                // No state change needed for other states
934            }
935        }
936    }
937}
938
939impl Default for BasicParser {
940    fn default() -> Self {
941        Self::new(String::new())
942    }
943}
944
945impl Parser for BasicParser {
946    fn check_event(&self) -> bool {
947        // For streaming: check if we have cached events or can generate more
948        self.event_index < self.events.len() || self.scanner.check_token()
949    }
950
951    fn peek_event(&self) -> Result<Option<&Event>> {
952        // Peek at cached events only (don't generate new ones)
953        Ok(self.events.get(self.event_index))
954    }
955
956    fn get_event(&mut self) -> Result<Option<Event>> {
957        // Generate next events until we have one available
958        // Some tokens (like directives) don't generate events
959        while self.event_index >= self.events.len() && self.scanner.check_token() {
960            let events_before = self.events.len();
961            self.generate_next_event()?;
962
963            // If no event was generated and we still have tokens, continue
964            if self.events.len() == events_before && self.scanner.check_token() {
965                continue;
966            }
967            break;
968        }
969
970        if self.event_index < self.events.len() {
971            let event = self.events[self.event_index].clone();
972            self.event_index += 1;
973            Ok(Some(event))
974        } else {
975            Ok(None)
976        }
977    }
978
979    fn reset(&mut self) {
980        self.event_index = 0;
981        self.scanner.reset();
982        self.state_stack.clear();
983        self.position = Position::start();
984        self.pending_anchor = None;
985        self.pending_tag = None;
986        self.last_token_type = None;
987    }
988
989    fn position(&self) -> Position {
990        self.position
991    }
992}
993
994impl BasicParser {
995    /// Check if there was a scanning error
996    #[allow(clippy::missing_const_for_fn)]
997    pub fn take_scanning_error(&mut self) -> Option<Error> {
998        self.scanning_error.take()
999    }
1000}
1001
1002#[cfg(test)]
1003mod tests {
1004    use super::*;
1005
1006    #[test]
1007    fn test_basic_parsing() {
1008        let mut parser = BasicParser::new_eager("42".to_string());
1009
1010        assert!(parser.check_event());
1011
1012        // Stream start
1013        let event = parser.get_event().unwrap().unwrap();
1014        assert!(matches!(event.event_type, EventType::StreamStart));
1015
1016        // Document start (implicit)
1017        let event = parser.get_event().unwrap().unwrap();
1018        if let EventType::DocumentStart { implicit, .. } = event.event_type {
1019            assert!(implicit);
1020        } else {
1021            panic!("Expected implicit document start");
1022        }
1023
1024        // Scalar
1025        let event = parser.get_event().unwrap().unwrap();
1026        if let EventType::Scalar { value, .. } = event.event_type {
1027            assert_eq!(value, "42");
1028        } else {
1029            panic!("Expected scalar event");
1030        }
1031
1032        // Document end (implicit)
1033        let event = parser.get_event().unwrap().unwrap();
1034        if let EventType::DocumentEnd { implicit } = event.event_type {
1035            assert!(implicit);
1036        } else {
1037            panic!("Expected implicit document end");
1038        }
1039
1040        // Stream end
1041        let event = parser.get_event().unwrap().unwrap();
1042        assert!(matches!(event.event_type, EventType::StreamEnd));
1043    }
1044
1045    #[test]
1046    fn test_flow_sequence_parsing() {
1047        let mut parser = BasicParser::new_eager("[1, 2, 3]".to_string());
1048
1049        // Stream start
1050        parser.get_event().unwrap();
1051
1052        // Document start (implicit)
1053        parser.get_event().unwrap();
1054
1055        // Sequence start
1056        let event = parser.get_event().unwrap().unwrap();
1057        if let EventType::SequenceStart { flow_style, .. } = event.event_type {
1058            assert!(flow_style);
1059        } else {
1060            panic!("Expected flow sequence start");
1061        }
1062
1063        // First scalar
1064        let event = parser.get_event().unwrap().unwrap();
1065        if let EventType::Scalar { value, .. } = event.event_type {
1066            assert_eq!(value, "1");
1067        } else {
1068            panic!("Expected scalar '1'");
1069        }
1070    }
1071
1072    #[test]
1073    fn test_flow_mapping_parsing() {
1074        let mut parser = BasicParser::new_eager("{'key': 'value'}".to_string());
1075
1076        // Stream start
1077        parser.get_event().unwrap();
1078
1079        // Document start (implicit)
1080        parser.get_event().unwrap();
1081
1082        // Mapping start
1083        let event = parser.get_event().unwrap().unwrap();
1084        if let EventType::MappingStart { flow_style, .. } = event.event_type {
1085            assert!(flow_style);
1086        } else {
1087            panic!("Expected flow mapping start");
1088        }
1089
1090        // Key scalar
1091        let event = parser.get_event().unwrap().unwrap();
1092        if let EventType::Scalar { value, .. } = event.event_type {
1093            assert_eq!(value, "key");
1094        } else {
1095            panic!("Expected scalar 'key'");
1096        }
1097    }
1098}