rib/type_checker/
path.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt;
16use std::fmt::Display;
17
18#[derive(Clone, Debug, Default, PartialEq)]
19pub struct Path(Vec<PathElem>);
20
21impl Path {
22    pub fn is_empty(&self) -> bool {
23        self.0.is_empty()
24    }
25
26    pub fn current(&self) -> Option<&PathElem> {
27        self.0.first()
28    }
29
30    pub fn progress(&mut self) {
31        if !self.0.is_empty() {
32            self.0.remove(0);
33        }
34    }
35
36    pub fn from_elem(elem: PathElem) -> Self {
37        Path(vec![elem])
38    }
39
40    pub fn from_elems(elems: Vec<&str>) -> Self {
41        Path(
42            elems
43                .iter()
44                .map(|x| PathElem::Field(x.to_string()))
45                .collect(),
46        )
47    }
48
49    pub fn push_front(&mut self, elem: PathElem) {
50        self.0.insert(0, elem);
51    }
52
53    pub fn push_back(&mut self, elem: PathElem) {
54        self.0.push(elem);
55    }
56}
57
58pub enum PathType {
59    RecordPath(Path),
60    IndexPath(Path),
61}
62
63impl PathType {
64    pub fn from_path(path: &Path) -> Option<PathType> {
65        if path.0.first().map(|elem| elem.is_field()).unwrap_or(false) {
66            Some(PathType::RecordPath(path.clone()))
67        } else if path.0.first().map(|elem| elem.is_index()).unwrap_or(false) {
68            Some(PathType::IndexPath(path.clone()))
69        } else {
70            None
71        }
72    }
73}
74
75impl Display for Path {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        let mut is_first = true;
78
79        for elem in &self.0 {
80            match elem {
81                PathElem::Field(name) => {
82                    if is_first {
83                        write!(f, "{name}")?;
84                        is_first = false;
85                    } else {
86                        write!(f, ".{name}")?;
87                    }
88                }
89                PathElem::Index(index) => {
90                    if is_first {
91                        write!(f, "index: {index}")?;
92                        is_first = false;
93                    } else {
94                        write!(f, "[{index}]")?;
95                    }
96                }
97            }
98        }
99        Ok(())
100    }
101}
102
103#[derive(Clone, Debug, PartialEq)]
104pub enum PathElem {
105    Field(String),
106    Index(usize),
107}
108
109impl PathElem {
110    pub fn is_field(&self) -> bool {
111        matches!(self, PathElem::Field(_))
112    }
113
114    pub fn is_index(&self) -> bool {
115        matches!(self, PathElem::Index(_))
116    }
117}