1#![deny(missing_docs)]
2
3use header_parsing::parse_header;
26use logical_expressions::{LogicalExpression, ParseError};
27use thiserror::Error;
28
29use multilinear::{Channel, Condition, Event, InvalidChangeError, MultilinearInfo};
30
31use std::{
32 io::{BufRead, BufReader, Read},
33 marker::PhantomData,
34};
35
36pub struct IndexMap<I: Into<usize> + From<usize>, V> {
38 entries: Vec<V>,
39 index: PhantomData<I>,
40}
41
42impl<I: Into<usize> + From<usize>, V> Default for IndexMap<I, V> {
43 fn default() -> Self {
44 Self {
45 entries: Vec::new(),
46 index: PhantomData,
47 }
48 }
49}
50
51impl<I: Into<usize> + From<usize>, V> IndexMap<I, V> {
52 fn insert(&mut self, index: I, value: V) {
53 let i = index.into();
54 assert_eq!(i, self.entries.len(), "Wrong insertion order");
55 self.entries.push(value);
56 }
57}
58
59pub struct IntoIter<I: Into<usize> + From<usize>, V> {
61 data: std::iter::Enumerate<std::vec::IntoIter<V>>,
62 index: PhantomData<I>,
63}
64
65impl<I: Into<usize> + From<usize>, V> Iterator for IntoIter<I, V> {
66 type Item = (I, V);
67
68 fn next(&mut self) -> Option<(I, V)> {
69 let (i, value) = self.data.next()?;
70 Some((i.into(), value))
71 }
72}
73
74impl<I: Into<usize> + From<usize>, V> IntoIterator for IndexMap<I, V> {
75 type Item = (I, V);
76 type IntoIter = IntoIter<I, V>;
77
78 fn into_iter(self) -> IntoIter<I, V> {
79 IntoIter {
80 data: self.entries.into_iter().enumerate(),
81 index: PhantomData,
82 }
83 }
84}
85
86#[derive(Copy, Clone, Debug)]
87struct ValueCheckingError(char);
88
89type Str = Box<str>;
90
91fn check_name(name: &str) -> Result<(), ValueCheckingError> {
92 if let Some(c) = name
93 .chars()
94 .find(|&c| !c.is_alphanumeric() && !"_- ".contains(c))
95 {
96 Err(ValueCheckingError(c))
97 } else {
98 Ok(())
99 }
100}
101
102fn valid_name(name: &str) -> Result<&str, ValueCheckingError> {
103 let name = name.trim();
104 check_name(name)?;
105 Ok(name)
106}
107
108fn value_index(value_names: &mut Vec<Str>, name: &str) -> Result<usize, ValueCheckingError> {
109 let name = valid_name(name)?;
110
111 if let Some(index) = value_names.iter().position(|x| x.as_ref() == name) {
112 return Ok(index);
113 }
114
115 let index = value_names.len();
116 value_names.push(name.into());
117 Ok(index)
118}
119
120fn channel_info<'a>(
121 channels: &'a mut IndexMap<Channel, (Str, Vec<Str>)>,
122 name: &str,
123 info: &mut MultilinearInfo,
124) -> Result<(Channel, &'a mut Vec<Str>), ValueCheckingError> {
125 let name = valid_name(name)?;
126
127 if let Some(i) = channels
128 .entries
129 .iter()
130 .position(|(checked_name, _)| checked_name.as_ref() == name)
131 {
132 return Ok((Channel(i), &mut channels.entries[i].1));
133 }
134
135 let channel = info.add_channel();
136 channels.insert(channel, (name.into(), Vec::new()));
137
138 let (_, value_names) = channels.entries.last_mut().unwrap();
139
140 let _ = value_index(value_names, "");
141
142 Ok((channel, value_names))
143}
144
145#[derive(Copy, Clone, Debug, Error)]
147pub enum ConditionParsingError {
148 #[error("Invalid character '{0}' for condition names")]
150 InvalidCharacter(char),
151
152 #[error("Invalid condition format")]
154 InvalidCondition,
155}
156
157impl From<ValueCheckingError> for ConditionParsingError {
158 fn from(ValueCheckingError(c): ValueCheckingError) -> Self {
159 Self::InvalidCharacter(c)
160 }
161}
162
163#[derive(Copy, Clone, Debug, Error)]
165pub enum ErrorKind {
166 #[error("Input error while parsing line")]
168 LineParsing,
169
170 #[error("Parsing expression failed: {0}")]
172 ExpressionParsing(ParseError<ConditionParsingError>),
173
174 #[error("Encountered conflicting conditions: {0}")]
176 ConflictingCondition(InvalidChangeError),
177
178 #[error("Invalid character '{0}' in event name")]
180 InvalidCharacterInEventName(char),
181
182 #[error("No event has been specified")]
184 NoEvent,
185
186 #[error("Subheader without matching header")]
188 SubheaderWithoutHeader,
189}
190
191trait ErrorLine {
192 type Output;
193
194 fn line(self, line: usize) -> Self::Output;
195}
196
197impl ErrorLine for ErrorKind {
198 type Output = Error;
199
200 fn line(self, line: usize) -> Error {
201 Error { line, kind: self }
202 }
203}
204
205impl<T> ErrorLine for Result<T, ErrorKind> {
206 type Output = Result<T, Error>;
207
208 fn line(self, line: usize) -> Result<T, Error> {
209 match self {
210 Ok(value) => Ok(value),
211 Err(err) => Err(err.line(line)),
212 }
213 }
214}
215
216#[derive(Debug, Error)]
218#[error("Line {line}: {kind}")]
219pub struct Error {
220 line: usize,
222 kind: ErrorKind,
224}
225
226#[derive(Default)]
228pub struct NamedMultilinearInfo {
229 pub info: MultilinearInfo,
231 pub events: IndexMap<Event, Vec<Str>>,
233 pub channels: IndexMap<Channel, (Str, Vec<Str>)>,
235}
236
237#[derive(Default)]
240pub struct MultilinearParser(NamedMultilinearInfo);
241
242impl MultilinearParser {
243 pub fn parse<R: Read>(&mut self, reader: R, parent_namespace: &[Str]) -> Result<(), Error> {
261 let mut child_namespace = Vec::new();
262
263 let NamedMultilinearInfo {
264 info,
265 events,
266 channels,
267 } = &mut self.0;
268
269 let mut condition_groups = Vec::new();
270 let mut condition_lines = Vec::new();
271
272 let mut last_header_line = 0;
273
274 for (line_number, line) in BufReader::new(reader).lines().enumerate() {
275 let Ok(line) = line else {
276 return Err(ErrorKind::LineParsing.line(line_number));
277 };
278
279 if line.trim().is_empty() {
280 if !condition_lines.is_empty() {
281 condition_groups.push(LogicalExpression::and(condition_lines));
282 condition_lines = Vec::new();
283 }
284 continue;
285 }
286
287 if let Some(success) = parse_header(&mut child_namespace, &line) {
288 let Ok(changes) = success else {
289 return Err(ErrorKind::SubheaderWithoutHeader.line(line_number));
290 };
291
292 if let Err(ValueCheckingError(c)) = check_name(&changes.header) {
293 return Err(ErrorKind::InvalidCharacterInEventName(c)).line(line_number);
294 }
295
296 if !condition_lines.is_empty() {
297 condition_groups.push(LogicalExpression::and(condition_lines));
298 condition_lines = Vec::new();
299 }
300
301 if !condition_groups.is_empty() {
302 let mut event_edit = info.add_event();
303 for conditions in LogicalExpression::or(condition_groups).expand() {
304 if let Err(err) = event_edit.add_change(&conditions) {
305 return Err(ErrorKind::ConflictingCondition(err).line(last_header_line));
306 }
307 }
308
309 let mut namespace = parent_namespace.to_vec();
310 namespace.extend(changes.path.clone());
311 events.insert(event_edit.event(), namespace);
312
313 condition_groups = Vec::new();
314 }
315
316 last_header_line = line_number + 1;
317
318 changes.apply();
319
320 continue;
321 }
322
323 if parent_namespace.is_empty() && child_namespace.is_empty() {
324 return Err(ErrorKind::NoEvent.line(line_number));
325 }
326
327 let parse_expression = |condition: &str| {
328 let Some((channel, changes)) = condition.split_once(':') else {
329 return Err(ConditionParsingError::InvalidCondition);
330 };
331
332 let (channel, value_names) = channel_info(channels, channel.trim(), info)?;
333 Ok(LogicalExpression::or(
334 changes
335 .split(';')
336 .map(|change| -> Result<_, ValueCheckingError> {
337 Ok(LogicalExpression::Condition(
338 if let Some((from, to)) = change.split_once('>') {
339 let from = value_index(value_names, from)?;
340 let to = value_index(value_names, to)?;
341 Condition::change(channel, from, to)
342 } else {
343 let change = value_index(value_names, change)?;
344 Condition::new(channel, change)
345 },
346 ))
347 })
348 .collect::<Result<_, _>>()?,
349 ))
350 };
351
352 let conditions = LogicalExpression::parse_with_expression(&line, parse_expression);
353
354 let conditions = match conditions {
355 Ok(conditions) => conditions,
356 Err(err) => return Err(ErrorKind::ExpressionParsing(err).line(line_number)),
357 };
358
359 condition_lines.push(conditions);
360 }
361
362 if !condition_lines.is_empty() {
363 condition_groups.push(LogicalExpression::and(condition_lines));
364 }
365
366 if !condition_groups.is_empty() {
367 let mut event_edit = info.add_event();
368 for conditions in LogicalExpression::or(condition_groups).expand() {
369 if let Err(err) = event_edit.add_change(&conditions) {
370 return Err(ErrorKind::ConflictingCondition(err).line(last_header_line));
371 }
372 }
373
374 let mut namespace = parent_namespace.to_vec();
375 namespace.extend(child_namespace);
376 events.insert(event_edit.event(), namespace);
377 }
378
379 Ok(())
380 }
381
382 pub fn into_info(self) -> NamedMultilinearInfo {
386 self.0
387 }
388}
389
390pub fn parse_multilinear<R: Read>(reader: R) -> Result<NamedMultilinearInfo, Error> {
404 let mut result = MultilinearParser::default();
405 result.parse(reader, &Vec::new())?;
406 Ok(result.0)
407}