Skip to main content

veryl_analyzer/
namespace.rs

1use crate::attribute::Attribute;
2use crate::attribute_table;
3use crate::namespace_table;
4use crate::symbol::Symbol;
5use crate::symbol::SymbolKind;
6use crate::symbol_path::SymbolPath;
7use crate::symbol_table;
8use crate::{HashMap, SVec, svec};
9use std::collections::BTreeSet;
10use std::fmt;
11use veryl_parser::resource_table::{self, StrId};
12use veryl_parser::veryl_token::{Token, VerylToken};
13
14#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
15pub struct DefineContext {
16    pos: BTreeSet<StrId>,
17    neg: BTreeSet<StrId>,
18}
19
20impl DefineContext {
21    pub fn exclusive(&self, value: &DefineContext) -> bool {
22        !self.pos.is_disjoint(&value.neg) || !self.neg.is_disjoint(&value.pos)
23    }
24
25    pub fn is_default(&self) -> bool {
26        self.pos.is_empty()
27    }
28}
29
30impl From<Token> for DefineContext {
31    fn from(token: Token) -> Self {
32        let attrs = attribute_table::get(&token);
33        attrs.as_slice().into()
34    }
35}
36
37impl From<&VerylToken> for DefineContext {
38    fn from(token: &VerylToken) -> Self {
39        let attrs = attribute_table::get(&token.token);
40        attrs.as_slice().into()
41    }
42}
43
44impl From<&[Attribute]> for DefineContext {
45    fn from(value: &[Attribute]) -> Self {
46        let mut ret = DefineContext::default();
47        for x in value {
48            match x {
49                Attribute::Ifdef(x) => {
50                    ret.pos.insert(*x);
51                }
52                Attribute::Ifndef(x) => {
53                    ret.neg.insert(*x);
54                }
55                Attribute::Elsif(x, y, z) => {
56                    ret.pos.insert(*x);
57                    for y in y {
58                        ret.pos.insert(*y);
59                    }
60                    for z in z {
61                        ret.neg.insert(*z);
62                    }
63                }
64                Attribute::Else(x, y) => {
65                    for x in x {
66                        ret.pos.insert(*x);
67                    }
68                    for y in y {
69                        ret.neg.insert(*y);
70                    }
71                }
72                _ => (),
73            }
74        }
75        ret
76    }
77}
78
79impl fmt::Display for DefineContext {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        let mut text = String::new();
82        for x in &self.pos {
83            text.push_str(&format!("+{x}"));
84        }
85        for x in &self.neg {
86            text.push_str(&format!("-{x}"));
87        }
88        text.fmt(f)
89    }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Hash)]
93pub struct Namespace {
94    pub paths: SVec<StrId>,
95    pub define_context: DefineContext,
96}
97
98impl Namespace {
99    pub fn new() -> Self {
100        Self {
101            paths: SVec::new(),
102            define_context: DefineContext::default(),
103        }
104    }
105
106    pub fn push(&mut self, path: StrId) {
107        self.paths.push(resource_table::canonical_str_id(path));
108    }
109
110    pub fn pop(&mut self) -> Option<StrId> {
111        self.paths.pop()
112    }
113
114    pub fn depth(&self) -> usize {
115        self.paths.len()
116    }
117
118    pub fn included(&self, x: &Namespace) -> bool {
119        let exclusive = self.define_context.exclusive(&x.define_context);
120        for (i, x) in x.paths.iter().enumerate() {
121            if let Some(path) = self.paths.get(i) {
122                if path != x {
123                    return false;
124                }
125            } else {
126                return false;
127            }
128        }
129        !exclusive
130    }
131
132    pub fn matched(&self, x: &Namespace) -> bool {
133        if self.paths.len() != x.paths.len() {
134            false
135        } else {
136            self.included(x)
137        }
138    }
139
140    pub fn replace(&self, table: &HashMap<StrId, StrId>) -> Self {
141        let mut paths = SVec::new();
142        for x in &self.paths {
143            if let Some(x) = table.get(x) {
144                paths.push(*x);
145            } else {
146                paths.push(*x);
147            }
148        }
149        Self {
150            paths,
151            define_context: self.define_context.clone(),
152        }
153    }
154
155    pub fn strip_prefix(&mut self, x: &Namespace) {
156        let mut paths = svec![];
157        for (i, p) in self.paths.iter().enumerate() {
158            if x.paths.get(i) != Some(p) {
159                paths.push(*p);
160            }
161        }
162        self.paths = paths;
163    }
164
165    pub fn strip_anonymous_path(&mut self) {
166        self.paths.retain(|x| x.to_string().find('@').is_none());
167    }
168
169    pub fn get_symbol(&self) -> Option<Symbol> {
170        let mut namespace = self.clone();
171        namespace.strip_anonymous_path();
172
173        if let Some(path) = namespace.pop()
174            && namespace.depth() >= 1
175        {
176            symbol_table::resolve((path, &namespace))
177                .map(|x| (*x.found).clone())
178                .ok()
179        } else {
180            None
181        }
182    }
183
184    pub fn generic_namespace(&self) -> Self {
185        let mut ret = Namespace::new();
186        for i in 0..self.depth() {
187            let path = self.paths[i];
188            if i == 0 || !path.to_string().starts_with("__") {
189                ret.push(path);
190            } else if let Ok(symbol) = symbol_table::resolve((path, &ret))
191                && let SymbolKind::GenericInstance(inst) = &symbol.found.kind
192            {
193                let base = inst.base_symbol();
194                ret.push(base.token.text);
195            }
196        }
197        ret
198    }
199}
200
201impl Default for Namespace {
202    fn default() -> Self {
203        namespace_table::get_default()
204    }
205}
206
207impl fmt::Display for Namespace {
208    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209        let mut text = String::new();
210        if let Some(first) = self.paths.first() {
211            text.push_str(&format!("{first}"));
212            for path in &self.paths[1..] {
213                text.push_str(&format!("::{path}"));
214            }
215        }
216        text.push_str(&self.define_context.to_string());
217        text.fmt(f)
218    }
219}
220
221impl From<&SymbolPath> for Namespace {
222    fn from(value: &SymbolPath) -> Self {
223        let mut paths = SVec::new();
224        for x in value.as_slice() {
225            paths.push(*x);
226        }
227        Namespace {
228            paths,
229            define_context: DefineContext::default(),
230        }
231    }
232}
233
234impl From<&[StrId]> for Namespace {
235    fn from(value: &[StrId]) -> Self {
236        Namespace {
237            paths: value.into(),
238            define_context: DefineContext::default(),
239        }
240    }
241}
242
243impl From<&str> for Namespace {
244    fn from(value: &str) -> Self {
245        let mut paths = SVec::new();
246        for x in value.split("::") {
247            paths.push(x.into());
248        }
249        Namespace {
250            paths,
251            define_context: DefineContext::default(),
252        }
253    }
254}
255
256#[cfg(test)]
257mod tests {
258    use super::*;
259
260    #[test]
261    fn define_context() {
262        let mut a = DefineContext::default();
263        a.pos.insert(StrId(0));
264        a.pos.insert(StrId(1));
265        a.neg.insert(StrId(2));
266        let mut b = DefineContext::default();
267        b.pos.insert(StrId(2));
268
269        assert!(a.exclusive(&b));
270
271        let mut a = DefineContext::default();
272        a.pos.insert(StrId(0));
273        a.pos.insert(StrId(1));
274        a.neg.insert(StrId(2));
275        let mut b = DefineContext::default();
276        b.pos.insert(StrId(1));
277
278        assert!(!a.exclusive(&b));
279
280        let mut a = DefineContext::default();
281        a.pos.insert(StrId(0));
282        a.pos.insert(StrId(1));
283        a.neg.insert(StrId(2));
284        let mut b = DefineContext::default();
285        b.neg.insert(StrId(0));
286
287        assert!(a.exclusive(&b));
288
289        let a = DefineContext::default();
290        let b = DefineContext::default();
291
292        assert!(!a.exclusive(&b));
293    }
294}