prqlc_parser/parser/pr/
ident.rs

1use std::fmt::Write;
2
3use schemars::JsonSchema;
4use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
5
6/// A name. Generally columns, tables, functions, variables.
7/// This is glorified way of writing a "vec with at least one element".
8#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, JsonSchema)]
9pub struct Ident {
10    pub path: Vec<String>,
11    pub name: String,
12}
13
14impl Ident {
15    pub fn from_name<S: ToString>(name: S) -> Self {
16        Ident {
17            path: Vec::new(),
18            name: name.to_string(),
19        }
20    }
21
22    /// Creates a new ident from a non-empty path.
23    ///
24    /// Panics if path is empty.
25    pub fn from_path<S: ToString>(mut path: Vec<S>) -> Self {
26        let name = path.pop().unwrap().to_string();
27        Ident {
28            path: path.into_iter().map(|x| x.to_string()).collect(),
29            name,
30        }
31    }
32
33    pub fn len(&self) -> usize {
34        self.path.len() + 1
35    }
36
37    pub fn is_empty(&self) -> bool {
38        false
39    }
40
41    /// Remove last part of the ident.
42    /// Result will generally refer to the parent of this ident.
43    pub fn pop(self) -> Option<Self> {
44        let mut path = self.path;
45        path.pop().map(|name| Ident { path, name })
46    }
47
48    pub fn pop_front(mut self) -> (String, Option<Ident>) {
49        if self.path.is_empty() {
50            (self.name, None)
51        } else {
52            let first = self.path.remove(0);
53            (first, Some(self))
54        }
55    }
56
57    pub fn prepend(self, mut parts: Vec<String>) -> Ident {
58        parts.extend(self);
59        Ident::from_path(parts)
60    }
61
62    pub fn push(&mut self, name: String) {
63        self.path.push(std::mem::take(&mut self.name));
64        self.name = name;
65    }
66
67    pub fn with_name<S: ToString>(mut self, name: S) -> Self {
68        self.name = name.to_string();
69        self
70    }
71
72    pub fn iter(&self) -> impl Iterator<Item = &String> {
73        self.path.iter().chain(std::iter::once(&self.name))
74    }
75
76    pub fn starts_with(&self, prefix: &Ident) -> bool {
77        if prefix.len() > self.len() {
78            return false;
79        }
80        prefix
81            .iter()
82            .zip(self.iter())
83            .all(|(prefix_component, self_component)| prefix_component == self_component)
84    }
85
86    pub fn starts_with_path<S: AsRef<str>>(&self, prefix: &[S]) -> bool {
87        // self is an I
88        if prefix.len() > self.len() {
89            return false;
90        }
91        prefix
92            .iter()
93            .zip(self.iter())
94            .all(|(prefix_component, self_component)| prefix_component.as_ref() == self_component)
95    }
96
97    pub fn starts_with_part(&self, prefix: &str) -> bool {
98        self.starts_with_path(&[prefix])
99    }
100}
101
102impl std::fmt::Debug for Ident {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        f.debug_list()
105            .entries(&self.path)
106            .entry(&self.name)
107            .finish()
108    }
109}
110
111impl std::fmt::Display for Ident {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        display_ident(f, self)
114    }
115}
116
117impl IntoIterator for Ident {
118    type Item = String;
119    type IntoIter = std::iter::Chain<
120        std::vec::IntoIter<std::string::String>,
121        std::option::IntoIter<std::string::String>,
122    >;
123
124    fn into_iter(self) -> Self::IntoIter {
125        self.path.into_iter().chain(Some(self.name))
126    }
127}
128
129impl std::ops::Add<Ident> for Ident {
130    type Output = Ident;
131
132    fn add(self, rhs: Ident) -> Self::Output {
133        Ident {
134            path: self.into_iter().chain(rhs.path).collect(),
135            name: rhs.name,
136        }
137    }
138}
139
140impl Serialize for Ident {
141    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
142    where
143        S: Serializer,
144    {
145        let mut seq = serializer.serialize_seq(Some(self.len()))?;
146        for part in &self.path {
147            seq.serialize_element(part)?;
148        }
149        seq.serialize_element(&self.name)?;
150        seq.end()
151    }
152}
153
154impl<'de> Deserialize<'de> for Ident {
155    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
156    where
157        D: Deserializer<'de>,
158    {
159        <Vec<String> as Deserialize>::deserialize(deserializer).map(Ident::from_path)
160    }
161}
162
163pub fn display_ident(f: &mut std::fmt::Formatter, ident: &Ident) -> Result<(), std::fmt::Error> {
164    let path = &ident.path[..];
165
166    for part in path {
167        display_ident_part(f, part)?;
168        f.write_char('.')?;
169    }
170    display_ident_part(f, &ident.name)?;
171    Ok(())
172}
173
174pub fn display_ident_part(f: &mut std::fmt::Formatter, s: &str) -> Result<(), std::fmt::Error> {
175    fn forbidden_start(c: char) -> bool {
176        !(c.is_ascii_alphabetic() || matches!(c, '_' | '$'))
177    }
178    fn forbidden_subsequent(c: char) -> bool {
179        !(c.is_ascii_alphabetic() || c.is_ascii_digit() || c == '_')
180    }
181    let needs_escape = s.is_empty()
182        || s.starts_with(forbidden_start)
183        || (s.len() > 1 && s.chars().skip(1).any(forbidden_subsequent));
184
185    if needs_escape {
186        write!(f, "`{s}`")
187    } else {
188        write!(f, "{s}")
189    }
190}