gsd_parser/
parser.rs

1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4mod gsd_parser {
5    #[derive(pest_derive::Parser)]
6    #[grammar = "gsd.pest"]
7    pub struct GsdParser;
8}
9
10pub type ParseError = pest::error::Error<gsd_parser::Rule>;
11pub type ParseResult<T> = Result<T, ParseError>;
12
13fn parse_error(e: impl std::fmt::Display, span: pest::Span<'_>) -> ParseError {
14    let message = format!("{}", e);
15    pest::error::Error::new_from_span(pest::error::ErrorVariant::CustomError { message }, span)
16}
17
18fn parse_number<T: TryFrom<u32>>(
19    pair: pest::iterators::Pair<'_, gsd_parser::Rule>,
20) -> ParseResult<T>
21where
22    <T as TryFrom<u32>>::Error: std::fmt::Display,
23{
24    match pair.as_rule() {
25        gsd_parser::Rule::dec_number => pair.as_str().parse(),
26        gsd_parser::Rule::hex_number => {
27            u32::from_str_radix(pair.as_str().trim_start_matches("0x"), 16)
28        }
29        _ => panic!("Called parse_number() on a non-number pair: {:?}", pair),
30    }
31    .map_err(|_| parse_error("invalid digit found while parsing integer", pair.as_span()))
32    .and_then(|i| i.try_into().map_err(|e| parse_error(e, pair.as_span())))
33}
34
35fn parse_signed_number(pair: pest::iterators::Pair<'_, gsd_parser::Rule>) -> ParseResult<i64> {
36    match pair.as_rule() {
37        gsd_parser::Rule::dec_number => pair.as_str().parse(),
38        gsd_parser::Rule::hex_number => {
39            i64::from_str_radix(pair.as_str().trim_start_matches("0x"), 16)
40        }
41        _ => panic!("Called parse_number() on a non-number pair: {:?}", pair),
42    }
43    .map_err(|_| {
44        parse_error(
45            "invalid digit found while parsing signed integer",
46            pair.as_span(),
47        )
48    })
49}
50
51fn parse_number_list<T: TryFrom<u32>>(
52    pair: pest::iterators::Pair<'_, gsd_parser::Rule>,
53) -> ParseResult<Vec<T>>
54where
55    <T as TryFrom<u32>>::Error: std::fmt::Display,
56{
57    Ok(match pair.as_rule() {
58        gsd_parser::Rule::number_list => pair
59            .into_inner()
60            .into_iter()
61            .map(|p| parse_number::<T>(p))
62            .collect::<ParseResult<Vec<T>>>()?,
63        gsd_parser::Rule::dec_number | gsd_parser::Rule::hex_number => {
64            vec![parse_number(pair)?]
65        }
66        _ => panic!(
67            "Called parse_number_list() on a pair that cannot be a number list: {:?}",
68            pair
69        ),
70    })
71}
72
73fn parse_bool(pair: pest::iterators::Pair<'_, gsd_parser::Rule>) -> ParseResult<bool> {
74    Ok(parse_number::<u32>(pair)? != 0)
75}
76
77fn parse_string_literal(pair: pest::iterators::Pair<'_, gsd_parser::Rule>) -> String {
78    assert!(pair.as_rule() == gsd_parser::Rule::string_literal);
79    // drop the quotation marks
80    let mut chars = pair.as_str().chars();
81    chars.next();
82    chars.next_back();
83    let s = chars.as_str().to_owned();
84
85    // remove long-line markers
86    s.replace("\\\r\n", "").replace("\\\n", "")
87}
88
89pub fn parse(
90    file: &std::path::Path,
91    source: &str,
92) -> ParseResult<crate::GenericStationDescription> {
93    parse_inner(source).map_err(|e| e.with_path(&file.to_string_lossy()))
94}
95
96fn parse_inner(source: &str) -> ParseResult<crate::GenericStationDescription> {
97    use pest::Parser;
98
99    let gsd_pairs = gsd_parser::GsdParser::parse(gsd_parser::Rule::gsd, &source)?
100        .next()
101        .expect("pest grammar wrong?");
102
103    let mut gsd = crate::GenericStationDescription::default();
104    let mut prm_texts = BTreeMap::new();
105    let mut user_prm_data_definitions = BTreeMap::new();
106    let mut legacy_prm = Some(crate::UserPrmData::default());
107
108    for statement in gsd_pairs.into_inner() {
109        let statement_span = statement.as_span();
110        match statement.as_rule() {
111            gsd_parser::Rule::prm_text => {
112                let mut content = statement.into_inner();
113                let id: u16 = parse_number(content.next().expect("pest grammar wrong?"))?;
114                let mut values = BTreeMap::new();
115                for value_pairs in content {
116                    assert!(value_pairs.as_rule() == gsd_parser::Rule::prm_text_value);
117                    let mut iter = value_pairs.into_inner();
118                    let number = parse_signed_number(iter.next().expect("pest grammar wrong?"))?;
119                    let value = parse_string_literal(iter.next().expect("pest grammar wrong?"));
120                    assert!(iter.next().is_none());
121                    values.insert(value, number);
122                }
123                prm_texts.insert(id, Arc::new(values));
124            }
125            gsd_parser::Rule::ext_user_prm_data => {
126                let mut content = statement.into_inner();
127                // TODO: actually u32?
128                let id: u32 = parse_number(content.next().expect("pest grammar wrong?"))?;
129                let name = parse_string_literal(content.next().expect("pest grammar wrong?"));
130
131                let data_type_pair = content.next().expect("pest grammar wrong?");
132                assert_eq!(
133                    data_type_pair.as_rule(),
134                    gsd_parser::Rule::prm_data_type_name
135                );
136                let data_type_rule = data_type_pair
137                    .into_inner()
138                    .next()
139                    .expect("pest grammar wrong?");
140                let data_type = match data_type_rule.as_rule() {
141                    gsd_parser::Rule::identifier => {
142                        match data_type_rule.as_str().to_lowercase().as_str() {
143                            "unsigned8" => crate::UserPrmDataType::Unsigned8,
144                            "unsigned16" => crate::UserPrmDataType::Unsigned16,
145                            "unsigned32" => crate::UserPrmDataType::Unsigned32,
146                            "signed8" => crate::UserPrmDataType::Signed8,
147                            "signed16" => crate::UserPrmDataType::Signed16,
148                            "signed32" => crate::UserPrmDataType::Signed32,
149                            dt => panic!("unknown data type {dt:?}"),
150                        }
151                    }
152                    gsd_parser::Rule::bit => {
153                        let bit = parse_number(
154                            data_type_rule
155                                .into_inner()
156                                .next()
157                                .expect("pest grammar wrong?"),
158                        )?;
159                        crate::UserPrmDataType::Bit(bit)
160                    }
161                    gsd_parser::Rule::bit_area => {
162                        let mut content = data_type_rule.into_inner();
163                        let first_bit = parse_number(content.next().expect("pest grammar wrong?"))?;
164                        let last_bit = parse_number(content.next().expect("pest grammar wrong?"))?;
165                        crate::UserPrmDataType::BitArea(first_bit, last_bit)
166                    }
167                    _ => unreachable!(),
168                };
169
170                let default_value =
171                    parse_signed_number(content.next().expect("pest grammar wrong?"))?;
172
173                let mut constraint = crate::PrmValueConstraint::Unconstrained;
174                let mut text_ref = None;
175                let mut changeable = true;
176                let mut visible = true;
177
178                for rule in content {
179                    match rule.as_rule() {
180                        gsd_parser::Rule::prm_data_value_range => {
181                            let mut content = rule.into_inner();
182                            let min_value =
183                                parse_signed_number(content.next().expect("pest grammar wrong?"))?;
184                            let max_value =
185                                parse_signed_number(content.next().expect("pest grammar wrong?"))?;
186                            constraint = crate::PrmValueConstraint::MinMax(min_value, max_value);
187                        }
188                        gsd_parser::Rule::prm_data_value_set => {
189                            let mut values = Vec::new();
190                            for pairs in rule.into_inner() {
191                                let number = parse_signed_number(pairs)?;
192                                values.push(number);
193                            }
194                            constraint = crate::PrmValueConstraint::Enum(values);
195                        }
196                        gsd_parser::Rule::prm_text_ref => {
197                            let text_id = parse_number(
198                                rule.into_inner().next().expect("pest grammar wrong?"),
199                            )?;
200                            text_ref = Some(
201                                prm_texts
202                                    .get(&text_id)
203                                    .ok_or_else(|| {
204                                        parse_error(
205                                            format!("PrmText {} was not found", text_id),
206                                            statement_span,
207                                        )
208                                    })?
209                                    .clone(),
210                            );
211                        }
212                        gsd_parser::Rule::prm_data_changeable => {
213                            changeable = parse_bool(rule.into_inner().next().unwrap())?;
214                        }
215                        gsd_parser::Rule::prm_data_visible => {
216                            visible = parse_bool(rule.into_inner().next().unwrap())?;
217                        }
218                        rule => unreachable!("unexpected rule {rule:?}"),
219                    }
220                }
221
222                user_prm_data_definitions.insert(
223                    id,
224                    Arc::new(crate::UserPrmDataDefinition {
225                        name,
226                        data_type,
227                        text_ref,
228                        default_value,
229                        constraint,
230                        changeable,
231                        visible,
232                    }),
233                );
234            }
235            gsd_parser::Rule::unit_diag_area => {
236                let mut content = statement.into_inner();
237                let first = parse_number(content.next().unwrap())?;
238                let last = parse_number(content.next().unwrap())?;
239                let mut values = BTreeMap::new();
240                for value_pairs in content {
241                    assert!(value_pairs.as_rule() == gsd_parser::Rule::unit_diag_area_value);
242                    let mut iter = value_pairs.into_inner();
243                    let number = parse_number(iter.next().unwrap())?;
244                    let value = parse_string_literal(iter.next().unwrap());
245                    assert!(iter.next().is_none());
246                    values.insert(number, value);
247                }
248                gsd.unit_diag.areas.push(crate::UnitDiagArea {
249                    first,
250                    last,
251                    values,
252                });
253            }
254            gsd_parser::Rule::module => {
255                let mut content = statement.into_inner();
256                let name = parse_string_literal(content.next().unwrap());
257                let mut info_text = None;
258                let module_config: Vec<u8> = parse_number_list(content.next().unwrap())?;
259                let mut module_reference = None;
260                let mut module_prm_data = crate::UserPrmData::default();
261
262                for rule in content {
263                    match rule.as_rule() {
264                        gsd_parser::Rule::module_reference => {
265                            module_reference =
266                                Some(parse_number(rule.into_inner().next().unwrap())?);
267                        }
268                        gsd_parser::Rule::setting => {
269                            let mut pairs = rule.into_inner();
270                            let key = pairs.next().unwrap().as_str();
271                            let value_pair = pairs.next().unwrap();
272                            match key.to_lowercase().as_str() {
273                                "ext_module_prm_data_len" => {
274                                    module_prm_data.length = parse_number(value_pair)?;
275                                }
276                                "ext_user_prm_data_ref" => {
277                                    let offset = parse_number(value_pair)?;
278                                    let data_id = parse_number(pairs.next().unwrap())?;
279                                    let data_ref =
280                                        user_prm_data_definitions.get(&data_id).unwrap().clone();
281                                    module_prm_data.data_ref.push((offset, data_ref));
282                                }
283                                "ext_user_prm_data_const" => {
284                                    let offset = parse_number(value_pair)?;
285                                    let values: Vec<u8> = parse_number_list(pairs.next().unwrap())?;
286                                    module_prm_data.data_const.push((offset, values));
287                                }
288                                "info_text" => {
289                                    info_text = Some(parse_string_literal(value_pair));
290                                }
291                                _ => (),
292                            }
293                        }
294                        gsd_parser::Rule::data_area => (),
295                        r => unreachable!("found rule {r:?}"),
296                    }
297                }
298
299                let module = crate::Module {
300                    name,
301                    info_text,
302                    config: module_config,
303                    reference: module_reference,
304                    module_prm_data,
305                };
306                gsd.available_modules.push(Arc::new(module));
307            }
308            gsd_parser::Rule::slot_definition => {
309                for rule in statement.into_inner() {
310                    match rule.as_rule() {
311                        gsd_parser::Rule::slot => {
312                            let mut pairs = rule.into_inner();
313                            let number = parse_number(pairs.next().unwrap())?;
314                            let name = parse_string_literal(pairs.next().unwrap());
315
316                            #[allow(unused)]
317                            let find_module =
318                                |reference: u16,
319                                 slot_ref: &str,
320                                 slot_num: u8|
321                                 -> Option<Arc<crate::Module>> {
322                                    for module in gsd.available_modules.iter() {
323                                        if module.reference == Some(reference.into()) {
324                                            return Some(module.clone());
325                                        }
326                                    }
327                                    // TODO: Warning management?
328                                    // log::warn!("No module with reference {reference} found for slot {slot_num} (\"{slot_ref}\")");
329                                    None
330                                };
331
332                            let default_pair = pairs.next().unwrap();
333                            let default_span = default_pair.as_span();
334                            let default_ref = parse_number(default_pair)?;
335
336                            let value_pair = pairs.next().unwrap();
337                            let allowed_modules = match value_pair.as_rule() {
338                                gsd_parser::Rule::slot_value_range => {
339                                    let mut pairs = value_pair.into_inner();
340                                    let first = parse_number(pairs.next().unwrap())?;
341                                    let last = parse_number(pairs.next().unwrap())?;
342                                    (first..=last)
343                                        .filter_map(|r| find_module(r, &name, number))
344                                        .collect::<Vec<_>>()
345                                }
346                                gsd_parser::Rule::slot_value_set => {
347                                    let mut allowed_modules = Vec::new();
348                                    for pairs in value_pair.into_inner() {
349                                        let reference = parse_number(pairs)?;
350                                        if let Some(module) = find_module(reference, &name, number)
351                                        {
352                                            allowed_modules.push(module);
353                                        }
354                                    }
355                                    allowed_modules
356                                }
357                                r => unreachable!("found rule {r:?}"),
358                            };
359
360                            let Some(default) = find_module(default_ref, &name, number) else {
361                                return Err(parse_error(
362                                    format!(
363                                        "The default module for slot {number} (\"{name}\") with reference {default_ref} is not available",
364                                    ),
365                                    default_span,
366                                ));
367                            };
368                            if !allowed_modules.contains(&default) {
369                                // TODO: Warning management?
370                                // log::warn!("Default module not part of allowed modules?!");
371                            }
372
373                            let slot = crate::Slot {
374                                name,
375                                number,
376                                default,
377                                allowed_modules,
378                            };
379
380                            gsd.slots.push(slot);
381                        }
382                        r => unreachable!("found rule {r:?}"),
383                    }
384                }
385            }
386            gsd_parser::Rule::setting => {
387                let mut pairs = statement.into_inner();
388                let key = pairs.next().unwrap().as_str();
389                let value_pair = pairs.next().unwrap();
390                match key.to_lowercase().as_str() {
391                    "gsd_revision" => gsd.gsd_revision = parse_number(value_pair)?,
392                    "vendor_name" => gsd.vendor = parse_string_literal(value_pair),
393                    "model_name" => gsd.model = parse_string_literal(value_pair),
394                    "revision" => gsd.revision = parse_string_literal(value_pair),
395                    "revision_number" => gsd.revision_number = parse_number(value_pair)?,
396                    "ident_number" => gsd.ident_number = parse_number(value_pair)?,
397                    //
398                    "hardware_release" => gsd.hardware_release = parse_string_literal(value_pair),
399                    "software_release" => gsd.software_release = parse_string_literal(value_pair),
400                    //
401                    "fail_safe" => gsd.fail_safe = parse_bool(value_pair)?,
402                    //
403                    "9.6_supp" => {
404                        if parse_bool(value_pair)? {
405                            gsd.supported_speeds |= crate::SupportedSpeeds::B9600;
406                        }
407                    }
408                    "19.2_supp" => {
409                        if parse_bool(value_pair)? {
410                            gsd.supported_speeds |= crate::SupportedSpeeds::B19200;
411                        }
412                    }
413                    "31.25_supp" => {
414                        if parse_bool(value_pair)? {
415                            gsd.supported_speeds |= crate::SupportedSpeeds::B31250;
416                        }
417                    }
418                    "45.45_supp" => {
419                        if parse_bool(value_pair)? {
420                            gsd.supported_speeds |= crate::SupportedSpeeds::B45450;
421                        }
422                    }
423                    "93.75_supp" => {
424                        if parse_bool(value_pair)? {
425                            gsd.supported_speeds |= crate::SupportedSpeeds::B93750;
426                        }
427                    }
428                    "187.5_supp" => {
429                        if parse_bool(value_pair)? {
430                            gsd.supported_speeds |= crate::SupportedSpeeds::B187500;
431                        }
432                    }
433                    "500_supp" => {
434                        if parse_bool(value_pair)? {
435                            gsd.supported_speeds |= crate::SupportedSpeeds::B500000;
436                        }
437                    }
438                    "1.5m_supp" => {
439                        if parse_bool(value_pair)? {
440                            gsd.supported_speeds |= crate::SupportedSpeeds::B1500000;
441                        }
442                    }
443                    "3m_supp" => {
444                        if parse_bool(value_pair)? {
445                            gsd.supported_speeds |= crate::SupportedSpeeds::B3000000;
446                        }
447                    }
448                    "6m_supp" => {
449                        if parse_bool(value_pair)? {
450                            gsd.supported_speeds |= crate::SupportedSpeeds::B6000000;
451                        }
452                    }
453                    "12m_supp" => {
454                        if parse_bool(value_pair)? {
455                            gsd.supported_speeds |= crate::SupportedSpeeds::B12000000;
456                        }
457                    }
458                    "maxtsdr_9.6" => gsd.max_tsdr.b9600 = parse_number(value_pair)?,
459                    "maxtsdr_19.2" => gsd.max_tsdr.b19200 = parse_number(value_pair)?,
460                    "maxtsdr_31.25" => gsd.max_tsdr.b31250 = parse_number(value_pair)?,
461                    "maxtsdr_45.45" => gsd.max_tsdr.b45450 = parse_number(value_pair)?,
462                    "maxtsdr_93.75" => gsd.max_tsdr.b93750 = parse_number(value_pair)?,
463                    "maxtsdr_187.5" => gsd.max_tsdr.b187500 = parse_number(value_pair)?,
464                    "maxtsdr_500" => gsd.max_tsdr.b500000 = parse_number(value_pair)?,
465                    "maxtsdr_1.5m" => gsd.max_tsdr.b1500000 = parse_number(value_pair)?,
466                    "maxtsdr_3m" => gsd.max_tsdr.b3000000 = parse_number(value_pair)?,
467                    "maxtsdr_6m" => gsd.max_tsdr.b6000000 = parse_number(value_pair)?,
468                    "maxtsdr_12m" => gsd.max_tsdr.b12000000 = parse_number(value_pair)?,
469                    "implementation_type" => {
470                        gsd.implementation_type = parse_string_literal(value_pair)
471                    }
472                    //
473                    "modular_station" => gsd.modular_station = parse_bool(value_pair)?,
474                    "max_module" => gsd.max_modules = parse_number(value_pair)?,
475                    "max_input_len" => gsd.max_input_length = parse_number(value_pair)?,
476                    "max_output_len" => gsd.max_output_length = parse_number(value_pair)?,
477                    "max_data_len" => gsd.max_data_length = parse_number(value_pair)?,
478                    "max_diag_data_len" => gsd.max_diag_data_length = parse_number(value_pair)?,
479                    "freeze_mode_supp" => gsd.freeze_mode_supported = parse_bool(value_pair)?,
480                    "sync_mode_supp" => gsd.sync_mode_supported = parse_bool(value_pair)?,
481                    "auto_baud_supp" => gsd.auto_baud_supported = parse_bool(value_pair)?,
482                    "set_slave_add_supp" => gsd.set_slave_addr_supported = parse_bool(value_pair)?,
483                    "ext_user_prm_data_ref" => {
484                        let offset = parse_number(value_pair)?;
485                        let data_id = parse_number(pairs.next().unwrap())?;
486                        let data_ref = user_prm_data_definitions.get(&data_id).unwrap().clone();
487                        gsd.user_prm_data.data_ref.push((offset, data_ref));
488                        // The presence of this keywords means `User_Prm_Data` and
489                        // `User_Prm_Data_Len` should be ignored.
490                        legacy_prm = None;
491                    }
492                    "ext_user_prm_data_const" => {
493                        let offset = parse_number(value_pair)?;
494                        let values: Vec<u8> = parse_number_list(pairs.next().unwrap())?;
495                        gsd.user_prm_data.data_const.push((offset, values));
496                        // The presence of this keywords means `User_Prm_Data` and
497                        // `User_Prm_Data_Len` should be ignored.
498                        legacy_prm = None;
499                    }
500                    "max_user_prm_data_len" => {
501                        // TODO: Actually evaluate this value.
502
503                        // The presence of this keywords means `User_Prm_Data` and
504                        // `User_Prm_Data_Len` should be ignored.
505                        legacy_prm = None;
506                    }
507                    "user_prm_data_len" => {
508                        // If legacy_prm is not None, we didn't encounter new-style Ext_User_Prm
509                        // yet, so legacy User_Prm_Data should be evaluated.
510                        if let Some(prm) = legacy_prm.as_mut() {
511                            prm.length = parse_number(value_pair)?;
512
513                            // Check if length matches data
514                            let current_max_length = prm
515                                .data_const
516                                .iter()
517                                .map(|(offset, values)| offset + values.len())
518                                .max()
519                                .unwrap_or(0);
520
521                            if usize::from(prm.length) < current_max_length {
522                                return Err(parse_error(
523                                    format!(
524                                        "User_Prm_Data has maximum length of {} while User_Prm_Data_Len only permits {}",
525                                        current_max_length,
526                                        prm.length,
527                                    ),
528                                    statement_span,
529                                ));
530                            }
531                        }
532                    }
533                    "user_prm_data" => {
534                        // If legacy_prm is not None, we didn't encounter new-style Ext_User_Prm
535                        // yet, so legacy User_Prm_Data should be evaluated.
536                        if let Some(prm) = legacy_prm.as_mut() {
537                            let values: Vec<u8> = parse_number_list(value_pair)?;
538
539                            // Only check length when it was already defined
540                            if prm.length != 0 && usize::from(prm.length) < values.len() {
541                                return Err(parse_error(
542                                    format!(
543                                        "User_Prm_Data has maximum length of {} while User_Prm_Data_Len only permits {}",
544                                        values.len(),
545                                        prm.length,
546                                    ),
547                                    statement_span,
548                                ));
549                            }
550
551                            prm.data_const.push((0, values));
552                        }
553                    }
554                    "unit_diag_bit" => {
555                        let bit = parse_number(value_pair)?;
556                        let text = parse_string_literal(pairs.next().unwrap());
557                        gsd.unit_diag.bits.entry(bit).or_default().text = text;
558                    }
559                    "unit_diag_bit_help" => {
560                        let bit = parse_number(value_pair)?;
561                        let text = parse_string_literal(pairs.next().unwrap());
562                        gsd.unit_diag.bits.entry(bit).or_default().help = Some(text);
563                    }
564                    "unit_diag_not_bit" => {
565                        let bit = parse_number(value_pair)?;
566                        let text = parse_string_literal(pairs.next().unwrap());
567                        gsd.unit_diag.not_bits.entry(bit).or_default().text = text;
568                    }
569                    "unit_diag_not_bit_help" => {
570                        let bit = parse_number(value_pair)?;
571                        let text = parse_string_literal(pairs.next().unwrap());
572                        gsd.unit_diag.not_bits.entry(bit).or_default().help = Some(text);
573                    }
574                    _ => (),
575                }
576            }
577            _ => (),
578        }
579    }
580
581    // If no `Ext_User_Prm` was present, commit the legacy Prm data into the gsd struct.
582    if let Some(prm) = legacy_prm {
583        gsd.user_prm_data = prm;
584    }
585
586    // If this is a compact station, only allow one module
587    if !gsd.modular_station {
588        if !gsd.max_modules == 1 {
589            // TODO: Warnings
590        }
591        if !gsd.available_modules.len() == 1 {
592            // TODO: Warnings
593        }
594        gsd.max_modules = 1;
595    }
596
597    Ok(gsd)
598}