regen/sdk/
ast_parser.rs

1use super::{Error, TokenStream, TokenType};
2
3/// ASTParser provides methods for parsing the language from token stream to:
4/// 1. List of tokens
5/// 2. Abstract Syntax Tree (AST) (either one or until the token stream is exhausted)
6///
7/// The generated language SDK will include implementation of this trait
8pub trait ASTParser {
9    /// Token type
10    ///
11    /// This type is generated in the environment. See [`crate::grammar::Tok`]
12    type T: TokenType;
13    /// AST root type
14    ///
15    /// This type is generated in the environment. See [`crate::grammar::ast::TopLevelStatement`].
16    /// Note that the first rule in the grammar file becomes the root.
17    type A;
18
19    /// Parse one AST root from the [`TokenStream`]
20    ///
21    /// Returns `None` when there's syntax error
22    fn parse_ast(&self, ts: &mut TokenStream<Self::T>) -> Option<Self::A>;
23
24    /// Create all ASTs from the source code, until the token stream is exhausted
25    ///
26    /// This method is useful for parsing multiple roots in a single source code,
27    /// for example, many statements where each statement is the target.
28    ///
29    /// On success, it returns a vector of ASTs. If there's any error, it returns an `Err` variant
30    /// with the ASTs that have been succesfully parsed, along with the errors.
31    fn parse_ast_all(&self, ts: &mut TokenStream<Self::T>) -> ASTResult<Self::A> {
32        let mut last_failed = false;
33        let mut asts = vec![];
34        let mut errors = vec![];
35
36        loop {
37            match self.parse_ast(ts) {
38                Some(ast) => {
39                    last_failed = false;
40                    asts.push(ast);
41                    if ts.is_exhausted() {
42                        break;
43                    }
44                }
45                None => {
46                    if let Some(token) = ts.consume() {
47                        if !last_failed {
48                            last_failed = true;
49                            if let Some(err_token) = ts.get_guess_err_token() {
50                                errors.push(Error::from_token_without_help(
51                                    err_token,
52                                    "Syntax error near this location".to_owned(),
53                                ));
54                            } else {
55                                errors.push(Error::from_token_without_help(
56                                    token,
57                                    "Syntax error".to_owned(),
58                                ));
59                            }
60                        }
61                    } else {
62                        break;
63                    }
64                }
65            }
66        }
67        if errors.is_empty() {
68            Ok(asts)
69        } else {
70            Err((asts, errors))
71        }
72    }
73}
74
75pub type ASTResult<A> = Result<Vec<A>, (Vec<A>, Vec<Error>)>;