Skip to main content

veryl_analyzer/
analyzer.rs

1use crate::analyzer_error::AnalyzerError;
2use crate::attribute_table;
3use crate::conv::{Context, Conv};
4use crate::generic_inference_table;
5use crate::handlers::*;
6use crate::ir::{Ir, IrResult};
7use crate::msb_table;
8use crate::namespace::Namespace;
9use crate::namespace_table;
10use crate::reference_table;
11use crate::resolved_type_table;
12use crate::symbol::{DocComment, Symbol, SymbolKind};
13use crate::symbol_table;
14use crate::type_dag;
15use veryl_metadata::{Build, Lint, Metadata};
16use veryl_parser::resource_table::{self, StrId};
17use veryl_parser::veryl_grammar_trait::*;
18use veryl_parser::veryl_token::{Token, TokenSource};
19use veryl_parser::veryl_walker::{Handler, VerylWalker};
20
21pub struct AnalyzerPass1 {
22    handlers: Pass1Handlers,
23}
24
25impl AnalyzerPass1 {
26    pub fn new(build_opt: &Build, lint_opt: &Lint, is_dependency: bool) -> Self {
27        AnalyzerPass1 {
28            handlers: Pass1Handlers::new(build_opt, lint_opt, is_dependency),
29        }
30    }
31}
32
33impl VerylWalker for AnalyzerPass1 {
34    fn get_handlers(&mut self) -> Option<Vec<&mut dyn Handler>> {
35        Some(self.handlers.get_handlers())
36    }
37}
38
39pub struct Analyzer {
40    project_name: String,
41    build_opt: Build,
42    lint_opt: Lint,
43}
44
45fn insert_namespace_symbol(name: &str, public: bool) -> StrId {
46    let token = Token::new(name, 0, 0, 0, 0, TokenSource::External);
47    let symbol = Symbol::new(
48        &token,
49        SymbolKind::Namespace,
50        &Namespace::new(),
51        public,
52        DocComment::default(),
53    );
54    symbol_table::insert(&token, symbol);
55    token.text
56}
57
58impl Analyzer {
59    pub fn new(metadata: &Metadata) -> Self {
60        insert_namespace_symbol(&metadata.project.name, true);
61        for locks in metadata.lockfile.lock_table.values() {
62            for lock in locks {
63                let prj = insert_namespace_symbol(&lock.name, lock.visible);
64                for lock_dep in &lock.dependencies {
65                    let from = resource_table::insert_str(&lock_dep.name);
66                    let to = metadata
67                        .lockfile
68                        .lock_table
69                        .get(&lock_dep.source.to_url())
70                        .unwrap();
71
72                    let to = to.iter().find(|x| x.source == lock_dep.source).unwrap();
73                    let to = insert_namespace_symbol(&to.name, to.visible);
74                    symbol_table::add_project_local(prj, from, to);
75                }
76            }
77        }
78        Analyzer {
79            project_name: metadata.project.name.clone(),
80            build_opt: metadata.build.clone(),
81            lint_opt: metadata.lint.clone(),
82        }
83    }
84
85    pub fn analyze_pass1(&self, project_name: &str, input: &Veryl) -> Vec<AnalyzerError> {
86        let mut ret = Vec::new();
87
88        let is_dependency = project_name != self.project_name;
89        namespace_table::set_project(project_name.into(), !is_dependency);
90        let mut pass1 = AnalyzerPass1::new(&self.build_opt, &self.lint_opt, is_dependency);
91        pass1.veryl(input);
92        ret.append(&mut pass1.handlers.get_errors());
93
94        ret
95    }
96
97    pub fn analyze_post_pass1() -> Vec<AnalyzerError> {
98        let mut ret = Vec::new();
99
100        symbol_table::apply_import();
101        symbol_table::resolve_user_defined();
102        symbol_table::resolve_function();
103        ret.append(&mut symbol_table::resolve_enum());
104        ret.append(&mut symbol_table::apply_bind());
105        ret.append(&mut symbol_table::apply_msb());
106        ret.append(&mut symbol_table::apply_connect());
107        generic_inference_table::resolve_pending();
108        ret.append(&mut reference_table::apply());
109        ret.append(&mut type_dag::apply());
110
111        ret
112    }
113
114    fn create_ir(context: &mut Context, input: &Veryl) -> (Ir, Vec<AnalyzerError>) {
115        let ir: IrResult<Ir> = Conv::conv(context, input);
116
117        if let Ok(ir) = ir {
118            ir.eval_assign(context);
119            let errors = context.drain_errors();
120            (ir, errors)
121        } else {
122            let errors = context.drain_errors();
123            (Ir::default(), errors)
124        }
125    }
126
127    pub fn analyze_pass2(
128        &self,
129        project_name: &str,
130        input: &Veryl,
131        context: &mut Context,
132        ir: Option<&mut Ir>,
133    ) -> Vec<AnalyzerError> {
134        let mut ret = Vec::new();
135
136        context.config.retain_component_body = ir.is_some();
137        context.config.instance_depth_limit = self.build_opt.instance_depth_limit;
138        context.config.instance_total_limit = self.build_opt.instance_total_limit;
139        context.config.evaluate_size_limit = self.build_opt.evaluate_size_limit;
140        context.config.evaluate_array_limit = self.build_opt.evaluate_array_limit;
141
142        namespace_table::set_default(&[project_name.into()]);
143        let mut ir_result = Self::create_ir(context, input);
144        if let Some(x) = ir {
145            x.append(&mut ir_result.0);
146        }
147        ret.append(&mut ir_result.1);
148
149        ret
150    }
151
152    pub fn analyze_post_pass2() -> Vec<AnalyzerError> {
153        let mut ret = Vec::new();
154
155        ret.append(&mut symbol_table::check_unused_variable());
156        ret.append(&mut symbol_table::check_wavedrom());
157
158        ret
159    }
160
161    pub fn clear(&self) {
162        attribute_table::clear();
163        msb_table::clear();
164        namespace_table::clear();
165        symbol_table::clear();
166        type_dag::clear();
167        resolved_type_table::clear();
168        generic_inference_table::clear();
169    }
170}