rvs_parser/
parser.rs

1use crate::ast;
2use crate::grammar;
3use crate::searchpath::SearchPath;
4use crate::sourcepaths::SourcePaths;
5use crate::error::{Error, ParseError, Result};
6
7pub struct Parser {
8    searchpath: SearchPath,
9}
10
11impl Parser {
12    pub fn new(searchpath: SearchPath) -> Parser {
13        Parser { searchpath }
14    }
15
16    pub fn parse(&self, s: &str) -> Result<Vec<Box<ast::Node>>> {
17        match grammar::items(s, &mut SourcePaths::new(self.searchpath.clone())) {
18            Ok(items) => self.flatten(items),
19            Err(error) => {
20                // FIXME: Improve formatting source code in errors
21                //
22                // Current format:
23                //
24                // error at 2:3: expected `=`
25                // a += b;
26                //   ^
27                //
28                // Example: rustc
29                //
30                // error: expected expression, found `+`
31                //   --> /home/rfdonnelly/repos/rvs/src/lib.rs:28:24
32                //    |
33                // 28 |                 error, +
34                //    |                        ^
35                //
36                // Notable features:
37                //
38                // * Source file path
39                // * Single space above and below source line
40                // * Source line prefixed with line number and '|' separator
41                let mut indent = String::with_capacity(error.location.column);
42                for _ in 0..error.location.column - 1 {
43                    indent.push_str(" ");
44                }
45                let line = s.lines().nth(error.location.line - 1).unwrap();
46                let description = format!("{}\n{}\n{}^", error, line, indent,);
47
48                Err(Error::Parse(ParseError::new(description)))
49            }
50        }
51    }
52
53    fn flatten_recursive(
54        &self,
55        mut items: Vec<ast::Item>,
56        nodes: &mut Vec<Box<ast::Node>>,
57    ) -> Result<()> {
58        for item in items.drain(..) {
59            match item {
60                ast::Item::Single(node) => nodes.push(node),
61                ast::Item::Multiple(items) => self.flatten_recursive(items, nodes)?,
62                ast::Item::ImportError(path, err) => {
63                    return Err(Error::Io(err));
64                }
65            }
66        }
67
68        Ok(())
69    }
70
71    /// Strips out all ast::Items while keeping their contents
72    ///
73    /// ast::Items only serve as packaging for ast::Nodes.  `import` adds the packaging.  `flatten`
74    /// removes the packaging.  ast::Items are an implementation detail for `import` and only add
75    /// noise to the AST.
76    fn flatten(&self, items: Vec<ast::Item>) -> Result<Vec<Box<ast::Node>>> {
77        let mut nodes: Vec<Box<ast::Node>> = Vec::new();
78
79        self.flatten_recursive(items, &mut nodes)?;
80
81        Ok(nodes)
82    }
83}