1use can_dbc_pest::{Pair, Pairs, Rule};
2
3use crate::ast::MessageId;
4use crate::parser::{
5 inner_str, next, next_optional_rule, next_rule, next_string, parse_next_inner_str,
6 single_inner, validated_inner, DbcError,
7};
8
9#[derive(Clone, Debug, PartialEq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum Comment {
13 Node {
14 name: String,
15 comment: String,
16 },
17 Message {
18 id: MessageId,
19 comment: String,
20 },
21 Signal {
22 message_id: MessageId,
23 name: String,
24 comment: String,
25 },
26 EnvVar {
27 name: String,
28 comment: String,
29 },
30 Plain {
31 comment: String,
32 },
33}
34
35impl TryFrom<Pair<'_, Rule>> for Comment {
36 type Error = DbcError;
37
38 fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
40 let mut inner_pairs = validated_inner(value, Rule::comment)?;
41
42 let pair = next(&mut inner_pairs)?;
43
44 if pair.as_rule() == Rule::comment_plain {
45 let comment = inner_str(single_inner(pair, Rule::quoted_str)?);
47 Ok(Comment::Plain { comment })
48 } else {
49 let rule = pair.as_rule();
50 let mut inner = pair.into_inner();
51 match rule {
52 Rule::comment_signal => parse_signal_comment(inner),
53 Rule::comment_message | Rule::comment_message_implicit => {
54 Ok(Comment::Message {
57 id: next_rule(&mut inner, Rule::message_id)?.try_into()?,
58 comment: parse_next_inner_str(&mut inner, Rule::quoted_str)?,
59 })
60 }
61 Rule::comment_node => {
62 Ok(Comment::Node {
64 name: next_string(&mut inner, Rule::node_name)?,
65 comment: parse_next_inner_str(&mut inner, Rule::quoted_str)?,
66 })
67 }
68 Rule::comment_env_var => {
69 Ok(Comment::EnvVar {
71 name: next_string(&mut inner, Rule::env_var_name)?,
72 comment: parse_next_inner_str(&mut inner, Rule::quoted_str)?,
73 })
74 }
75 rule => Err(DbcError::UnknownRule(rule)),
76 }
77 }
78 }
79}
80
81fn parse_signal_comment(mut pairs: Pairs<Rule>) -> Result<Comment, DbcError> {
84 let message_id = next_rule(&mut pairs, Rule::message_id)?.try_into()?;
85 if let Some(name) = next_optional_rule(&mut pairs, Rule::signal_name) {
86 Ok(Comment::Signal {
88 message_id,
89 name: name.as_str().to_string(),
90 comment: parse_next_inner_str(&mut pairs, Rule::quoted_str)?,
91 })
92 } else {
93 Ok(Comment::Message {
95 id: message_id,
96 comment: parse_next_inner_str(&mut pairs, Rule::quoted_str)?,
97 })
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::test_helpers::*;
105
106 #[test]
107 fn signal_comment_test() {
108 let def = r#"
109CM_ SG_ 193 KLU_R_X "This is a signal comment test";
110"#;
111 let exp = Comment::Signal {
112 message_id: MessageId::Standard(193),
113 name: "KLU_R_X".to_string(),
114 comment: "This is a signal comment test".to_string(),
115 };
116 let val = test_into::<Comment>(def.trim_start(), Rule::comment);
117 assert_eq!(val, exp);
118 }
119
120 #[test]
121 fn message_definition_comment_test() {
122 let def = r#"
123CM_ BO_ 34544 "Some Message comment";
124"#;
125 let exp = Comment::Message {
126 id: MessageId::Standard(34544),
127 comment: "Some Message comment".to_string(),
128 };
129 let val = test_into::<Comment>(def.trim_start(), Rule::comment);
130 assert_eq!(val, exp);
131 }
132
133 #[test]
134 fn node_comment_test() {
135 let def = r#"
136CM_ BU_ network_node "Some network node comment";
137"#;
138 let exp = Comment::Node {
139 name: "network_node".to_string(),
140 comment: "Some network node comment".to_string(),
141 };
142 let val = test_into::<Comment>(def.trim_start(), Rule::comment);
143 assert_eq!(val, exp);
144 }
145
146 #[test]
147 fn env_var_comment_test() {
148 let def = r#"
149CM_ EV_ ENVXYZ "Some env var name comment";
150"#;
151 let exp = Comment::EnvVar {
152 name: "ENVXYZ".to_string(),
153 comment: "Some env var name comment".to_string(),
154 };
155 let val = test_into::<Comment>(def.trim_start(), Rule::comment);
156 assert_eq!(val, exp);
157 }
158
159 #[test]
160 fn signal_comment_with_escaped_characters_test() {
161 let def = r#"
162CM_ SG_ 2147548912 FooBar "Foo\\ \n \"Bar\"";
163"#;
164 let exp = Comment::Signal {
165 message_id: MessageId::Extended(65264),
166 name: "FooBar".to_string(),
167 comment: r#"Foo\\ \n \"Bar\""#.to_string(),
168 };
169 let val = test_into::<Comment>(def.trim_start(), Rule::comment);
170 assert_eq!(val, exp);
171 }
172
173 #[test]
174 fn empty_signal_comment_test() {
175 let def = r#"
176CM_ SG_ 2147548912 FooBar "";
177"#;
178 let exp = Comment::Signal {
179 message_id: MessageId::Extended(65264),
180 name: "FooBar".to_string(),
181 comment: String::new(),
182 };
183 let val = test_into::<Comment>(def.trim_start(), Rule::comment);
184 assert_eq!(val, exp);
185 }
186}