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}