blob: c2fd3a0e1dfff2f2fa4fecdffa2a1befefeed7e2 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::parser_common::{
compound_identifier, condition_value, many_until_eof, map_err, ws, BindParserError,
CompoundIdentifier, Value,
};
use nom::{bytes::complete::tag, sequence::separated_pair, IResult};
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq)]
pub struct Ast {
pub properties: Vec<Property>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Property {
pub key: CompoundIdentifier,
pub value: Value,
}
impl FromStr for Ast {
type Err = BindParserError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
match device_specification(input) {
Ok((_, ast)) => Ok(ast),
Err(nom::Err::Error(e)) => Err(e),
Err(nom::Err::Failure(e)) => Err(e),
Err(nom::Err::Incomplete(_)) => {
unreachable!("Parser should never generate Incomplete errors")
}
}
}
}
fn property(input: &str) -> IResult<&str, Property, BindParserError> {
let key = ws(compound_identifier);
let separator = ws(map_err(tag("="), BindParserError::Assignment));
let (input, (key, value)) = separated_pair(key, separator, condition_value)(input)?;
Ok((input, Property { key, value }))
}
fn device_specification(input: &str) -> IResult<&str, Ast, BindParserError> {
let (_, properties) = many_until_eof(ws(property))(input)?;
Ok(("", Ast { properties }))
}
#[cfg(test)]
mod test {
use super::*;
use crate::make_identifier;
mod properties {
use super::*;
#[test]
fn simple() {
assert_eq!(
property("abc = 5"),
Ok((
"",
Property { key: make_identifier!["abc"], value: Value::NumericLiteral(5) }
))
);
}
#[test]
fn invalid() {
assert_eq!(
property("abc 5"),
Err(nom::Err::Error(BindParserError::Assignment("5".to_string())))
);
assert_eq!(
property("abc ="),
Err(nom::Err::Error(BindParserError::ConditionValue("".to_string())))
);
assert_eq!(
property("= 5"),
Err(nom::Err::Error(BindParserError::Identifier("= 5".to_string())))
);
}
#[test]
fn empty() {
assert_eq!(
property(""),
Err(nom::Err::Error(BindParserError::Identifier("".to_string())))
);
}
}
mod device_specifications {
use super::*;
#[test]
fn simple() {
assert_eq!(
device_specification("abc = 5\nxyz = true"),
Ok((
"",
Ast {
properties: vec![
Property {
key: make_identifier!["abc"],
value: Value::NumericLiteral(5)
},
Property {
key: make_identifier!["xyz"],
value: Value::BoolLiteral(true)
},
]
}
))
);
}
#[test]
fn empty() {
assert_eq!(device_specification(""), Ok(("", Ast { properties: Vec::new() })));
}
}
}