gtk_ui/
preprocessor.rs

1use super::lexer::{
2    Lexer,
3};
4use super::parser::{
5    Parser,
6    Statement,
7    StatementValue
8};
9use super::util::{check_error, get_include_path};
10use std::ops::Range;
11use std::fs;
12
13
14// TODO: Warn about a file being included multiple times.
15// At the moment, regardless of where the library is included, if it is included twice, everything defined in the library is redefined
16// This is of course very easily avoidable, but for user friendliness, a notification about this would be nice
17
18pub struct Preprocessor {
19    pub statements: Vec<Statement>,
20}
21
22impl Preprocessor { 
23
24    // Pubs
25    pub fn preprocess(&mut self, input: Vec<Statement>, included_files: Vec<String>) -> Result<(), (String, Range<usize>)> {
26        for statement in input {
27            match statement.value {
28                StatementValue::Include(path) => {
29                    if let Some(path) = get_include_path(&path) {
30                        match fs::read_to_string(&path) {
31                            Ok(content) => {
32                                if included_files.iter().any(|n| n == &path) {
33                                    return Err((format!("recursive include of '{}'", path), (1..0)));
34                                }
35                            
36                                let mut lexer = Lexer::new(content.clone());
37                                check_error(lexer.lex(false), &path, &content);
38                                let mut parser = Parser::new(lexer.tokens, included_files.last().unwrap().clone());
39                                check_error(parser.parse(), &path, &content);
40
41                                let mut included_files = included_files.clone();
42                                included_files.push(path);
43
44                                if let Err(err) = self.preprocess(parser.statements, included_files) {
45                                    return Err(err);
46                                }
47                            },
48                            Err(err) => return Err((String::from(err.to_string()), 1..0))
49                        }
50                    } else {
51                        return Err((format!("could not find file '{}' in lib directory or current working directory", path), (1..0)));
52                    }
53                },
54                _ => {
55                    self.statements.push(statement);
56                }
57            }
58        }
59        Ok(())
60    }
61
62    pub fn new() -> Self {
63        Self {
64            statements: Vec::new(),
65        }
66    } 
67}