diff --git a/src/ast.rs b/src/ast.rs index 74e85a35..8b940af8 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -11,7 +11,7 @@ use std::{ #[cfg(feature = "std")] use std::borrow::Cow; -#[cfg(any(target_arch = "wasm32"))] +#[cfg(target_arch = "wasm32")] use serde::{self, Serialize}; #[cfg(not(feature = "std"))] @@ -79,6 +79,18 @@ impl<'a, 'b: 'a> From<&'b GroupRule<'a>> for CDDLType<'a, 'b> { } } +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) @@ -139,6 +151,24 @@ impl<'a, 'b: 'a> From<&'b GenericParam<'a>> for CDDLType<'a, 'b> { } } +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) + } +} + #[cfg(feature = "ast-comments")] #[derive(Default, Debug, PartialEq, Eq, Clone)] #[doc(hidden)] diff --git a/src/validator/parent_visitor.rs b/src/validator/parent_visitor.rs index 81b0370f..cf9a11b7 100644 --- a/src/validator/parent_visitor.rs +++ b/src/validator/parent_visitor.rs @@ -172,6 +172,46 @@ impl<'a, 'b: 'a> Parent<'a, 'b, GenericParams<'a>> for GenericParam<'a> { } } +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); + } + + 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); + } + + 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); + } + + None + } +} + #[derive(Debug, Default, Clone)] struct ArenaTree<'a, 'b: 'a> { arena: Vec>, @@ -789,7 +829,8 @@ mod tests { let pv = ParentVisitor::new(&cddl).unwrap(); if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { - assert_eq!(rule.value.parent(&pv).unwrap(), rule); + let parent: &TypeRule = rule.value.parent(&pv).unwrap(); + assert_eq!(parent, rule); } Ok(()) @@ -938,4 +979,52 @@ mod tests { Ok(()) } + + #[test] + fn generic_args_parent_is_type2() -> Result<()> { + let cddl = cddl_from_str( + r#" + messages = message<"reboot", "now"> / message<"sleep", 1..100> + "#, + true, + ) + .unwrap(); + let pv = ParentVisitor::new(&cddl).unwrap(); + + if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { + if let t2 @ Type2::Typename { + generic_args: Some(ga), + .. + } = &rule.value.type_choices.first().unwrap().type1.type2 + { + assert_eq!(ga.parent(&pv).unwrap(), t2); + } + } + + Ok(()) + } + + #[test] + fn generic_arg_parent_is_generic_args() -> Result<()> { + let cddl = cddl_from_str( + r#" + messages = message<"reboot", "now"> / message<"sleep", 1..100> + "#, + true, + ) + .unwrap(); + let pv = ParentVisitor::new(&cddl).unwrap(); + + if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() { + if let Type2::Typename { + generic_args: Some(ga), + .. + } = &rule.value.type_choices.first().unwrap().type1.type2 + { + assert_eq!(ga.args.first().unwrap().parent(&pv).unwrap(), ga); + } + } + + Ok(()) + } }