use crate::ast::*;
use escape8259::unescape;
use nom::{
branch::alt,
bytes::complete::{tag, take_while1},
character::complete::{
anychar, char as charx, digit0, digit1, hex_digit1, multispace1, not_line_ending, one_of,
},
combinator::{all_consuming, map, map_res, opt, recognize, value as valuex},
multi::{many0, many1, separated_nonempty_list},
sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
};
use std::convert::TryFrom;
use std::error;
use std::fmt;
type JResult<I, O> = nom::IResult<I, O, ParseError>;
#[rustversion::attr(since(1.40), non_exhaustive)]
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
MalformedInteger,
MalformedFloat,
MalformedHex,
MalformedText,
MalformedBase64,
Unparseable,
}
use ErrorKind::*;
#[derive(Debug, PartialEq)]
pub struct ParseError {
pub kind: ErrorKind,
pub ctx: String,
}
fn parse_error<S: Into<String>>(kind: ErrorKind, ctx: S) -> ParseError {
ParseError {
kind,
ctx: ctx.into(),
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}({})", self.kind, self.ctx)
}
}
impl error::Error for ParseError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
impl From<nom::Err<ParseError>> for ParseError {
fn from(e: nom::Err<ParseError>) -> ParseError {
match e {
nom::Err::Incomplete(_) => parse_error(Unparseable, "Incomplete"),
nom::Err::Error(pe) => pe,
nom::Err::Failure(pe) => pe,
}
}
}
impl<I: Into<String>> nom::error::ParseError<I> for ParseError {
fn from_error_kind(input: I, _kind: nom::error::ErrorKind) -> Self {
parse_error(Unparseable, input)
}
fn append(_input: I, _kind: nom::error::ErrorKind, other: Self) -> Self {
other
}
}
fn map_res_fail<I: Clone, O1, O2, E: nom::error::ParseError<I>, F, G>(
first: F,
second: G,
) -> impl Fn(I) -> nom::IResult<I, O2, E>
where
F: Fn(I) -> nom::IResult<I, O1, E>,
G: Fn(O1) -> Result<O2, E>,
{
move |input: I| {
let (input, o1) = first(input)?;
match second(o1) {
Ok(o2) => Ok((input, o2)),
Err(e) => Err(nom::Err::Failure(e)),
}
}
}
#[rustfmt::skip]
fn comment(input: &str) -> JResult<&str, &str> {
preceded(
charx(';'),
not_line_ending
)(input)
}
#[rustfmt::skip]
fn ws(input: &str) -> JResult<&str, &str> {
recognize(
many0(
alt((
multispace1,
comment
))
)
)
(input)
}
#[rustfmt::skip]
fn optcom(input: &str) -> JResult<&str, ()> {
valuex((), pair(
ws,
opt(pair(
tag(","),
ws
))
))
(input)
}
fn ealpha_char(c: char) -> bool {
c.is_ascii_alphabetic() || c == '@' || c == '_' || c == '$'
}
#[rustfmt::skip]
fn ealpha(input: &str) -> JResult<&str, &str> {
take_while1(ealpha_char)
(input)
}
#[rustfmt::skip]
fn ident_tail(input: &str) -> JResult<&str, &str> {
recognize(
preceded(
opt(many1(one_of("-."))),
alt((
ealpha,
digit1
))
)
)
(input)
}
#[rustfmt::skip]
fn ident(input: &str) -> JResult<&str, &str> {
recognize(
preceded(
ealpha,
many0(ident_tail)
)
)
(input)
}
#[rustfmt::skip]
fn uint_hex(input: &str) -> JResult<&str, &str> {
preceded(
tag("0x"),
hex_digit1
)
(input)
}
#[rustfmt::skip]
fn uint_binary(input: &str) -> JResult<&str, &str> {
preceded(
tag("0b"),
recognize(many1(one_of("01")))
)
(input)
}
#[rustfmt::skip]
fn uint_decimal(input: &str) -> JResult<&str, &str> {
alt((
tag("0"),
recognize(
pair(
one_of("123456789"),
digit0
)
)
))
(input)
}
struct RawUint<'a> {
slice: &'a str,
base: u32,
}
#[rustfmt::skip]
fn uint(input: &str) -> JResult<&str, RawUint> {
alt((
map(uint_hex, |slice| RawUint{slice, base: 16}),
map(uint_binary, |slice| RawUint{slice, base: 2}),
map(uint_decimal, |slice| {
RawUint{slice, base: 10}
}),
))
(input)
}
#[rustfmt::skip]
fn uint_u64(input: &str) -> JResult<&str, u64> {
map_res_fail(uint, |raw| {
u64::from_str_radix(raw.slice, raw.base)
.map_err(|_| {
parse_error(MalformedInteger, raw.slice)
})
})
(input)
}
struct RawInt<'a> {
slice: &'a str,
base: u32,
neg: bool,
}
#[rustfmt::skip]
fn int(input: &str) -> JResult<&str, RawInt> {
let f = pair(
opt(charx('-')),
uint
);
map(f, |(optneg, rawuint)| {
RawInt {
slice: rawuint.slice,
base: rawuint.base,
neg: optneg.is_some(),
}
})
(input)
}
#[rustfmt::skip]
fn dot_fraction(input: &str) -> JResult<&str, &str> {
recognize(
pair(
charx('.'),
digit1
)
)
(input)
}
#[rustfmt::skip]
fn e_exponent(input: &str) -> JResult<&str, &str> {
recognize(
tuple((
charx('e'),
opt(one_of("+-")),
digit1
))
)
(input)
}
#[rustfmt::skip]
fn parse_float(s: &str) -> Result<Value, ParseError> {
match s.parse::<f64>() {
Ok(fl) => Ok(Value::Float(fl)),
Err(_) => Err(parse_error(MalformedFloat, s)),
}
}
fn parse_int(raw: RawInt) -> Result<Value, ParseError> {
let posint = u64::from_str_radix(raw.slice, raw.base)
.map_err(|_| parse_error(MalformedInteger, raw.slice))?;
if raw.neg {
let negint: i64 = try_into_int(posint, raw.slice)?;
Ok(Value::Nint(-negint))
} else {
Ok(Value::Uint(posint))
}
}
fn offset(whole: &str, part: &str) -> usize {
part.as_ptr() as usize - whole.as_ptr() as usize
}
fn recognizer<'a, O, E, F>(parser: F) -> impl Fn(&'a str) -> nom::IResult<&'a str, (&'a str, O), E>
where
E: nom::error::ParseError<&'a str>,
F: Fn(&'a str) -> nom::IResult<&'a str, O, E>,
{
move |input: &'a str| {
#[allow(clippy::clone_double_ref)]
let i = input.clone();
match parser(i) {
Ok((i, output)) => {
let index = offset(input, &i);
let output_slice = &input[..index];
let output_tuple = (output_slice, output);
Ok((i, output_tuple))
}
Err(e) => Err(e),
}
}
}
fn float_or_int(input: &str) -> JResult<&str, Value> {
let f = recognizer(tuple((int, opt(dot_fraction), opt(e_exponent))));
map_res_fail(f, |(recognized, output)| {
let (firstint, frac, exp) = output;
let dot_or_e = frac.is_some() || exp.is_some();
if dot_or_e {
parse_float(recognized)
} else {
parse_int(firstint)
}
})(input)
}
#[rustfmt::skip]
fn is_unescaped_bchar(c: char) -> bool {
let ranges = [
(0x20 ..= 0x26),
(0x28 ..= 0x5B),
(0x5D ..= 0x7E),
(0x80 ..= 0x10FFD),
];
let cv = c as u32;
ranges.iter().any(|range| range.contains(&cv))
}
#[rustfmt::skip]
fn unescaped_bchar(input: &str) -> JResult<&str, &str> {
take_while1(is_unescaped_bchar)
(input)
}
#[rustfmt::skip]
fn bchar(input: &str) -> JResult<&str, &str> {
recognize(
many0(
alt((
unescaped_bchar,
sesc
))
)
)
(input)
}
#[rustfmt::skip]
fn bytestring_utf8(input: &str) -> JResult<&str, String> {
let f = delimited(
tag("'"),
bchar,
tag("'")
);
map_res_fail(f, |s| {
unescape(s).map_err(|_| parse_error(MalformedText, s) )
})
(input)
}
#[rustfmt::skip]
fn bytestring_hex(input: &str) -> JResult<&str, &str> {
delimited(
tag("h'"),
bchar,
tag("\'")
)(input)
}
#[rustfmt::skip]
fn bytestring_base64(input: &str) -> JResult<&str, &str> {
delimited(
tag("b64'"),
bchar,
charx('\'')
)(input)
}
fn parse_hex(s: &str) -> Result<Vec<u8>, ParseError> {
let s: String = s.chars().filter(|c| !c.is_ascii_whitespace()).collect();
hex::decode(&s).map_err(|_| parse_error(MalformedHex, s))
}
#[rustfmt::skip]
fn bytestring(input: &str) -> JResult<&str, Vec<u8>> {
alt((
map(bytestring_utf8, |s| s.as_bytes().into()),
map_res_fail(bytestring_hex, |s| parse_hex(s)),
map_res_fail(bytestring_base64, |s| {
base64::decode_config(s, base64::URL_SAFE).map_err(|_| {
parse_error(MalformedBase64, s)
})
}),
))
(input)
}
#[rustfmt::skip]
fn is_unescaped_schar(c: char) -> bool {
let ranges = [
(0x20 ..= 0x21),
(0x23 ..= 0x5B),
(0x5D ..= 0x7E),
(0x80 ..= 0x10FFD),
];
let cv = c as u32;
ranges.iter().any(|range| range.contains(&cv))
}
#[rustfmt::skip]
fn unescaped_schar(input: &str) -> JResult<&str, &str> {
take_while1(is_unescaped_schar)
(input)
}
#[rustfmt::skip]
fn sesc(input: &str) -> JResult<&str, &str> {
preceded(charx('\\'), recognize(anychar))
(input)
}
#[rustfmt::skip]
fn schar(input: &str) -> JResult<&str, &str> {
recognize(
many0(
alt((
unescaped_schar,
sesc
))
)
)
(input)
}
#[rustfmt::skip]
fn text_literal(input: &str) -> JResult<&str, String> {
let f = delimited(
charx('"'),
schar,
charx('"')
);
map_res_fail(f, |s| {
unescape(s).map_err(|_| parse_error(MalformedText, s) )
})
(input)
}
#[rustfmt::skip]
fn value(input: &str) -> JResult<&str, Value> {
alt((
float_or_int,
map(text_literal, Value::Text),
map(bytestring, Value::Bytes),
))(input)
}
#[rustfmt::skip]
fn grpent_memberkey_tail(input: &str) -> JResult<&str, Type> {
preceded(
pair(
tag(":"),
ws,
),
ty,
)(input)
}
fn assemble_basic_member(key: Type1, value: Type) -> Result<Member, ParseError> {
let member_key = match key {
Type1::Simple(Type2::Value(v)) => MemberKeyVal::Value(v),
Type1::Simple(Type2::Typename(s)) => {
if !s.generic_args.is_empty() {
return Err(parse_error(Unparseable, "Bareword with generic arguments"));
}
MemberKeyVal::Bareword(s.name)
}
_ => panic!("assemble_basic_member wrong key type"),
};
Ok(Member {
key: Some(MemberKey {
val: member_key,
cut: true,
}),
value,
})
}
#[rustfmt::skip]
fn grpent_member(input: &str) -> JResult<&str, Member> {
let (input, first_type1) = terminated(type1, ws)(input)?;
match first_type1 {
Type1::Simple(Type2::Value(_)) |
Type1::Simple(Type2::Typename(_)) => {
if let Ok((input, tail_type)) = grpent_memberkey_tail(input) {
let member = assemble_basic_member(first_type1, tail_type);
match member {
Ok(member) => return Ok((input, member)),
Err(e) => return Err(nom::Err::Failure(e)),
}
}
}
_ => {}
}
if let Ok((input, matched_tuple)) = tuple((
opt(terminated(tag("^"), ws)),
tag("=>"),
ws,
ty,
))(input) {
let (cut, _, _, val) = matched_tuple;
let member = Member {
key: Some(MemberKey {
val: MemberKeyVal::Type1(first_type1),
cut: cut.is_some(),
}),
value: val,
};
return Ok((input, member));
}
if let Ok((input, mut ty1s)) = many0(
preceded(
delimited(ws, tag("/"), ws),
type1
)
)(input) {
ty1s.insert(0, first_type1);
let member = Member {
key: None,
value: Type(ty1s),
};
return Ok((input, member));
}
Err(nom::Err::Error(parse_error(Unparseable, "grpent_member")))
}
#[rustfmt::skip]
fn grpent_parens(input: &str) -> JResult<&str, Group> {
delimited(
charx('('),
delimited(
ws,
group,
ws,
),
charx(')')
)(input)
}
#[rustfmt::skip]
fn grpent_val(input: &str) -> JResult<&str, GrpEntVal> {
alt((
map(grpent_member, GrpEntVal::Member),
map(ident, |s| GrpEntVal::Groupname(s.into())),
map(grpent_parens, GrpEntVal::Parenthesized),
))
(input)
}
fn try_into_int<T, U>(x: T, source: &str) -> Result<U, ParseError>
where
U: TryFrom<T>,
{
<U>::try_from(x).map_err(|_| parse_error(MalformedInteger, source))
}
#[rustfmt::skip]
fn occur_star(input: &str) -> JResult<&str, Occur> {
let f = tuple((
opt(uint_u64),
tag("*"),
opt(uint_u64),
));
map_res(f, |tup| -> Result<Occur, ParseError> {
if tup.0.is_none() && tup.2.is_none() {
Ok(Occur::ZeroOrMore)
} else {
let lower: usize = match tup.0 {
Some(n) => try_into_int(n, input)?,
None => 0,
};
let upper: usize = match tup.2 {
Some(n) => try_into_int(n, input)?,
None => std::usize::MAX,
};
Ok(Occur::Numbered(lower, upper))
}
})
(input)
}
#[rustfmt::skip]
fn occur(input: &str) -> JResult<&str, Occur> {
alt((
occur_star,
valuex(Occur::OneOrMore, tag("+")),
valuex(Occur::Optional, tag("?"))
))
(input)
}
#[rustfmt::skip]
fn grpent(input: &str) -> JResult<&str, GrpEnt> {
let f = pair(
opt(terminated(occur, ws)),
grpent_val
);
map(f, |(occur, val)| GrpEnt{ occur, val } )
(input)
}
#[rustfmt::skip]
fn grpchoice(input: &str) -> JResult<&str, GrpChoice> {
let f = many0(
terminated(grpent, optcom)
);
map(f, GrpChoice)
(input)
}
#[rustfmt::skip]
fn group(input: &str) -> JResult<&str, Group> {
let f = pair(
grpchoice,
many0(preceded(
delimited(
ws,
tag("//"),
ws,
),
grpchoice
))
);
map(f, |(first, mut rest)| {
let mut gcs = vec![first];
gcs.append(&mut rest);
Group(gcs)
})(input)
}
#[rustfmt::skip]
fn type2_parens(input: &str) -> JResult<&str, Type> {
delimited(
charx('('),
delimited(
ws,
ty,
ws,
),
charx(')')
)(input)
}
#[rustfmt::skip]
fn type2_map(input: &str) -> JResult<&str, Group> {
delimited(
charx('{'),
delimited(
ws,
group,
ws,
),
charx('}')
)(input)
}
#[rustfmt::skip]
fn type2_array(input: &str) -> JResult<&str, Group> {
delimited(
charx('['),
delimited(
ws,
group,
ws,
),
charx(']')
)(input)
}
#[rustfmt::skip]
fn type2_unwrap(input: &str) -> JResult<&str, NameGeneric> {
preceded(
tag("~"),
preceded(
ws,
name_generic
)
)
(input)
}
#[rustfmt::skip]
fn type2(input: &str) -> JResult<&str, Type2> {
alt((
map(value, Type2::Value),
map(name_generic, Type2::Typename),
map(type2_parens, Type2::Parethesized),
map(type2_map, Type2::Map),
map(type2_array, Type2::Array),
map(type2_unwrap, Type2::Unwrap),
))
(input)
}
#[rustfmt::skip]
fn control_op(input: &str) -> JResult<&str, &str> {
preceded(
tag("."),
ident
)
(input)
}
#[rustfmt::skip]
fn range_or_control_op(input: &str) -> JResult<&str, (&str, Type2)> {
pair(
alt((
tag("..."),
tag(".."),
control_op
)),
preceded(
ws,
type2
)
)
(input)
}
#[rustfmt::skip]
fn type1(input: &str) -> JResult<&str, Type1> {
let f = pair(
type2,
opt(
preceded(
ws,
range_or_control_op
)
)
);
map(f, |ty1| match ty1 {
(ty2, None) => Type1::Simple(ty2),
(start, Some(("..", end))) => Type1::Range(TypeRange {
start,
inclusive: true,
end,
}),
(start, Some(("...", end))) => Type1::Range(TypeRange {
start,
inclusive: false,
end,
}),
(first, Some((op, second))) => Type1::Control(TypeControl {
first,
op: op.into(),
second,
}),
})
(input)
}
#[rustfmt::skip]
fn ty(input: &str) -> JResult<&str, Type> {
let f = separated_nonempty_list(
delimited(ws, tag("/"), ws),
type1
);
map(f, Type)
(input)
}
#[rustfmt::skip]
fn rule_val(input: &str) -> JResult<&str, RuleVal> {
let f = separated_pair(
tag("="),
ws,
alt((
map(ty, RuleVal::AssignType),
map(grpent, RuleVal::AssignGroup)
))
);
map(f, |(_op, val)| val )
(input)
}
#[rustfmt::skip]
fn generic_parm(input: &str) -> JResult<&str, Vec<&str>> {
delimited(
pair(tag("<"), ws),
separated_nonempty_list(
pair(tag(","), ws),
terminated(ident, ws)),
tag(">"),
)(input)
}
#[rustfmt::skip]
fn generic_arg(input: &str) -> JResult<&str, Vec<Type1>> {
delimited(
pair(tag("<"), ws),
separated_nonempty_list(
pair(tag(","), ws),
terminated(type1, ws)),
tag(">"),
)(input)
}
#[rustfmt::skip]
fn name_generic(input: &str) -> JResult<&str, NameGeneric> {
let f = pair(ident, opt(generic_arg));
map(f, |(name, generic)| {
let generic_args = generic.unwrap_or_default();
NameGeneric {
name: name.to_string(),
generic_args,
}
})
(input)
}
#[rustfmt::skip]
fn rule(input: &str) -> JResult<&str, Rule> {
let f = separated_pair(
pair(
ident,
opt(generic_parm)
),
ws,
rule_val
);
map(f, |((name, gp), val)| Rule {
name: name.into(),
generic_parms: gp.unwrap_or_default().drain(..).map(|s| s.to_string()).collect(),
val,
})(input)
}
#[rustfmt::skip]
fn cddl(input: &str) -> JResult<&str, Cddl> {
let f = preceded(ws,
many1(
terminated(rule, ws)
)
);
map(f, |r| Cddl{rules: r})
(input)
}
#[rustfmt::skip]
fn cddl_slice(input: &str) -> JResult<&str, CddlSlice> {
let f = preceded(ws,
many1(
terminated(
map(recognizer(rule), |(s, r)| {
(r, s.to_string())
}),
ws
)
)
);
map(f, |r| CddlSlice{rules: r})
(input)
}
pub fn parse_cddl(input: &str) -> Result<Cddl, ParseError> {
let result = all_consuming(cddl)(input)?;
Ok(result.1)
}
pub fn slice_parse_cddl(input: &str) -> Result<CddlSlice, ParseError> {
let result = all_consuming(cddl_slice)(input)?;
Ok(result.1)
}
#[cfg(test)]
#[macro_use]
mod test_utils {
use super::*;
macro_rules! vec_strings {
($($str:expr),*) => ({
vec![$(String::from($str),)*] as Vec<String>
});
}
impl From<&str> for NameGeneric {
fn from(s: &str) -> Self {
NameGeneric {
name: s.to_string(),
generic_args: Vec::new(),
}
}
}
impl From<&str> for Type2 {
fn from(s: &str) -> Self {
Type2::Typename(s.into())
}
}
impl From<&str> for Type1 {
fn from(s: &str) -> Self {
Type1::Simple(Type2::Typename(s.into()))
}
}
impl From<Value> for Type1 {
fn from(v: Value) -> Self {
Type1::Simple(Type2::Value(v))
}
}
impl From<&str> for Member {
fn from(s: &str) -> Self {
Member {
key: None,
value: s.into(),
}
}
}
impl From<Value> for Member {
fn from(v: Value) -> Self {
Member {
key: None,
value: Type1::from(v).into(),
}
}
}
impl From<&str> for GrpEnt {
fn from(s: &str) -> GrpEnt {
GrpEnt {
occur: None,
val: GrpEntVal::Member(s.into()),
}
}
}
pub trait CreateLiteral {
fn literal(self) -> Value;
}
impl CreateLiteral for &str {
fn literal(self) -> Value {
Value::Text(self.to_string())
}
}
impl CreateLiteral for i64 {
fn literal(self) -> Value {
if self >= 0 {
Value::Uint(self as u64)
} else {
Value::Nint(self)
}
}
}
impl From<Value> for Type2 {
fn from(x: Value) -> Type2 {
Type2::Value(x)
}
}
impl From<Value> for MemberKeyVal {
fn from(k: Value) -> MemberKeyVal {
MemberKeyVal::Value(k)
}
}
impl From<Type1> for MemberKeyVal {
fn from(t: Type1) -> MemberKeyVal {
MemberKeyVal::Type1(t)
}
}
impl From<&str> for MemberKeyVal {
fn from(k: &str) -> MemberKeyVal {
MemberKeyVal::Type1(k.into())
}
}
#[derive(Copy, Clone)]
pub enum MemberCut {
Cut,
NoCut,
}
pub use MemberCut::*;
impl From<MemberCut> for bool {
fn from(c: MemberCut) -> bool {
match c {
Cut => true,
NoCut => false,
}
}
}
pub fn kv_member<K: Into<MemberKeyVal>>(k: K, v: &str, cut: MemberCut) -> Member {
Member {
key: Some(MemberKey {
val: k.into(),
cut: cut.into(),
}),
value: v.into(),
}
}
pub fn kv<K: Into<MemberKeyVal>>(k: K, v: &str, cut: MemberCut) -> GrpEnt {
GrpEnt {
occur: None,
val: GrpEntVal::Member(kv_member(k, v, cut)),
}
}
pub fn gen_group<T: Into<GrpEnt>>(mut members: Vec<T>) -> Group {
let grpents: Vec<GrpEnt> = members.drain(..).map(|x| x.into()).collect();
Group(vec![GrpChoice(grpents)])
}
pub fn gen_array<T: Into<GrpEnt>>(members: Vec<T>) -> Type1 {
Type1::Simple(Type2::Array(gen_group(members)))
}
pub fn gen_map<T: Into<GrpEnt>>(members: Vec<T>) -> Type1 {
Type1::Simple(Type2::Map(gen_group(members)))
}
impl From<Type1> for Type {
fn from(x: Type1) -> Self {
Type(vec![x])
}
}
impl From<&str> for Type {
fn from(s: &str) -> Self {
Type(vec![Type1::from(s)])
}
}
pub fn generic<T: Into<Type1>>(name: &str, mut generic_args: Vec<T>) -> Type1 {
Type1::Simple(Type2::Typename(NameGeneric {
name: name.to_string(),
generic_args: generic_args.drain(..).map(|x| x.into()).collect(),
}))
}
}
#[cfg(test)]
mod tests {
use super::test_utils::*;
use super::*;
#[test]
fn test_whitespace() {
let cddl = " ; a comment\n \r\n; another;;;comment\n ";
let (remainder, _result) = ws(cddl).unwrap();
assert_eq!(remainder, "");
}
#[test]
fn test_ident() {
assert_eq!(ident("a"), Ok(("", "a")));
assert_eq!(ident("a1"), Ok(("", "a1")));
assert_eq!(ident("a.1"), Ok(("", "a.1")));
assert_eq!(ident("a1."), Ok((".", "a1")));
assert_eq!(ident("@a1"), Ok(("", "@a1")));
assert_eq!(ident("a..b"), Ok(("", "a..b")));
assert!(ident("1a").is_err());
}
#[test]
fn test_uint() {
assert_eq!(uint_u64("999"), Ok(("", 999)));
assert_eq!(uint_u64("0"), Ok(("", 0)));
assert_eq!(uint_u64("0x100"), Ok(("", 256)));
assert_eq!(uint_u64("0b101"), Ok(("", 5)));
assert_eq!(uint_u64("00"), Ok(("0", 0)));
}
#[test]
fn test_float_or_int() {
assert_eq!(float_or_int("0.0"), Ok(("", Value::Float(0.0))));
assert_eq!(float_or_int("1e99"), Ok(("", Value::Float(1e99))));
assert_eq!(float_or_int("-1e-99"), Ok(("", Value::Float(-1e-99))));
assert_eq!(float_or_int("123"), Ok(("", Value::Uint(123))));
assert_eq!(float_or_int("-123"), Ok(("", Value::Nint(-123))));
assert_eq!(float_or_int("1e"), Ok(("e", Value::Uint(1))));
assert_eq!(float_or_int("1."), Ok((".", Value::Uint(1))));
assert!(float_or_int("abc").is_err());
assert_eq!(float_or_int("0x100"), Ok(("", Value::Uint(256))));
assert_eq!(float_or_int("0b101"), Ok(("", Value::Uint(5))));
assert_eq!(float_or_int("00"), Ok(("0", Value::Uint(0))));
assert_eq!(float_or_int("-0x100"), Ok(("", Value::Nint(-256))));
assert_eq!(float_or_int("-0b101"), Ok(("", Value::Nint(-5))));
assert!(float_or_int("0b1e99").is_err());
assert!(float_or_int("0b1.1").is_err());
}
#[test]
fn test_bytestring() {
let result1 = bytestring("'abc'");
let result = format!("{:?}", result1);
assert_eq!(result, r#"Ok(("", [97, 98, 99]))"#);
assert_eq!(result1, bytestring("h'61 62 63'"));
assert_eq!(result1, bytestring("h' 6 1626 3 '"));
assert_eq!(result1, bytestring("b64'YWJj'"));
assert_eq!(bytestring(r#"'a\nb'"#), Ok(("", "a\nb".into())));
assert_eq!(bytestring(r#"'\uD834\uDD1E'"#), Ok(("", "𝄞".into())));
let result2 = vec![0u8, 0xFF, 1, 0x7F];
assert_eq!(Ok(("", result2.clone())), bytestring("h'00FF017f'"));
assert_eq!(Ok(("", result2.clone())), bytestring("b64'AP8Bfw=='"));
assert_eq!(Ok(("", vec![])), bytestring("h''"));
assert_eq!(Ok(("", vec![])), bytestring("b64''"));
fn fail_kind(e: nom::Err<ParseError>) -> ErrorKind {
match e {
nom::Err::Failure(e) => e.kind,
_ => panic!("expected nom::err::Failure, got {:?}", e),
}
}
assert_eq!(
fail_kind(bytestring("h'0g1234'").unwrap_err()),
ErrorKind::MalformedHex
);
assert_eq!(
fail_kind(bytestring("b64'AP!Bfw=='").unwrap_err()),
ErrorKind::MalformedBase64
);
assert_eq!(
fail_kind(bytestring("b64'++8A'").unwrap_err()),
ErrorKind::MalformedBase64
);
assert_eq!(
fail_kind(bytestring("b64'////'").unwrap_err()),
ErrorKind::MalformedBase64
);
}
#[test]
fn test_text() {
assert!(is_unescaped_schar('A'));
assert!(is_unescaped_schar('の'));
assert!(is_unescaped_schar(std::char::from_u32(0x10FF0).unwrap()));
assert!(!is_unescaped_schar(0x7F as char));
assert_eq!(unescaped_schar("Aの"), Ok(("", "Aの")));
assert_eq!(sesc(r#"\n"#), Ok(("", "n")));
assert_eq!(sesc(r#"\nn"#), Ok(("n", "n")));
assert_eq!(sesc(r#"\の"#), Ok(("", "の")));
assert_eq!(schar(r#"Ab! \c の \\"#), Ok(("", r#"Ab! \c の \\"#)));
assert_eq!(schar(r#"a\nb"#), Ok(("", r#"a\nb"#)));
assert_eq!(schar("a\nb"), Ok(("\nb", "a")));
assert!(text_literal("\"a\nb").is_err());
assert!(text_literal("abc").is_err());
assert_eq!(text_literal(r#""""#), Ok(("", "".into())));
assert_eq!(text_literal(r#""a\nb""#), Ok(("", "a\nb".into())));
assert_eq!(text_literal(r#""\uD834\uDD1E""#), Ok(("", "𝄞".into())));
assert_eq!(text_literal(r#""の""#), Ok(("", "の".into())));
}
#[test]
fn test_value() {
assert_eq!(value("123"), Ok(("", Value::Uint(123))));
assert_eq!(value(r#""abc""#), Ok(("", Value::Text("abc".into()))));
assert!(value("abc").is_err());
}
#[test]
fn test_member() {
let result = grpent_member("a:b");
assert_eq!(
result.unwrap().1,
kv_member(MemberKeyVal::Bareword("a".into()), "b", Cut)
);
let result = grpent_member("foo");
assert_eq!(result.unwrap().1, "foo".into());
let result = grpent_member("a => b");
assert_eq!(result.unwrap().1, kv_member("a", "b", NoCut));
let result = grpent_member("42 ^ => b");
assert_eq!(
result.unwrap().1,
kv_member(Type1::from(42.literal()), "b", Cut)
);
let result = grpent_member("abc<T> => def");
assert_eq!(
result.unwrap().1,
kv_member(generic("abc", vec!["T"]), "def", NoCut)
);
grpent_member("abc<T> : def").unwrap_err();
}
#[test]
fn test_grpent_parens() {
let result = grpent_parens("()");
assert_eq!(result.unwrap().1, Group(vec![GrpChoice(vec![])]));
}
#[test]
fn test_grpent_val() {
let result = grpent_val("foo");
assert_eq!(result.unwrap().1, GrpEntVal::Member("foo".into()));
let result = grpent_val("17");
assert_eq!(result.unwrap().1, GrpEntVal::Member(17.literal().into()));
}
#[test]
fn test_occur() {
assert_eq!(occur("?"), Ok(("", Occur::Optional)));
assert_eq!(occur("+"), Ok(("", Occur::OneOrMore)));
assert_eq!(occur("*"), Ok(("", Occur::ZeroOrMore)));
assert_eq!(occur("*9"), Ok(("", Occur::Numbered(0, 9))));
assert_eq!(occur("7*"), Ok(("", Occur::Numbered(7, std::usize::MAX))));
assert_eq!(occur("7*9"), Ok(("", Occur::Numbered(7, 9))));
assert_eq!(occur("0b100*0x10"), Ok(("", Occur::Numbered(4, 16))));
}
#[test]
fn test_grpent() {
let result = grpent("foo").unwrap();
assert_eq!(result.1, "foo".into());
let result = grpent("foo: bar").unwrap();
assert_eq!(
result.1,
kv(MemberKeyVal::Bareword("foo".into()), "bar", Cut)
);
}
#[test]
fn test_grpchoice_empty() {
let result = grpchoice("").unwrap();
assert_eq!(result.1, GrpChoice(vec![]));
}
#[test]
fn test_group_empty() {
let result = group("").unwrap();
assert_eq!(result.1, Group(vec![GrpChoice(vec![])]));
}
#[test]
fn test_type1() {
let result = type1("1 .. 9");
assert_eq!(
result.unwrap().1,
Type1::Range(TypeRange {
start: 1.literal().into(),
end: 9.literal().into(),
inclusive: true
})
);
let result = type1("0x10 .. 0x1C");
assert_eq!(
result.unwrap().1,
Type1::Range(TypeRange {
start: 16.literal().into(),
end: 28.literal().into(),
inclusive: true
})
);
let result = type1("1 ... 9");
assert_eq!(
result.unwrap().1,
Type1::Range(TypeRange {
start: 1.literal().into(),
end: 9.literal().into(),
inclusive: false
})
);
let result = type1("uint .size 3");
assert_eq!(
result.unwrap().1,
Type1::Control(TypeControl {
first: "uint".into(),
second: 3.literal().into(),
op: "size".to_string()
})
);
let result = type2("min..max");
assert_eq!(result.unwrap().1, "min..max".into());
}
#[test]
fn test_grpchoice() {
let result = grpchoice("abc").unwrap();
assert_eq!(result.1, GrpChoice(vec!["abc".into()]));
let result = grpchoice("abc, def").unwrap();
assert_eq!(result.1, GrpChoice(vec!["abc".into(), "def".into(),]));
}
#[test]
fn test_generic_parm() {
assert!(generic_parm("").is_err());
assert!(generic_parm("<>").is_err());
let result = generic_parm("<foo>").unwrap();
assert_eq!(result.1, vec!["foo"]);
let result = generic_parm("<foo,bar>").unwrap();
assert_eq!(result.1, vec!["foo", "bar"]);
let result = generic_parm("< foo , _bar_ >").unwrap();
assert_eq!(result.1, vec!["foo", "_bar_"]);
}
#[test]
fn test_generic_arg() {
assert!(generic_arg("").is_err());
assert!(generic_arg("<>").is_err());
let result = generic_arg("<foo>").unwrap();
assert_eq!(result.1, vec!["foo".into()]);
let result = generic_arg("<foo,bar>").unwrap();
assert_eq!(result.1, vec!["foo".into(), "bar".into()]);
let result = generic_arg("< foo , _bar_ >").unwrap();
assert_eq!(result.1, vec!["foo".into(), "_bar_".into()]);
}
#[test]
fn test_rule() {
let result = rule("foo=bar").unwrap().1;
assert_eq!(
result,
Rule {
name: "foo".into(),
generic_parms: vec![],
val: RuleVal::AssignType("bar".into())
}
);
let result = rule("foo=(bar, baz)").unwrap().1;
assert_eq!(
result,
Rule {
name: "foo".into(),
generic_parms: vec![],
val: RuleVal::AssignGroup(GrpEnt {
occur: None,
val: GrpEntVal::Parenthesized(gen_group(vec!["bar", "baz"]).into()),
})
}
);
let result = rule("message<t, v> = [t, v]").unwrap().1;
assert_eq!(
result,
Rule {
name: "message".into(),
generic_parms: vec_strings!["t", "v"],
val: RuleVal::AssignType(gen_array(vec!["t", "v"]).into())
}
);
}
#[test]
fn test_cddl() {
let result = parse_cddl("foo = {\"a\": bar,\n b => baz}");
assert_eq!(
result.unwrap(),
Cddl {
rules: vec![Rule {
name: "foo".into(),
generic_parms: vec![],
val: RuleVal::AssignType(Type(vec![gen_map(vec![
kv("a".literal(), "bar", Cut),
kv("b", "baz", NoCut)
])]))
}]
}
);
}
#[test]
fn test_cddl_slice() {
let result = slice_parse_cddl(" foo = { a: tstr } bar = \n[ int ] ").unwrap();
assert_eq!(result.rules[0].1, "foo = { a: tstr }");
assert_eq!(result.rules[1].1, "bar = \n[ int ]");
}
#[test]
fn test_stuff() {
parse_cddl("thing = { foo : tstr }").unwrap();
parse_cddl("bar = (c: int)").unwrap();
parse_cddl("thing = {agroup empty} agroup = (age: int, name: tstr) empty = ()").unwrap();
parse_cddl(
r#"
address = { delivery }
delivery = (
street: tstr, ? "number": uint, city //
po_box: uint, city //
per_pickup: true )
city = (
name: tstr, zip_code: uint
)"#,
)
.unwrap();
}
#[test]
fn test_errors() {
let err = parse_cddl("x=9999999999999999999999999999999").unwrap_err();
assert_eq!(err.kind, MalformedInteger);
let err = parse_cddl(r#"x="\ud800""#).unwrap_err();
assert_eq!(err.kind, MalformedText);
let err = parse_cddl("x=h'61 62 6'").unwrap_err();
assert_eq!(err.kind, MalformedHex);
}
}