rd_ast/view/
conditional.rs1use super::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4#[non_exhaustive]
5pub enum RdConditionalKind {
6 If,
7 IfElse,
8}
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct RdConditional<'a> {
12 path: RdPath,
13 kind: RdConditionalKind,
14 format_nodes: &'a [RdNode],
15 format: String,
16 then_branch: &'a [RdNode],
17 else_branch: Option<&'a [RdNode]>,
18}
19
20impl<'a> RdConditional<'a> {
21 pub fn path(&self) -> &RdPath {
22 &self.path
23 }
24 pub fn kind(&self) -> RdConditionalKind {
25 self.kind
26 }
27 pub fn format_nodes(&self) -> &'a [RdNode] {
28 self.format_nodes
29 }
30 pub fn format(&self) -> &str {
32 &self.format
33 }
34 pub fn then_branch(&self) -> &'a [RdNode] {
35 self.then_branch
36 }
37 pub fn else_branch(&self) -> Option<&'a [RdNode]> {
38 self.else_branch
39 }
40}
41
42fn kind(tag: &RdTag) -> Option<RdConditionalKind> {
43 match tag {
44 RdTag::If => Some(RdConditionalKind::If),
45 RdTag::IfElse => Some(RdConditionalKind::IfElse),
46 _ => None,
47 }
48}
49
50impl RdNode {
51 pub fn conditional(&self, base_path: &RdPath) -> Option<RdConditional<'_>> {
52 self.inspect_conditional(base_path).ok().flatten()
53 }
54
55 pub fn inspect_conditional(
56 &self,
57 base_path: &RdPath,
58 ) -> Result<Option<RdConditional<'_>>, RdShapeError> {
59 let tagged = match self {
60 RdNode::Tagged(tagged) => tagged,
61 RdNode::Raw(raw) => {
62 let Some(tag) = raw.tag().map(RdTag::from_rd_tag) else {
63 return Ok(None);
64 };
65 if kind(&tag).is_some() {
66 return Err(shape(
67 base_path.clone(),
68 Some(tag),
69 RdShapeErrorKind::UnexpectedNode {
70 expected: RdExpectedNode::Tagged,
71 actual: RdNodeKind::Raw,
72 },
73 ));
74 }
75 return Ok(None);
76 }
77 _ => return Ok(None),
78 };
79 let Some(kind) = kind(tagged.tag()) else {
80 return Ok(None);
81 };
82 if tagged.option().is_some() {
83 return Err(shape(
84 base_path.clone(),
85 Some(tagged.tag().clone()),
86 RdShapeErrorKind::UnexpectedOption,
87 ));
88 }
89 let expected = match kind {
90 RdConditionalKind::If => 2,
91 RdConditionalKind::IfElse => 3,
92 };
93 let children = tagged.children();
94 if children.len() != expected {
95 return Err(shape(
96 base_path.clone(),
97 Some(tagged.tag().clone()),
98 RdShapeErrorKind::WrongArity {
99 expected: RdArity::Exactly(expected),
100 actual: children.len(),
101 },
102 ));
103 }
104 for (index, child) in children.iter().enumerate() {
105 if child.as_group().is_none() {
106 return Err(shape(
107 base_path.with_child(index),
108 Some(tagged.tag().clone()),
109 RdShapeErrorKind::UnexpectedNode {
110 expected: RdExpectedNode::Group,
111 actual: RdNodeKind::of(child),
112 },
113 ));
114 }
115 }
116 let format_nodes = children[0].as_group().unwrap().children();
117 let format = concat_exact(
118 format_nodes,
119 RdNodeKind::Text,
120 &base_path.with_child(0),
121 tagged.tag(),
122 )?;
123 Ok(Some(RdConditional {
124 path: base_path.clone(),
125 kind,
126 format_nodes,
127 format,
128 then_branch: children[1].as_group().unwrap().children(),
129 else_branch: (kind == RdConditionalKind::IfElse)
130 .then(|| children[2].as_group().unwrap().children()),
131 }))
132 }
133}