diff --git a/src/ast.rs b/src/ast.rs index 8b940af8..6caeeb9c 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -55,118 +55,43 @@ pub enum CDDLType<'a, 'b: 'a> { NonMemberKey(&'b NonMemberKey<'a>), } -impl<'a, 'b: 'a> From<&'b CDDL<'a>> for CDDLType<'a, 'b> { - fn from(cddl: &'b CDDL<'a>) -> Self { - CDDLType::CDDL(cddl) - } -} - -impl<'a, 'b: 'a> From<&'b Rule<'a>> for CDDLType<'a, 'b> { - fn from(rule: &'b Rule<'a>) -> Self { - CDDLType::Rule(rule) - } -} - -impl<'a, 'b: 'a> From<&'b TypeRule<'a>> for CDDLType<'a, 'b> { - fn from(rule: &'b TypeRule<'a>) -> Self { - CDDLType::TypeRule(rule) - } -} - -impl<'a, 'b: 'a> From<&'b GroupRule<'a>> for CDDLType<'a, 'b> { - fn from(rule: &'b GroupRule<'a>) -> Self { - CDDLType::GroupRule(rule) - } -} - -impl<'a, 'b: 'a> From<&'b Group<'a>> for CDDLType<'a, 'b> { - fn from(group: &'b Group<'a>) -> Self { - CDDLType::Group(group) - } -} - -impl<'a, 'b: 'a> From<&'b GroupChoice<'a>> for CDDLType<'a, 'b> { - fn from(group_choice: &'b GroupChoice<'a>) -> Self { - CDDLType::GroupChoice(group_choice) - } -} - -impl<'a, 'b: 'a> From<&'b Identifier<'a>> for CDDLType<'a, 'b> { - fn from(ident: &'b Identifier<'a>) -> Self { - CDDLType::Identifier(ident) - } -} - -impl<'a, 'b: 'a> From<&'b Type<'a>> for CDDLType<'a, 'b> { - fn from(t: &'b Type<'a>) -> Self { - CDDLType::Type(t) - } -} - -impl<'a, 'b: 'a> From<&'b TypeChoice<'a>> for CDDLType<'a, 'b> { - fn from(tc: &'b TypeChoice<'a>) -> Self { - CDDLType::TypeChoice(tc) - } -} - -impl<'a, 'b: 'a> From<&'b Type1<'a>> for CDDLType<'a, 'b> { - fn from(t1: &'b Type1<'a>) -> Self { - CDDLType::Type1(t1) - } -} - -impl<'a, 'b: 'a> From<&'b Type2<'a>> for CDDLType<'a, 'b> { - fn from(t2: &'b Type2<'a>) -> Self { - CDDLType::Type2(t2) - } -} - -impl<'a, 'b: 'a> From> for CDDLType<'a, 'b> { - fn from(value: Value<'a>) -> Self { - CDDLType::Value(value) - } -} - -impl<'a, 'b: 'a> From<&'b Cow<'a, str>> for CDDLType<'a, 'b> { - fn from(text_value: &'b Cow<'a, str>) -> Self { - CDDLType::Value(Value::TEXT(Cow::Borrowed(text_value))) - } -} - -impl<'a, 'b: 'a> From<&'b GroupEntry<'a>> for CDDLType<'a, 'b> { - fn from(ge: &'b GroupEntry<'a>) -> Self { - CDDLType::GroupEntry(ge) - } -} - -impl<'a, 'b: 'a> From<&'b GenericParams<'a>> for CDDLType<'a, 'b> { - fn from(params: &'b GenericParams<'a>) -> Self { - CDDLType::GenericParams(params) - } -} - -impl<'a, 'b: 'a> From<&'b GenericParam<'a>> for CDDLType<'a, 'b> { - fn from(param: &'b GenericParam<'a>) -> Self { - CDDLType::GenericParam(param) - } -} - -impl<'a, 'b: 'a> From<&'b GenericArgs<'a>> for CDDLType<'a, 'b> { - fn from(args: &'b GenericArgs<'a>) -> Self { - CDDLType::GenericArgs(args) - } -} - -impl<'a, 'b: 'a> From<&'b GenericArg<'a>> for CDDLType<'a, 'b> { - fn from(arg: &'b GenericArg<'a>) -> Self { - CDDLType::GenericArg(arg) - } -} - -impl<'a, 'b: 'a> From<&'b Operator<'a>> for CDDLType<'a, 'b> { - fn from(operator: &'b Operator<'a>) -> Self { - CDDLType::Operator(operator) - } +macro_rules! cddl_types_from_ast { + ($($t:ty => $p:path),* $(,)?) => { + $( + impl<'a, 'b: 'a> From<$t> for CDDLType<'a, 'b> { + fn from(value: $t) -> Self { + $p(value) + } + } + )* + }; +} + +cddl_types_from_ast! { + &'b CDDL<'a> => CDDLType::CDDL, + &'b Rule<'a> => CDDLType::Rule, + &'b TypeRule<'a> => CDDLType::TypeRule, + &'b GroupRule<'a> => CDDLType::GroupRule, + &'b Group<'a> => CDDLType::Group, + &'b GroupChoice<'a> => CDDLType::GroupChoice, + &'b GenericParams<'a> => CDDLType::GenericParams, + &'b GenericParam<'a> => CDDLType::GenericParam, + &'b GenericArgs<'a> => CDDLType::GenericArgs, + &'b GenericArg<'a> => CDDLType::GenericArg, + &'b GroupEntry<'a> => CDDLType::GroupEntry, + &'b Identifier<'a> => CDDLType::Identifier, + &'b Type<'a> => CDDLType::Type, + &'b TypeChoice<'a> => CDDLType::TypeChoice, + &'b Type1<'a> => CDDLType::Type1, + &'b Type2<'a> => CDDLType::Type2, + &'b Operator<'a> => CDDLType::Operator, + &'b Occurrence<'a> => CDDLType::Occurrence, + &'b ValueMemberKeyEntry<'a> => CDDLType::ValueMemberKeyEntry, + &'b TypeGroupnameEntry<'a> => CDDLType::TypeGroupnameEntry, + &'b MemberKey<'a> => CDDLType::MemberKey, + &'b NonMemberKey<'a> => CDDLType::NonMemberKey, + Occur => CDDLType::Occur, + Value<'a> => CDDLType::Value, } #[cfg(feature = "ast-comments")] diff --git a/src/lib.rs b/src/lib.rs index ddcdeff0..ec8542f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,7 +202,7 @@ //! Include comment strings in the AST. Enabled by default. //! //! **`--feature ast-parent`** - +//! //! Add the `ParentVisitor` implementation so that the AST can be traversed //! using parent pointers. Enabled by default. //! diff --git a/src/validator/mod.rs b/src/validator/mod.rs index 40f08c00..66f681c5 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -6,7 +6,7 @@ pub mod cbor; pub mod json; /// parent visitor implementation -mod parent_visitor; +pub mod parent_visitor; mod control; @@ -50,8 +50,11 @@ struct ParserError { msg: ErrorMsg, } -trait Validator<'a, 'b, E: Error>: Visitor<'a, 'b, E> { +/// Validator trait. Implemented for JSON documents and CBOR binaries +pub trait Validator<'a, 'b, E: Error>: Visitor<'a, 'b, E> { + /// Validate the target fn validate(&mut self) -> std::result::Result<(), E>; + /// Collect validation errors fn add_error(&mut self, reason: String); } diff --git a/src/validator/parent_visitor.rs b/src/validator/parent_visitor.rs index cf9a11b7..c3ea1d1d 100644 --- a/src/validator/parent_visitor.rs +++ b/src/validator/parent_visitor.rs @@ -32,180 +32,83 @@ impl std::error::Error for Error { } } +/// Parent trait retrieving the implemented type's parent pub trait Parent<'a, 'b: 'a, T> { + /// Returns the parent for the AST type fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&T>; } -impl<'a, 'b: 'a> Parent<'a, 'b, ()> for CDDL<'a> { - fn parent(&'a self, _parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&()> { - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, CDDL<'a>> for Rule<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&CDDL<'a>> { - if let Some(CDDLType::CDDL(cddl)) = CDDLType::from(self).parent(parent_visitor) { - return Some(cddl); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, Rule<'a>> for TypeRule<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Rule<'a>> { - if let Some(CDDLType::Rule(rule)) = CDDLType::from(self).parent(parent_visitor) { - return Some(rule); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, Rule<'a>> for GroupRule<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Rule<'a>> { - if let Some(CDDLType::Rule(rule)) = CDDLType::from(self).parent(parent_visitor) { - return Some(rule); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, TypeRule<'a>> for Type<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&TypeRule<'a>> { - if let Some(CDDLType::TypeRule(tr)) = CDDLType::from(self).parent(parent_visitor) { - return Some(tr); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, Type<'a>> for TypeChoice<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Type<'a>> { - if let Some(CDDLType::Type(t)) = CDDLType::from(self).parent(parent_visitor) { - return Some(t); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, TypeChoice<'a>> for Type1<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&TypeChoice<'a>> { - if let Some(CDDLType::TypeChoice(tc)) = CDDLType::from(self).parent(parent_visitor) { - return Some(tc); - } - - None - } +macro_rules! impl_parent { + ($($parent:ty => ([$($child:ty),+], $p:path)),* $(,)?) => { + $( + $( + impl<'a, 'b: 'a> Parent<'a, 'b, $parent> for $child { + fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&$parent> { + if let Some($p(value)) = CDDLType::from(self).parent(parent_visitor) { + return Some(value); + } + None + } + } + )* + )* + }; +} + +impl_parent! { + CDDL<'a> => ([Rule<'a>], CDDLType::CDDL), + Rule<'a> => ([GroupRule<'a>, TypeRule<'a>], CDDLType::Rule), + TypeRule<'a> => ([Identifier<'a>, GenericParams<'a>, Type<'a>], CDDLType::TypeRule), + GroupRule<'a> => ([Identifier<'a>, GenericParams<'a>, GroupEntry<'a>], CDDLType::GroupRule), + Type<'a> => ([TypeChoice<'a>], CDDLType::Type), + TypeChoice<'a> => ([Type1<'a>], CDDLType::TypeChoice), + Type1<'a> => ([Operator<'a>, Type2<'a>], CDDLType::Type1), + Operator<'a> => ([Type2<'a>], CDDLType::Operator), + Type2<'a> => ([Identifier<'a>, GenericArgs<'a>, Type<'a>, Group<'a>], CDDLType::Type2), + Group<'a> => ([GroupChoice<'a>, Occurrence<'a>], CDDLType::Group), + GroupChoice<'a> => ([GroupEntry<'a>], CDDLType::GroupChoice), + GroupEntry<'a> => ([ValueMemberKeyEntry<'a>, TypeGroupnameEntry<'a>, Occurrence<'a>, Group<'a>], CDDLType::GroupEntry), + ValueMemberKeyEntry<'a> => ([Occurrence<'a>, MemberKey<'a>, Type<'a>], CDDLType::ValueMemberKeyEntry), + TypeGroupnameEntry<'a> => ([Occurrence<'a>, GenericArgs<'a>, Identifier<'a>], CDDLType::TypeGroupnameEntry), + MemberKey<'a> => ([Type1<'a>, Identifier<'a>, NonMemberKey<'a>], CDDLType::MemberKey), + GenericArgs<'a> => ([GenericArg<'a>], CDDLType::GenericArgs), + GenericArg<'a> => ([Type1<'a>], CDDLType::GenericArg), + GenericParams<'a> => ([GenericParam<'a>], CDDLType::GenericParams), + GenericParam<'a> => ([Identifier<'a>], CDDLType::GenericParam), + NonMemberKey<'a> => ([Group<'a>, Type<'a>], CDDLType::NonMemberKey), } -impl<'a, 'b: 'a> Parent<'a, 'b, Type1<'a>> for Type2<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Type1<'a>> { - if let Some(CDDLType::Type1(t1)) = CDDLType::from(self).parent(parent_visitor) { - return Some(t1); - } - +impl<'a, 'b: 'a> Parent<'a, 'b, ()> for CDDL<'a> { + fn parent(&'a self, _parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&()> { None } } impl<'a, 'b: 'a> Parent<'a, 'b, Type2<'a>> for Value<'a> { fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Type2<'a>> { - if let Some(CDDLType::Type2(t2)) = CDDLType::from(self.to_owned()).parent(parent_visitor) { - return Some(t2); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, Type2<'a>> for Cow<'a, str> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Type2<'a>> { - if let Some(CDDLType::Type2(t2)) = CDDLType::from(self).parent(parent_visitor) { - return Some(t2); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, GroupRule<'a>> for GroupEntry<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&GroupRule<'a>> { - if let Some(CDDLType::GroupRule(gr)) = CDDLType::from(self).parent(parent_visitor) { - return Some(gr); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, TypeRule<'a>> for Identifier<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&TypeRule<'a>> { - if let Some(CDDLType::TypeRule(tr)) = CDDLType::from(self).parent(parent_visitor) { - return Some(tr); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, TypeRule<'a>> for GenericParams<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&TypeRule<'a>> { - if let Some(CDDLType::TypeRule(tr)) = CDDLType::from(self).parent(parent_visitor) { - return Some(tr); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, GenericParams<'a>> for GenericParam<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&GenericParams<'a>> { - if let Some(CDDLType::GenericParams(params)) = CDDLType::from(self).parent(parent_visitor) { - return Some(params); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, Type2<'a>> for GenericArgs<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Type2<'a>> { - if let Some(CDDLType::Type2(t2)) = CDDLType::from(self).parent(parent_visitor) { - return Some(t2); - } - - None - } -} - -impl<'a, 'b: 'a> Parent<'a, 'b, GenericArgs<'a>> for GenericArg<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&GenericArgs<'a>> { - if let Some(CDDLType::GenericArgs(args)) = CDDLType::from(self).parent(parent_visitor) { - return Some(args); + if let Some(CDDLType::Type2(value)) = CDDLType::from(self.to_owned()).parent(parent_visitor) { + return Some(value); } None } } -impl<'a, 'b: 'a> Parent<'a, 'b, Type1<'a>> for Operator<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Type1<'a>> { - if let Some(CDDLType::Type1(t1)) = CDDLType::from(self).parent(parent_visitor) { - return Some(t1); +impl<'a, 'b: 'a> Parent<'a, 'b, MemberKey<'a>> for Value<'a> { + fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&MemberKey<'a>> { + if let Some(CDDLType::MemberKey(value)) = CDDLType::from(self.to_owned()).parent(parent_visitor) + { + return Some(value); } None } } -impl<'a, 'b: 'a> Parent<'a, 'b, Type2<'a>> for Type<'a> { - fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Type2<'a>> { - if let Some(CDDLType::Type2(t2)) = CDDLType::from(self).parent(parent_visitor) { - return Some(t2); +impl<'a, 'b: 'a> Parent<'a, 'b, Occurrence<'a>> for Occur { + fn parent(&self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&Occurrence<'a>> { + if let Some(CDDLType::Occurrence(value)) = CDDLType::from(*self).parent(parent_visitor) { + return Some(value); } None @@ -257,6 +160,7 @@ pub struct ParentVisitor<'a, 'b: 'a> { } impl<'a, 'b: 'a> ParentVisitor<'a, 'b> { + /// Creates a new parent visitor given a CDDL reference pub fn new(cddl: &'a CDDL<'a>) -> Result { let mut p = ParentVisitor { arena_tree: ArenaTree { @@ -272,13 +176,8 @@ impl<'a, 'b: 'a> ParentVisitor<'a, 'b> { impl<'a, 'b: 'a> ParentVisitor<'a, 'b> { fn insert(&mut self, parent: usize, child: usize) -> Result<()> { - match self.arena_tree.arena[child].parent { - Some(_) => { - // return Err(Error::Overwrite); - } - None => { - self.arena_tree.arena[child].parent = Some(parent); - } + if let None = self.arena_tree.arena[child].parent { + self.arena_tree.arena[child].parent = Some(parent); } self.arena_tree.arena[parent].children.push(child); @@ -369,7 +268,8 @@ impl<'a, 'b: 'a> Visitor<'a, 'b, Error> for ParentVisitor<'a, 'b> { if let Some(params) = &gr.generic_params { let child = self.arena_tree.node(CDDLType::GenericParams(params)); self.insert(parent, child)?; - walk_generic_params(self, params)?; + + self.visit_generic_params(params)?; } let child = self.arena_tree.node(CDDLType::GroupEntry(&gr.entry)); @@ -783,9 +683,8 @@ impl<'a, 'b: 'a> Visitor<'a, 'b, Error> for ParentVisitor<'a, 'b> { mod tests { #![allow(unused_imports)] - use core::any::Any; - use crate::cddl_from_str; + use std::borrow::Borrow; use super::*; @@ -863,17 +762,16 @@ mod tests { let pv = ParentVisitor::new(&cddl).unwrap(); if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { - assert_eq!( - rule - .value - .type_choices - .first() - .unwrap() - .type1 - .parent(&pv) - .unwrap(), - rule.value.type_choices.first().unwrap() - ); + let parent: &TypeChoice = rule + .value + .type_choices + .first() + .unwrap() + .type1 + .parent(&pv) + .unwrap(); + + assert_eq!(parent, rule.value.type_choices.first().unwrap()); } Ok(()) @@ -885,18 +783,17 @@ mod tests { let pv = ParentVisitor::new(&cddl).unwrap(); if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { - assert_eq!( - rule - .value - .type_choices - .first() - .unwrap() - .type1 - .type2 - .parent(&pv) - .unwrap(), - &rule.value.type_choices.first().unwrap().type1 - ); + let parent: &Type1 = rule + .value + .type_choices + .first() + .unwrap() + .type1 + .type2 + .parent(&pv) + .unwrap(); + + assert_eq!(parent, &rule.value.type_choices.first().unwrap().type1); } Ok(()) @@ -911,7 +808,10 @@ mod tests { if let t2 @ Type2::TextValue { value, .. } = &rule.value.type_choices.first().unwrap().type1.type2 { - assert_eq!(value.parent(&pv).unwrap(), t2); + let value = Value::from(value.borrow()); + + let parent: &Type2 = value.parent(&pv).unwrap(); + assert_eq!(parent, t2); } } @@ -924,7 +824,9 @@ mod tests { let pv = ParentVisitor::new(&cddl).unwrap(); if let Rule::Group { rule, .. } = cddl.rules.first().unwrap() { - assert_eq!(rule.entry.parent(&pv).unwrap(), rule.as_ref()); + let parent: &GroupRule = rule.entry.parent(&pv).unwrap(); + + assert_eq!(parent, rule.as_ref()); } Ok(()) @@ -936,7 +838,8 @@ mod tests { let pv = ParentVisitor::new(&cddl).unwrap(); if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { - assert_eq!(rule.name.parent(&pv).unwrap(), rule); + let parent: &TypeRule = rule.name.parent(&pv).unwrap(); + assert_eq!(parent, rule); } Ok(()) @@ -948,10 +851,9 @@ mod tests { let pv = ParentVisitor::new(&cddl).unwrap(); if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { - assert_eq!( - rule.generic_params.as_ref().unwrap().parent(&pv).unwrap(), - rule - ); + let parent: &TypeRule = rule.generic_params.as_ref().unwrap().parent(&pv).unwrap(); + + assert_eq!(parent, rule); } Ok(()) @@ -997,7 +899,9 @@ mod tests { .. } = &rule.value.type_choices.first().unwrap().type1.type2 { - assert_eq!(ga.parent(&pv).unwrap(), t2); + let parent: &Type2 = ga.parent(&pv).unwrap(); + + assert_eq!(parent, t2); } } @@ -1027,4 +931,54 @@ mod tests { Ok(()) } + + #[test] + fn group_parent_is_type2() -> Result<()> { + let cddl = cddl_from_str( + r#" + a = { b } + b = ( * tstr => int ) + "#, + true, + ) + .unwrap(); + let pv = ParentVisitor::new(&cddl).unwrap(); + + if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { + if let t2 @ Type2::Map { group, .. } = &rule.value.type_choices.first().unwrap().type1.type2 { + let parent: &Type2 = group.parent(&pv).unwrap(); + + assert_eq!(parent, t2); + } + } + + Ok(()) + } + + #[test] + fn identifier_parent_is_type2() -> Result<()> { + let cddl = cddl_from_str( + r#" + terminal-color = &basecolors + basecolors = ( + black: 0, red: 1, green: 2, yellow: 3, + blue: 4, magenta: 5, cyan: 6, white: 7, + ) + "#, + true, + ) + .unwrap(); + let pv = ParentVisitor::new(&cddl).unwrap(); + + if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { + if let t2 @ Type2::ChoiceFromGroup { ident, .. } = + &rule.value.type_choices.first().unwrap().type1.type2 + { + let parent: &Type2 = ident.parent(&pv).unwrap(); + assert_eq!(parent, t2); + } + } + + Ok(()) + } }