Skip to main content

rib/type_checker/
path.rs

1use std::fmt;
2use std::fmt::Display;
3
4#[derive(Clone, Debug, Default, PartialEq)]
5pub struct Path(Vec<PathElem>);
6
7impl Path {
8    pub fn is_empty(&self) -> bool {
9        self.0.is_empty()
10    }
11
12    pub fn current(&self) -> Option<&PathElem> {
13        self.0.first()
14    }
15
16    pub fn progress(&mut self) {
17        if !self.0.is_empty() {
18            self.0.remove(0);
19        }
20    }
21
22    pub fn from_elem(elem: PathElem) -> Self {
23        Path(vec![elem])
24    }
25
26    pub fn from_elems(elems: Vec<&str>) -> Self {
27        Path(
28            elems
29                .iter()
30                .map(|x| PathElem::Field(x.to_string()))
31                .collect(),
32        )
33    }
34
35    pub fn push_front(&mut self, elem: PathElem) {
36        self.0.insert(0, elem);
37    }
38
39    pub fn push_back(&mut self, elem: PathElem) {
40        self.0.push(elem);
41    }
42}
43
44pub enum PathType {
45    RecordPath(Path),
46    IndexPath(Path),
47}
48
49impl PathType {
50    pub fn from_path(path: &Path) -> Option<PathType> {
51        if path.0.first().map(|elem| elem.is_field()).unwrap_or(false) {
52            Some(PathType::RecordPath(path.clone()))
53        } else if path.0.first().map(|elem| elem.is_index()).unwrap_or(false) {
54            Some(PathType::IndexPath(path.clone()))
55        } else {
56            None
57        }
58    }
59}
60
61impl Display for Path {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        let mut is_first = true;
64
65        for elem in &self.0 {
66            match elem {
67                PathElem::Field(name) => {
68                    if is_first {
69                        write!(f, "{name}")?;
70                        is_first = false;
71                    } else {
72                        write!(f, ".{name}")?;
73                    }
74                }
75                PathElem::Index(index) => {
76                    if is_first {
77                        write!(f, "index: {index}")?;
78                        is_first = false;
79                    } else {
80                        write!(f, "[{index}]")?;
81                    }
82                }
83            }
84        }
85        Ok(())
86    }
87}
88
89#[derive(Clone, Debug, PartialEq)]
90pub enum PathElem {
91    Field(String),
92    Index(usize),
93}
94
95impl PathElem {
96    pub fn is_field(&self) -> bool {
97        matches!(self, PathElem::Field(_))
98    }
99
100    pub fn is_index(&self) -> bool {
101        matches!(self, PathElem::Index(_))
102    }
103}