1use crate::error::{Error, ErrorKind};
8use crate::prelude::*;
9use crate::productions::{Production, ProductionBody, ProductionHead};
10use crate::Result;
11
12pub fn parse_production_body(body: &str) -> Result<ProductionBody> {
17 let body = body.trim();
18 if body.is_empty() {
19 return Ok(ProductionBody::empty());
20 }
21
22 let body = body.split_ascii_whitespace();
23
24 let mut body_tokens = Vec::new();
25 let mut chance : Option<f32> = None;
26
27 for (index, term) in body.enumerate() {
28 if index == 0 {
29 if let Ok(val) = term.parse() {
30 chance = Some(val);
31 continue;
32 }
33 }
34
35 body_tokens.push(Symbol::build(term)?);
36 }
37
38 match chance {
39 None => Ok(ProductionBody::new(ProductionString::from(body_tokens))),
40 Some(chance) => ProductionBody::try_with_chance(chance, ProductionString::from(body_tokens))
41 }
42}
43
44pub fn parse_production_head(head: &str) -> Result<ProductionHead> {
46 let head = head.trim();
47
48 if head.is_empty() {
49 return Err(Error::new(ErrorKind::Parse, "no head in production string"));
50 }
51
52 let tokens : Vec<_> = head.split_ascii_whitespace().collect();
53 let split: Vec<_> = tokens.splitn(2, |s| *s == "<").collect();
54
55 let mut left : Option<&[&str]> = None;
56 let mut right : Option<&[&str]> = None;
57
58
59 let remains = if split.len() == 2 {
60 left = Some(split[0]);
61 split[1]
62 } else {
63 split[0]
64 };
65
66 let split : Vec<_> = remains.splitn(2, |s| *s == ">").collect();
67 let remains = if split.len() == 2 {
68 right = Some(split[1]);
69 split[0]
70 } else {
71 split[0]
72 };
73
74 if remains.len() != 1 {
75 return Err(Error::new(ErrorKind::Parse, "There should be exactly one token as the head target"))
76 }
77
78 let center = remains[0];
79 let head_token = Symbol::build(center)?;
80
81 let left = parse_head_context(left);
82 if let Some(Err(e)) = left {
83 return Err(e);
84 }
85
86 let left = left.map(|d| d.unwrap());
87
88 let right = parse_head_context(right);
89 if let Some(Err(e)) = right {
90 return Err(e);
91 }
92
93 let right = right.map(|d| d.unwrap());
94
95 ProductionHead::build(
96 left,
97 head_token,
98 right)
99}
100
101fn parse_head_context(strings: Option<&[&str]>) -> Option<Result<ProductionString>> {
102 strings.map(|strings| {
103 let iter = strings.iter().map(|s| Symbol::build(*s));
104 let error = iter.clone().find(|t| t.is_err());
105
106 if let Some(Err(e)) = error {
107 return Err(e);
108 }
109
110 let tokens: Vec<_> = iter.map(|t| t.unwrap()).collect();
111
112 Ok(ProductionString::from(tokens))
113 })
114}
115
116
117pub fn parse_production(production: &str) -> Result<Production> {
165 let production = production.trim();
166 if production.is_empty() {
167 return Err(Error::new(ErrorKind::Parse,
168 String::from("production string should not be an empty string")));
169 }
170
171 let index = production
172 .find("->")
173 .ok_or_else(|| Error::new(ErrorKind::Parse,
174 String::from("supplied string is not a production: ") + production))?;
175
176 let head_str = &production[0..index];
177 let body_str = &production[index + 2..];
178
179 let head = parse_production_head(head_str)?;
180 let body = parse_production_body(body_str)?;
181
182 Ok(Production::new(head, body))
183}
184
185
186
187pub fn parse_prod_string(string: &str) -> Result<ProductionString> {
190 let mut result = ProductionString::default();
191
192 let items = string.trim().split_ascii_whitespace();
193
194
195 for term in items {
196 result.push_symbol(Symbol::build(term)?);
197 }
198
199 Ok(result)
200}
201
202
203
204
205#[cfg(test)]
206mod test {
207 use crate::parser::{parse_production_body, parse_production_head};
208 use crate::symbols::{get_code};
209
210 #[test]
211 fn can_parse_empty_body() {
212 let body = parse_production_body("");
213
214 assert!(body.unwrap().is_empty());
215 }
216
217 #[test]
218 fn can_parse_body_without_chance() {
219 let body = parse_production_body("A B").unwrap();
220
221 assert_eq!(body.len(), 2);
222 assert!(body.chance().is_derived());
223 }
224
225 #[test]
226 fn can_parse_body_with_chance() {
227 let body = parse_production_body("0.3 A B").unwrap();
228
229 assert_eq!(body.len(), 2);
230 assert!(body.chance().is_user_set());
231 assert_eq!(body.chance().unwrap(), 0.3);
232 }
233
234 #[test]
235 fn parsing_production_head() {
236 let head = parse_production_head("A").unwrap();
237 assert_eq!(get_code("A").unwrap(), head.target().code());
238
239 let head = parse_production_head("Pre < A > Post").unwrap();
240 assert_eq!(get_code("A").unwrap(), head.target().code());
241
242 let left = head.pre_context().unwrap();
243 assert_eq!(left.len(), 1);
244 assert_eq!(get_code("Pre").unwrap(), left[0].code());
245
246 let right = head.post_context().unwrap();
247 assert_eq!(right.len(), 1);
248 assert_eq!(get_code("Post").unwrap(), right[0].code());
249 }
250}
251