Skip to main content

argumentation/parsers/
tgf.rs

1//! Parser for Trivial Graph Format (TGF).
2//!
3//! TGF splits nodes and edges with a `#` line:
4//!   a
5//!   b
6//!   c
7//!   #
8//!   a b
9//!   b c
10//!
11//! Lines starting with `%` are treated as comments and ignored, matching
12//! the APX parser's convention. (TGF itself does not standardise
13//! comments; this is a crate-level convenience.)
14
15use crate::Error;
16use crate::framework::ArgumentationFramework;
17
18/// Parse a TGF document into an argumentation framework with `String` arguments.
19pub fn parse_tgf(input: &str) -> Result<ArgumentationFramework<String>, Error> {
20    let mut af = ArgumentationFramework::new();
21    let mut in_edges = false;
22    for (lineno, raw_line) in input.lines().enumerate() {
23        let line = raw_line.trim();
24        if line.is_empty() || line.starts_with('%') {
25            continue;
26        }
27        if line == "#" {
28            in_edges = true;
29            continue;
30        }
31        if !in_edges {
32            let id = line.split_whitespace().next().unwrap().to_string();
33            af.add_argument(id);
34        } else {
35            let parts: Vec<&str> = line.split_whitespace().collect();
36            if parts.len() < 2 {
37                return Err(Error::Parse(format!(
38                    "line {}: edge needs two ids",
39                    lineno + 1
40                )));
41            }
42            af.add_attack(&parts[0].to_string(), &parts[1].to_string())
43                .map_err(|e| Error::Parse(format!("line {}: {}", lineno + 1, e)))?;
44        }
45    }
46    Ok(af)
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn parse_simple_tgf() {
55        let input = "a\nb\nc\n#\na b\nb c\n";
56        let af = parse_tgf(input).unwrap();
57        assert_eq!(af.arguments().count(), 3);
58        assert_eq!(af.attackers(&"b".to_string()).len(), 1);
59        assert_eq!(af.attackers(&"c".to_string()).len(), 1);
60    }
61
62    #[test]
63    fn parse_tgf_with_percent_comments() {
64        let input = "% header comment\na\nb\n% mid comment\nc\n#\n% edge section\na b\nb c\n";
65        let af = parse_tgf(input).unwrap();
66        assert_eq!(af.arguments().count(), 3);
67        assert_eq!(af.attackers(&"b".to_string()).len(), 1);
68        assert_eq!(af.attackers(&"c".to_string()).len(), 1);
69    }
70}