plantuml_parser/dsl/token/
start_diagram.rs1use crate::DiagramIdToken;
2use crate::{ParseContainer, ParseResult, wr, wr2};
3use nom::branch::alt;
4use nom::bytes::complete::tag;
5use nom::character::complete::{alpha1, space1};
6use nom::{IResult, Parser};
7
8#[derive(Clone, Debug)]
49pub struct StartDiagramToken {
50 diagram_kind: ParseContainer,
51 id: Option<DiagramIdToken>,
52}
53
54impl StartDiagramToken {
55 pub fn parse(input: ParseContainer) -> ParseResult<Self> {
57 let (rest, (start, diagram_kind, (id_raw, id))) =
58 (wr!(tag("@start")), wr!(alpha1), parse_id_part).parse(input)?;
59
60 let ret0 = ParseContainer::from(vec![start, diagram_kind.clone(), id_raw]);
61 let ret1 = Self { diagram_kind, id };
62
63 Ok((rest, (ret0, ret1)))
64 }
65
66 pub fn diagram_kind(&self) -> &str {
68 self.diagram_kind.as_str()
69 }
70
71 pub fn id(&self) -> Option<&str> {
73 self.id.as_ref().map(|x| x.id())
74 }
75}
76
77type ParsedResult = IResult<ParseContainer, (ParseContainer, Option<DiagramIdToken>)>;
78
79fn parse_id_part(input: ParseContainer) -> ParsedResult {
81 alt((parse_spaced_id, parse_parened_id, parse_none)).parse(input)
82}
83
84fn parse_spaced_id(input: ParseContainer) -> ParsedResult {
86 let (input, (space, (id_raw, id))) = (wr!(space1), wr2!(DiagramIdToken::parse)).parse(input)?;
87
88 let parsed = Vec::from([space, id_raw]);
89 let parsed = ParseContainer::from(parsed);
90 Ok((input, (parsed, Some(id))))
91}
92
93fn parse_parened_id(input: ParseContainer) -> ParsedResult {
95 let (input, (open, (id_raw, id), close)) =
96 (wr!(tag("(id=")), wr2!(DiagramIdToken::parse), wr!(tag(")"))).parse(input)?;
97
98 let parsed = Vec::from([open, id_raw, close]);
99 let parsed = ParseContainer::from(parsed);
100 Ok((input, (parsed, Some(id))))
101}
102
103fn parse_none(input: ParseContainer) -> ParsedResult {
105 let (input, parsed) = input.split_at(0);
106 Ok((input, (parsed, None)))
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_parse() -> anyhow::Result<()> {
115 let testdata = "@startuml";
116 let (rest, (raws, StartDiagramToken { diagram_kind, id })) =
117 StartDiagramToken::parse(testdata.into())?;
118 assert_eq!(rest, "");
119 assert_eq!(raws, testdata);
120 assert_eq!(diagram_kind, "uml");
121 assert!(id.is_none());
122
123 let testdata = "@startjson \t\n";
124 let (rest, (parsed, StartDiagramToken { diagram_kind, id })) =
125 StartDiagramToken::parse(testdata.into())?;
126 assert_eq!(rest, " \t\n");
127 assert_eq!(parsed, "@startjson");
128 assert_eq!(format!("{parsed}{rest}"), testdata);
129 assert_eq!(diagram_kind, "json");
130 assert!(id.is_none());
131
132 let testdata = "@startuml \t id aaa\n";
133 let (rest, (parsed, StartDiagramToken { diagram_kind, id })) =
134 StartDiagramToken::parse(testdata.into())?;
135 assert_eq!(rest, " aaa\n");
136 assert_eq!(parsed, "@startuml \t id");
137 assert_eq!(format!("{parsed}{rest}"), testdata);
138 assert_eq!(diagram_kind, "uml");
139 assert_eq!(id.as_ref().map(|x| x.id()), Some("id"));
140
141 let testdata = "@startuml(id=foo_BAR) bbb\n";
142 let (rest, (parsed, StartDiagramToken { diagram_kind, id })) =
143 StartDiagramToken::parse(testdata.into())?;
144 assert_eq!(rest, " bbb\n");
145 assert_eq!(parsed, "@startuml(id=foo_BAR)");
146 assert_eq!(format!("{parsed}{rest}"), testdata);
147 assert_eq!(diagram_kind, "uml");
148 assert_eq!(id.as_ref().map(|x| x.id()), Some("foo_BAR"));
149
150 Ok(())
151 }
152
153 #[test]
154 fn test_parse_id_part() -> anyhow::Result<()> {
155 let testdata = "";
156 let (rest, (parsed, id)) = parse_id_part(testdata.into())?;
157 assert_eq!(rest, "");
158 assert_eq!(parsed, testdata);
159 assert!(id.is_none());
160
161 let testdata = " aaa ";
162 let (rest, (parsed, id)) = parse_id_part(testdata.into())?;
163 assert_eq!(rest, " ");
164 assert_eq!(parsed, " aaa");
165 assert_eq!(format!("{parsed}{rest}"), testdata);
166 assert_eq!(id.as_ref().map(|x| x.id()), Some("aaa"));
167
168 let testdata = "(id=FOO_bar) \txxx";
169 let (rest, (parsed, id)) = parse_id_part(testdata.into())?;
170 assert_eq!(rest, " \txxx");
171 assert_eq!(parsed, "(id=FOO_bar)");
172 assert_eq!(format!("{parsed}{rest}"), testdata);
173 assert_eq!(id.as_ref().map(|x| x.id()), Some("FOO_bar"));
174
175 Ok(())
176 }
177
178 #[test]
179 fn test_parse_spaced_id() -> anyhow::Result<()> {
180 let testdata = " aaa ";
181 let (rest, (parsed, id)) = parse_spaced_id(testdata.into())?;
182 assert_eq!(rest, " ");
183 assert_eq!(parsed, " aaa");
184 assert_eq!(format!("{parsed}{rest}"), testdata);
185 assert_eq!(id.as_ref().map(|x| x.id()), Some("aaa"));
186
187 Ok(())
188 }
189
190 #[test]
191 fn test_parse_parened_id() -> anyhow::Result<()> {
192 let testdata = "(id=FOO_bar) \txxx";
193 let (rest, (parsed, id)) = parse_parened_id(testdata.into())?;
194 assert_eq!(rest, " \txxx");
195 assert_eq!(parsed, "(id=FOO_bar)");
196 assert_eq!(format!("{parsed}{rest}"), testdata);
197 assert_eq!(id.as_ref().map(|x| x.id()), Some("FOO_bar"));
198
199 Ok(())
200 }
201
202 #[test]
203 fn test_parse_none() -> anyhow::Result<()> {
204 let testdata = " ";
205 let (rest, (parsed, id)) = parse_none(testdata.into())?;
206 assert_eq!(rest, " ");
207 assert_eq!(parsed, "");
208 assert_eq!(format!("{parsed}{rest}"), testdata);
209 assert!(id.is_none());
210
211 Ok(())
212 }
213}