1#![deny(missing_docs)]
2
3use header_parsing::parse_header;
26use logical_expressions::{LogicalExpression, ParseError};
27use thiserror::Error;
28
29use multilinear::{Channel, Condition, Event, EventInfo, 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, mut namespace: Vec<Str>) -> Result<(), Error> {
261 let NamedMultilinearInfo {
262 info,
263 events,
264 channels,
265 } = &mut self.0;
266
267 let mut condition_groups = Vec::new();
268 let mut condition_lines = Vec::new();
269
270 let mut last_header_line = 0;
271
272 for (line_number, line) in BufReader::new(reader).lines().enumerate() {
273 let Ok(line) = line else {
274 return Err(ErrorKind::LineParsing.line(line_number));
275 };
276
277 if line.trim().is_empty() {
278 if !condition_lines.is_empty() {
279 condition_groups.push(LogicalExpression::and(condition_lines));
280 condition_lines = Vec::new();
281 }
282 continue;
283 }
284
285 if let Some(success) = parse_header(&mut namespace, &line) {
286 let Ok(changes) = success else {
287 return Err(ErrorKind::SubheaderWithoutHeader.line(line_number));
288 };
289
290 if let Err(ValueCheckingError(c)) = check_name(&changes.header) {
291 return Err(ErrorKind::InvalidCharacterInEventName(c)).line(line_number);
292 }
293
294 if !condition_lines.is_empty() {
295 condition_groups.push(LogicalExpression::and(condition_lines));
296 condition_lines = Vec::new();
297 }
298
299 if !condition_groups.is_empty() {
300 let mut event = EventInfo::new();
301 for conditions in LogicalExpression::or(condition_groups).expand() {
302 if let Err(err) = event.add_change(&conditions) {
303 return Err(ErrorKind::ConflictingCondition(err).line(last_header_line));
304 }
305 }
306
307 let event = info.add_event(event);
308 events.insert(event, changes.path.clone());
309
310 condition_groups = Vec::new();
311 }
312
313 last_header_line = line_number + 1;
314
315 changes.apply();
316
317 continue;
318 }
319
320 if namespace.is_empty() {
321 return Err(ErrorKind::NoEvent.line(line_number));
322 }
323
324 let parse_conditions = |condition: &str| {
325 let Some((channel, change)) = condition.split_once(':') else {
326 return Err(ConditionParsingError::InvalidCondition);
327 };
328
329 let (channel, value_names) = channel_info(channels, channel.trim(), info)?;
330 Ok(if let Some((from, to)) = change.split_once('>') {
331 let from = value_index(value_names, from)?;
332 let to = value_index(value_names, to)?;
333 Condition::change(channel, from, to)
334 } else {
335 let change = value_index(value_names, change)?;
336 Condition::new(channel, change)
337 })
338 };
339
340 let conditions = LogicalExpression::parse_with(&line, parse_conditions);
341
342 let conditions = match conditions {
343 Ok(conditions) => conditions,
344 Err(err) => return Err(ErrorKind::ExpressionParsing(err).line(line_number)),
345 };
346
347 condition_lines.push(conditions);
348 }
349
350 if !condition_lines.is_empty() {
351 condition_groups.push(LogicalExpression::and(condition_lines));
352 }
353
354 if !condition_groups.is_empty() {
355 let mut event = EventInfo::new();
356 for conditions in LogicalExpression::or(condition_groups).expand() {
357 if let Err(err) = event.add_change(&conditions) {
358 return Err(ErrorKind::ConflictingCondition(err).line(last_header_line));
359 }
360 }
361
362 let event = info.add_event(event);
363 events.insert(event, namespace);
364 }
365
366 Ok(())
367 }
368
369 pub fn into_info(self) -> NamedMultilinearInfo {
373 self.0
374 }
375}
376
377pub fn parse_multilinear<R: Read>(reader: R) -> Result<NamedMultilinearInfo, Error> {
391 let mut result = MultilinearParser::default();
392 result.parse(reader, Vec::new())?;
393 Ok(result.0)
394}