Skip to main content

vexy_json_core/parser/
mod.rs

1// this_file: src/parser/mod.rs
2
3/// Array parsing functionality.
4pub mod array;
5/// Boolean value parsing.
6pub mod boolean;
7/// Stack-based iterative parser implementation.
8pub mod iterative;
9/// Null value parsing.
10pub mod null;
11/// Number parsing with integer and float support.
12pub mod number;
13/// Object parsing with key-value pairs.
14pub mod object;
15pub mod optimized;
16pub mod optimized_v2;
17pub mod optimized_v3;
18/// Clean recursive descent parser implementation.
19pub mod recursive;
20/// Parser state management.
21pub mod state;
22/// String parsing with escape sequence handling.
23pub mod string;
24
25use self::boolean::{parse_false, parse_true};
26use self::null::parse_null;
27use self::number::parse_number_token;
28use self::string::parse_string_token;
29use crate::ast::{Number, Token, Value};
30use crate::error::repair::{EnhancedParseResult, ParsingTier, RepairAction};
31use crate::error::{Error, ErrorContext, ErrorRecoveryEngineV2, Result, Span};
32use crate::lexer::{FastLexer, JsonLexer, Lexer, LexerConfig, LexerMode};
33use crate::optimization::ValueBuilder;
34use crate::repair::JsonRepairer;
35pub use iterative::{parse_iterative, IterativeParser};
36pub use optimized::{
37    parse_optimized, parse_optimized_with_options, parse_with_stats, OptimizedParser,
38};
39pub use optimized_v2::{
40    parse_optimized_v2, parse_optimized_v2_with_options, parse_v2_with_stats, OptimizedParserV2,
41};
42pub use optimized_v3::{
43    parse_optimized_v3, parse_optimized_v3_with_options, parse_v3_with_stats, OptimizedParserV3,
44};
45pub use recursive::{parse_recursive, RecursiveDescentParser};
46use rustc_hash::FxHashMap;
47pub use state::ParserState;
48
49#[cfg(feature = "serde")]
50use serde::{Deserialize, Serialize};
51
52/// Configuration options for the vexy_json parser.
53///
54/// These options control which forgiving features are enabled during parsing.
55/// By default, all forgiving features are enabled.
56#[derive(Debug, Clone)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58#[cfg_attr(feature = "serde", serde(default))]
59pub struct ParserOptions {
60    /// Whether to allow single-line and multi-line comments.
61    pub allow_comments: bool,
62    /// Whether to allow trailing commas in arrays and objects.
63    pub allow_trailing_commas: bool,
64    /// Whether to allow unquoted object keys (e.g., {key: "value"}).
65    pub allow_unquoted_keys: bool,
66    /// Whether to allow single-quoted strings (e.g., 'value').
67    pub allow_single_quotes: bool,
68    /// Whether to allow implicit top-level objects and arrays.
69    /// When enabled, `key: value` becomes `{key: value}` and `1, 2, 3` becomes `[1, 2, 3]`.
70    pub implicit_top_level: bool,
71    /// Whether to treat newlines as commas in arrays and objects.
72    pub newline_as_comma: bool,
73    /// Maximum nesting depth for objects and arrays to prevent stack overflow.
74    pub max_depth: usize,
75    /// Enable JSON repair functionality for bracket mismatches.
76    pub enable_repair: bool,
77    /// Maximum number of repairs to attempt.
78    pub max_repairs: usize,
79    /// Prefer speed over repair quality.
80    pub fast_repair: bool,
81    /// Report all repairs made.
82    pub report_repairs: bool,
83}
84
85impl Default for ParserOptions {
86    fn default() -> Self {
87        ParserOptions {
88            allow_comments: true,
89            allow_trailing_commas: true,
90            allow_unquoted_keys: true,
91            allow_single_quotes: true,
92            implicit_top_level: true,
93            newline_as_comma: true,
94            max_depth: 128,
95            enable_repair: true,
96            max_repairs: 100,
97            fast_repair: false,
98            report_repairs: true,
99        }
100    }
101}
102
103/// The vexy_json parser.
104///
105/// Parses tokens from a Lexer into a Value tree structure.
106/// Supports both strict JSON and various forgiving extensions.
107pub struct Parser<'a> {
108    pub(super) lexer: Box<dyn JsonLexer + 'a>,
109    pub(super) original_input: &'a str,
110    pub(super) options: ParserOptions,
111    pub(super) current_token: Option<(Token, Span)>,
112    /// Offset of the current lexer within the original input.
113    /// This is 0 when the lexer is working on the full original input,
114    /// but becomes non-zero when we create a new lexer from a slice.
115    pub(super) state: ParserState,
116    /// Value builder for optimized object and array construction
117    #[allow(dead_code)]
118    pub(super) value_builder: ValueBuilder,
119}
120
121impl<'a> Parser<'a> {
122    /// Creates a new parser with the given input and options.
123    pub fn new(input: &'a str, options: ParserOptions) -> Self {
124        // Determine if we need forgiving features
125        let needs_forgiving = options.allow_comments
126            || options.allow_trailing_commas
127            || options.allow_unquoted_keys
128            || options.allow_single_quotes
129            || options.implicit_top_level
130            || options.newline_as_comma;
131
132        // Create appropriate lexer based on options
133        let lexer: Box<dyn JsonLexer + 'a> = if needs_forgiving {
134            // Use FastLexer with forgiving mode for non-strict parsing
135            let config = LexerConfig {
136                mode: if options.allow_comments {
137                    LexerMode::Forgiving
138                } else {
139                    LexerMode::Strict
140                },
141                collect_stats: false,
142                buffer_size: 8192,
143                max_depth: options.max_depth,
144                track_positions: true,
145            };
146            Box::new(FastLexer::new(input, config))
147        } else {
148            // Use LogosLexer for strict parsing
149            Box::new(Lexer::new(input))
150        };
151
152        Parser {
153            lexer,
154            original_input: input,
155            options,
156            current_token: None, // Will be populated by first advance()
157            state: ParserState::new(),
158            value_builder: ValueBuilder::new(),
159        }
160    }
161
162    /// Parses the input and returns a Value.
163    ///
164    /// This is the main entry point for parsing. It handles:
165    /// - Empty input (returns null)
166    /// - Single values
167    /// - Implicit arrays (when multiple comma-separated values are found)
168    /// - Implicit objects (when key:value pairs are found at top level)
169    pub fn parse(&mut self) -> Result<Value> {
170        self.advance()?;
171        self.skip_comments()?;
172
173        // Handle empty input - check if we have only whitespace/newlines
174        if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
175            return Ok(Value::Null);
176        }
177
178        // Check if input is only newlines and whitespace (effectively empty)
179        // NOTE: This check is only meaningful if we're at the start of the input
180        // and haven't consumed any actual values yet
181        // TEMPORARILY DISABLED - this seems to be causing issues
182        // if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Newline) && self.is_only_whitespace_and_newlines() {
183        //     return Ok(Value::Null);
184        // }
185
186        // Skip leading newlines when they appear after comments - they should not start implicit arrays
187        // This is different from commas which can legitimately start implicit arrays
188        if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Newline)
189            && self.options.newline_as_comma
190        {
191            self.skip_comments_and_newlines()?;
192            if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
193                return Ok(Value::Null);
194            }
195        }
196
197        // Check if it starts with a separator (implicit array with null first element)
198        if self.is_separator() && self.options.implicit_top_level {
199            let mut array = vec![Value::Null];
200            self.advance()?;
201
202            loop {
203                self.skip_comments_and_newlines()?;
204                if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
205                    break;
206                }
207
208                // Check for consecutive separators (which mean null values)
209                if self.is_separator() {
210                    array.push(Value::Null);
211                    self.advance()?;
212                    continue;
213                }
214
215                array.push(self.parse_value()?);
216
217                self.skip_comments_and_newlines()?;
218                if self.is_separator() {
219                    self.advance()?;
220                } else if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
221                    break;
222                } else {
223                    return Err(Error::Expected {
224                        expected: ", or newline or end of input".to_string(),
225                        found: format!("{:?}", self.current_token.as_ref().map(|(t, _)| t)),
226                        position: self.lexer.position(),
227                    });
228                }
229            }
230
231            return Ok(Value::Array(array));
232        }
233
234        // Try to parse as a regular value first (with implicit object support if enabled)
235        // However, if we start with explicit braces/brackets, parse as regular value
236        let is_explicit_structure = matches!(
237            self.current_token.as_ref().map(|(t, _)| t),
238            Some(&Token::LeftBrace) | Some(&Token::LeftBracket)
239        );
240
241        let first_value = if self.options.implicit_top_level && !is_explicit_structure {
242            self.parse_value_or_implicit()?
243        } else {
244            self.parse_value()?
245        };
246
247        // Check for trailing content
248        self.skip_comments()?;
249
250        match self.current_token.as_ref().map(|(t, _)| t) {
251            Some(&Token::Eof) => Ok(first_value),
252            _ if is_explicit_structure => {
253                // For explicit JSON structures (arrays/objects), check if there's a trailing comma
254                // that should start an implicit array
255                if self.options.implicit_top_level
256                    && matches!(
257                        self.current_token.as_ref().map(|(t, _)| t),
258                        Some(&Token::Comma)
259                    )
260                {
261                    // Treat the explicit structure as the first element of an implicit array
262                    let mut array = vec![first_value];
263                    self.advance()?;
264
265                    loop {
266                        self.skip_comments_and_newlines()?;
267                        if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
268                            break;
269                        }
270
271                        // Check for consecutive separators (which mean null values)
272                        if self.is_separator() {
273                            array.push(Value::Null);
274                            self.advance()?;
275                            continue;
276                        }
277
278                        array.push(self.parse_value()?);
279
280                        self.skip_comments_and_newlines()?;
281                        if self.is_separator() {
282                            self.advance()?;
283                        } else if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
284                            break;
285                        } else {
286                            return Err(Error::Expected {
287                                expected: ", or newline or end of input".to_string(),
288                                found: format!("{:?}", self.current_token.as_ref().map(|(t, _)| t)),
289                                position: self.lexer.position(),
290                            });
291                        }
292                    }
293
294                    Ok(Value::Array(array))
295                } else {
296                    // For explicit JSON structures (arrays/objects), require end of input
297                    Err(Error::Expected {
298                        expected: "end of input".to_string(),
299                        found: format!("{:?}", self.current_token.as_ref().map(|(t, _)| t)),
300                        position: self.lexer.position(),
301                    })
302                }
303            }
304            Some(&Token::Comma) | Some(&Token::Newline)
305                if matches!(
306                    self.current_token.as_ref().map(|(t, _)| t),
307                    Some(&Token::Comma)
308                ) || (self.options.newline_as_comma
309                    && matches!(
310                        self.current_token.as_ref().map(|(t, _)| t),
311                        Some(&Token::Newline)
312                    )) =>
313            {
314                // Check if this is just trailing newlines/whitespace by advancing and checking
315                if self.options.newline_as_comma
316                    && matches!(
317                        self.current_token.as_ref().map(|(t, _)| t),
318                        Some(&Token::Newline)
319                    )
320                {
321                    self.advance()?;
322                    self.skip_comments_and_newlines()?;
323
324                    // If we reach EOF after skipping newlines/comments, the newline was trailing
325                    if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
326                        return Ok(first_value);
327                    } else {
328                        // There's content after the newline, so this is a real separator
329                        // We need to create an implicit array
330                        let mut array = vec![first_value];
331                        array.push(self.parse_value()?);
332
333                        loop {
334                            self.skip_comments_and_newlines()?;
335                            if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
336                                break;
337                            }
338
339                            if self.is_separator() {
340                                self.advance()?;
341                                self.skip_comments_and_newlines()?;
342                                if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof)
343                                {
344                                    break;
345                                }
346                            }
347
348                            array.push(self.parse_value()?);
349                        }
350
351                        return Ok(Value::Array(array));
352                    }
353                }
354
355                // It's an implicit array (for commas)
356                if self.options.implicit_top_level {
357                    let mut array = vec![first_value];
358                    self.advance()?;
359
360                    loop {
361                        self.skip_comments_and_newlines()?;
362                        if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
363                            break;
364                        }
365
366                        // Check for consecutive separators (which mean null values)
367                        if self.is_separator() {
368                            array.push(Value::Null);
369                            self.advance()?;
370                            continue;
371                        }
372
373                        array.push(self.parse_value()?);
374
375                        self.skip_comments_and_newlines()?;
376                        if self.is_separator() {
377                            self.advance()?;
378                        } else if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
379                            break;
380                        } else {
381                            return Err(Error::Expected {
382                                expected: ", or newline or end of input".to_string(),
383                                found: format!("{:?}", self.current_token.as_ref().map(|(t, _)| t)),
384                                position: self.lexer.position(),
385                            });
386                        }
387                    }
388
389                    Ok(Value::Array(array))
390                } else {
391                    Err(Error::Expected {
392                        expected: "end of input".to_string(),
393                        found: format!("{:?}", self.current_token.as_ref().map(|(t, _)| t)),
394                        position: self.lexer.position(),
395                    })
396                }
397            }
398            _ => {
399                // Check if this is another value in an implicit array (space-separated)
400                if self.options.implicit_top_level && self.is_value_token() {
401                    // Create an implicit array with the first value and continue parsing
402                    let mut array = vec![first_value];
403
404                    // Parse the remaining values
405                    loop {
406                        // Check for consecutive separators (which mean null values)
407                        if self.is_separator() {
408                            array.push(Value::Null);
409                            self.advance()?;
410                            self.skip_comments_and_newlines()?;
411                            if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
412                                break;
413                            }
414                            continue;
415                        }
416
417                        array.push(self.parse_value()?);
418                        self.skip_comments()?;
419
420                        if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
421                            break;
422                        }
423
424                        // Check if there's a separator
425                        if self.is_separator() {
426                            self.advance()?;
427                            self.skip_comments_and_newlines()?;
428                            if self.current_token.as_ref().map(|(t, _)| t) == Some(&Token::Eof) {
429                                break;
430                            }
431                        } else if !self.is_value_token() {
432                            return Err(Error::Expected {
433                                expected: "value, separator, or end of input".to_string(),
434                                found: format!("{:?}", self.current_token.as_ref().map(|(t, _)| t)),
435                                position: self.lexer.position(),
436                            });
437                        }
438                    }
439
440                    Ok(Value::Array(array))
441                } else {
442                    Err(Error::Expected {
443                        expected: "end of input".to_string(),
444                        found: format!("{:?}", self.current_token.as_ref().map(|(t, _)| t)),
445                        position: self.lexer.position(),
446                    })
447                }
448            }
449        }
450    }
451
452    pub(super) fn advance(&mut self) -> Result<()> {
453        loop {
454            let (token, span) = self.lexer.next_token()?;
455            self.state.span = span; // Update parser state with the current token's span
456            self.current_token = Some((token, span));
457
458            match self.current_token.as_ref().map(|(t, _)| t) {
459                Some(&Token::SingleLineComment) | Some(&Token::MultiLineComment) => {
460                    if self.options.allow_comments {
461                        continue;
462                    } else {
463                        return Err(Error::Custom("Comments are not allowed".to_string()));
464                    }
465                }
466                _ => break,
467            }
468        }
469        Ok(())
470    }
471
472    pub(super) fn skip_comments(&mut self) -> Result<()> {
473        while matches!(
474            self.current_token.as_ref().map(|(t, _)| t),
475            Some(&Token::SingleLineComment) | Some(&Token::MultiLineComment)
476        ) {
477            self.advance()?;
478        }
479        Ok(())
480    }
481
482    /// Check if the current token can start a value
483    fn is_value_token(&self) -> bool {
484        matches!(
485            self.current_token.as_ref().map(|(t, _)| t),
486            Some(&Token::String)
487                | Some(&Token::UnquotedString)
488                | Some(&Token::Number)
489                | Some(&Token::LeftBrace)
490                | Some(&Token::LeftBracket)
491                | Some(&Token::True)
492                | Some(&Token::False)
493                | Some(&Token::Null)
494        )
495    }
496
497    /// Skips comments and optionally newlines if newline_as_comma is enabled.
498    pub(super) fn skip_comments_and_newlines(&mut self) -> Result<()> {
499        let mut just_had_single_line_comment = false;
500
501        loop {
502            match self.current_token.as_ref().map(|(t, _)| t) {
503                Some(&Token::SingleLineComment) => {
504                    just_had_single_line_comment = true;
505                    self.advance()?;
506                }
507                Some(&Token::MultiLineComment) => {
508                    just_had_single_line_comment = false;
509                    self.advance()?;
510                }
511                Some(&Token::Newline)
512                    if self.options.newline_as_comma || just_had_single_line_comment =>
513                {
514                    just_had_single_line_comment = false;
515                    self.advance()?;
516                }
517                _ => break,
518            }
519        }
520        Ok(())
521    }
522
523    /// Checks if the current token is a separator (comma or newline when newline_as_comma is enabled).
524    pub(super) fn is_separator(&self) -> bool {
525        matches!(
526            self.current_token.as_ref().map(|(t, _)| t),
527            Some(&Token::Comma)
528        ) || (self.options.newline_as_comma
529            && matches!(
530                self.current_token.as_ref().map(|(t, _)| t),
531                Some(&Token::Newline)
532            ))
533    }
534
535    /// Checks if the input contains only whitespace, newlines, and comments (effectively empty).
536    #[allow(dead_code)]
537    fn is_only_whitespace_and_newlines(&mut self) -> bool {
538        // Create a temporary lexer to peek without modifying the main lexer's state
539        let current_pos = self.lexer.position();
540        let remaining_input = &self.original_input[current_pos..];
541
542        // Create same type of lexer as the main parser
543        let needs_forgiving = self.options.allow_comments
544            || self.options.allow_trailing_commas
545            || self.options.allow_unquoted_keys
546            || self.options.allow_single_quotes
547            || self.options.implicit_top_level
548            || self.options.newline_as_comma;
549
550        let mut temp_lexer: Box<dyn JsonLexer> = if needs_forgiving {
551            let config = LexerConfig {
552                mode: if self.options.allow_comments {
553                    LexerMode::Forgiving
554                } else {
555                    LexerMode::Strict
556                },
557                collect_stats: false,
558                buffer_size: 8192,
559                max_depth: self.options.max_depth,
560                track_positions: true,
561            };
562            Box::new(FastLexer::new(remaining_input, config))
563        } else {
564            Box::new(Lexer::new(remaining_input))
565        };
566
567        loop {
568            match temp_lexer.next_token() {
569                Ok((Token::Eof, _)) => return true,
570                Ok((Token::Newline, _)) => continue,
571                Ok((Token::SingleLineComment, _)) => continue,
572                Ok((Token::MultiLineComment, _)) => continue,
573                Ok((_, _)) => return false,
574                Err(_) => return false, // Any lexer error means it's not just whitespace
575            }
576        }
577    }
578
579    fn parse_value_or_implicit(&mut self) -> Result<Value> {
580        self.skip_comments()?;
581
582        // Check if it's an implicit object (key:value pattern)
583        if self.options.implicit_top_level {
584            match self.current_token {
585                Some((Token::UnquotedString, _))
586                | Some((Token::String, _))
587                | Some((Token::Number, _)) => {
588                    // We don't need to calculate token positions manually anymore - the lexer provides spans
589
590                    // Read the potential key
591                    let potential_key = match self.current_token {
592                        Some((Token::String, span)) => {
593                            // Use the helper function to parse the string
594                            match parse_string_token(self.original_input, span, &self.options)? {
595                                Value::String(s) => s,
596                                _ => {
597                                    unreachable!("parse_string_token should always return a String")
598                                }
599                            }
600                        }
601                        Some((Token::UnquotedString, span)) => {
602                            // Use the span information directly - no quotes to remove
603                            self.original_input[span.start..span.end].to_string()
604                        }
605                        Some((Token::Number, span)) => {
606                            // Use the span information directly
607                            self.original_input[span.start..span.end].to_string()
608                        }
609                        _ => unreachable!(),
610                    };
611
612                    // Save the current token info before advancing
613                    let key_token = self.current_token;
614
615                    // Advance past the key token
616                    self.advance()?;
617                    self.skip_comments_and_newlines()?;
618
619                    if let Some((Token::Colon, _)) = self.current_token {
620                        // It's an implicit object
621                        let mut object = FxHashMap::default();
622
623                        // Parse first key-value pair
624                        self.advance()?; // Skip colon
625                        let value = self.parse_value()?;
626                        object.insert(potential_key, value);
627
628                        // Continue parsing object pairs
629                        loop {
630                            self.skip_comments_and_newlines()?;
631
632                            if let Some((Token::Eof, _)) = self.current_token {
633                                break;
634                            }
635
636                            if self.is_separator() {
637                                self.advance()?;
638                                self.skip_comments_and_newlines()?;
639
640                                if let Some((Token::Eof, _)) = self.current_token {
641                                    break;
642                                }
643                            }
644
645                            // Parse next key
646                            let key = match self.current_token {
647                                Some((Token::String, span)) => {
648                                    // Use the helper function to parse the string
649                                    let k = match parse_string_token(
650                                        self.original_input,
651                                        span,
652                                        &self.options,
653                                    )? {
654                                        Value::String(s) => s,
655                                        _ => unreachable!(
656                                            "parse_string_token should always return a String"
657                                        ),
658                                    };
659                                    self.advance()?;
660                                    k
661                                }
662                                Some((Token::UnquotedString, span)) => {
663                                    // Use the span information directly - no quotes to remove
664                                    let k = self.original_input[span.start..span.end].to_string();
665                                    self.advance()?;
666                                    k
667                                }
668                                Some((Token::Number, span)) => {
669                                    // Use the span information directly
670                                    let k = self.original_input[span.start..span.end].to_string();
671                                    self.advance()?;
672                                    k
673                                }
674                                _ => break,
675                            };
676
677                            // Expect colon
678                            self.skip_comments_and_newlines()?;
679                            if !matches!(self.current_token, Some((Token::Colon, _))) {
680                                return Err(Error::Expected {
681                                    expected: ":".to_string(),
682                                    found: format!("{:?}", self.current_token),
683                                    position: self.lexer.position(),
684                                });
685                            }
686                            self.advance()?;
687
688                            // Parse value
689                            let value = self.parse_value()?;
690                            object.insert(key, value);
691                        }
692
693                        return Ok(Value::Object(object));
694                    } else {
695                        // Not an implicit object, parse the original token as a value
696                        let value = match key_token {
697                            Some((Token::String, span)) => {
698                                // Use the helper function to parse the string
699                                parse_string_token(self.original_input, span, &self.options)?
700                            }
701                            Some((Token::UnquotedString, span)) => {
702                                // Handle unquoted strings as values
703                                let s = self.original_input[span.start..span.end].to_string();
704                                Value::String(s)
705                            }
706                            Some((Token::Number, span)) => {
707                                // Use the same number parsing logic as parse_number_token
708                                parse_number_token(self.original_input, span)?
709                            }
710                            _ => unreachable!(),
711                        };
712
713                        // Don't advance again - we've already advanced past the token
714                        return Ok(value);
715                    }
716                }
717                _ => {}
718            }
719        }
720
721        // Parse as regular value
722        self.parse_value()
723    }
724
725    pub(super) fn parse_value(&mut self) -> Result<Value> {
726        self.skip_comments_and_newlines()?;
727
728        match self.current_token {
729            Some((Token::Null, _)) => {
730                self.advance()?;
731                parse_null()
732            }
733            Some((Token::True, _)) => {
734                self.advance()?;
735                parse_true()
736            }
737            Some((Token::False, _)) => {
738                self.advance()?;
739                parse_false()
740            }
741            Some((Token::String, span)) => {
742                let value = parse_string_token(self.original_input, span, &self.options)?;
743                self.advance()?;
744                Ok(value)
745            }
746            Some((Token::UnquotedString, span)) => {
747                // Handle unquoted strings as values - extract from span
748                let s = self.original_input[span.start..span.end].to_string();
749                self.advance()?;
750                Ok(Value::String(s))
751            }
752            Some((Token::Number, span)) => {
753                let value = parse_number_token(self.original_input, span)?;
754                self.advance()?;
755                Ok(value)
756            }
757            Some((Token::LeftBrace, _)) => self.parse_object(),
758            Some((Token::LeftBracket, _)) => self.parse_array(),
759            None => {
760                // If we reached EOF where a value is expected, treat it as null (likely comment)
761                if self.options.allow_comments {
762                    Ok(Value::Null)
763                } else {
764                    Err(Error::Expected {
765                        expected: "value".to_string(),
766                        found: "EOF".to_string(),
767                        position: self.lexer.position(),
768                    })
769                }
770            }
771            Some((Token::Eof, _)) => {
772                // If we reached EOF where a value is expected, treat it as null (likely comment)
773                if self.options.allow_comments {
774                    Ok(Value::Null)
775                } else {
776                    Err(Error::Expected {
777                        expected: "value".to_string(),
778                        found: "EOF".to_string(),
779                        position: self.lexer.position(),
780                    })
781                }
782            }
783            _ => Err(Error::Expected {
784                expected: "value".to_string(),
785                found: format!("{:?}", self.current_token),
786                position: self.lexer.position(),
787            }),
788        }
789    }
790
791    pub(super) fn check_depth(&self) -> Result<()> {
792        if self.state.depth >= self.options.max_depth {
793            Err(Error::DepthLimitExceeded(self.lexer.position()))
794        } else {
795            Ok(())
796        }
797    }
798}
799
800/// Parses a JSON string with default options (all forgiving features enabled).
801///
802/// # Examples
803///
804/// ```
805/// use vexy_json_core::parse;
806///
807/// // Standard JSON
808/// let result = parse(r#"{"key": "value"}"#);
809/// assert!(result.is_ok());
810///
811/// // With forgiving features - unquoted keys
812/// let result = parse(r#"{key: "value"}"#);
813/// assert!(result.is_ok());
814/// ```
815pub fn parse(input: &str) -> Result<Value> {
816    let mut parser = Parser::new(input, ParserOptions::default());
817    parser.parse()
818}
819
820/// Parses a JSON string with custom options.
821///
822/// # Arguments
823///
824/// * `input` - The JSON string to parse
825/// * `options` - Parser configuration options
826///
827/// # Examples
828///
829/// ```
830/// use vexy_json_core::{parse_with_options, ParserOptions};
831///
832/// let mut options = ParserOptions::default();
833/// options.allow_comments = false;
834///
835/// let result = parse_with_options(r#"{"key": "value"}"#, options);
836/// assert!(result.is_ok());
837/// ```
838pub fn parse_with_options(input: &str, options: ParserOptions) -> Result<Value> {
839    let mut parser = Parser::new(input, options);
840    parser.parse()
841}
842
843/// Enhanced parsing with three-tier fallback strategy (serde_json → vexy_json → repair)
844///
845/// This function implements a progressive parsing strategy:
846/// 1. First tries serde_json for maximum performance on valid JSON
847/// 2. Falls back to vexy_json for forgiving parsing of non-standard JSON
848/// 3. Finally attempts repair for malformed JSON (bracket imbalances, etc.)
849///
850/// Returns an `EnhancedParseResult` that includes information about which
851/// parsing tier was used and any repairs that were applied.
852pub fn parse_with_fallback(input: &str, options: ParserOptions) -> EnhancedParseResult<Value> {
853    // Tier 1: Try serde_json for maximum performance on valid JSON
854    if let Ok(serde_value) = serde_json::from_str::<serde_json::Value>(input) {
855        // Convert serde_json::Value to vexy_json::Value
856        let vexy_json_value = convert_serde_to_vexy_json(serde_value);
857        return EnhancedParseResult::success(vexy_json_value, ParsingTier::Fast);
858    }
859
860    // Tier 2: Try vexy_json for forgiving parsing
861    match parse_with_options(input, options.clone()) {
862        Ok(value) => EnhancedParseResult::success(value, ParsingTier::Forgiving),
863        Err(error) => {
864            // Tier 3: Try repair if enabled
865            if options.enable_repair {
866                parse_with_repair(input, &options)
867            } else {
868                EnhancedParseResult::failure(Value::Null, vec![error], ParsingTier::Forgiving)
869            }
870        }
871    }
872}
873
874/// Parse with repair functionality for bracket mismatches and pattern-based recovery
875fn parse_with_repair(input: &str, options: &ParserOptions) -> EnhancedParseResult<Value> {
876    // First, try the basic JsonRepairer for bracket mismatches
877    let mut repairer = if options.fast_repair {
878        JsonRepairer::new_without_cache(options.max_repairs)
879    } else {
880        JsonRepairer::new(options.max_repairs)
881    };
882
883    match repairer.repair(input) {
884        Ok((repaired_json, repairs)) => {
885            // Try to parse the repaired JSON with vexy_json
886            match parse_with_options(&repaired_json, options.clone()) {
887                Ok(value) => {
888                    EnhancedParseResult::success_with_repairs(value, repairs, ParsingTier::Repair)
889                }
890                Err(error) => {
891                    // Basic repair didn't work, try advanced pattern-based recovery
892                    parse_with_advanced_recovery(input, options, error, repairs)
893                }
894            }
895        }
896        Err(_repair_error) => {
897            // Basic repair failed, try advanced pattern-based recovery
898            // First try to parse to get the specific error
899            match parse_with_options(input, options.clone()) {
900                Ok(value) => {
901                    // Shouldn't happen, but handle gracefully
902                    EnhancedParseResult::success(value, ParsingTier::Repair)
903                }
904                Err(parse_error) => {
905                    parse_with_advanced_recovery(input, options, parse_error, vec![])
906                }
907            }
908        }
909    }
910}
911
912/// Use ErrorRecoveryEngineV2 for advanced pattern-based recovery
913fn parse_with_advanced_recovery(
914    input: &str,
915    options: &ParserOptions,
916    original_error: Error,
917    previous_repairs: Vec<RepairAction>,
918) -> EnhancedParseResult<Value> {
919    // Create the error recovery engine
920    let mut recovery_engine = ErrorRecoveryEngineV2::new();
921    
922    // Build error context for the recovery engine
923    let error_context = ErrorContext {
924        error: original_error.clone(),
925        input: input.to_string(),
926        position: match &original_error {
927            Error::UnexpectedEof(pos) => *pos,
928            Error::UnterminatedString(pos) => *pos,
929            Error::Expected { position, .. } => *position,
930            Error::InvalidNumber(pos) => *pos,
931            Error::InvalidEscape(pos) => *pos,
932            Error::UnexpectedChar(_, pos) => *pos,
933            Error::DepthLimitExceeded(pos) => *pos,
934            _ => 0,
935        },
936        tokens_before: vec![], // Could be populated if we track tokens
937        partial_ast: None,
938        parsing_context: "top_level".to_string(),
939    };
940    
941    // Get recovery suggestions
942    let suggestions = recovery_engine.suggest_recovery(&error_context);
943    
944    // Try each suggestion in order of confidence
945    let mut all_repairs = previous_repairs;
946    
947    for suggestion in suggestions {
948        // Try to parse the suggested fix first
949        match parse_with_options(&suggestion.fixed_input, options.clone()) {
950            Ok(value) => {
951                // Create repair action based on what was actually changed
952                let repair_action = RepairAction {
953                    position: suggestion.fix_location.start,
954                    action_type: suggestion.category.clone().into(),
955                    original: input[suggestion.fix_location.start..suggestion.fix_location.end.min(input.len())].to_string(),
956                    replacement: match suggestion.category {
957                        crate::error::SuggestionCategory::MissingBracket => {
958                            if suggestion.fixed_input.ends_with('}') {
959                                "}".to_string()
960                            } else if suggestion.fixed_input.ends_with(']') {
961                                "]".to_string()
962                            } else {
963                                "".to_string()
964                            }
965                        }
966                        crate::error::SuggestionCategory::UnmatchedQuote => "\"".to_string(),
967                        crate::error::SuggestionCategory::MissingComma => ",".to_string(),
968                        _ => "".to_string(),
969                    },
970                    description: suggestion.description.clone(),
971                };
972                
973                all_repairs.push(repair_action);
974                return EnhancedParseResult::success_with_repairs(
975                    value,
976                    all_repairs,
977                    ParsingTier::Repair,
978                );
979            }
980            Err(_) => {
981                // This suggestion didn't work, try the next one
982                continue;
983            }
984        }
985    }
986    
987    // All recovery attempts failed
988    EnhancedParseResult::failure_with_repairs(
989        Value::Null,
990        vec![original_error],
991        all_repairs,
992        ParsingTier::Repair,
993    )
994}
995
996/// Convert serde_json::Value to vexy_json::Value
997fn convert_serde_to_vexy_json(serde_value: serde_json::Value) -> Value {
998    match serde_value {
999        serde_json::Value::Null => Value::Null,
1000        serde_json::Value::Bool(b) => Value::Bool(b),
1001        serde_json::Value::Number(n) => {
1002            if let Some(i) = n.as_i64() {
1003                Value::Number(Number::Integer(i))
1004            } else if let Some(f) = n.as_f64() {
1005                Value::Number(Number::Float(f))
1006            } else {
1007                Value::Number(Number::Float(0.0))
1008            }
1009        }
1010        serde_json::Value::String(s) => Value::String(s),
1011        serde_json::Value::Array(arr) => {
1012            let converted: Vec<Value> = arr.into_iter().map(convert_serde_to_vexy_json).collect();
1013            Value::Array(converted)
1014        }
1015        serde_json::Value::Object(obj) => {
1016            let converted: FxHashMap<String, Value> = obj
1017                .into_iter()
1018                .map(|(k, v)| (k, convert_serde_to_vexy_json(v)))
1019                .collect();
1020            Value::Object(converted)
1021        }
1022    }
1023}
1024
1025/// Enhanced parsing function that reports all repairs made
1026pub fn parse_with_detailed_repair_tracking(
1027    input: &str,
1028    options: ParserOptions,
1029) -> EnhancedParseResult<Value> {
1030    let mut repairer = JsonRepairer::new(options.max_repairs);
1031
1032    match repairer.repair_with_detailed_tracking(input) {
1033        Ok((repaired_json, repairs)) => match parse_with_options(&repaired_json, options) {
1034            Ok(value) => {
1035                EnhancedParseResult::success_with_repairs(value, repairs, ParsingTier::Repair)
1036            }
1037            Err(error) => EnhancedParseResult::failure_with_repairs(
1038                Value::Null,
1039                vec![error],
1040                repairs,
1041                ParsingTier::Repair,
1042            ),
1043        },
1044        Err(repair_error) => EnhancedParseResult::failure(
1045            Value::Null,
1046            vec![Error::RepairFailed(repair_error)],
1047            ParsingTier::Repair,
1048        ),
1049    }
1050}