• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::string::parse_string;
2 use crate::{context_tag, end_delimiter, utils::*};
3 use nom::combinator::map_res;
4 use nom::Err;
5 use nom::{
6     branch::alt,
7     bytes::complete::tag,
8     character::complete::char,
9     combinator::{cut, map, opt},
10     error::{context, convert_error, VerboseError},
11     multi::{many0, separated_list0},
12     sequence::{delimited, tuple},
13 };
14 use std::collections::HashMap;
15 use std::ops::{Deref, DerefMut};
16 use std::path::Path;
17 
18 /// a dictionary in a blueprint file
19 #[derive(Debug, PartialEq, Clone, Eq)]
20 pub struct Map(pub HashMap<String, Value>);
21 impl Deref for Map {
22     type Target = HashMap<String, Value>;
deref(&self) -> &Self::Target23     fn deref(&self) -> &Self::Target {
24         &self.0
25     }
26 }
27 impl DerefMut for Map {
deref_mut(&mut self) -> &mut Self::Target28     fn deref_mut(&mut self) -> &mut Self::Target {
29         &mut self.0
30     }
31 }
parse_dict(input: &str) -> VerboseResult<Map>32 fn parse_dict(input: &str) -> VerboseResult<Map> {
33     context(
34         "dict",
35         map(
36             delimited(
37                 tuple((space_or_comments, context_tag!("{"), space_or_comments)),
38                 separated_list0(char(','), parse_module_entry),
39                 end_delimiter!("}"),
40             ),
41             |entries| Map(entries.into_iter().collect()),
42         ),
43     )(input)
44 }
45 #[derive(Debug, PartialEq, Clone, Eq)]
46 pub struct Function {
47     pub name: String,
48     pub args: Vec<Value>,
49 }
parse_function(input: &str) -> VerboseResult<Function>50 fn parse_function(input: &str) -> VerboseResult<Function> {
51     context(
52         "function",
53         map(
54             tuple((
55                 space_or_comments,
56                 identifier,
57                 space_or_comments,
58                 delimited(
59                     tuple((space_or_comments, context_tag!("("), space_or_comments)),
60                     separated_list0(comma, parse_expr),
61                     end_delimiter!(")"),
62                 ),
63             )),
64             |(_, name, _, args)| Function {
65                 name: name.to_string(),
66                 args,
67             },
68         ),
69     )(input)
70 }
71 /// a value in a blueprint file
72 #[derive(Debug, PartialEq, Clone, Eq)]
73 pub enum Value {
74     String(String),
75     Integer(i64),
76     Array(Vec<Value>),
77     Boolean(bool),
78     Map(Map),
79     Ident(String),
80     ConcatExpr(Vec<Value>),
81     Function(Function),
82 }
83 // convert value from str
84 impl From<&str> for Value {
from(s: &str) -> Self85     fn from(s: &str) -> Self {
86         Value::String(s.to_string())
87     }
88 }
parse_value(input: &str) -> VerboseResult<Value>89 fn parse_value(input: &str) -> VerboseResult<Value> {
90     context(
91         "value",
92         alt((
93             map(parse_array, Value::Array),
94             map(parse_function, Value::Function),
95             map(string_literal, Value::String),
96             map(parse_bool, Value::Boolean),
97             map(parse_dict, Value::Map),
98             map(parse_int, Value::Integer),
99             map(identifier, |x| Value::Ident(x.to_string())),
100         )),
101     )(input)
102 }
concat_value_string(values: Vec<Value>) -> Result<Value, &'static str>103 fn concat_value_string(values: Vec<Value>) -> Result<Value, &'static str> {
104     let mut result = String::new();
105     for value in values {
106         match value {
107             Value::String(s) => result.push_str(&s),
108             _ => Err("value is not a string")?,
109         }
110     }
111     Ok(Value::String(result))
112 }
concat_value_array(values: Vec<Value>) -> Result<Value, &'static str>113 fn concat_value_array(values: Vec<Value>) -> Result<Value, &'static str> {
114     let mut result = Vec::new();
115     for value in values {
116         match value {
117             Value::Array(a) => result.extend(a),
118             _ => Err("value is not an array")?,
119         }
120     }
121     Ok(Value::Array(result))
122 }
parse_expr(input: &str) -> VerboseResult<Value>123 pub(crate) fn parse_expr(input: &str) -> VerboseResult<Value> {
124     // in bp, value can be combined with '+' operator
125     // this parser parse the expression and combine the values
126     // into a single value, if there is no Ident in the values
127     context(
128         "expr",
129         map_res(
130             separated_list0(
131                 tuple((space_or_comments, char('+'), space_or_comments)),
132                 parse_value,
133             ),
134             |values| {
135                 match values.len() {
136                     0 => Err("no value"),
137                     1 => Ok(values[0].clone()),
138                     _ => {
139                         // if there is one ident we cannot concat
140                         if values
141                             .iter()
142                             .any(|v| matches!(v, Value::Ident(_) | Value::Function(_)))
143                         {
144                             return Ok(Value::ConcatExpr(values));
145                         }
146                         match &values[0] {
147                             Value::String(_) => concat_value_string(values),
148                             Value::Array(_) => concat_value_array(values),
149                             _ => Err("first value is not a string"),
150                         }
151                     }
152                 }
153             },
154         ),
155     )(input)
156 }
parse_array(input: &str) -> VerboseResult<Vec<Value>>157 pub(crate) fn parse_array(input: &str) -> VerboseResult<Vec<Value>> {
158     context(
159         "array",
160         delimited(
161             ws(char('[')),
162             separated_list0(comma, parse_expr),
163             end_delimiter!("]"),
164         ),
165     )(input)
166 }
167 
168 /// a blueprint file
169 #[derive(Debug, PartialEq, Clone, Eq)]
170 pub struct BluePrint {
171     /// variables in the blueprint file
172     /// found in root of the file in the form of `key = value`
173     pub variables: HashMap<String, Value>,
174     /// all ordered modules in the blueprint file
175     pub modules: Vec<Module>,
176 }
177 
178 /// a module in a blueprint file
179 #[derive(Debug, PartialEq, Clone, Eq)]
180 pub struct Module {
181     pub typ: String,
182     pub entries: HashMap<String, Value>,
183 }
184 impl Module {
185     /// get an attribute value from a module
get(&self, key: &str) -> Option<&Value>186     pub fn get(&self, key: &str) -> Option<&Value> {
187         self.entries.get(key)
188     }
189     /// get a string attribute value from a module
get_string(&self, key: &str) -> Option<&String>190     pub fn get_string(&self, key: &str) -> Option<&String> {
191         match self.get(key) {
192             Some(Value::String(s)) => Some(s),
193             _ => None,
194         }
195     }
196     /// get a boolean attribute value from a module
get_bool(&self, key: &str) -> Option<bool>197     pub fn get_bool(&self, key: &str) -> Option<bool> {
198         match self.get(key) {
199             Some(Value::Boolean(b)) => Some(*b),
200             _ => None,
201         }
202     }
203     /// get an array attribute value from a module
get_array(&self, key: &str) -> Option<&Vec<Value>>204     pub fn get_array(&self, key: &str) -> Option<&Vec<Value>> {
205         match self.get(key) {
206             Some(Value::Array(a)) => Some(a),
207             _ => None,
208         }
209     }
210     /// get a map attribute value from a module
get_map(&self, key: &str) -> Option<&Map>211     pub fn get_map(&self, key: &str) -> Option<&Map> {
212         match self.get(key) {
213             Some(Value::Map(d)) => Some(d),
214             _ => None,
215         }
216     }
217     /// get an identifier attribute value from a module
get_ident(&self, key: &str) -> Option<&String>218     pub fn get_ident(&self, key: &str) -> Option<&String> {
219         match self.get(key) {
220             Some(Value::Ident(i)) => Some(i),
221             _ => None,
222         }
223     }
224     /// get an integer attribute value from a module
get_int(&self, key: &str) -> Option<i64>225     pub fn get_int(&self, key: &str) -> Option<i64> {
226         match self.get(key) {
227             Some(Value::Integer(i)) => Some(*i),
228             _ => None,
229         }
230     }
231 }
232 /// parse a module entry, with `:` as delimiter
parse_module_entry(input: &str) -> VerboseResult<(String, Value)>233 pub(crate) fn parse_module_entry(input: &str) -> VerboseResult<(String, Value)> {
234     _parse_module_entry(input, ':')
235 }
236 /// second form of module entry, with `=` as delimiter
parse_module_entry2(input: &str) -> VerboseResult<(String, Value)>237 pub(crate) fn parse_module_entry2(input: &str) -> VerboseResult<(String, Value)> {
238     _parse_module_entry(input, '=')
239 }
_parse_module_entry(input: &str, delimiter: char) -> VerboseResult<(String, Value)>240 pub(crate) fn _parse_module_entry(input: &str, delimiter: char) -> VerboseResult<(String, Value)> {
241     context(
242         "module entry",
243         map(
244             tuple((
245                 space_or_comments,
246                 alt((
247                     map(identifier, |x| x.to_string()),
248                     parse_string::<VerboseError<&str>>,
249                 )),
250                 space_or_comments,
251                 char(delimiter),
252                 space_or_comments,
253                 cut(parse_expr),
254                 space_or_comments,
255             )),
256             |(_, key, _, _, _, value, _)| (key.to_string(), value),
257         ),
258     )(input)
259 }
260 
parse_module(input: &str) -> VerboseResult<Module>261 pub(crate) fn parse_module(input: &str) -> VerboseResult<Module> {
262     // parse a identifier followed by a module of entries
263     let (input, _) = space_or_comments(input)?;
264     let (input, ident) = identifier(input)?;
265     let (input, _) = space_or_comments(input)?;
266     let (input, module) = context(
267         "module",
268         alt((
269             map(
270                 delimited(
271                     tuple((space_or_comments, context_tag!("{"), space_or_comments)),
272                     separated_list0(char(','), parse_module_entry),
273                     end_delimiter!("}"),
274                 ),
275                 |entries| entries.into_iter().collect(),
276             ),
277             map(
278                 delimited(
279                     tuple((space_or_comments, context_tag!("("), space_or_comments)),
280                     separated_list0(char(','), parse_module_entry2),
281                     end_delimiter!(")"),
282                 ),
283                 |entries| entries.into_iter().collect(),
284             ),
285         )),
286     )(input)?;
287     Ok((
288         input,
289         Module {
290             typ: ident.to_string(),
291             entries: module,
292         },
293     ))
294 }
295 
parse_define(input: &str) -> VerboseResult<(String, String, Value)>296 pub(crate) fn parse_define(input: &str) -> VerboseResult<(String, String, Value)> {
297     context(
298         "define",
299         map(
300             tuple((
301                 space_or_comments,
302                 identifier,
303                 space_or_comments,
304                 alt((tag("="), tag("+="))),
305                 space_or_comments,
306                 cut(parse_expr),
307                 space_or_comments,
308             )),
309             |(_, key, _, op, _, value, _)| (key.to_string(), op.to_string(), value),
310         ),
311     )(input)
312 }
313 
parse_blueprint(input: &str) -> VerboseResult<BluePrint>314 pub(crate) fn parse_blueprint(input: &str) -> VerboseResult<BluePrint> {
315     let mut entries = Vec::new();
316     let mut variables = HashMap::new();
317     let (input, _) = context(
318         "blueprint",
319         many0(alt((
320             map(parse_module, |b| {
321                 entries.push(b);
322                 ()
323             }),
324             map_res(parse_define, |(k, op, v)| match op.as_str() {
325                 "=" => {
326                     variables.insert(k, v);
327                     Ok(())
328                 }
329                 "+=" => {
330                     let e = variables.entry(k);
331                     match e {
332                         std::collections::hash_map::Entry::Occupied(prev) => {
333                             let prev = prev.into_mut();
334                             match prev {
335                                 Value::String(s) => {
336                                     match v {
337                                         Value::String(s2) => {
338                                             s.push_str(&s2);
339                                         }
340                                         _ => Err("cannot append value to string")?,
341                                     }
342                                 }
343                                 Value::Array(a) => {
344                                     match v {
345                                         Value::Array(a2) => {
346                                             a.extend(a2);
347                                         }
348                                         Value::Ident(_) => {
349                                             Err("FIXME in this case, we should turn the Array into ConcatExpr")?
350                                         }
351                                         _ => Err("cannot append value to array")?,
352                                     }
353                                 }
354                                 Value::Integer(i) => {
355                                     match v {
356                                         Value::Integer(i2) => {
357                                             *i += i2;
358                                         }
359                                         _ => Err("cannot append value to integer")?,
360                                     }
361                                 }
362                                 _ => Err("cannot append value to this type")?,
363                             }
364                         }
365                         std::collections::hash_map::Entry::Vacant(_) => Err("variable not found")?,
366                     }
367                     Ok(())
368                 }
369                 _ => Err("unknown operator"),
370             }),
371             space_or_comments1,
372         ))),
373     )(input)?;
374     Ok((
375         input,
376         BluePrint {
377             variables: variables,
378             modules: entries,
379         },
380     ))
381 }
382 
format_err(input: &str, err: Err<VerboseError<&str>>) -> String383 pub(crate) fn format_err(input: &str, err: Err<VerboseError<&str>>) -> String {
384     match err {
385         Err::Error(e) | Err::Failure(e) => convert_error(input, e.into()),
386         Err::Incomplete(_) => "Incomplete".to_string(),
387     }
388 }
389 impl BluePrint {
390     /// parse an Android.bp file from a string
parse(input: &str) -> Result<Self, String>391     pub fn parse(input: &str) -> Result<Self, String> {
392         match parse_blueprint(input) {
393             Ok((rest, result)) => {
394                 if rest.len() > 0 {
395                     return Err(format!("Unexpected left input: {}", rest));
396                 }
397                 Ok(result)
398             }
399             Err(err) => Err(format_err(input, err)),
400         }
401     }
402     /// parse an Android.bp file from a file path
from_file<P: AsRef<Path>>(path: P) -> Result<Self, String>403     pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, String> {
404         let input = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
405         Self::parse(&input)
406     }
407     /// get all modules of a specific type
modules_by_type<'a>(&'a self, typ: &'static str) -> impl Iterator<Item = &'a Module>408     pub fn modules_by_type<'a>(&'a self, typ: &'static str) -> impl Iterator<Item = &'a Module> {
409         self.modules.iter().filter(move |b| b.typ == typ)
410     }
411 }
412