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}