1extern crate dot;
2
3use std::collections::HashMap;
4use std::fmt;
5
6macro_rules! matches(
7 ($e:expr, $p:pat) => (
8 match $e {
9 $p => true,
10 _ => false
11 }
12 )
13);
14
15fn unwrap_to_printable<'a>(id: &'a Option<dot::Id<'_>>) -> Option<&'a str> {
16 match &id {
17 None => None,
18 Some(a) => Some(a.as_slice()),
19 }
20}
21
22trait Parsable<'t> {
23 type Output;
24 fn parse_from(edgeop: &'t str, tokens: &[&'t str]) -> Result<Self::Output, (usize, &'t str)>;
25}
26
27#[derive(Copy, Clone)]
28enum CompassPt {
29 N,
30 NE,
31 E,
32 SE,
33 S,
34 SW,
35 W,
36 NW,
37 C,
38 UND,
39}
40
41impl fmt::Debug for CompassPt {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 let comp_str = match self {
44 CompassPt::N => "N",
45 CompassPt::NE => "NE",
46 CompassPt::E => "E",
47 CompassPt::SE => "SE",
48 CompassPt::S => "S",
49 CompassPt::SW => "SW",
50 CompassPt::W => "W",
51 CompassPt::NW => "NW",
52 CompassPt::C => "C",
53 CompassPt::UND => "UND",
54 };
55 write!(f, "{:?}", comp_str)
56 }
57}
58
59struct AssignmentStmt<'a> {
61 lhs: IdWrapper<'a>,
62 rhs: IdWrapper<'a>,
63}
64
65impl<'a> Parsable<'a> for AssignmentStmt<'a> {
66 type Output = AssignmentStmt<'a>;
67 fn parse_from(_edgeop: &'a str, tokens: &[&'a str]) -> Result<Self::Output, (usize, &'a str)> {
69 match &tokens[..] {
70 [lhs_str, "=", rhs_str] => match (IdWrapper::new(lhs_str), IdWrapper::new(rhs_str)) {
71 (Ok(lhs), Ok(rhs)) => Ok(AssignmentStmt { lhs: lhs, rhs: rhs }),
72 (Err(_), _) => Err((0, "Invalid ID")),
73 (_, Err(_)) => Err((2, "Invalid ID")),
74 },
75 _ => Err((1, "Expect '='")),
76 }
77 }
78}
79
80#[derive(Default)]
81pub struct Stmt<'a> {
82 node_stmt: Option<NodeStmt<'a>>,
83 edge_stmt: Option<EdgeStmt<'a>>,
84 attr_stmt: Option<AttrStmt<'a>>,
85 assign_stmt: Option<AssignmentStmt<'a>>,
86 subgraph: Option<SubGraph<'a>>,
87}
88
89impl fmt::Debug for Stmt<'_> {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 if self.node_stmt.is_some() {
92 return write!(f, "NodeStmt{{..}}")
93 }
94 if self.edge_stmt.is_some() {
95 return write!(f, "EdgeStmt{{..}}")
96 }
97 if self.attr_stmt.is_some() {
98 return write!(f, "AttrStmt{{..}}")
99 }
100 if self.assign_stmt.is_some() {
101 return write!(f, "AssignStmt{{..}}")
102 }
103 if self.subgraph.is_some() {
104 return write!(f, "SubGraph{{..}}")
105 }
106 return Err(fmt::Error);
107 }
108}
109
110impl<'a> Stmt<'a> {
111 fn parse_from(edgeop: &'a str, tokens: &[&'a str]) -> Result<Stmt<'a>, (usize, &'a str)> {
112 fn try_different_stmt<'b, T: Parsable<'b, Output = T>>(
113 tokens_internal: &[&'b str],
114 edgeop: &'b str,
115 idx_err: &mut usize,
116 err_msg: &mut String,
117 ) -> Option<T> {
118 match T::parse_from(&edgeop, &tokens_internal) {
119 Err((idx_err_edge, err_msg_edge)) => {
120 if idx_err_edge < *idx_err {
121 *idx_err = idx_err_edge;
122 *err_msg = err_msg_edge.to_string();
123 }
124 None
125 }
126 Ok(stmt) => Some(stmt),
127 }
128 }
129
130 let mut result = Stmt {
131 ..Default::default()
132 };
133 let mut idx_err: usize = tokens.len();
134 let mut err_msg = String::new();
135
136 if let Some(node_stmt) =
137 try_different_stmt::<NodeStmt>(&tokens, &edgeop, &mut idx_err, &mut err_msg)
138 {
139 result.node_stmt = Some(node_stmt);
140 Ok(result)
141 } else if let Some(edge_stmt) =
142 try_different_stmt::<EdgeStmt>(&tokens, &edgeop, &mut idx_err, &mut err_msg)
143 {
144 result.edge_stmt = Some(edge_stmt);
145 Ok(result)
146 } else if let Some(attr_stmt) =
147 try_different_stmt::<AttrStmt>(&tokens, &edgeop, &mut idx_err, &mut err_msg)
148 {
149 result.attr_stmt = Some(attr_stmt);
150 Ok(result)
151 } else if let Some(assign_stmt) =
152 try_different_stmt::<AssignmentStmt>(&tokens, &edgeop, &mut idx_err, &mut err_msg)
153 {
154 result.assign_stmt = Some(assign_stmt);
155 Ok(result)
156 } else if let Some(sub_graph) =
157 try_different_stmt::<SubGraph>(&tokens, &edgeop, &mut idx_err, &mut err_msg)
158 {
159 result.subgraph = Some(sub_graph);
160 Ok(result)
161 } else {
162 Err((0, ""))
163 }
164 }
165}
166
167struct StmtList<'a>(Vec<Stmt<'a>>);
168
169impl fmt::Debug for StmtList<'_> {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 write!(f, "{:?}", self.0)
172 }
173}
174
175impl StmtList<'_> {
176 fn parse_from<'a>(
177 edgeop: &'a str,
178 tokens: &[&'a str],
179 ) -> Result<StmtList<'a>, (usize, &'a str)> {
180 if tokens.len() == 0 {
181 return Ok(StmtList(vec![]));
182 }
183 if let Ok(stmt) = Stmt::parse_from(edgeop, tokens) {
184 return Ok(StmtList(vec![stmt]));
185 }
186 for (token_idx, token) in tokens.iter().enumerate() {
187 if token == &";" {
189 match (
190 Stmt::parse_from(edgeop, &tokens[0..token_idx]),
191 StmtList::parse_from(edgeop, &tokens[token_idx + 1..]),
192 ) {
193 (Ok(stmt), Ok(mut stmt_list)) => {
194 stmt_list.0.insert(0, stmt);
195 return Ok(stmt_list);
196 }
197 _ => {}
198 }
199 }
200 }
201 Err((0, "failed parsing statement list."))
203 }
204}
205
206#[derive(Default)]
207pub struct Port<'a> {
208 id: Option<dot::Id<'a>>,
209 compass_pt: Option<CompassPt>,
210}
211
212impl fmt::Debug for Port<'_> {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 write!(
215 f,
216 "Port{{id={:?}, compass={:?}}}",
217 unwrap_to_printable(&self.id),
218 self.compass_pt
219 )
220 }
221}
222
223impl PartialEq for Port<'_> {
224 fn eq(&self, other: &Self) -> bool {
225 fn id_match(lhs: &Port, rhs: &Port) -> bool {
226 match ((*lhs).id.as_ref(), (*rhs).id.as_ref()) {
227 (None, None) => true,
228 (Some(a), Some(b)) => a.as_slice() == b.as_slice(),
229 _ => false,
230 }
231 }
232
233 match (self.compass_pt, other.compass_pt) {
234 (None, None) => id_match(self, other),
235 (Some(a), Some(_b)) => matches!(a, _b) && id_match(self, other),
236 _ => false,
237 }
238 }
239}
240
241impl<'a> Port<'a> {
242 fn parse_from(tokens: &[&'a str]) -> Result<Port<'a>, ()> {
243 fn parse_compass_pt_from(token: &str) -> Result<CompassPt, ()> {
244 match token {
245 "n" => Ok(CompassPt::N),
246 "ne" => Ok(CompassPt::NE),
247 "e" => Ok(CompassPt::E),
248 "se" => Ok(CompassPt::SE),
249 "s" => Ok(CompassPt::S),
250 "sw" => Ok(CompassPt::SW),
251 "w" => Ok(CompassPt::W),
252 "nw" => Ok(CompassPt::NW),
253 "c" => Ok(CompassPt::C),
254 "_" => Ok(CompassPt::UND),
255 _ => Err(()),
256 }
257 };
258
259 if tokens.len() == 2 {
260 if tokens[0] != ":" {
261 return Err(());
262 } else {
263 match parse_compass_pt_from(tokens[1]) {
264 Ok(comp) => Ok(Port {
265 compass_pt: Some(comp),
266 ..Default::default()
267 }),
268 Err(_) => match dot::Id::new(tokens[1]) {
269 Ok(id) => Ok(Port {
270 id: Some(id),
271 ..Default::default()
272 }),
273 Err(_) => Err(()),
274 },
275 }
276 }
277 } else if tokens.len() == 4 {
278 if tokens[0] != ":" || tokens[2] != ":" {
279 return Err(());
280 } else {
281 match parse_compass_pt_from(tokens[3]) {
282 Err(_) => Err(()),
283 Ok(comp) => match dot::Id::new(tokens[1]) {
284 Ok(id) => Ok(Port {
285 id: Some(id),
286 compass_pt: Some(comp),
287 }),
288 Err(_) => Err(()),
289 },
290 }
291 }
292 } else {
293 Err(())
294 }
295 }
296}
297
298struct IdWrapper<'a>(dot::Id<'a>);
299
300impl<'a> fmt::Debug for IdWrapper<'a> {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 write!(f, "{:?}", self.0.as_slice())
303 }
304}
305
306impl<'a> PartialEq for IdWrapper<'a> {
307 fn eq(&self, other: &Self) -> bool {
308 self.0.as_slice() == other.0.as_slice()
309 }
310}
311
312impl<'a> PartialEq<&str> for IdWrapper<'a> {
313 fn eq(&self, other: &&str) -> bool {
314 self.0.as_slice() == *other
315 }
316}
317
318impl<'a> IdWrapper<'a> {
319 fn new(name: &'a str) -> Result<IdWrapper<'a>, ()> {
320 match (name, dot::Id::new(name)) {
321 ("graph", _) => Err(()),
322 ("node", _) => Err(()),
323 ("edge", _) => Err(()),
324 ("digraph", _) => Err(()),
325 ("strict", _) => Err(()),
326 (_, Err(_)) => Err(()),
327 (_, Ok(id)) => Ok(IdWrapper(id)),
328 }
329 }
330}
331
332pub struct NodeId<'a> {
333 id: IdWrapper<'a>,
334 port: Option<Port<'a>>,
335}
336
337impl fmt::Debug for NodeId<'_> {
338 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
339 write!(f, "NodeId{{id={:?}, port={:?}}}", self.id, self.port)
340 }
341}
342
343impl PartialEq for NodeId<'_> {
344 fn eq(&self, other: &Self) -> bool {
345 self.id == other.id && self.port == other.port
346 }
347}
348
349impl<'a> NodeId<'a> {
350 fn parse_from(tokens: &[&'a str]) -> Result<NodeId<'a>, ((usize, &'a str))> {
351 fn parse_option_port_from<'b>(
352 tokens: &[&'b str],
353 ) -> Result<Option<Port<'b>>, (usize, &'b str)> {
354 if tokens.len() == 0 {
355 return Ok(None);
356 }
357 match Port::parse_from(tokens) {
358 Ok(port) => Ok(Some(port)),
359 Err(_) => Err((0, "error parsing port")),
360 }
361 };
362
363 if tokens.len() == 0 {
364 return Err((0, "expecting node id"));
365 }
366 match IdWrapper::new(tokens[0]) {
367 Err(_) => Err((0, "cannot be used as id")),
368 Ok(id) => match parse_option_port_from(&tokens[1..]) {
369 Err((idx_err, err_msg)) => Err((idx_err + 1, err_msg)),
370 Ok(port) => Ok(NodeId { id: id, port: port }),
371 },
372 }
373 }
374}
375
376struct AList<'a>(HashMap<std::borrow::Cow<'a, str>, IdWrapper<'a>>);
377
378impl<'a> fmt::Debug for AList<'a> {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 write!(f, "{:?}", self.0)
381 }
382}
383
384impl<'a> AList<'a> {
385 fn parse_from(tokens: &[&'a str]) -> Result<AList<'a>, (usize, &'a str)> {
386 fn parse_helper<'b>(
387 tokens: &[&'b str],
388 slice_idx: usize,
389 ) -> Result<AList<'b>, (usize, &'b str)> {
390 match (
391 AssignmentStmt::parse_from("", &tokens[0..3]),
392 AList::parse_from(&tokens[slice_idx..]),
393 ) {
394 (Ok(assignment), Ok(mut sub_list)) => {
395 sub_list.0.insert(assignment.lhs.0.name(), assignment.rhs);
396 Ok(sub_list)
397 }
398 (Err(err_info), _) => Err(err_info),
399 (_, Err((idx_err, err_msg))) => Err((idx_err + 3, err_msg)),
400 }
401 };
402
403 match tokens.len() {
404 0 => Ok(AList::new()),
405 1 => Err((0, "Expecting assignment statement")),
407 2 => Err((0, "Expecting assignment statement")),
408 3 => parse_helper(tokens, 3),
409 _ => match tokens[3] {
410 ";" => parse_helper(tokens, 4),
411 "," => parse_helper(tokens, 4),
412 _ => parse_helper(tokens, 3),
413 },
414 }
415 }
416
417 fn new() -> AList<'a> {
418 AList(HashMap::new())
419 }
420
421 fn get(&self, key: &str) -> Option<&IdWrapper<'a>> {
422 self.0.get(std::borrow::Borrow::borrow(key))
423 }
424
425 fn len(&self) -> usize {
426 self.0.len()
427 }
428}
429
430struct AttrList<'a>(Vec<AList<'a>>);
431
432impl<'a> fmt::Debug for AttrList<'a> {
433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434 write!(f, "{:?}", self.0)
435 }
436}
437
438impl AttrList<'_> {
439 fn parse_from<'a>(tokens: &[&'a str]) -> Result<AttrList<'a>, (usize, &'a str)> {
440 struct Internal {}
442 impl Internal {
443 fn parse_helper<'b>(tokens: &[&'b str]) -> Result<AttrList<'b>, (usize, &'b str)> {
444 match tokens.first() {
445 None => Ok(AttrList(vec![])),
446 Some(&"[") => match tokens.iter().position(|x| x == &"]") {
447 None => Err((tokens.len(), &"expecting ']'")),
448 Some(idx_right_bracket) => {
449 match Self::parse_helper(&tokens[idx_right_bracket + 1..]) {
450 Err((idx_err, err_msg)) => {
451 Err((idx_err + idx_right_bracket + 1, err_msg))
452 }
453 Ok(mut sub_attr_list) => {
454 match AList::parse_from(&tokens[1..idx_right_bracket]) {
455 Err(_) => Err((1, &"internal error")),
456 Ok(a_list) => {
457 sub_attr_list.0.push(a_list);
458 Ok(sub_attr_list)
459 }
460 }
461 }
462 }
463 }
464 },
465 _ => Err((0, &"expecting '['")),
466 }
467 }
468 }
469
470 match Internal::parse_helper(tokens) {
471 Err(err_info) => Err(err_info),
472 Ok(result) => match result.0.len() {
473 0 => Err((0, &"expecting valid AttrList here")),
474 _ => Ok(result),
475 },
476 }
477 }
478}
479
480enum AttrStmtKey {
481 GRAPH,
482 NODE,
483 EDGE,
484}
485
486impl PartialEq for AttrStmtKey {
487 fn eq(&self, other: &Self) -> bool {
488 matches!(self, other)
489 }
490}
491
492impl fmt::Debug for AttrStmtKey {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 let s = match self {
495 AttrStmtKey::GRAPH => "GRAPH",
496 AttrStmtKey::NODE => "NODE",
497 AttrStmtKey::EDGE => "EDGE",
498 };
499 write!(f, "{:?}", s)
500 }
501}
502
503pub struct AttrStmt<'a> {
504 key: AttrStmtKey,
505 attr_list: AttrList<'a>,
506}
507
508impl<'a> Parsable<'a> for AttrStmt<'a> {
509 type Output = AttrStmt<'a>;
510 fn parse_from(_edgeop: &'a str, tokens: &[&'a str]) -> Result<Self::Output, (usize, &'a str)> {
512 let parse_helper =
513 |attr_key: AttrStmtKey, tokens: &[&'a str]| -> Result<AttrStmt<'a>, (usize, &'a str)> {
514 match AttrList::parse_from(&tokens[1..]) {
515 Err((idx_err, err_msg)) => Err((idx_err + 1, err_msg)),
516 Ok(attr_list) => Ok(AttrStmt {
517 key: attr_key,
518 attr_list: attr_list,
519 }),
520 }
521 };
522
523 match tokens.first() {
524 Some(&"graph") => parse_helper(AttrStmtKey::GRAPH, &tokens),
525 Some(&"node") => parse_helper(AttrStmtKey::NODE, &tokens),
526 Some(&"edge") => parse_helper(AttrStmtKey::EDGE, &tokens),
527 _ => Err((0, &"AttrStmt must starts with graph|node|edge")),
528 }
529 }
530}
531
532pub struct NodeStmt<'a> {
533 id: NodeId<'a>,
534 attr_list: Option<AttrList<'a>>,
535}
536
537impl<'a> Parsable<'a> for NodeStmt<'a> {
548 type Output = NodeStmt<'a>;
549 fn parse_from(_edgeop: &'a str, tokens: &[&'a str]) -> Result<Self::Output, (usize, &'a str)> {
551 match tokens.iter().position(|x| x == &"[") {
552 None => match NodeId::parse_from(tokens) {
553 Err(err_info) => Err(err_info),
554 Ok(node_id) => Ok(NodeStmt {
555 id: node_id,
556 attr_list: None,
557 }),
558 },
559 Some(idx_left_bracket) => {
560 match (
561 NodeId::parse_from(&tokens[..idx_left_bracket]),
562 AttrList::parse_from(&tokens[idx_left_bracket..]),
563 ) {
564 (Ok(node_id), Ok(attr_list)) => Ok(NodeStmt {
565 id: node_id,
566 attr_list: Some(attr_list),
567 }),
568 (Err(err_info), _) => Err(err_info),
569 (Ok(_), Err((idx_err, err_msg))) => Err((idx_err + idx_left_bracket, err_msg)),
570 }
571 }
572 }
573 }
574}
575
576pub struct SubGraph<'a> {
577 id: Option<dot::Id<'a>>,
578 stmt_list: StmtList<'a>,
579}
580
581impl<'a> Parsable<'a> for SubGraph<'a> {
582 type Output = SubGraph<'a>;
583 fn parse_from(edgeop: &'a str, tokens: &[&'a str]) -> Result<SubGraph<'a>, (usize, &'a str)> {
585 let parse_stmt_list_and_return = |id: Option<dot::Id<'a>>,
586 id_stmt_start: usize|
587 -> Result<SubGraph<'a>, (usize, &'a str)> {
588 match StmtList::parse_from(edgeop, &tokens[id_stmt_start..tokens.len() - 1]) {
589 Err((idx_err, err_msg)) => Err((idx_err + id_stmt_start, err_msg)),
590 Ok(stmt_list) => Ok(SubGraph {
591 id: id,
592 stmt_list: stmt_list,
593 }),
594 }
595 };
596
597 let key_subgraph: &str = "subgraph";
598 let right_brace: &str = "}";
599 match (tokens.iter().position(|x| x == &"{"), tokens.last()) {
600 (Some(idx_left_brace), Some(&right_brace)) => match idx_left_brace {
601 0 => parse_stmt_list_and_return(None, 1),
602 1 => match tokens[0] {
603 key_subgraph => parse_stmt_list_and_return(None, 2),
604 _ => Err((0, "expecting subgraph")),
605 },
606 2 => match (tokens[0], dot::Id::new(tokens[1])) {
607 (_, Err(_)) => Err((1, "expecting valid id")),
608 (key_subgraph, Ok(id)) => parse_stmt_list_and_return(Some(id), 3),
609 (_, Ok(_)) => Err((0, "expecting subgraph")),
610 },
611 _ => Err((idx_left_brace, "wrong grammer")),
612 },
613 (None, _) => Err((0, "expecting '{'")),
614 (_, None) => Err((tokens.len(), "expecting '}'")),
615 }
616 }
617}
618
619type NodeOrSubgraph<'b> = (Option<NodeId<'b>>, Option<SubGraph<'b>>, (usize, &'b str));
620
621fn parse_node_or_subgraph<'a>(tokens_n_s: &[&'a str]) -> NodeOrSubgraph<'a> {
622 match (
623 NodeId::parse_from(tokens_n_s),
624 SubGraph::parse_from("", tokens_n_s),
625 ) {
626 (Ok(node_id), _) => (Some(node_id), None, (0, "")),
627 (_, Ok(subgraph)) => (None, Some(subgraph), (0, "")),
628 (Err((idx_err_node, err_msg_node)), Err((idx_err_subg, err_msg_subg))) => {
629 if idx_err_node >= idx_err_subg {
631 (None, None, (idx_err_node, err_msg_node))
632 } else {
633 (None, None, (idx_err_subg, err_msg_subg))
634 }
635 }
636 }
637}
638
639#[derive(Default)]
640pub struct EdgeRhs<'a> {
641 node_id_or_subgraph: Vec<(Option<NodeId<'a>>, Option<SubGraph<'a>>)>,
643}
644
645impl<'a> EdgeRhs<'a> {
646 fn parse_from(edgeop: &'a str, tokens: &[&'a str]) -> Result<EdgeRhs<'a>, (usize, &'a str)> {
647 fn parse_internal<'b>(
649 edgeop: &'b str,
650 tokens_internal: &[&'b str],
651 ) -> Result<EdgeRhs<'b>, (usize, &'b str)> {
652 let merge_and_return = |node_or_subgraph: NodeOrSubgraph<'b>,
653 idx_res_tokens_start: usize,
654 res_tokens: &[&'b str]|
655 -> Result<EdgeRhs<'b>, (usize, &'b str)> {
656 match node_or_subgraph {
657 (None, None, (idx_err, err_msg)) => Err((idx_err, err_msg)),
658 (Some(node_id), None, _) => match parse_internal(edgeop, res_tokens) {
659 Err((idx_sub_err, sub_err_msg)) => {
660 Err((idx_sub_err + idx_res_tokens_start, sub_err_msg))
661 }
662 Ok(mut sub_rhs) => {
663 sub_rhs.node_id_or_subgraph.insert(0, (Some(node_id), None));
664 Ok(sub_rhs)
665 }
666 },
667 (None, Some(subgraph), _) => match parse_internal(edgeop, res_tokens) {
668 Err((idx_sub_err, sub_err_msg)) => {
669 Err((idx_sub_err + idx_res_tokens_start, sub_err_msg))
670 }
671 Ok(mut sub_rhs) => {
672 sub_rhs
673 .node_id_or_subgraph
674 .insert(0, (None, Some(subgraph)));
675 Ok(sub_rhs)
676 }
677 },
678 (Some(_), Some(_), _) => panic!("Should never happen"),
679 }
680 };
681
682 match tokens_internal.len() {
683 0 => Ok(EdgeRhs {
684 ..Default::default()
685 }),
686 _ => {
687 match (
688 tokens_internal.iter().position(|x| x == &edgeop),
689 tokens_internal[1..].iter().position(|x| x == &edgeop),
690 ) {
691 (Some(0), None) => merge_and_return(
692 parse_node_or_subgraph(&tokens_internal[1..]),
693 tokens_internal.len(),
694 &tokens_internal[0..0],
695 ),
696 (Some(0), Some(idx_next_edgeop)) => merge_and_return(
697 parse_node_or_subgraph(&tokens_internal[1..idx_next_edgeop + 1]),
698 idx_next_edgeop,
699 &tokens_internal[idx_next_edgeop + 1..],
700 ),
701 (_, _) => Err((0, "edgeRHS should begin with edgeop")),
702 }
703 }
704 }
705 };
706
707 match (tokens.len(), edgeop) {
708 (0, _) => Err((0, "edgeRHS expects non-empty token list")),
709 (_, "->") | (_, "--") => parse_internal(edgeop, tokens),
710 _ => Err((0, "edgeop should be '->'|'--'")),
711 }
712 }
713}
714
715pub struct EdgeStmt<'a> {
716 node_id_or_subgraph: Vec<(Option<NodeId<'a>>, Option<SubGraph<'a>>)>,
718 attr_list: Option<AttrList<'a>>,
719}
720
721impl<'a> Parsable<'a> for EdgeStmt<'a> {
722 type Output = EdgeStmt<'a>;
723 fn parse_from(edgeop: &'a str, tokens: &[&'a str]) -> Result<Self::Output, (usize, &'a str)> {
724 let parse_edge = |idx_edge_rhs: usize,
725 tokens_internal: &[&'a str]|
726 -> Result<EdgeStmt<'a>, (usize, &'a str)> {
727 match (
728 parse_node_or_subgraph(&tokens_internal[0..idx_edge_rhs]),
729 EdgeRhs::parse_from(edgeop, &tokens_internal[idx_edge_rhs..]),
730 ) {
731 ((None, None, (idx_err, err_msg)), _) => Err((idx_err, err_msg)),
732 (_, Err((idx_err, err_msg))) => Err((idx_err + idx_edge_rhs, err_msg)),
733 ((Some(_), Some(_), _), _) => panic!("Shouldn't happen"),
734 ((opt_node, opt_subgraph, _), Ok(mut edge_rhs)) => {
735 edge_rhs
736 .node_id_or_subgraph
737 .insert(0, (opt_node, opt_subgraph));
738 Ok(EdgeStmt {
739 node_id_or_subgraph: edge_rhs.node_id_or_subgraph,
740 attr_list: None,
741 })
742 }
743 }
744 };
745
746 match (
747 tokens.iter().position(|x| x == &edgeop),
748 tokens.iter().position(|x| x == &"["),
749 ) {
750 (Some(idx_edge_rhs), Some(idx_attr_list)) => {
751 if idx_attr_list <= idx_edge_rhs {
752 return Err((
753 idx_attr_list,
754 "Attr list should be at the end of statement.",
755 ));
756 }
757 match (
758 parse_edge(idx_edge_rhs, &tokens[0..idx_attr_list]),
759 AttrList::parse_from(&tokens[idx_attr_list..]),
760 ) {
761 (Err(err_info), _) => Err(err_info),
762 (_, Err((idx_err, err_msg))) => Err((idx_err + idx_attr_list, err_msg)),
763 (Ok(edge), Ok(attr_list)) => Ok(EdgeStmt {
764 node_id_or_subgraph: edge.node_id_or_subgraph,
765 attr_list: Some(attr_list),
766 }),
767 }
768 }
769 (Some(idx_edge_rhs), None) => parse_edge(idx_edge_rhs, &tokens[0..]),
770 (None, Some(idx_attr_list)) => Err((idx_attr_list, "Expect edgeop")),
771 (None, None) => Err((tokens.len(), "Expect edgeop")),
772 }
773 }
774}
775
776pub struct Graph<'a> {
777 kind: dot::Kind,
780 id: Option<IdWrapper<'a>>,
781 stmt_list: StmtList<'a>,
782}
783
784impl fmt::Debug for Graph<'_> {
785 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786 let kind_str = match self.kind {
787 dot::Kind::Graph => "graph",
788 dot::Kind::Digraph => "digraph",
789 };
790 write!(
791 f,
792 "Graph{{
793 kind: {:?},
794 id: {:?},
795 stmt_list: {:?}
796}}",
797 kind_str, self.id, self.stmt_list
798 )
799 }
800}
801
802impl Graph<'_> {
803 pub fn parse_from<'a>(tokens: &[&'a str]) -> Option<Graph<'a>> {
804 if tokens.len() < 3 {
805 return None;
806 }
807 if tokens.last().unwrap() != &"}" {
808 return None;
809 }
810 if tokens[0] == "strict" {
811 return Graph::parse_from(&tokens[1..]);
812 }
813 let edgeop: &str = match tokens[0] {
814 "graph" => "--",
815 "digraph" => "->",
816 _ => return None,
817 };
818 let kind: dot::Kind = match tokens[0] {
819 "graph" => dot::Kind::Graph,
820 "digraph" => dot::Kind::Digraph,
821 _ => return None,
822 };
823 let mut id: Option<IdWrapper<'a>> = None;
824 let tokens_stmtlist = match (tokens[0], tokens[1]) {
825 ("{", _) => &tokens[1..tokens.len() - 1],
826 (id_str, "{") => {
827 match IdWrapper::new(id_str) {
828 Ok(id_wrapper) => {
829 id = Some(id_wrapper);
830 }
831 _ => {}
832 }
833 &tokens[2..tokens.len() - 1]
834 }
835 _ => return None,
836 };
837 match StmtList::parse_from(edgeop, tokens_stmtlist) {
838 Ok(stmtlist) => {
839 return Some(Graph {
840 kind: kind,
841 id: id,
842 stmt_list: stmtlist,
843 })
844 }
845 Err(_) => return None,
846 }
847 }
848}
849
850#[cfg(test)]
851mod tests {
852 use super::*;
853
854 #[test]
855 fn format_print() {
856 assert_eq!(
857 format!(
858 "{:?}",
859 Port {
860 id: Some(::dot::Id::new("id_1").unwrap()),
861 ..Default::default()
862 }
863 ),
864 "Port{id=Some(\"id_1\"), compass=None}"
865 );
866 assert_eq!(
867 format!(
868 "{:?}",
869 Port {
870 compass_pt: Some(CompassPt::NE),
871 ..Default::default()
872 }
873 ),
874 "Port{id=None, compass=Some(\"NE\")}"
875 );
876 {
877 let mut alist = AList::new();
878 alist.0.insert(
879 std::borrow::Cow::Borrowed("a"),
880 IdWrapper::new("a1").unwrap(),
881 );
882 assert_eq!(format!("{:?}", alist), "{\"a\": \"a1\"}");
883 }
884 {
885 let tokens: Vec<&str> = "[ a = v1 ] [ b = v2 ] [ c = v3 ]"
886 .split_whitespace()
887 .collect();
888 let attr_list = AttrList::parse_from(&tokens).unwrap();
889 assert_eq!(
890 format!("{:?}", attr_list),
891 "[{\"c\": \"v3\"}, {\"b\": \"v2\"}, {\"a\": \"v1\"}]"
892 );
893 }
894 }
895
896 #[test]
897 fn parse_nodeid() {
898 let n1 = NodeId::parse_from(&["id1"]).unwrap();
899 assert_eq!(n1.id, "id1");
900 assert!(n1.port.is_none());
901
902 let n2 = NodeId::parse_from(&["id1", ":", "id2"]).unwrap();
903 assert_eq!(n2.id, "id1");
904 assert_eq!(n2.port.unwrap().id.unwrap().name(), "id2");
905
906 let n3 = NodeId::parse_from(&["id1", ":", "n"]).unwrap();
907 assert_eq!(n3.id, "id1");
908 assert!(matches!(n3.port.unwrap().compass_pt.unwrap(), CompassPt::N));
909
910 let n4 = NodeId::parse_from(&["id1", ":", "id2", ":", "c"]).unwrap();
911 assert_eq!(n4.id, "id1");
912 assert_eq!(
913 n4.port.unwrap(),
914 Port {
915 id: Some(::dot::Id::new("id2").unwrap()),
916 compass_pt: Some(CompassPt::C)
917 }
918 );
919 }
920
921 fn alist_entry_match(alist: &AList, key: &str, value: &str) -> bool {
923 alist.get(key).unwrap() == &value
924 }
925
926 #[test]
927 fn parse_alist() {
928 let alist_1 = AList::parse_from(&[]).unwrap();
929 assert_eq!(alist_1.len(), 0);
930
931 let alist_2 = AList::parse_from(&["id1", "=", "value1"]).unwrap();
932 assert_eq!(alist_2.len(), 1);
933 assert!(alist_entry_match(&alist_2, "id1", "value1"));
934
935 let alist_3 =
936 AList::parse_from(&["id1", "=", "value1", ";", "id2", "=", "value2"]).unwrap();
937 assert_eq!(alist_3.len(), 2);
938 assert!(alist_entry_match(&alist_3, "id1", "value1"));
939 assert!(alist_entry_match(&alist_3, "id2", "value2"));
940
941 let alist_4 =
942 AList::parse_from(&["id1", "=", "value1", "id2", "=", "value2", ","]).unwrap();
943 assert_eq!(alist_4.len(), 2);
944 assert!(alist_entry_match(&alist_4, "id1", "value1"));
945 assert!(alist_entry_match(&alist_4, "id2", "value2"));
946
947 let alist_5 = AList::parse_from(&["id1", "value1"]);
948 assert!(!alist_5.is_ok(), alist_5.unwrap());
949
950 let alist_6 = AList::parse_from(&["id1", "=", "value1", ":"]);
951 assert!(!alist_6.is_ok(), alist_6.unwrap());
952 }
953
954 #[test]
955 fn parse_attrlist() {
956 {
957 match AttrList::parse_from(&[]) {
958 Err((idx_err, err_msg)) => {
959 assert_eq!(idx_err, 0, "{}", err_msg);
960 }
961 Ok(_) => {
962 assert!(false, "cannot be empty");
963 }
964 }
965 }
966
967 {
968 match AttrList::parse_from(&["[", "id1", "=", "value1", "]"]) {
969 Err((idx_err, err_msg)) => {
970 assert!(false, "error at index {}: {}", idx_err, err_msg);
971 }
972 Ok(attr_list) => {
973 assert_eq!(attr_list.0.len(), 1);
974 assert!(alist_entry_match(&attr_list.0[0], "id1", "value1"));
975 }
976 }
977 }
978
979 {
980 match AttrList::parse_from(&["[", "]", "[", "id1", "=", "value1", "]"]) {
981 Err((idx_err, err_msg)) => {
982 assert!(false, "error at index {}: {}", idx_err, err_msg);
983 }
984 Ok(attr_list) => {
985 assert_eq!(attr_list.0.len(), 2);
986 }
987 }
988 }
989
990 {
991 let attr_list = AttrList::parse_from(&["[", "]", ",", "[", "id1", "=", "value1", "]"]);
992 assert!(!attr_list.is_ok(), attr_list.unwrap());
993 }
994
995 {
996 let attr_list = AttrList::parse_from(&["[", "]", "[", "id1", "value1", "]"]);
997 assert!(!attr_list.is_ok(), attr_list.unwrap());
998 }
999 }
1000
1001 #[test]
1002 fn parse_node_stmt() {
1003 {
1004 let node_stmt = NodeStmt::parse_from("", &[]);
1005 assert!(!node_stmt.is_ok(), node_stmt.unwrap());
1006 }
1007
1008 {
1009 let tokens: Vec<&str> = "id1 : id2 : nw".split_whitespace().collect();
1010 let node_stmt = NodeStmt::parse_from("", tokens.as_slice()).unwrap();
1011 assert_eq!(node_stmt.id.id, "id1");
1012 assert_eq!(
1013 node_stmt.id.port.unwrap(),
1014 Port {
1015 id: Some(::dot::Id::new("id2").unwrap()),
1016 compass_pt: Some(CompassPt::NW)
1017 }
1018 )
1019 }
1020
1021 {
1022 let tokens: Vec<&str> = "id1 [ id2 = value2 ]".split_whitespace().collect();
1023 let node_stmt = NodeStmt::parse_from("", tokens.as_slice()).unwrap();
1024 assert_eq!(node_stmt.id.id, "id1");
1025 assert_eq!(node_stmt.attr_list.unwrap().0.len(), 1)
1026 }
1027
1028 {
1029 let tokens: Vec<&str> = "id1 : id2 : sw [ id3 = value3 ] [ id4 = value4 ]"
1030 .split_whitespace()
1031 .collect();
1032 let node_stmt = NodeStmt::parse_from("", tokens.as_slice()).unwrap();
1033 assert_eq!(node_stmt.id.id, "id1");
1034 assert_eq!(node_stmt.attr_list.unwrap().0.len(), 2)
1035 }
1036 }
1037
1038 #[test]
1039 fn parse_attr_stmt() {
1040 {
1041 let tokens: Vec<&str> = "[ ]".split_whitespace().collect();
1042 let node_stmt = AttrStmt::parse_from("", tokens.as_slice());
1043 assert!(!node_stmt.is_ok(), node_stmt.unwrap());
1044 }
1045
1046 {
1047 let tokens: Vec<&str> = "graph [ ]".split_whitespace().collect();
1048 let node_stmt = AttrStmt::parse_from("", tokens.as_slice()).unwrap();
1049 assert_eq!(node_stmt.key, AttrStmtKey::GRAPH);
1050 }
1051
1052 {
1053 let tokens: Vec<&str> = "edge".split_whitespace().collect();
1054 let node_stmt = AttrStmt::parse_from("", tokens.as_slice());
1055 assert!(!node_stmt.is_ok(), node_stmt.unwrap());
1056 }
1057
1058 {
1059 let tokens: Vec<&str> = "other_keyword []".split_whitespace().collect();
1060 let node_stmt = AttrStmt::parse_from("", tokens.as_slice());
1061 assert!(!node_stmt.is_ok(), node_stmt.unwrap());
1062 }
1063 }
1064
1065 #[test]
1066 fn parse_subgraph() {
1067 {
1068 let tokens: Vec<&str> = "{ }".split_whitespace().collect();
1069 let maybe_subgraph = SubGraph::parse_from("", tokens.as_slice());
1070 match maybe_subgraph {
1071 Ok(subgraph) => {
1072 assert!(subgraph.id.is_none());
1073 }
1074 Err((idx_err, err_msg)) => {
1075 assert!(false, format!("{} {}", idx_err, err_msg));
1076 }
1077 };
1078 }
1079
1080 {
1081 let tokens: Vec<&str> = "subgraph { }".split_whitespace().collect();
1082 let maybe_subgraph = SubGraph::parse_from("", tokens.as_slice());
1083 match maybe_subgraph {
1084 Ok(subgraph) => {
1085 assert!(subgraph.id.is_none());
1086 }
1087 Err((idx_err, err_msg)) => {
1088 assert!(false, format!("{} {}", idx_err, err_msg));
1089 }
1090 };
1091 }
1092
1093 {
1094 let tokens: Vec<&str> = "subgraph id1 { }".split_whitespace().collect();
1095 let maybe_subgraph = SubGraph::parse_from("", tokens.as_slice());
1096 match maybe_subgraph {
1097 Ok(subgraph) => {
1098 assert!(subgraph.id.is_some());
1099 assert_eq!(subgraph.id.unwrap().name(), "id1");
1100 }
1101 Err((idx_err, err_msg)) => {
1102 assert!(false, format!("{} {}", idx_err, err_msg));
1103 }
1104 };
1105 }
1106
1107 {
1108 let tokens: Vec<&str> = "subgraph [ ]".split_whitespace().collect();
1109 let maybe_subgraph = SubGraph::parse_from("", tokens.as_slice());
1110 match maybe_subgraph {
1111 Ok(subgraph) => {
1112 assert!(false, subgraph);
1113 }
1114 Err((idx_err, _)) => {
1115 assert_eq!(idx_err, 0);
1116 }
1117 };
1118 }
1119
1120 {
1121 let tokens: Vec<&str> = "wrong_keyword [ ]".split_whitespace().collect();
1122 let maybe_subgraph = SubGraph::parse_from("", tokens.as_slice());
1123 match maybe_subgraph {
1124 Ok(subgraph) => {
1125 assert!(false, subgraph);
1126 }
1127 Err((idx_err, _)) => {
1128 assert_eq!(idx_err, 0);
1129 }
1130 };
1131 }
1132 }
1133
1134 #[test]
1135 fn parse_edge_rhs() {
1136 {
1137 let tokens: Vec<&str> = "-- id1".split_whitespace().collect();
1138 let maybe_edge_rhs = EdgeRhs::parse_from("--", tokens.as_slice());
1139 match maybe_edge_rhs {
1140 Ok(edge_rhs) => {
1141 assert!(edge_rhs.node_id_or_subgraph.len() == 1);
1142 assert!(edge_rhs.node_id_or_subgraph[0].1.is_none());
1143 }
1144 Err((idx_err, err_msg)) => {
1145 assert!(false, format!("{} {}", idx_err, err_msg));
1146 }
1147 };
1148 }
1149
1150 {
1151 let tokens: Vec<&str> = "-> id1 -> id2 : id3 : n".split_whitespace().collect();
1152 let maybe_edge_rhs = EdgeRhs::parse_from("->", tokens.as_slice());
1153 match maybe_edge_rhs {
1154 Ok(edge_rhs) => {
1155 assert!(edge_rhs.node_id_or_subgraph.len() == 2);
1156 assert!(edge_rhs.node_id_or_subgraph[0].1.is_none());
1157 }
1158 Err((idx_err, err_msg)) => {
1159 assert!(false, format!("{} {}", idx_err, err_msg));
1160 }
1161 };
1162 }
1163
1164 }
1166
1167 #[test]
1168 fn parse_edge_stmt() {
1169 {
1170 let tokens: Vec<&str> = "id1 -- id2 -- id3 : id4 : n".split_whitespace().collect();
1171 let maybe_edge = EdgeStmt::parse_from("--", tokens.as_slice());
1172 match maybe_edge {
1173 Ok(edge) => {
1174 assert!(edge.node_id_or_subgraph.len() == 3);
1175 assert!(edge.node_id_or_subgraph[2].1.is_none());
1176 assert_eq!(
1177 edge.node_id_or_subgraph[2].0,
1178 Some(NodeId {
1179 id: IdWrapper::new("id3").unwrap(),
1180 port: Some(Port {
1181 id: Some(::dot::Id::new("id4").unwrap()),
1182 compass_pt: Some(CompassPt::C)
1183 })
1184 })
1185 );
1186 assert!(edge.attr_list.is_none());
1187 }
1188 Err((idx_err, err_msg)) => {
1189 assert!(false, format!("{} {}", idx_err, err_msg));
1190 }
1191 };
1192 }
1193
1194 {
1195 let tokens: Vec<&str> = "id1 -> id2 [ ]".split_whitespace().collect();
1196 let maybe_edge = EdgeStmt::parse_from("->", tokens.as_slice());
1197 match maybe_edge {
1198 Ok(edge) => {
1199 assert!(edge.node_id_or_subgraph.len() == 2);
1200 assert!(edge.attr_list.is_some());
1201 }
1202 Err((idx_err, err_msg)) => {
1203 assert!(false, format!("{} {}", idx_err, err_msg));
1204 }
1205 };
1206 }
1207
1208 }
1210
1211 #[test]
1212 fn parse_stmt() {
1213 {
1214 let tokens: Vec<&str> = "id1 : id2".split_whitespace().collect();
1215 let maybe_stmt = Stmt::parse_from("--", tokens.as_slice());
1216 match maybe_stmt {
1217 Ok(stmt) => {
1218 assert!(stmt.node_stmt.is_some());
1219 assert_eq!(stmt.node_stmt.unwrap().id.id, "id1")
1220 }
1221 Err((idx_err, err_msg)) => {
1222 assert!(false, format!("{} {}", idx_err, err_msg));
1223 }
1224 };
1225 }
1226
1227 {
1228 let tokens: Vec<&str> = "id1 -- id2 : id3".split_whitespace().collect();
1229 let maybe_stmt = Stmt::parse_from("--", tokens.as_slice());
1230 match maybe_stmt {
1231 Ok(stmt) => {
1232 assert!(stmt.edge_stmt.is_some());
1233 assert_eq!(stmt.edge_stmt.unwrap().node_id_or_subgraph.len(), 2);
1234 }
1235 Err((idx_err, err_msg)) => {
1236 assert!(false, format!("{} {}", idx_err, err_msg));
1237 }
1238 };
1239 }
1240
1241 {
1242 let tokens: Vec<&str> = "graph [ ]".split_whitespace().collect();
1243 let maybe_stmt = Stmt::parse_from("--", tokens.as_slice());
1244 match maybe_stmt {
1245 Ok(stmt) => {
1246 assert!(stmt.attr_stmt.is_some(), stmt);
1247 assert_eq!(stmt.attr_stmt.unwrap().key, AttrStmtKey::GRAPH);
1248 }
1249 Err((idx_err, err_msg)) => {
1250 assert!(false, format!("{} {}", idx_err, err_msg));
1251 }
1252 };
1253 }
1254
1255 {
1256 let tokens: Vec<&str> = "id1 = value1".split_whitespace().collect();
1257 let maybe_stmt = Stmt::parse_from("--", tokens.as_slice());
1258 match maybe_stmt {
1259 Ok(stmt) => {
1260 assert!(stmt.assign_stmt.is_some(), stmt);
1261 let assign_stmt = stmt.assign_stmt.unwrap();
1262 assert_eq!(assign_stmt.lhs.0.as_slice(), "id1");
1263 assert_eq!(assign_stmt.rhs.0.as_slice(), "value1");
1264 }
1265 Err((idx_err, err_msg)) => {
1266 assert!(false, format!("{} {}", idx_err, err_msg));
1267 }
1268 };
1269 }
1270
1271 {
1272 let tokens: Vec<&str> = "subgraph { }".split_whitespace().collect();
1273 let maybe_stmt = Stmt::parse_from("--", tokens.as_slice());
1274 match maybe_stmt {
1275 Ok(stmt) => {
1276 assert!(stmt.subgraph.is_some(), stmt);
1277 }
1278 Err((idx_err, err_msg)) => {
1279 assert!(false, format!("{} {}", idx_err, err_msg));
1280 }
1281 };
1282 }
1283 }
1284
1285 #[test]
1286 fn parse_stmt_list() {
1287 {
1288 let tokens: Vec<&str> =
1289 "id1 : id2 ; id3 : id4 ; node1 [ ] ; node2 -- node3 ; subgraph { }"
1290 .split_whitespace()
1291 .collect();
1292 let maybe_stmtlist = StmtList::parse_from("--", tokens.as_slice());
1293 match maybe_stmtlist {
1294 Ok(stmtlist) => {
1295 assert_eq!(stmtlist.0.len(), 5);
1296 }
1297 Err((idx_err, err_msg)) => {
1298 assert!(false, format!("{} {}", idx_err, err_msg));
1299 }
1300 };
1301 }
1302 }
1303}