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