error_recovery/
error_recovery.rs

1//! Error recovery example demonstrating sync token usage.
2//!
3//! This example shows how to configure error recovery using sync tokens.
4//! When a parse error occurs, the parser will scan forward for sync tokens
5//! and attempt to recover.
6//!
7//! Run with: cargo run --example error_recovery --package sipha-parse
8
9use sipha_core::{span::Span, token::Token as TokenStruct, traits::TokenKind};
10use sipha_parse::{helpers, parser::Parser, state::ParserState};
11use sipha_tree::{NodeArena, RawNodeId};
12
13#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
14enum Token {
15    Ident,
16    Plus,
17    Semicolon,
18    Invalid,
19}
20
21impl TokenKind for Token {
22    fn is_trivia(&self) -> bool {
23        false
24    }
25}
26
27#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
28enum Rule {
29    Statement,
30}
31
32fn main() {
33    let mut parser = Parser::create();
34
35    // Define a simple statement rule: Ident Plus Ident Semicolon
36    parser.register_rule(
37        Rule::Statement,
38        helpers::seq(vec![
39            helpers::token(Token::Ident),
40            helpers::token(Token::Plus),
41            helpers::token(Token::Ident),
42            helpers::token(Token::Semicolon),
43        ]),
44    );
45
46    // Configure error recovery: use semicolon as sync token
47    parser.set_sync_tokens(vec![Token::Semicolon]);
48
49    // Create token stream with an error: "a + invalid ; b + c ;"
50    // The parser should recover after the first semicolon
51    let tokens = vec![
52        TokenStruct::create(Token::Ident, Span::new(0, 1), "a", Vec::new(), Vec::new()),
53        TokenStruct::create(Token::Plus, Span::new(2, 3), "+", Vec::new(), Vec::new()),
54        TokenStruct::create(
55            Token::Invalid,
56            Span::new(4, 10),
57            "invalid",
58            Vec::new(),
59            Vec::new(),
60        ),
61        TokenStruct::create(
62            Token::Semicolon,
63            Span::new(11, 12),
64            ";",
65            Vec::new(),
66            Vec::new(),
67        ),
68        TokenStruct::create(Token::Ident, Span::new(13, 14), "b", Vec::new(), Vec::new()),
69        TokenStruct::create(Token::Plus, Span::new(15, 16), "+", Vec::new(), Vec::new()),
70        TokenStruct::create(Token::Ident, Span::new(17, 18), "c", Vec::new(), Vec::new()),
71        TokenStruct::create(
72            Token::Semicolon,
73            Span::new(19, 20),
74            ";",
75            Vec::new(),
76            Vec::new(),
77        ),
78    ];
79
80    let mut arena: NodeArena<Token, Rule, RawNodeId> = NodeArena::new();
81    let mut state = ParserState::new(&tokens, &mut arena, false, ());
82
83    println!("Parsing with error recovery enabled...");
84    println!("Input: a + invalid ; b + c ;");
85    println!();
86
87    // Try to parse - should recover after first error
88    match parser.parse_rule(Rule::Statement, &mut state) {
89        Ok(_) => {
90            println!("✓ Parsed successfully (with recovery)!");
91        }
92        Err(e) => {
93            println!("✗ Parse error: {:?}", e);
94            println!("Note: Error recovery attempted to sync at semicolon");
95        }
96    }
97}