Skip to content

Commit

Permalink
feat: support += in defines
Browse files Browse the repository at this point in the history
  • Loading branch information
tardyp committed Jun 9, 2024
1 parent fcfab21 commit 879963d
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 45 deletions.
7 changes: 7 additions & 0 deletions examples/parse_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ fn walk_dir(dir: &Path) -> usize {
for entry in dir.read_dir().unwrap() {
let path = entry.unwrap().path();
if path.is_dir() {
if path.file_name().unwrap().to_str().unwrap() == "out" {
continue;
}
if path.file_name().unwrap().to_str().unwrap().starts_with("."){
continue;
}

num_files += walk_dir(&path);
} else {
let file_name = path.file_name().unwrap().to_str().unwrap();
Expand Down
127 changes: 87 additions & 40 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use nom::{
sequence::{delimited, tuple},
};
use std::collections::HashMap;
use std::ops::{DerefMut, Deref};
use std::ops::{Deref, DerefMut};
use std::path::Path;

/// a dictionary in a blueprint file
Expand All @@ -38,7 +38,7 @@ fn parse_dict(input: &str) -> VerboseResult<Map> {
separated_list0(char(','), parse_module_entry),
end_delimiter!("}"),
),
|entries| Map(entries.into_iter().collect())
|entries| Map(entries.into_iter().collect()),
),
)(input)
}
Expand All @@ -61,7 +61,10 @@ fn parse_function(input: &str) -> VerboseResult<Function> {
end_delimiter!(")"),
),
)),
|(_, name, _, args)| Function { name: name.to_string(), args },
|(_, name, _, args)| Function {
name: name.to_string(),
args,
},
),
)(input)
}
Expand All @@ -78,7 +81,7 @@ pub enum Value {
Function(Function),
}
// convert value from str
impl From <&str> for Value {
impl From<&str> for Value {
fn from(s: &str) -> Self {
Value::String(s.to_string())
}
Expand Down Expand Up @@ -124,19 +127,20 @@ pub(crate) fn parse_expr(input: &str) -> VerboseResult<Value> {
context(
"expr",
map_res(
separated_list0(tuple((
space_or_comments,
char('+'),
space_or_comments,
)
), parse_value),
separated_list0(
tuple((space_or_comments, char('+'), space_or_comments)),
parse_value,
),
|values| {
match values.len() {
0 => Err("no value"),
1 => Ok(values[0].clone()),
_ => {
// if there is one ident we cannot concat
if values.iter().any(|v| matches!(v, Value::Ident(_) | Value::Function(_))) {
if values
.iter()
.any(|v| matches!(v, Value::Ident(_) | Value::Function(_)))
{
return Ok(Value::ConcatExpr(values));
}
match &values[0] {
Expand All @@ -146,7 +150,7 @@ pub(crate) fn parse_expr(input: &str) -> VerboseResult<Value> {
}
}
}
}
},
),
)(input)
}
Expand All @@ -164,14 +168,13 @@ pub(crate) fn parse_array(input: &str) -> VerboseResult<Vec<Value>> {
/// a blueprint file
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct BluePrint {
/// variables in the blueprint file
/// variables in the blueprint file
/// found in root of the file in the form of `key = value`
pub variables: HashMap<String, Value>,
/// all ordered modules in the blueprint file
pub modules: Vec<Module>,
}


/// a module in a blueprint file
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct Module {
Expand Down Expand Up @@ -225,7 +228,6 @@ impl Module {
_ => None,
}
}

}
/// parse a module entry, with `:` as delimiter
pub(crate) fn parse_module_entry(input: &str) -> VerboseResult<(String, Value)> {
Expand All @@ -241,7 +243,10 @@ pub(crate) fn _parse_module_entry(input: &str, delimiter: char) -> VerboseResult
map(
tuple((
space_or_comments,
alt((map(identifier, |x| x.to_string()), parse_string::<VerboseError<&str>>)),
alt((
map(identifier, |x| x.to_string()),
parse_string::<VerboseError<&str>>,
)),
space_or_comments,
char(delimiter),
space_or_comments,
Expand All @@ -261,22 +266,22 @@ pub(crate) fn parse_module(input: &str) -> VerboseResult<Module> {
let (input, module) = context(
"module",
alt((
map(
delimited(
tuple((space_or_comments, context_tag!("{"), space_or_comments)),
separated_list0(char(','), parse_module_entry),
end_delimiter!("}"),
map(
delimited(
tuple((space_or_comments, context_tag!("{"), space_or_comments)),
separated_list0(char(','), parse_module_entry),
end_delimiter!("}"),
),
|entries| entries.into_iter().collect(),
),
|entries| entries.into_iter().collect(),
),
map(
delimited(
tuple((space_or_comments, context_tag!("("), space_or_comments)),
separated_list0(char(','), parse_module_entry2),
end_delimiter!(")"),
map(
delimited(
tuple((space_or_comments, context_tag!("("), space_or_comments)),
separated_list0(char(','), parse_module_entry2),
end_delimiter!(")"),
),
|entries| entries.into_iter().collect(),
),
|entries| entries.into_iter().collect(),
),
)),
)(input)?;
Ok((
Expand All @@ -288,23 +293,24 @@ pub(crate) fn parse_module(input: &str) -> VerboseResult<Module> {
))
}

pub(crate) fn parse_define(input: &str) -> VerboseResult<(String, Value)> {
pub(crate) fn parse_define(input: &str) -> VerboseResult<(String, String, Value)> {
context(
"define",
map(
tuple((
space_or_comments,
identifier,
space_or_comments,
char('='),
alt((tag("="), tag("+="))),
space_or_comments,
cut(parse_expr),
space_or_comments,
)),
|(_, key, _, _, _, value, _)| (key.to_string(), value),
|(_, key, _, op, _, value, _)| (key.to_string(), op.to_string(), value),
),
)(input)
}

pub(crate) fn parse_blueprint(input: &str) -> VerboseResult<BluePrint> {
let mut entries = Vec::new();
let mut variables = HashMap::new();
Expand All @@ -315,9 +321,52 @@ pub(crate) fn parse_blueprint(input: &str) -> VerboseResult<BluePrint> {
entries.push(b);
()
}),
map(parse_define, |(k, v)| {
variables.insert(k, v);
()
map_res(parse_define, |(k, op, v)| match op.as_str() {
"=" => {
variables.insert(k, v);
Ok(())
}
"+=" => {
let e = variables.entry(k);
match e {
std::collections::hash_map::Entry::Occupied(prev) => {
let prev = prev.into_mut();
match prev {
Value::String(s) => {
match v {
Value::String(s2) => {
s.push_str(&s2);
}
_ => Err("cannot append value to string")?,
}
}
Value::Array(a) => {
match v {
Value::Array(a2) => {
a.extend(a2);
}
Value::Ident(_) => {
Err("FIXME in this case, we should turn the Array into ConcatExpr")?
}
_ => Err("cannot append value to array")?,
}
}
Value::Integer(i) => {
match v {
Value::Integer(i2) => {
*i += i2;
}
_ => Err("cannot append value to integer")?,
}
}
_ => Err("cannot append value to this type")?,
}
}
std::collections::hash_map::Entry::Vacant(_) => Err("variable not found")?,
}
Ok(())
}
_ => Err("unknown operator"),
}),
space_or_comments1,
))),
Expand All @@ -331,7 +380,7 @@ pub(crate) fn parse_blueprint(input: &str) -> VerboseResult<BluePrint> {
))
}

pub(crate)fn format_err(input: &str, err: Err<VerboseError<&str>>) -> String {
pub(crate) fn format_err(input: &str, err: Err<VerboseError<&str>>) -> String {
match err {
Err::Error(e) | Err::Failure(e) => convert_error(input, e.into()),
Err::Incomplete(_) => "Incomplete".to_string(),
Expand All @@ -357,8 +406,6 @@ impl BluePrint {
}
/// get all modules of a specific type
pub fn modules_by_type<'a>(&'a self, typ: &'static str) -> impl Iterator<Item = &'a Module> {
self.modules
.iter()
.filter(move |b| b.typ == typ)
self.modules.iter().filter(move |b| b.typ == typ)
}
}
4 changes: 2 additions & 2 deletions src/test_db.tar.xz
Git LFS file not shown
38 changes: 35 additions & 3 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod tests {

use crate::parser::*;
use nom::error::VerboseError;
use nom::{bytes, Err};
use nom::Err;

#[test]
fn test_parse_array() {
Expand Down Expand Up @@ -315,6 +315,36 @@ mod tests {

}
#[test]
fn test_defines_extends(){
let input = r#"
var = ["a", "b"]
var2 = 12
var += ["c"]
var2 += 1
var3 = "abc"
var3 += "def"
"#;
let output = BluePrint::parse(input);
assert!(output.is_ok());
let bp = output.unwrap();
assert_eq!(bp.variables.get("var").unwrap(), &Value::Array(vec!["a".into(), "b".into(), "c".into()]));
assert_eq!(bp.variables.get("var2").unwrap(), &Value::Integer(13));
assert_eq!(bp.variables.get("var3").unwrap(), &Value::String("abcdef".to_string()));
}

#[test]
fn test_defines_extends_error(){
let input = r#"
var = ["a", "b"]
var2 = 12
var += 1
var2 += "a"
"#;
let output = BluePrint::parse(input);
println!("Error: {}", output.unwrap_err());
// assert!(output.is_err());
}
#[test]
fn test_function() {
let input = r#"method("ss")"#;
let output = parse_expr(input);
Expand All @@ -329,11 +359,12 @@ mod tests {
#[test]
fn test_aosp_db() {
// generate tarball from aosp tree
// fd -g Android.bp |xargs tar cJf ../rs-bp/src/test_db.tar.xz
// fd -g Android.bp | tar cJf ../rs-bp/src/test_db.tar.xz -T -
let data = include_bytes!("test_db.tar.xz");
let mut archive = tar::Archive::new(liblzma::read::XzDecoder::new(&data[..]));
let mut count = 0;
let mut bytes = 0;
let mut num_errors = 0;
let mut all_bp = Vec::new();
// first decompress in memory to avoid disk IO for measuring performance
for entry in archive.entries().unwrap() {
Expand All @@ -351,11 +382,12 @@ mod tests {
println!("Error for file: {:?}", path);
println!("File content: {}", contents);
println!("Error: {}", output.unwrap_err());
panic!("Error in parsing");
num_errors += 1;
}
count += 1;
}
let elapsed = now.elapsed().as_secs_f32();
println!("{} files ({} bytes) parsed in {:.3}s {}MB/s", count, bytes, elapsed, bytes as f32 / elapsed / 1024.0 / 1024.0);
assert_eq!(num_errors, 0);
}
}

0 comments on commit 879963d

Please sign in to comment.