#![cfg(feature = "ast-parent")]
use crate::{
ast::*,
token::{ByteValue, ControlOperator, Value},
visitor::{self, *},
};
use std::{borrow::Cow, fmt};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
Overwrite,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Overwrite => write!(f, "attempt to overwrite existing tree node"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
pub trait Parent<'a, 'b: 'a, T> {
fn parent(&'a self, parent_visitor: &'b ParentVisitor<'a, 'b>) -> Option<&T>;
}
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),
RangeCtlOp => ([ControlOperator], CDDLType::RangeCtlOp),
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, ()> 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(value)) = CDDLType::from(self.to_owned()).parent(parent_visitor) {
return Some(value);
}
None
}
}
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, 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
}
}
#[derive(Debug, Default, Clone)]
struct ArenaTree<'a, 'b: 'a> {
arena: Vec<Node<'a, 'b>>,
}
impl<'a, 'b: 'a> ArenaTree<'a, 'b> {
fn node(&mut self, val: CDDLType<'a, 'b>) -> usize {
for node in self.arena.iter() {
if node.val == val {
return node.idx;
}
}
let idx = self.arena.len();
self.arena.push(Node::new(idx, val));
idx
}
}
#[derive(Debug, Clone)]
struct Node<'a, 'b: 'a> {
idx: usize,
val: CDDLType<'a, 'b>,
parent: Option<usize>,
children: Vec<usize>,
}
impl<'a, 'b: 'a> Node<'a, 'b> {
fn new(idx: usize, val: CDDLType<'a, 'b>) -> Self {
Self {
idx,
val,
parent: None,
children: vec![],
}
}
}
pub struct ParentVisitor<'a, 'b: 'a> {
arena_tree: ArenaTree<'a, 'b>,
}
impl<'a, 'b: 'a> ParentVisitor<'a, 'b> {
pub fn new(cddl: &'a CDDL<'a>) -> Result<Self> {
let mut p = ParentVisitor {
arena_tree: ArenaTree {
arena: Vec::default(),
},
};
p.visit_cddl(cddl)?;
Ok(p)
}
}
impl<'a, 'b: 'a> ParentVisitor<'a, 'b> {
fn insert(&mut self, parent: usize, child: usize) -> Result<()> {
if self.arena_tree.arena[child].parent.is_none() {
self.arena_tree.arena[child].parent = Some(parent);
}
self.arena_tree.arena[parent].children.push(child);
Ok(())
}
}
impl<'a, 'b: 'a> CDDLType<'a, 'b> {
pub fn parent(&self, visitor: &'b ParentVisitor<'a, 'b>) -> Option<&'b CDDLType<'a, 'b>> {
for node in visitor.arena_tree.arena.iter() {
if self == &node.val {
if let Some(parent_idx) = node.parent {
if let Some(parent) = visitor.arena_tree.arena.get(parent_idx) {
return Some(&parent.val);
}
}
}
}
None
}
}
impl<'a, 'b: 'a> Visitor<'a, 'b, Error> for ParentVisitor<'a, 'b> {
fn visit_cddl(&mut self, cddl: &'b CDDL<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::CDDL(cddl));
for rule in cddl.rules.iter() {
let child = self.arena_tree.node(CDDLType::Rule(rule));
self.insert(parent, child)?;
self.visit_rule(rule)?;
}
Ok(())
}
fn visit_rule(&mut self, rule: &'b Rule<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Rule(rule));
match rule {
Rule::Group { rule, .. } => {
let child = self.arena_tree.node(CDDLType::GroupRule(rule));
self.insert(parent, child)?;
self.visit_group_rule(rule)?;
}
Rule::Type { rule, .. } => {
let child = self.arena_tree.node(CDDLType::TypeRule(rule));
self.insert(parent, child)?;
self.visit_type_rule(rule)?;
}
}
Ok(())
}
fn visit_type_rule(&mut self, tr: &'b TypeRule<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::TypeRule(tr));
let child = self.arena_tree.node(CDDLType::Identifier(&tr.name));
self.insert(parent, child)?;
if let Some(params) = &tr.generic_params {
let child = self.arena_tree.node(CDDLType::GenericParams(params));
self.insert(parent, child)?;
self.visit_generic_params(params)?;
}
let child = self.arena_tree.node(CDDLType::Type(&tr.value));
self.insert(parent, child)?;
self.visit_type(&tr.value)
}
fn visit_group_rule(&mut self, gr: &'b GroupRule<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::GroupRule(gr));
let child = self.arena_tree.node(CDDLType::Identifier(&gr.name));
self.insert(parent, child)?;
self.visit_identifier(&gr.name)?;
if let Some(params) = &gr.generic_params {
let child = self.arena_tree.node(CDDLType::GenericParams(params));
self.insert(parent, child)?;
self.visit_generic_params(params)?;
}
let child = self.arena_tree.node(CDDLType::GroupEntry(&gr.entry));
self.insert(parent, child)?;
self.visit_group_entry(&gr.entry)
}
fn visit_type(&mut self, t: &'b Type<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Type(t));
for tc in t.type_choices.iter() {
let child = self.arena_tree.node(CDDLType::TypeChoice(tc));
self.insert(parent, child)?;
self.visit_type_choice(tc)?;
}
Ok(())
}
fn visit_type_choice(&mut self, tc: &'a TypeChoice<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::TypeChoice(tc));
let child = self.arena_tree.node(CDDLType::Type1(&tc.type1));
self.insert(parent, child)?;
self.visit_type1(&tc.type1)
}
fn visit_type1(&mut self, t1: &'b Type1<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Type1(t1));
if let Some(operator) = &t1.operator {
let child = self.arena_tree.node(CDDLType::Operator(operator));
self.insert(parent, child)?;
self.visit_operator(t1, operator)?;
}
let child = self.arena_tree.node(CDDLType::Type2(&t1.type2));
self.insert(parent, child)?;
self.visit_type2(&t1.type2)
}
fn visit_operator(
&mut self,
target: &'b Type1<'a>,
o: &'b Operator<'a>,
) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Operator(o));
let child = self.arena_tree.node(CDDLType::Type2(&o.type2));
self.insert(parent, child)?;
let child = self.arena_tree.node(CDDLType::RangeCtlOp(&o.operator));
self.insert(parent, child)?;
self.visit_rangectlop(&o.operator, target, &o.type2)
}
fn visit_rangectlop(
&mut self,
op: &'b RangeCtlOp,
target: &'b Type1<'a>,
controller: &'b Type2<'a>,
) -> visitor::Result<Error> {
match op {
RangeCtlOp::RangeOp { is_inclusive, .. } => {
self.visit_range(&target.type2, controller, *is_inclusive)
}
RangeCtlOp::CtlOp { ctrl, .. } => {
let parent = self.arena_tree.node(CDDLType::RangeCtlOp(op));
let child = self.arena_tree.node(CDDLType::ControlOperator(ctrl));
self.insert(parent, child)?;
self.visit_control_operator(&target.type2, *ctrl, controller)
}
}
}
fn visit_type2(&mut self, t2: &'b Type2<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Type2(t2));
match t2 {
Type2::IntValue { value, .. } => {
let child = self.arena_tree.node(CDDLType::Value(Value::INT(*value)));
self.insert(parent, child)?;
}
Type2::UintValue { value, .. } => {
let child = self.arena_tree.node(CDDLType::Value(Value::UINT(*value)));
self.insert(parent, child)?;
}
Type2::FloatValue { value, .. } => {
let child = self.arena_tree.node(CDDLType::Value(Value::FLOAT(*value)));
self.insert(parent, child)?;
}
Type2::TextValue { value, .. } => {
let child = self
.arena_tree
.node(CDDLType::Value(Value::TEXT(Cow::Borrowed(value))));
self.insert(parent, child)?;
}
Type2::UTF8ByteString { value, .. } => {
let child = self
.arena_tree
.node(CDDLType::Value(Value::BYTE(ByteValue::UTF8(
Cow::Borrowed(value),
))));
self.insert(parent, child)?;
}
Type2::B16ByteString { value, .. } => {
let child = self
.arena_tree
.node(CDDLType::Value(Value::BYTE(ByteValue::B16(Cow::Borrowed(
value,
)))));
self.insert(parent, child)?;
}
Type2::B64ByteString { value, .. } => {
let child = self
.arena_tree
.node(CDDLType::Value(Value::BYTE(ByteValue::B64(Cow::Borrowed(
value,
)))));
self.insert(parent, child)?;
}
Type2::Typename {
ident,
generic_args,
..
} => {
let child = self.arena_tree.node(CDDLType::Identifier(ident));
self.insert(parent, child)?;
if let Some(generic_args) = generic_args {
let child = self.arena_tree.node(CDDLType::GenericArgs(generic_args));
self.insert(parent, child)?;
self.visit_generic_args(generic_args)?;
}
}
Type2::ParenthesizedType { pt, .. } => {
let child = self.arena_tree.node(CDDLType::Type(pt));
self.insert(parent, child)?;
self.visit_type(pt)?;
}
Type2::Map { group, .. } => {
let child = self.arena_tree.node(CDDLType::Group(group));
self.insert(parent, child)?;
self.visit_group(group)?;
}
Type2::Array { group, .. } => {
let child = self.arena_tree.node(CDDLType::Group(group));
self.insert(parent, child)?;
self.visit_group(group)?;
}
Type2::Unwrap { ident, .. } => {
let child = self.arena_tree.node(CDDLType::Identifier(ident));
self.insert(parent, child)?;
self.visit_identifier(ident)?;
}
Type2::ChoiceFromInlineGroup { group, .. } => {
let child = self.arena_tree.node(CDDLType::Group(group));
self.insert(parent, child)?;
self.visit_group(group)?;
}
Type2::ChoiceFromGroup {
ident,
generic_args,
..
} => {
let child = self.arena_tree.node(CDDLType::Identifier(ident));
self.insert(parent, child)?;
if let Some(generic_args) = generic_args {
let child = self.arena_tree.node(CDDLType::GenericArgs(generic_args));
self.insert(parent, child)?;
self.visit_generic_args(generic_args)?;
}
}
Type2::TaggedData { t, .. } => {
let child = self.arena_tree.node(CDDLType::Type(t));
self.insert(parent, child)?;
self.visit_type(t)?;
}
_ => (),
}
Ok(())
}
fn visit_group(&mut self, g: &'b Group<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Group(g));
for gc in g.group_choices.iter() {
let child = self.arena_tree.node(CDDLType::GroupChoice(gc));
self.insert(parent, child)?;
self.visit_group_choice(gc)?;
}
Ok(())
}
fn visit_group_choice(&mut self, gc: &'b GroupChoice<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::GroupChoice(gc));
for (ge, _) in gc.group_entries.iter() {
let child = self.arena_tree.node(CDDLType::GroupEntry(ge));
self.insert(parent, child)?;
self.visit_group_entry(ge)?;
}
Ok(())
}
fn visit_group_entry(&mut self, entry: &'b GroupEntry<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::GroupEntry(entry));
match entry {
GroupEntry::ValueMemberKey { ge, .. } => {
let child = self.arena_tree.node(CDDLType::ValueMemberKeyEntry(ge));
self.insert(parent, child)?;
self.visit_value_member_key_entry(ge)?;
}
GroupEntry::TypeGroupname { ge, .. } => {
let child = self.arena_tree.node(CDDLType::TypeGroupnameEntry(ge));
self.insert(parent, child)?;
self.visit_type_groupname_entry(ge)?;
}
GroupEntry::InlineGroup { occur, group, .. } => {
if let Some(occur) = occur {
let child = self.arena_tree.node(CDDLType::Occurrence(occur));
self.insert(parent, child)?;
self.visit_occurrence(occur)?;
}
let child = self.arena_tree.node(CDDLType::Group(group));
self.insert(parent, child)?;
self.visit_group(group)?;
}
}
Ok(())
}
fn visit_value_member_key_entry(
&mut self,
entry: &'b ValueMemberKeyEntry<'a>,
) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::ValueMemberKeyEntry(entry));
if let Some(occur) = &entry.occur {
let child = self.arena_tree.node(CDDLType::Occurrence(occur));
self.insert(parent, child)?;
self.visit_occurrence(occur)?;
}
if let Some(mk) = &entry.member_key {
let child = self.arena_tree.node(CDDLType::MemberKey(mk));
self.insert(parent, child)?;
self.visit_memberkey(mk)?;
}
let child = self.arena_tree.node(CDDLType::Type(&entry.entry_type));
self.insert(parent, child)?;
self.visit_type(&entry.entry_type)
}
fn visit_type_groupname_entry(
&mut self,
entry: &'b TypeGroupnameEntry<'a>,
) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::TypeGroupnameEntry(entry));
if let Some(o) = &entry.occur {
let child = self.arena_tree.node(CDDLType::Occurrence(o));
self.insert(parent, child)?;
self.visit_occurrence(o)?;
}
if let Some(ga) = &entry.generic_args {
let child = self.arena_tree.node(CDDLType::GenericArgs(ga));
self.insert(parent, child)?;
self.visit_generic_args(ga)?;
}
let child = self.arena_tree.node(CDDLType::Identifier(&entry.name));
self.insert(parent, child)?;
self.visit_identifier(&entry.name)
}
fn visit_inline_group_entry(
&mut self,
occur: Option<&'b Occurrence<'a>>,
g: &'b Group<'a>,
) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Group(g));
if let Some(o) = occur {
self.visit_occurrence(o)?;
}
for gc in g.group_choices.iter() {
let child = self.arena_tree.node(CDDLType::GroupChoice(gc));
self.insert(parent, child)?;
}
self.visit_group(g)
}
fn visit_occurrence(&mut self, o: &'b Occurrence<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::Occurrence(o));
let child = self.arena_tree.node(CDDLType::Occur(o.occur));
self.insert(parent, child)?;
Ok(())
}
fn visit_memberkey(&mut self, mk: &'b MemberKey<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::MemberKey(mk));
match mk {
MemberKey::Type1 { t1, .. } => {
let child = self.arena_tree.node(CDDLType::Type1(t1));
self.insert(parent, child)?;
self.visit_type1(t1)
}
MemberKey::Bareword { ident, .. } => {
let child = self.arena_tree.node(CDDLType::Identifier(ident));
self.insert(parent, child)?;
self.visit_identifier(ident)
}
MemberKey::Value { value, .. } => {
let child = self.arena_tree.node(CDDLType::Value(value.to_owned()));
self.insert(parent, child)?;
self.visit_value(value)
}
MemberKey::NonMemberKey { non_member_key, .. } => {
let child = self.arena_tree.node(CDDLType::NonMemberKey(non_member_key));
self.insert(parent, child)?;
self.visit_nonmemberkey(non_member_key)
}
}
}
fn visit_generic_args(&mut self, args: &'b GenericArgs<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::GenericArgs(args));
for arg in args.args.iter() {
let child = self.arena_tree.node(CDDLType::GenericArg(arg));
self.insert(parent, child)?;
self.visit_generic_arg(arg)?;
}
Ok(())
}
fn visit_generic_arg(&mut self, arg: &'b GenericArg<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::GenericArg(arg));
let child = self.arena_tree.node(CDDLType::Type1(&arg.arg));
self.insert(parent, child)?;
self.visit_type1(&arg.arg)
}
fn visit_generic_params(&mut self, params: &'b GenericParams<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::GenericParams(params));
for param in params.params.iter() {
let child = self.arena_tree.node(CDDLType::GenericParam(param));
self.insert(parent, child)?;
self.visit_generic_param(param)?;
}
Ok(())
}
fn visit_generic_param(&mut self, param: &'b GenericParam<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::GenericParam(param));
let child = self.arena_tree.node(CDDLType::Identifier(¶m.param));
self.insert(parent, child)?;
self.visit_identifier(¶m.param)
}
fn visit_nonmemberkey(&mut self, nmk: &'b NonMemberKey<'a>) -> visitor::Result<Error> {
let parent = self.arena_tree.node(CDDLType::NonMemberKey(nmk));
match nmk {
NonMemberKey::Group(group) => {
let child = self.arena_tree.node(CDDLType::Group(group));
self.insert(parent, child)?;
self.visit_group(group)
}
NonMemberKey::Type(t) => {
let child = self.arena_tree.node(CDDLType::Type(t));
self.insert(parent, child)?;
self.visit_type(t)
}
}
}
}
#[cfg(test)]
#[cfg(not(target_arch = "wasm32"))]
mod tests {
#![allow(unused_imports)]
use crate::cddl_from_str;
use std::borrow::Borrow;
use super::*;
#[test]
fn rule_parent_is_cddl() -> Result<()> {
let cddl = cddl_from_str(r#"a = "myrule""#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
let rule = cddl.rules.first().unwrap();
assert_eq!(rule.parent(&pv).unwrap(), &cddl);
Ok(())
}
#[test]
fn type_and_group_rule_parent_is_rule() -> Result<()> {
let cddl = cddl_from_str(
r#"
a = "myrule"
b = ( * tstr )
"#,
true,
)
.unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let r @ Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
assert_eq!(rule.parent(&pv).unwrap(), r);
}
if let r @ Rule::Group { rule, .. } = cddl.rules.get(1).unwrap() {
assert_eq!(rule.parent(&pv).unwrap(), r);
}
Ok(())
}
#[test]
fn type_parent_is_type_rule() -> Result<()> {
let cddl = cddl_from_str(r#"a = "myrule""#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
let parent: &TypeRule = rule.value.parent(&pv).unwrap();
assert_eq!(parent, rule);
}
Ok(())
}
#[test]
fn type_choice_parent_is_type() -> Result<()> {
let cddl = cddl_from_str(r#"a = "myrule""#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
assert_eq!(
rule
.value
.type_choices
.first()
.unwrap()
.parent(&pv)
.unwrap(),
&rule.value
);
}
Ok(())
}
#[test]
fn type1_parent_is_type_choice() -> Result<()> {
let cddl = cddl_from_str(r#"a = "myrule""#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.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(())
}
#[test]
fn type2_parent_is_type1() -> Result<()> {
let cddl = cddl_from_str(r#"a = "myrule""#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
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(())
}
#[test]
fn text_value_parent_is_type2() -> Result<()> {
let cddl = cddl_from_str(r#"a = "myrule""#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
if let t2 @ Type2::TextValue { value, .. } =
&rule.value.type_choices.first().unwrap().type1.type2
{
let value = Value::from(value.borrow());
let parent: &Type2 = value.parent(&pv).unwrap();
assert_eq!(parent, t2);
}
}
Ok(())
}
#[test]
fn group_entry_parent_is_group_rule() -> Result<()> {
let cddl = cddl_from_str(r#"a = ( * tstr )"#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Group { rule, .. } = cddl.rules.first().unwrap() {
let parent: &GroupRule = rule.entry.parent(&pv).unwrap();
assert_eq!(parent, rule.as_ref());
}
Ok(())
}
#[test]
fn type_rule_name_ident_parent_is_type_rule() -> Result<()> {
let cddl = cddl_from_str(r#"a = "myrule""#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
let parent: &TypeRule = rule.name.parent(&pv).unwrap();
assert_eq!(parent, rule);
}
Ok(())
}
#[test]
fn generic_params_parent_is_type_rule() -> Result<()> {
let cddl = cddl_from_str(r#"a<t> = { type: t }"#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
let parent: &TypeRule = rule.generic_params.as_ref().unwrap().parent(&pv).unwrap();
assert_eq!(parent, rule);
}
Ok(())
}
#[test]
fn generic_param_parent_is_generic_params() -> Result<()> {
let cddl = cddl_from_str(r#"a<t> = { type: t }"#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
assert_eq!(
rule
.generic_params
.as_ref()
.unwrap()
.params
.first()
.unwrap()
.parent(&pv)
.unwrap(),
rule.generic_params.as_ref().unwrap()
);
}
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
{
let parent: &Type2 = ga.parent(&pv).unwrap();
assert_eq!(parent, 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(())
}
#[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(())
}
#[test]
fn ctrl_parent_is_rangectlop() -> Result<()> {
let cddl = cddl_from_str(r#"ip4 = bstr .size 4"#, true).unwrap();
let pv = ParentVisitor::new(&cddl).unwrap();
if let Rule::Type { rule, .. } = cddl.rules.first().unwrap() {
if let op @ RangeCtlOp::CtlOp { ctrl, .. } = &rule
.value
.type_choices
.first()
.unwrap()
.type1
.operator
.as_ref()
.unwrap()
.operator
{
assert_eq!(ctrl.parent(&pv).unwrap(), op)
}
}
Ok(())
}
}