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 collections::HashMap,
33 io::{BufRead, BufReader, Read},
34};
35
36#[derive(Copy, Clone, Debug)]
37struct ValueCheckingError(char);
38
39type Str = Box<str>;
40
41fn check_name(name: &str) -> Result<(), ValueCheckingError> {
42 if let Some(c) = name
43 .chars()
44 .find(|&c| !c.is_alphanumeric() && !"_- ".contains(c))
45 {
46 Err(ValueCheckingError(c))
47 } else {
48 Ok(())
49 }
50}
51
52fn valid_name(name: &str) -> Result<&str, ValueCheckingError> {
53 let name = name.trim();
54 check_name(name)?;
55 Ok(name)
56}
57
58struct ValueMap {
59 map: HashMap<Str, usize>,
60}
61
62impl ValueMap {
63 fn into_array(self) -> Box<[Str]> {
64 let mut result = vec!["".into(); self.map.len()].into_boxed_slice();
65 for (name, index) in self.map {
66 result[index] = name;
67 }
68 result
69 }
70}
71
72impl ValueMap {
73 fn new() -> Self {
74 let mut result = Self {
75 map: HashMap::new(),
76 };
77 let _ = result.index("");
78 result
79 }
80
81 fn index(&mut self, name: &str) -> Result<usize, ValueCheckingError> {
82 let name = valid_name(name)?;
83
84 if !self.map.contains_key(name) {
85 let index = self.map.len();
86 self.map.insert(name.into(), index);
87 }
88
89 let name = self.map.get_mut(name).unwrap();
90 Ok(*name)
91 }
92}
93
94#[derive(Copy, Clone, Debug, Error)]
96pub enum ConditionParsingError {
97 #[error("Invalid character '{0}' for condition names")]
99 InvalidCharacter(char),
100
101 #[error("Invalid condition format")]
103 InvalidCondition,
104}
105
106impl From<ValueCheckingError> for ConditionParsingError {
107 fn from(ValueCheckingError(c): ValueCheckingError) -> Self {
108 Self::InvalidCharacter(c)
109 }
110}
111
112#[derive(Copy, Clone, Debug, Error)]
114pub enum LineErrorKind {
115 #[error("Input error while parsing line")]
117 LineParsing,
118
119 #[error("Parsing expression failed: {0}")]
121 ExpressionParsing(ParseError<ConditionParsingError>),
122
123 #[error("Encountered conflicting conditions: {0}")]
125 ConflictingCondition(InvalidChangeError),
126
127 #[error("Invalid character '{0}' in event name")]
129 InvalidCharacterInEventName(char),
130
131 #[error("No event has been specified")]
133 NoEvent,
134
135 #[error("Subheader without matching header")]
137 SubheaderWithoutHeader,
138}
139
140trait ErrorLine {
141 type Output;
142
143 fn line(self, line: usize) -> Self::Output;
144}
145
146impl ErrorLine for LineErrorKind {
147 type Output = Error;
148
149 fn line(self, line: usize) -> Error {
150 Error::Line { line, kind: self }
151 }
152}
153
154impl<T> ErrorLine for Result<T, LineErrorKind> {
155 type Output = Result<T, Error>;
156
157 fn line(self, line: usize) -> Result<T, Error> {
158 match self {
159 Ok(value) => Ok(value),
160 Err(err) => Err(err.line(line)),
161 }
162 }
163}
164
165#[derive(Debug, Error)]
167pub enum Error {
168 #[error("Line {line}: {kind}")]
170 Line {
171 line: usize,
173 kind: LineErrorKind,
175 },
176
177 #[error("Conflicting conditions detected")]
179 ConflictingCondition,
180}
181
182struct ChannelMap {
183 map: HashMap<Str, (Channel, ValueMap)>,
184}
185
186impl ChannelMap {
187 fn new() -> Self {
188 Self {
189 map: HashMap::new(),
190 }
191 }
192
193 fn index(
194 &mut self,
195 name: &str,
196 info: &mut MultilinearInfo,
197 ) -> Result<(Channel, &mut ValueMap), ValueCheckingError> {
198 let name = valid_name(name)?;
199
200 if !self.map.contains_key(name) {
201 let channel = info.add_channel();
202 self.map.insert(name.into(), (channel, ValueMap::new()));
203 }
204
205 let (name, value) = self.map.get_mut(name).unwrap();
206 Ok((*name, value))
207 }
208}
209
210pub struct NamedMultilinearInfo {
212 pub info: MultilinearInfo,
214 pub events: HashMap<Event, Vec<Str>>,
216 pub channels: HashMap<Channel, (Str, Box<[Str]>)>,
218}
219
220pub fn parse_multilinear<R: Read>(reader: R) -> Result<NamedMultilinearInfo, Error> {
225 let mut info = MultilinearInfo::new();
226 let mut current_event_name = Vec::new();
227 let mut event_names = HashMap::new();
228 let mut channel_names = ChannelMap::new();
229
230 let mut condition_groups = Vec::new();
231 let mut condition_lines = Vec::new();
232
233 for (line_number, line) in BufReader::new(reader).lines().enumerate() {
234 let Ok(line) = line else {
235 return Err(LineErrorKind::LineParsing.line(line_number));
236 };
237
238 if line.trim().is_empty() {
239 if !condition_lines.is_empty() {
240 condition_groups.push(LogicalExpression::and(condition_lines));
241 condition_lines = Vec::new();
242 }
243 continue;
244 }
245
246 if let Some(success) = parse_header(&mut current_event_name, &line) {
247 let Ok(changes) = success else {
248 return Err(LineErrorKind::SubheaderWithoutHeader.line(line_number));
249 };
250
251 if let Err(ValueCheckingError(c)) = check_name(&changes.header) {
252 return Err(LineErrorKind::InvalidCharacterInEventName(c)).line(line_number);
253 }
254
255 if !condition_lines.is_empty() {
256 condition_groups.push(LogicalExpression::and(condition_lines));
257 condition_lines = Vec::new();
258 }
259
260 if !condition_groups.is_empty() {
261 let mut event = EventInfo::new();
262 for conditions in LogicalExpression::or(condition_groups).expand() {
263 if let Err(err) = event.add_change(&conditions) {
264 return Err(LineErrorKind::ConflictingCondition(err).line(line_number));
265 }
266 }
267
268 let event = info.add_event(event);
269 event_names.insert(event, changes.path.clone());
270
271 condition_groups = Vec::new();
272 }
273
274 changes.apply();
275
276 continue;
277 }
278
279 if current_event_name.is_empty() {
280 return Err(LineErrorKind::NoEvent.line(line_number));
281 };
282
283 let parse_conditions = |condition: &str| {
284 let Some((channel, change)) = condition.split_once(':') else {
285 return Err(ConditionParsingError::InvalidCondition);
286 };
287
288 let (channel, value_names) = channel_names.index(channel.trim(), &mut info)?;
289 Ok(if let Some((from, to)) = change.split_once('>') {
290 let from = value_names.index(from)?;
291 let to = value_names.index(to)?;
292 Condition::change(channel, from, to)
293 } else {
294 let change = value_names.index(change)?;
295 Condition::new(channel, change)
296 })
297 };
298
299 let conditions = LogicalExpression::parse_with(&line, parse_conditions);
300
301 let conditions = match conditions {
302 Ok(conditions) => conditions,
303 Err(err) => return Err(LineErrorKind::ExpressionParsing(err).line(line_number)),
304 };
305
306 condition_lines.push(conditions);
307 }
308
309 if !condition_lines.is_empty() {
310 condition_groups.push(LogicalExpression::and(condition_lines));
311 }
312
313 if !condition_groups.is_empty() {
314 let mut event = EventInfo::new();
315 for conditions in LogicalExpression::or(condition_groups).expand() {
316 if event.add_change(&conditions).is_err() {
317 return Err(Error::ConflictingCondition);
318 }
319 }
320
321 let event = info.add_event(event);
322 event_names.insert(event, current_event_name);
323 }
324
325 let channels = channel_names
326 .map
327 .into_iter()
328 .map(|(name, (channel, values))| (channel, (name, values.into_array())))
329 .collect();
330
331 Ok(NamedMultilinearInfo {
332 info,
333 events: event_names,
334 channels,
335 })
336}