1use pest::Parser;
2
3use pest::iterators::Pair;
4use pest_derive::*;
5
6use crate::*;
7
8#[derive(Parser)]
9#[grammar = "../sgf.pest"]
10struct SGFParser;
11
12pub fn parse(input: &str) -> Result<GameTree, SgfError> {
27 let mut parse_roots =
28 SGFParser::parse(Rule::game_tree, input).map_err(SgfError::parse_error)?;
29 if let Some(game_tree) = parse_roots.next() {
30 let tree = parse_pair(game_tree);
31 let game = create_game_tree(tree, true)?;
32 Ok(game)
33 } else {
34 Ok(GameTree::default())
35 }
36}
37
38fn create_game_tree(parser_node: ParserNode<'_>, is_root: bool) -> Result<GameTree, SgfError> {
40 if let ParserNode::GameTree(tree_nodes) = parser_node {
41 let mut nodes: Vec<GameNode> = vec![];
42 let mut variations: Vec<GameTree> = vec![];
43 for node in tree_nodes {
44 match node {
45 ParserNode::Sequence(sequence_nodes) => {
46 nodes.extend(parse_sequence(sequence_nodes)?)
47 }
48 ParserNode::GameTree(_) => {
49 variations.push(create_game_tree(node, false)?);
50 }
51 _ => {
52 return Err(SgfErrorKind::ParseError.into());
53 }
54 }
55 }
56 let mut iter = nodes.iter();
57 if is_root {
58 iter.next();
59 }
60 let in_valid = iter.any(|node| node.tokens.iter().any(|token| token.is_root_token()));
61 if in_valid {
62 Err(SgfErrorKind::InvalidRootTokenPlacement.into())
63 } else {
64 Ok(GameTree { nodes, variations })
65 }
66 } else {
67 Err(SgfErrorKind::ParseError.into())
68 }
69}
70
71fn parse_sequence(sequence_nodes: Vec<ParserNode<'_>>) -> Result<Vec<GameNode>, SgfError> {
73 let mut nodes = vec![];
74 for sequence_node in &sequence_nodes {
75 if let ParserNode::Node(node_tokens) = sequence_node {
76 let mut tokens: Vec<SgfToken> = vec![];
77 for t in node_tokens {
78 if let ParserNode::Token(new_tokens) = t {
79 tokens.extend(new_tokens.clone());
80 } else {
81 return Err(SgfErrorKind::ParseError.into());
82 }
83 }
84 nodes.push(GameNode { tokens });
85 } else {
86 return Err(SgfErrorKind::ParseError.into());
87 }
88 }
89 Ok(nodes)
90}
91
92#[derive(Debug, PartialEq, Clone)]
94enum ParserNode<'a> {
95 Token(Vec<SgfToken>),
96 Text(&'a str),
97 Node(Vec<ParserNode<'a>>),
98 Sequence(Vec<ParserNode<'a>>),
99 GameTree(Vec<ParserNode<'a>>),
100}
101
102fn parse_pair(pair: Pair<'_, Rule>) -> ParserNode<'_> {
103 match pair.as_rule() {
104 Rule::game_tree => ParserNode::GameTree(pair.into_inner().map(parse_pair).collect()),
105 Rule::sequence => ParserNode::Sequence(pair.into_inner().map(parse_pair).collect()),
106 Rule::node => ParserNode::Node(pair.into_inner().map(parse_pair).collect()),
107 Rule::property => {
108 let text_nodes = pair.into_inner().map(parse_pair).collect::<Vec<_>>();
109 let (_, ts) = text_nodes
110 .iter()
111 .try_fold((None, vec![]), |(ident, mut tokens), value| {
112 if let ParserNode::Text(value) = value {
113 match ident {
114 None => Some((Some(*value), tokens)),
115 Some(id) => {
116 tokens.push(SgfToken::from_pair(id, value));
117 Some((ident, tokens))
118 }
119 }
120 } else {
121 None
122 }
123 })
124 .expect(
125 "Pest parsing guarantee that all properties have an identifier and a value",
126 );
127 ParserNode::Token(ts)
128 }
129 Rule::property_identifier => ParserNode::Text(pair.as_str()),
130 Rule::property_value => {
131 let value = pair.as_str();
132 let end = value.len() - 1;
133 ParserNode::Text(&value[1..end])
134 }
135 Rule::inner => {
136 unreachable!();
137 }
138 Rule::char => {
139 unreachable!();
140 }
141 Rule::WHITESPACE => {
142 unreachable!();
143 }
144 }
145}