ielr/lr/
precedence_annotations.rs

1/*
2 * Copyright 2022 Arnaud Golfouse
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 */
8
9use crate::input::PrecedenceLevel;
10
11/// Precedence annotations in a [`super::LRItem`].
12///
13/// Each item that wish to appear to the left or right of the item containing the
14/// annotations must meet the threshold for each concerned field.
15#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
16pub(crate) struct PrecedenceAnnotations {
17    /// Inherited precedence level on the left of the current item.
18    ///
19    /// This will forbid any item on the *left* of this one, whose left precedence
20    /// levels do not meet the threshold for this field.
21    pub(crate) forbidden_left: Vec<Option<PrecedenceLevel>>,
22    /// Precedence level on the right of the current item.
23    ///
24    /// This will forbid any item on the *right* of this one, whose right precedence
25    /// levels do not meet the threshold for this field.
26    pub(crate) forbidden_right: Vec<Option<PrecedenceLevel>>,
27}
28
29impl PrecedenceAnnotations {
30    pub(super) const fn new() -> Self {
31        Self {
32            forbidden_left: Vec::new(),
33            forbidden_right: Vec::new(),
34        }
35    }
36
37    /// Returns `true` if it does not contain any annotations.
38    pub(crate) fn is_empty(&self) -> bool {
39        self.forbidden_left.is_empty() && self.forbidden_right.is_empty()
40    }
41
42    /// One should be left, the other right.
43    ///
44    /// They are compatible if for every non-`None` `level` in `current_precendences`,
45    /// the `next_level` at the same index in `next_precendences` is `None`, or equal or
46    /// greater than `level`.
47    pub(crate) fn compatible_with(
48        current_precendences: &[Option<PrecedenceLevel>],
49        next_precendences: &[Option<PrecedenceLevel>],
50    ) -> bool {
51        for (&level, &next_level) in current_precendences.iter().zip(next_precendences) {
52            match (level, next_level) {
53                (Some(level), Some(next_level)) if level > next_level => return false,
54                _ => {}
55            }
56        }
57        true
58    }
59
60    /// Merge `annotations` into `self_annotations`, increasing the precedence levels.
61    ///
62    /// Returns `true` if `self_annotations` was changed.
63    pub(super) fn merge_increasing(
64        self_annotations: &mut Vec<Option<PrecedenceLevel>>,
65        annotations: &[Option<PrecedenceLevel>],
66    ) -> bool {
67        if self_annotations.len() < annotations.len() {
68            self_annotations.resize(annotations.len(), None);
69        }
70        let mut modified = false;
71        for (self_level, level) in self_annotations.iter_mut().zip(annotations) {
72            let level = match *level {
73                Some(l) => l,
74                None => continue,
75            };
76            match self_level {
77                Some(l) if *l < level => {
78                    modified = true;
79                    *l = level
80                }
81                None => {
82                    modified = true;
83                    *self_level = Some(level)
84                }
85                _ => {}
86            }
87        }
88        modified
89    }
90}