open_vaf/ast_lowering/
name_resolution.rs

1/*
2 * ******************************************************************************************
3 * Copyright (c) 2019 Pascal Kuthe. This file is part of the OpenVAF project.
4 * It is subject to the license terms in the LICENSE file found in the top-level directory
5 *  of this distribution and at  https://gitlab.com/DSPOM/OpenVAF/blob/master/LICENSE.
6 *  No part of OpenVAF, including this file, may be copied, modified, propagated, or
7 *  distributed except according to the terms contained in the LICENSE file.
8 * *****************************************************************************************
9 */
10
11use crate::ast::HierarchicalId;
12use crate::ast_lowering::error::Type::NotAScope;
13use crate::ast_lowering::error::*;
14#[doc(inline)]
15pub use crate::resolve;
16#[doc(inline)]
17pub use crate::resolve_hierarchical;
18use crate::symbol::Ident;
19use crate::symbol_table::{SymbolDeclaration, SymbolTable};
20use crate::Ast;
21
22/// A macro that hides the boiler plate required for name resolution using the resolver struct
23/// It is defined in the [`name_resolution`](crate::ast_lowering::name_resolution) module but due to limitations of rustdoc can't be shown there in the documentation
24/// If `$name` wasn't found or doesn't math any [`SymbolDeclaration`](crate::symbol_table::SymbolDeclaration)::`$declaration` the appropriate errors are added to `$self`.errors and execution continuous after the macro
25///
26/// # Arguments
27///
28/// * `$self` - reference to an ast fold (implementation of the [`Fold`](crate::ast_lowering::ast_to_hir_fold::Fold) trait)
29///
30/// * `$name` - The Identifier (type [`Ident`](crate::symbol::Ident)) that should be resolved
31///
32/// The following three arguments can be repeated as often as necessary (like in a match block)
33///
34/// * `$declaration` An identifier of an [`SymbolDeclaration`](crate::symbol_table::SymbolDeclaration) variant which you wish to resolve `$name`as
35///
36/// * `$id` The identifier under which the ID of the resolved declaration will be available inside the associated `$block
37///
38/// * `$block` A block (`{`statements`}`) which will be executed when `$name` is resolved as a [`SymbolDeclaration`](crate::symbol_table::SymbolDeclaration)::`$declaration`  
39///
40/// # Examples
41///
42/// The following tries to resolve ident as a Nature
43/// ```
44/// use OpenVAF::symbol_table::SymbolDeclaration::Nature;
45/// use OpenVAF::symbol_table::SymbolDeclaration::Discipline;
46///
47/// resolve!(fold; ident as
48///            Nature(id) => {
49///                 println!("Resolved nature")
50///             }
51///             Discipline(id) => {
52///                 println!("Resolved a discipline")
53///             }
54/// );
55///
56/// println!("Not found or not a discipline/nature")
57/// ```
58#[doc(inline)]
59#[macro_export]
60macro_rules! resolve {
61    ($fold:expr; $name:ident as $($declaration:ident($id:ident) => $block:block),+) => {
62        match $fold.resolver.resolve(&$name) {
63            $(Ok($crate::symbol_table::SymbolDeclaration::$declaration($id)) => $block),+
64            Err(error) => {
65                $fold.error(error);
66            }
67            Ok(found) => {
68                use $crate::ast_lowering::error;
69                $fold.error(Error {
70                    error_type: error::Type::DeclarationTypeMismatch {
71                        found,
72                        expected: vec![$(error::MockSymbolDeclaration::$declaration),+],
73                    },
74                    source: $name.span,
75                });
76            }
77        }
78    };
79}
80/// A macro that hides the boiler plate required for name resolution of hieraichal Identifiers using the resolver struct
81/// It is defined in the [`name_resolution`](crate::ast_lowering::name_resolution) module but due to limitations of rustdoc can't be shown there in the documentation   
82/// If `$name` wasn't found or doesn't math any [`SymbolDeclaration`](crate::symbol_table::SymbolDeclaration)::`$declaration` the appropriate errors are added to `$self`.errors and execution continuous after the macro
83///
84/// # Arguments
85///
86/// * `$fold` - identifer refering to an [`Fold`](crate::ast_lowering::ast_to_hir_fold::Fold) instance
87///
88/// * `$name` - The Identifier (type [`Ident`](crate::symbol::Ident)) that should be resolved
89///
90/// The following three arguments can be repeated as often as necessary (like in a match block)
91///
92/// * `$declaration` An identifier of an [`SymbolDeclaration`](crate::symbol_table::SymbolDeclaration) variant which you wish to resolve `$name`as
93///
94/// * `$id` The identifier under which the ID of the resolved declaration will be available inside the associated `$block
95///
96/// * `$block` A block (`{`statements`}`) which will be executed when `$name` is resolved as a [`SymbolDeclaration`](crate::symbol_table::SymbolDeclaration)::`$declaration`  
97///
98/// # Examples
99///
100/// The following tries to resolve ident as a Nature
101/// ```
102/// use OpenVAF::symbol_table::SymbolDeclaration::Net;
103/// use OpenVAF::symbol_table::SymbolDeclaration::Port;
104///
105/// resolve_hierarchical!(fold; ident as
106///            Net(id) => {
107///                 print!("Resolved net")
108///            }
109///            Port(id) => {
110///                 print!("Resolved port")
111///            }
112/// );
113///
114/// println!("Not found or not a port/net")
115/// ```
116#[macro_export]
117macro_rules! resolve_hierarchical {
118    ($fold:expr; $name:ident as  $($declaration:ident($id:ident) => $block:block),+) => {
119        match $fold.resolver.resolve_hierarchical($name) {
120            $(Ok($crate::symbol_table::SymbolDeclaration::$declaration($id)) => $block),+
121            Err(error) => {
122                $fold.error(error);
123            }
124            Ok(found) => {
125                use $crate::ast_lowering::error::*;
126                $fold.error(Error {
127                    error_type: Type::DeclarationTypeMismatch {
128                        found,
129                        expected:  vec![$(MockSymbolDeclaration::$declaration),+],
130                    },
131                    source: $name.span(),
132                });
133            }
134        }
135    };
136}
137
138/// Allows name resolution with the [`resolve`](crate::ast_lowering::name_resolution::Resolver::resolve)/[`resolve_hierarchical`](crate::ast_lowering::name_resolution::Resolver::resolve_hierarchical) methods
139pub struct Resolver<'lt> {
140    pub scope_stack: Vec<&'lt SymbolTable>,
141    ast: &'lt Ast,
142    inside_function: bool,
143}
144
145impl<'lt> Resolver<'lt> {
146    pub fn new(ast: &'lt Ast) -> Self {
147        Self {
148            scope_stack: Vec::with_capacity(8),
149            ast,
150            inside_function: false,
151        }
152    }
153
154    pub fn enter_function(&mut self, function_symbol_table: &'lt SymbolTable) {
155        debug_assert!(!self.inside_function, "Already inside a function!");
156        self.inside_function = true;
157        self.enter_scope(function_symbol_table);
158    }
159
160    pub fn exit_function(&mut self) -> Option<&'lt SymbolTable> {
161        debug_assert!(self.inside_function, "Not yet inside a function!");
162        self.inside_function = false;
163        self.exit_scope()
164    }
165
166    /// Tries to resolve the Identifier `ident`
167    ///
168    /// This functions first tries to find `ident in the current scope, then in the previous scope and so on
169    /// If it can't find ident in the global (first) Scope it returns an NotFound Error
170    pub fn resolve(&self, ident: &Ident) -> Result<SymbolDeclaration> {
171        let mut depth = 0;
172        for scope in self.scope_stack.iter().rev() {
173            if let Some(res) = scope.get(&ident.name) {
174                if self.inside_function
175                    && depth > 0
176                    && !matches!(res,SymbolDeclaration::Parameter(_)|SymbolDeclaration::Module(_))
177                {
178                    return Err(Error {
179                        error_type: Type::NotAllowedInFunction(
180                            NotAllowedInFunction::NonLocalAccess,
181                        ),
182                        source: ident.span,
183                    });
184                }
185                return Ok(*res);
186            }
187            depth += 1;
188        }
189        Err(Error {
190            error_type: Type::NotFound(ident.name),
191            source: ident.span,
192        })
193    }
194
195    /// Tries to resolve the Hierarchical Identifer `hierarchical_ident`
196    ///
197    /// This functions tires to resolve the first identifier using the [`resolve`](crate::ast_lowering::name_resolution::Resolver::resolve) function
198    /// Afterwards it tries to resolve all following identifier inside the scope of the previously resolved Identifier
199    pub fn resolve_hierarchical(
200        &self,
201        hierarchical_ident: &HierarchicalId,
202    ) -> Result<SymbolDeclaration> {
203        let mut identifiers = hierarchical_ident.names.iter();
204
205        let (mut current_span, mut current_declaration) = {
206            let first_ident = identifiers.next().unwrap();
207            (first_ident.span, self.resolve(first_ident)?)
208        };
209
210        for ident in identifiers {
211            let symbol_table = match current_declaration {
212                SymbolDeclaration::Module(module) => &self.ast[module].contents.symbol_table,
213
214                SymbolDeclaration::Block(_) if self.inside_function => {
215                    return Err(Error {
216                        error_type: Type::NotAllowedInFunction(
217                            NotAllowedInFunction::NonLocalAccess,
218                        ),
219                        source: current_span,
220                    });
221                }
222
223                SymbolDeclaration::Block(block_id) => {
224                    if let Some(scope) = &self.ast[block_id].contents.scope {
225                        &scope.symbols
226                    } else {
227                        return Err(Error {
228                            error_type: Type::NotFound(ident.name),
229                            source: current_span,
230                        });
231                    }
232                }
233
234                item_without_scope => {
235                    return Err(Error {
236                        error_type: NotAScope {
237                            declaration: item_without_scope.span(self.ast),
238                            name: item_without_scope.name(self.ast),
239                        },
240                        source: current_span,
241                    });
242                }
243            };
244
245            if let Some(found) = symbol_table.get(&ident.name) {
246                current_declaration = *found;
247                current_span = found.span(self.ast);
248                if self.inside_function
249                    && !matches!(found,SymbolDeclaration::Parameter(_)|SymbolDeclaration::Module(_))
250                {
251                    return Err(Error {
252                        error_type: Type::NotAllowedInFunction(
253                            NotAllowedInFunction::NonLocalAccess,
254                        ),
255                        source: ident.span,
256                    });
257                }
258            } else {
259                return Err(Error {
260                    error_type: Type::NotFound(ident.name),
261                    source: ident.span,
262                });
263            }
264        }
265
266        Ok(current_declaration)
267    }
268    /// Enter a new Scope
269    ///
270    /// This scope will be the first to be searched for identifiers until it is overshadowed by another enter_scope call or it is removed using [`exit_scope`](crate::ast_lowering::name_resolution::Resolver::exit_scope)
271    ///
272    /// # Arguments
273    /// * `scope_symbol_table` - Symbol table in which the resolver will look for definitions in this scope
274    pub fn enter_scope(&mut self, scope_symbol_table: &'lt SymbolTable) {
275        self.scope_stack.push(scope_symbol_table)
276    }
277    /// Leave the current Scope
278    ///
279    /// Items defined in the current scope will not be resolved anymore by this resolver after this method has been called
280    ///
281    /// # Returns
282    ///
283    /// * None if the Resolver doesn't hold any Scopes
284    /// * The Symbol_Table of the removed Scope
285    pub fn exit_scope(&mut self) -> Option<&'lt SymbolTable> {
286        self.scope_stack.pop()
287    }
288}