verilog_filelist_parser/
file_parser.rs1use regex::Regex;
2use std::collections::HashMap;
3use std::error::Error;
4use std::fs;
5use std::path::{Path, PathBuf};
6
7use crate::line_parser;
8use crate::line_parser::LineType;
9
10#[derive(PartialEq, Debug, Default)]
12pub struct Filelist {
13 pub files: Vec<PathBuf>,
15 pub incdirs: Vec<PathBuf>,
17 pub defines: HashMap<String, Option<String>>,
19 pub comments_present: bool,
21 pub unknowns_present: bool,
23}
24
25impl Filelist {
26 pub fn new() -> Filelist {
28 Filelist {
29 files: Vec::new(),
30 incdirs: Vec::new(),
31 defines: HashMap::new(),
32 comments_present: false,
33 unknowns_present: false,
34 }
35 }
36
37 pub fn extend(&mut self, other: Filelist) {
39 self.files.extend(other.files);
40 self.incdirs.extend(other.incdirs);
41 self.defines.extend(other.defines);
42 self.comments_present |= other.comments_present;
43 self.unknowns_present |= other.unknowns_present;
44 }
45}
46
47pub fn parse_file(path: impl AsRef<Path>) -> Result<Filelist, Box<dyn Error>> {
62 let path = path.as_ref();
63 let contents = fs::read_to_string(path)?;
64
65 let mut filelist = Filelist::new();
66
67 for line in contents.lines() {
68 let line = replace_env_vars(&line);
69 match line_parser::parse_line(&line) {
70 LineType::File(file) => filelist.files.push(PathBuf::from(file)),
71 LineType::Define(define_map) => {
72 for (d, t) in define_map.into_iter() {
73 match t {
74 Some(text) => filelist
75 .defines
76 .insert(d.to_string(), Some(text.to_string())),
77 None => filelist.defines.insert(d.to_string(), None),
78 };
79 }
80 }
81 LineType::IncDir(incdirs) => {
82 for dir in incdirs {
83 filelist.incdirs.push(PathBuf::from(dir));
84 }
85 }
86 LineType::Comment => filelist.comments_present = true,
87 LineType::Unknown => filelist.unknowns_present = true,
88 LineType::Empty => (),
89 LineType::Filelist(path) => {
90 filelist.extend(parse_file(path)?);
91 }
92 }
93 }
94 Ok(filelist)
95}
96
97fn replace_env_vars(line: &str) -> String {
98 let re_env_brace = Regex::new(r"\$\{(?P<env>[^}]+)\}").unwrap();
99 let re_env_paren = Regex::new(r"\$\((?P<env>[^)]+)\)").unwrap();
100
101 let mut expanded_line = String::from(line);
102 for caps in re_env_brace.captures_iter(&line) {
103 let env = &caps["env"];
104 if let Ok(env_var) = std::env::var(env) {
105 expanded_line = expanded_line.replace(&format!("${{{}}}", env), &env_var);
106 }
107 }
108 for caps in re_env_paren.captures_iter(&line) {
109 let env = &caps["env"];
110 if let Ok(env_var) = std::env::var(env) {
111 expanded_line = expanded_line.replace(&format!("$({})", env), &env_var);
112 }
113 }
114 expanded_line
115}