1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use super::{Error, TokenStream, TokenType};

/// ASTParser provides methods for parsing the language from token stream to:
/// 1. List of tokens
/// 2. Abstract Syntax Tree (AST) (either one or until the token stream is exhausted)
///
/// The generated language SDK will include implementation of this trait
pub trait ASTParser {
    /// Token type
    ///
    /// This type is generated in the environment. See [`crate::grammar::Tok`]
    type T: TokenType;
    /// AST root type
    ///
    /// This type is generated in the environment. See [`crate::grammar::ast::TopLevelStatement`].
    /// Note that the first rule in the grammar file becomes the root.
    type A;

    /// Parse one AST root from the [`TokenStream`]
    ///
    /// Returns `None` when there's syntax error
    fn parse_ast(&self, ts: &mut TokenStream<Self::T>) -> Option<Self::A>;

    /// Create all ASTs from the source code, until the token stream is exhausted
    ///
    /// This method is useful for parsing multiple roots in a single source code,
    /// for example, many statements where each statement is the target.
    ///
    /// On success, it returns a vector of ASTs. If there's any error, it returns an `Err` variant
    /// with the ASTs that have been succesfully parsed, along with the errors.
    fn parse_ast_all(&self, ts: &mut TokenStream<Self::T>) -> ASTResult<Self::A> {
        let mut last_failed = false;
        let mut asts = vec![];
        let mut errors = vec![];

        loop {
            match self.parse_ast(ts) {
                Some(ast) => {
                    last_failed = false;
                    asts.push(ast);
                    if ts.is_exhausted() {
                        break;
                    }
                }
                None => {
                    if let Some(token) = ts.consume() {
                        if !last_failed {
                            last_failed = true;
                            if let Some(err_token) = ts.get_guess_err_token() {
                                errors.push(Error::from_token_without_help(
                                    err_token,
                                    "Syntax error near this location".to_owned(),
                                ));
                            } else {
                                errors.push(Error::from_token_without_help(
                                    token,
                                    "Syntax error".to_owned(),
                                ));
                            }
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        if errors.is_empty() {
            Ok(asts)
        } else {
            Err((asts, errors))
        }
    }
}

pub type ASTResult<A> = Result<Vec<A>, (Vec<A>, Vec<Error>)>;