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!["".into()]));
137
138 let (_, value_names) = channels.entries.last_mut().unwrap();
139
140 Ok((channel, value_names))
141}
142
143#[derive(Debug, Error)]
145pub enum ChannelAddingError {
146 #[error("A channel of this name already exists")]
148 AlreadyExists,
149
150 #[error("Invalid character '{0}' for condition names")]
152 InvalidCharacter(char),
153}
154
155impl From<ValueCheckingError> for ChannelAddingError {
156 fn from(ValueCheckingError(c): ValueCheckingError) -> Self {
157 Self::InvalidCharacter(c)
158 }
159}
160
161#[derive(Copy, Clone, Debug, Error)]
163pub enum ConditionParsingError {
164 #[error("Invalid character '{0}' for condition names")]
166 InvalidCharacter(char),
167
168 #[error("Invalid condition format")]
170 InvalidCondition,
171}
172
173impl From<ValueCheckingError> for ConditionParsingError {
174 fn from(ValueCheckingError(c): ValueCheckingError) -> Self {
175 Self::InvalidCharacter(c)
176 }
177}
178
179#[derive(Copy, Clone, Debug, Error)]
181pub enum ErrorKind {
182 #[error("Input error while parsing line")]
184 LineParsing,
185
186 #[error("Parsing expression failed: {0}")]
188 ExpressionParsing(ParseError<ConditionParsingError>),
189
190 #[error("Encountered conflicting conditions: {0}")]
192 ConflictingCondition(InvalidChangeError),
193
194 #[error("Invalid character '{0}' in event name")]
196 InvalidCharacterInEventName(char),
197
198 #[error("No event has been specified")]
200 NoEvent,
201
202 #[error("Subheader without matching header")]
204 SubheaderWithoutHeader,
205}
206
207trait ErrorLine {
208 type Output;
209
210 fn line(self, line: usize) -> Self::Output;
211}
212
213impl ErrorLine for ErrorKind {
214 type Output = Error;
215
216 fn line(self, line: usize) -> Error {
217 Error { line, kind: self }
218 }
219}
220
221impl<T> ErrorLine for Result<T, ErrorKind> {
222 type Output = Result<T, Error>;
223
224 fn line(self, line: usize) -> Result<T, Error> {
225 match self {
226 Ok(value) => Ok(value),
227 Err(err) => Err(err.line(line)),
228 }
229 }
230}
231
232#[derive(Debug, Error)]
234#[error("Line {line}: {kind}")]
235pub struct Error {
236 line: usize,
238 kind: ErrorKind,
240}
241
242#[derive(Default)]
244pub struct NamedMultilinearInfo {
245 pub info: MultilinearInfo,
247 pub events: IndexMap<Event, Vec<Str>>,
249 pub channels: IndexMap<Channel, (Str, Vec<Str>)>,
251}
252
253#[derive(Default)]
256pub struct MultilinearParser(NamedMultilinearInfo);
257
258impl MultilinearParser {
259 pub fn add_new_channel(
263 &mut self,
264 channel_name: &str,
265 default_name: &str,
266 ) -> Result<Channel, ChannelAddingError> {
267 let channel_name = valid_name(channel_name)?;
268 let default_name = valid_name(default_name)?;
269
270 if self
271 .0
272 .channels
273 .entries
274 .iter()
275 .any(|(checked_name, _)| checked_name.as_ref() == channel_name)
276 {
277 return Err(ChannelAddingError::AlreadyExists);
278 }
279
280 let channel = self.0.info.add_channel();
281 self.0
282 .channels
283 .insert(channel, (channel_name.into(), vec![default_name.into()]));
284
285 Ok(channel)
286 }
287
288 pub fn parse<R: Read>(&mut self, reader: R, parent_namespace: &[Str]) -> Result<(), Error> {
306 let mut child_namespace = Vec::new();
307
308 let NamedMultilinearInfo {
309 info,
310 events,
311 channels,
312 } = &mut self.0;
313
314 let mut condition_groups = Vec::new();
315 let mut condition_lines = Vec::new();
316
317 let mut last_header_line = 0;
318
319 for (line_number, line) in BufReader::new(reader).lines().enumerate() {
320 let Ok(line) = line else {
321 return Err(ErrorKind::LineParsing.line(line_number));
322 };
323
324 if line.trim().is_empty() {
325 if !condition_lines.is_empty() {
326 condition_groups.push(LogicalExpression::and(condition_lines));
327 condition_lines = Vec::new();
328 }
329 continue;
330 }
331
332 if let Some(success) = parse_header(&mut child_namespace, &line) {
333 let Ok(changes) = success else {
334 return Err(ErrorKind::SubheaderWithoutHeader.line(line_number));
335 };
336
337 if let Err(ValueCheckingError(c)) = check_name(&changes.header) {
338 return Err(ErrorKind::InvalidCharacterInEventName(c)).line(line_number);
339 }
340
341 if !condition_lines.is_empty() {
342 condition_groups.push(LogicalExpression::and(condition_lines));
343 condition_lines = Vec::new();
344 }
345
346 if !condition_groups.is_empty() {
347 let mut event_edit = info.add_event();
348 for conditions in LogicalExpression::or(condition_groups).expand() {
349 if let Err(err) = event_edit.add_change(&conditions) {
350 return Err(ErrorKind::ConflictingCondition(err).line(last_header_line));
351 }
352 }
353
354 let mut namespace = parent_namespace.to_vec();
355 namespace.extend(changes.path.clone());
356 events.insert(event_edit.event(), namespace);
357
358 condition_groups = Vec::new();
359 }
360
361 last_header_line = line_number + 1;
362
363 changes.apply();
364
365 continue;
366 }
367
368 if parent_namespace.is_empty() && child_namespace.is_empty() {
369 return Err(ErrorKind::NoEvent.line(line_number));
370 }
371
372 let parse_expression = |condition: &str| {
373 let Some((channel, changes)) = condition.split_once(':') else {
374 return Err(ConditionParsingError::InvalidCondition);
375 };
376
377 let (channel, value_names) = channel_info(channels, channel.trim(), info)?;
378 Ok(LogicalExpression::or(
379 changes
380 .split(';')
381 .map(|change| -> Result<_, ValueCheckingError> {
382 Ok(LogicalExpression::Condition(
383 if let Some((from, to)) = change.split_once('>') {
384 let from = value_index(value_names, from)?;
385 let to = value_index(value_names, to)?;
386 Condition::change(channel, from, to)
387 } else {
388 let change = value_index(value_names, change)?;
389 Condition::new(channel, change)
390 },
391 ))
392 })
393 .collect::<Result<_, _>>()?,
394 ))
395 };
396
397 let conditions = LogicalExpression::parse_with_expression(&line, parse_expression);
398
399 let conditions = match conditions {
400 Ok(conditions) => conditions,
401 Err(err) => return Err(ErrorKind::ExpressionParsing(err).line(line_number)),
402 };
403
404 condition_lines.push(conditions);
405 }
406
407 if !condition_lines.is_empty() {
408 condition_groups.push(LogicalExpression::and(condition_lines));
409 }
410
411 if !condition_groups.is_empty() {
412 let mut event_edit = info.add_event();
413 for conditions in LogicalExpression::or(condition_groups).expand() {
414 if let Err(err) = event_edit.add_change(&conditions) {
415 return Err(ErrorKind::ConflictingCondition(err).line(last_header_line));
416 }
417 }
418
419 let mut namespace = parent_namespace.to_vec();
420 namespace.extend(child_namespace);
421 events.insert(event_edit.event(), namespace);
422 }
423
424 Ok(())
425 }
426
427 pub fn into_info(self) -> NamedMultilinearInfo {
431 self.0
432 }
433}
434
435pub fn parse_multilinear<R: Read>(reader: R) -> Result<NamedMultilinearInfo, Error> {
449 let mut result = MultilinearParser::default();
450 result.parse(reader, &Vec::new())?;
451 Ok(result.0)
452}