nom_kconfig/entry/
source.rs1use std::path::PathBuf;
2
3use nom::{
4 branch::alt,
5 bytes::complete::tag,
6 character::complete::{alphanumeric1, one_of},
7 combinator::{cut, map, recognize},
8 error::{Error, ErrorKind, ParseError},
9 multi::many1,
10 sequence::delimited,
11 IResult, Parser,
12};
13use regex::Regex;
14
15use crate::{
16 kconfig::{parse_kconfig, Kconfig},
17 util::{ws, wsi},
18 KconfigFile, KconfigInput,
19};
20
21pub fn parse_filepath(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, &str> {
22 map(
23 recognize(ws(many1(alt((
24 alphanumeric1::<KconfigInput, _>,
25 recognize(one_of(".$()-_$/")),
26 ))))),
27 |d| d.fragment().to_owned(),
28 )
29 .parse(input)
30}
31
32pub fn parse_source(input: KconfigInput) -> IResult<KconfigInput, Source> {
33 let (input, _) = ws(tag("source")).parse(input)?;
34 let (input, file) = wsi(alt((
35 delimited(tag("\""), parse_filepath, tag("\"")),
36 parse_filepath,
37 )))
38 .parse(input)?;
39 if let Some(file) = apply_vars(file, &input.extra.vars) {
40 let source_kconfig_file = KconfigFile::new_with_vars(
41 input.clone().extra.root_dir,
42 PathBuf::from(file),
43 &input.extra.vars,
44 );
45 let source_content = source_kconfig_file
46 .read_to_string()
47 .map_err(|_| nom::Err::Error(Error::from_error_kind(input.clone(), ErrorKind::Fail)))?;
48
49 let binding = source_content.clone();
50 #[allow(clippy::let_and_return)]
51 let x = match cut(parse_kconfig).parse(KconfigInput::new_extra(
52 &binding,
53 source_kconfig_file.clone(),
54 )) {
55 Ok((_, kconfig)) => Ok((input, kconfig)),
56 Err(_e) => Err(nom::Err::Error(nom::error::Error::new(
57 KconfigInput::new_extra("", source_kconfig_file),
58 ErrorKind::Fail,
59 ))),
60 };
61 x
62 } else {
63 Ok((
64 input,
65 Source {
66 file: file.to_string(),
67 ..Default::default()
68 },
69 ))
70 }
71}
72
73pub fn apply_vars(
74 file: &str,
75 extra_vars: &std::collections::HashMap<String, String>,
76) -> Option<String> {
77 let re = Regex::new(r"\$\((\S+)\)").unwrap();
78 let mut file_copy = String::from(file);
79 for (var_name, var_value) in re.captures_iter(file).map(|cap| {
80 let ex: (&str, [&str; 1]) = cap.extract();
81 let var = ex.1[0];
82 (var, extra_vars.get(var))
83 }) {
84 if let Some(var_value) = var_value {
85 file_copy = file_copy.replace(&format!("$({var_name})"), var_value);
86 } else {
87 return None;
88 }
89 }
90 Some(file_copy)
91}
92
93pub type Source = Kconfig;