open_vaf/ast_lowering/ast_to_hir_fold/
statements.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 log::*;
12
13use crate::ast::{BranchAccess, ModuleItem, ParameterType};
14use crate::ast_lowering::ast_to_hir_fold::expression::StatementExpressionFolder;
15use crate::ast_lowering::ast_to_hir_fold::{
16    DeclarationHandler, ExpressionFolder, Fold, VerilogContext,
17};
18use crate::ast_lowering::branch_resolution::BranchResolver;
19use crate::ast_lowering::error::{Error, NotAllowedInFunction, Type};
20
21use crate::hir::{Condition, Module, Statement};
22use crate::ir::hir::{DisciplineAccess, Function, FunctionArg, WhileLoop};
23use crate::ir::ids::IdRange;
24use crate::ir::NumericalParameterRangeExclude;
25use crate::ir::*;
26use crate::parser::error::Unsupported;
27use crate::symbol::Ident;
28use crate::symbol_table::SymbolDeclaration;
29use crate::{ast, Hir};
30use std::mem::take;
31
32/// The last fold folds all statements in textual order
33pub struct Statements<'lt, H: DeclarationHandler> {
34    pub(super) branch_resolver: BranchResolver,
35    pub(super) state: VerilogContext,
36    pub(super) base: Fold<'lt>,
37    pub(super) declaration_handler: &'lt mut H,
38}
39
40impl<'lt, H: DeclarationHandler> Statements<'lt, H> {
41    pub fn fold(mut self) -> Result<Hir, Vec<Error>> {
42        for module in self.base.ast.modules.iter() {
43            self.base
44                .resolver
45                .enter_scope(&module.contents.symbol_table);
46
47            for decl in module.contents.symbol_table.values().copied() {
48                match decl {
49                    SymbolDeclaration::Nature(_)
50                    | SymbolDeclaration::Module(_)
51                    | SymbolDeclaration::Discipline(_) => {
52                        unreachable_unchecked!("Parser cant create this")
53                    }
54
55                    SymbolDeclaration::Branch(_)
56                    | SymbolDeclaration::Port(_)
57                    | SymbolDeclaration::Net(_)
58                    | SymbolDeclaration::Block(_) => (), //Have already been visited or will be visited later
59
60                    SymbolDeclaration::Function(function) => self.fold_function(function),
61                    SymbolDeclaration::Variable(variable) => {
62                        self.state.insert(VerilogContext::CONSTANT);
63                        self.fold_variable(variable);
64                        self.state.remove(VerilogContext::CONSTANT);
65                    }
66                    SymbolDeclaration::Parameter(parameter) => {
67                        self.state.insert(VerilogContext::CONSTANT);
68                        self.fold_parameter(parameter);
69                        self.state.remove(VerilogContext::CONSTANT);
70                    }
71                }
72            }
73
74            let analog_stmts_start = self.base.hir.statements.len_idx();
75
76            for module_item in module.contents.children.iter() {
77                match module_item {
78                    ModuleItem::AnalogStmt(statement) => {
79                        self.fold_statement(*statement);
80                    }
81                    ModuleItem::GenerateStatement => unimplemented!("Generate Statement"),
82                }
83            }
84
85            self.base.resolver.exit_scope();
86            self.base.hir.modules.push(module.map_with(|old| Module {
87                name: old.name,
88                port_list: old.port_list.clone(),
89                analog: IdRange(analog_stmts_start..self.base.hir.statements.len_idx()),
90            }));
91        }
92
93        if self.base.errors.is_empty() {
94            Ok(self.base.hir)
95        } else {
96            Err(self.base.errors)
97        }
98    }
99
100    pub fn fold_function(&mut self, id: FunctionId) {
101        let function = &self.base.ast[id].contents;
102        let args = function
103            .args
104            .iter()
105            .filter_map(|arg| {
106                if let Some(SymbolDeclaration::Variable(local_var)) =
107                    function.declarations.get(&arg.name.name).copied()
108                {
109                    Some(FunctionArg {
110                        local_var,
111                        input: arg.input,
112                        output: arg.output,
113                    })
114                } else {
115                    self.base.errors.push(Error {
116                        error_type: Type::TypeDeclarationMissing(arg.name.name),
117                        source: arg.name.span,
118                    });
119                    None
120                }
121            })
122            .collect();
123
124        self.state.insert(VerilogContext::FUNCTION);
125        self.base.resolver.enter_function(&function.declarations);
126
127        for declaration in function.declarations.values().copied() {
128            match declaration {
129                SymbolDeclaration::Block(_) => { /*error will be generated upon encounter*/ }
130                SymbolDeclaration::Variable(var) => self.fold_variable(var),
131                SymbolDeclaration::Parameter(param) => self.fold_parameter(param),
132                SymbolDeclaration::Module(_)
133                | SymbolDeclaration::Branch(_)
134                | SymbolDeclaration::Net(_)
135                | SymbolDeclaration::Port(_)
136                | SymbolDeclaration::Function(_)
137                | SymbolDeclaration::Discipline(_)
138                | SymbolDeclaration::Nature(_) => {
139                    unreachable_unchecked!("Parser doesn't allow this")
140                }
141            }
142        }
143
144        self.fold_variable(function.return_variable);
145
146        let start = self.base.hir.statements.len_idx();
147        self.fold_statement(function.body);
148        self.base.hir[id] = self.base.ast[id].map(Function {
149            name: function.name,
150            args,
151            return_variable: function.return_variable,
152            body: IdRange(start..self.base.hir.statements.len_idx()),
153        });
154        self.base.resolver.exit_function();
155        self.state.remove(VerilogContext::FUNCTION);
156    }
157
158    /// Folds a statements. StatementIds are not stable because the amount of statements may change during this fold
159    /// The way that Statement Blocks are stored also changes. Instead of an Vec<StatementId> we switch to a Range of StatementIds
160    /// This is possible because this fold adds Statements in the order they are executed (conditions indicate themselves and their block as a statement before&after their block)
161    /// As such this function doesn't return the new StatementId instead `empty_range_from_end` and `extend_range_to_end` are used to create the range of the folded block by the calle
162    fn fold_statement(&mut self, id: StatementId) {
163        match self.base.ast[id] {
164            ast::Statement::Block(id) => {
165                if let Some(scope) = &self.base.ast[id].contents.scope {
166                    if self.state.contains(VerilogContext::FUNCTION) {
167                        self.base.error(Error {
168                            source: scope.name.span,
169                            error_type: Type::NotAllowedInFunction(
170                                NotAllowedInFunction::NamedBlocks,
171                            ),
172                        });
173                    }
174
175                    self.base.resolver.enter_scope(&scope.symbols);
176                    self.state.insert(VerilogContext::CONSTANT);
177
178                    for decl in scope.symbols.values().copied() {
179                        match decl {
180                            SymbolDeclaration::Nature(_) => unreachable_unchecked!("Natures can't be declared inside blocks so the parser won't ever place this here"),
181                            SymbolDeclaration::Module(_)=>unreachable_unchecked!("Module cant be declared inside blocks so the parser won't ever place this here"),
182                            SymbolDeclaration::Discipline(_) => unreachable_unchecked!("Discipline can't be declared inside blocks so the parser won't ever place this here"),
183                            SymbolDeclaration::Function(_) => unreachable_unchecked!("Functions can't be declared inside blocks so the parser won't ever place this here"),
184                            SymbolDeclaration::Branch(_) => unreachable_unchecked!("Functions can't be declared inside blocks so the parser won't ever place this here"),
185                            SymbolDeclaration::Block(_) => (),//Blocs are visited when the appropriate statements are reached
186                            SymbolDeclaration::Port(_) =>unreachable_unchecked!("Port can't be declared inside blocks so the parser won't ever place this here"),
187                            SymbolDeclaration::Net(_) =>unreachable_unchecked!("Net( can't be declared inside blocks so the parser won't ever place this here"),
188                            SymbolDeclaration::Variable(variableid) => {self.fold_variable(variableid);},
189                            SymbolDeclaration::Parameter(parameter_id) => {self.fold_parameter(parameter_id);},
190                        }
191                    }
192
193                    self.state.remove(VerilogContext::CONSTANT);
194                    self.fold_block(id);
195                    self.base.resolver.exit_scope();
196                } else {
197                    self.fold_block(id);
198                }
199            }
200
201            ast::Statement::Condition(ref condition) => {
202                let start = self.base.hir.statements.push(Statement::ConditionStart {
203                    condition_info_and_end: id, /*just a place holder*/
204                });
205                if let Some(contents) = self.fold_condition(&condition.contents) {
206                    let end = self
207                        .base
208                        .hir
209                        .statements
210                        .push(Statement::Condition(condition.map(contents)));
211                    self.base.hir[start] = Statement::ConditionStart {
212                        condition_info_and_end: end,
213                    };
214                }
215            }
216
217            ast::Statement::While(while_loop) => {
218                let start = self.base.hir.statements.push(Statement::WhileStart {
219                    while_info_and_start: id, //just a place holder
220                });
221
222                let condition = self.fold_expression(while_loop.contents.condition);
223                let body_start = self.base.hir.statements.len_idx();
224                self.fold_statement(while_loop.contents.body);
225                if let Some(condition) = condition {
226                    let end = self
227                        .base
228                        .hir
229                        .statements
230                        .push(Statement::While(while_loop.copy_as(WhileLoop {
231                            condition,
232                            body: IdRange(body_start..self.base.hir.statements.len_idx()),
233                        })));
234                    self.base.hir[start] = Statement::WhileStart {
235                        while_info_and_start: end,
236                    }
237                }
238            }
239
240            ast::Statement::Assign(ref attr, ref ident, value) => {
241                resolve_hierarchical!(self.base; ident as Variable(id) => {
242                    if let Some(value) = self.fold_expression(value){
243                        self.base.hir.statements.push(Statement::Assignment(*attr, id, value));
244                    }
245                })
246            }
247
248            ast::Statement::Contribute(attr, ref nature_name, ref branch, value) => {
249                if self.state.contains(VerilogContext::FUNCTION) {
250                    self.base.error(Error {
251                        source: nature_name.span.extend(self.base.ast[value].source),
252                        error_type: Type::NotAllowedInFunction(NotAllowedInFunction::Contribute),
253                    });
254                }
255
256                if let Some((discipline_access, branch, value)) =
257                    self.fold_contribute(nature_name, branch, value)
258                {
259                    self.base.hir.statements.push(Statement::Contribute(
260                        attr,
261                        discipline_access,
262                        branch,
263                        value,
264                    ));
265                }
266            }
267
268            ast::Statement::FunctionCall(attr, ref name, ref parameters) => {
269                let parameters = parameters
270                    .iter()
271                    .copied()
272                    .filter_map(|expr| self.fold_expression(expr))
273                    .collect();
274
275                resolve_hierarchical!(self.base; name as
276                        Function(fid) => {
277                            self.base.hir.statements.push(Statement::FunctionCall(attr,fid,parameters));
278                    }
279                )
280            }
281            ast::Statement::DisplayTask(_, _) => {
282                // TODO DisplayTask
283                warn!("All display task such as $display are currently ignored. Display tasks will be implemented in the future");
284            }
285        }
286    }
287
288    fn fold_contribute(
289        &mut self,
290        nature_name: &Ident,
291        branch: &Node<BranchAccess>,
292        value: ExpressionId,
293    ) -> Option<(DisciplineAccess, BranchId, ExpressionId)> {
294        let (branch, discipline) = self
295            .branch_resolver
296            .resolve_branch_access(&mut self.base, branch)?;
297
298        let nature = self.branch_resolver.resolve_discipline_access(
299            &mut self.base,
300            nature_name,
301            discipline,
302        )?;
303
304        let value = self.fold_expression(value)?;
305        Some((nature, branch, value))
306    }
307
308    /// folds a condition/if statement
309    fn fold_condition(&mut self, node: &ast::Condition) -> Option<Condition> {
310        let condition = self.fold_expression(node.condition);
311
312        let if_body_start = self.base.hir.statements.len_idx();
313
314        self.fold_statement(node.if_statement);
315        let main_condition_statements = IdRange(if_body_start..self.base.hir.statements.len_idx());
316
317        let else_statements_start = self.base.hir.statements.len_idx();
318        if let Some(statement) = node.else_statement {
319            self.fold_statement(statement);
320        }
321
322        Some(Condition {
323            condition: condition?,
324            if_statements: main_condition_statements,
325            else_statements: IdRange(else_statements_start..self.base.hir.statements.len_idx()),
326        })
327    }
328
329    /// Just a utility method that makes folding expressions a little more ergonomic
330    fn fold_expression(&mut self, expr: ExpressionId) -> Option<ExpressionId> {
331        StatementExpressionFolder {
332            state: self.state,
333            branch_resolver: &mut self.branch_resolver,
334        }
335        .fold(expr, &mut self.base)
336    }
337
338    fn fold_block(&mut self, block: BlockId) {
339        for statement in self.base.ast[block].contents.statements.iter().copied() {
340            self.fold_statement(statement);
341        }
342    }
343
344    /// Folds a variable
345    /// This is just folds the default value if it exists and just copys thre rest
346    fn fold_variable(&mut self, id: VariableId) {
347        self.base.hir[id].contents.default_value = self.base.hir[id]
348            .contents
349            .default_value
350            .and_then(|expr| self.fold_expression(expr));
351
352        self.declaration_handler
353            .handle_declaration(&mut self.base, SymbolDeclaration::Variable(id))
354    }
355
356    fn fold_parameter(&mut self, id: ParameterId) {
357        if let Some(expr) = self.fold_expression(self.base.hir[id].contents.default_value) {
358            self.base.hir[id].contents.default_value = expr
359        }
360
361        if let ParameterType::Numerical {
362            parameter_type,
363            ref mut from_ranges,
364            ref mut excluded,
365        } = self.base.hir[id].contents.parameter_type
366        {
367            let mut from_ranges = take(from_ranges);
368            let mut excluded = take(excluded);
369
370            for range in from_ranges.iter_mut() {
371                if let Some(expr) = self.fold_expression(range.start.bound) {
372                    range.start.bound = expr;
373                }
374                if let Some(expr) = self.fold_expression(range.end.bound) {
375                    range.end.bound = expr;
376                }
377            }
378
379            for exclude in excluded.iter_mut() {
380                match exclude {
381                    NumericalParameterRangeExclude::Value(val) => {
382                        if let Some(expr) = self.fold_expression(*val) {
383                            *val = expr;
384                        }
385                    }
386
387                    NumericalParameterRangeExclude::Range(range) => {
388                        if let Some(expr) = self.fold_expression(range.start.bound) {
389                            range.start.bound = expr;
390                        }
391                        if let Some(expr) = self.fold_expression(range.end.bound) {
392                            range.end.bound = expr;
393                        }
394                    }
395                }
396            }
397
398            self.base.hir[id].contents.parameter_type = ParameterType::Numerical {
399                parameter_type,
400                excluded,
401                from_ranges,
402            }
403        } else {
404            self.base.error(Error {
405                error_type: Type::Unsupported(Unsupported::StringParameters),
406                source: self.base.ast[id].source,
407            })
408        }
409
410        self.declaration_handler
411            .handle_declaration(&mut self.base, SymbolDeclaration::Parameter(id))
412    }
413}