Skip to main content

veryl_analyzer/conv/
ir.rs

1use crate::conv::checker::alias::{AliasType, check_alias_target};
2use crate::conv::checker::clock_domain::check_clock_domain;
3use crate::conv::checker::generic::check_generic_bound;
4use crate::conv::checker::proto::check_proto;
5use crate::conv::utils::check_module_with_unevaluable_generic_parameters;
6use crate::conv::{Affiliation, Context, Conv};
7use crate::ir::{self, IrResult, VarPath};
8use crate::symbol::SymbolKind;
9use crate::symbol_table;
10use crate::{HashMap, ir_error};
11use veryl_parser::token_range::TokenRange;
12use veryl_parser::veryl_grammar_trait::*;
13
14impl Conv<&Veryl> for ir::Ir {
15    fn conv(context: &mut Context, value: &Veryl) -> IrResult<Self> {
16        let mut components = vec![];
17
18        for x in &value.veryl_list {
19            let items: Vec<_> = x.description_group.as_ref().into();
20            for item in &items {
21                // ignore IrError of generic top-level components
22                let in_generic = context.in_generic;
23                if item.is_generic() {
24                    context.in_generic = true;
25                }
26
27                match item {
28                    DescriptionItem::DescriptionItemOptPublicDescriptionItem(x) => {
29                        match x.public_description_item.as_ref() {
30                            PublicDescriptionItem::ModuleDeclaration(x) => {
31                                let ret: IrResult<ir::Module> =
32                                    Conv::conv(context, x.module_declaration.as_ref());
33
34                                if let Ok(mut component) = ret {
35                                    // suppress unassigned check for modules with unevaluable generic parameters
36                                    if check_module_with_unevaluable_generic_parameters(
37                                        &x.module_declaration.identifier,
38                                    ) {
39                                        component.suppress_unassigned = true;
40                                    }
41
42                                    components.push(ir::Component::Module(component));
43                                }
44                            }
45                            PublicDescriptionItem::InterfaceDeclaration(x) => {
46                                let _: IrResult<ir::Interface> =
47                                    Conv::conv(context, x.interface_declaration.as_ref());
48                            }
49                            PublicDescriptionItem::PackageDeclaration(x) => {
50                                let _: IrResult<()> =
51                                    Conv::conv(context, x.package_declaration.as_ref());
52                            }
53                            PublicDescriptionItem::ProtoDeclaration(x) => {
54                                match x.proto_declaration.proto_declaration_group.as_ref() {
55                                    ProtoDeclarationGroup::ProtoModuleDeclaration(x) => {
56                                        let _: IrResult<ir::Module> = Conv::conv(
57                                            context,
58                                            x.proto_module_declaration.as_ref(),
59                                        );
60                                    }
61                                    ProtoDeclarationGroup::ProtoInterfaceDeclaration(x) => {
62                                        let _: IrResult<()> = Conv::conv(
63                                            context,
64                                            x.proto_interface_declaration.as_ref(),
65                                        );
66                                    }
67                                    ProtoDeclarationGroup::ProtoPackageDeclaration(x) => {
68                                        let _: IrResult<()> = Conv::conv(
69                                            context,
70                                            x.proto_package_declaration.as_ref(),
71                                        );
72                                    }
73                                }
74                            }
75                            PublicDescriptionItem::AliasDeclaration(x) => {
76                                let _: IrResult<()> =
77                                    Conv::conv(context, x.alias_declaration.as_ref());
78                            }
79                            PublicDescriptionItem::FunctionDeclaration(x) => {
80                                conv_global_function(context, x.function_declaration.as_ref());
81                            }
82                        }
83                    }
84                    DescriptionItem::BindDeclaration(x) => {
85                        let _: IrResult<()> = Conv::conv(context, x.bind_declaration.as_ref());
86                    }
87                    DescriptionItem::EmbedDeclaration(x) => {
88                        let _: IrResult<()> = Conv::conv(context, x.embed_declaration.as_ref());
89                    }
90                    DescriptionItem::ImportDeclaration(x) => {
91                        let _: IrResult<ir::DeclarationBlock> =
92                            Conv::conv(context, x.import_declaration.as_ref());
93                    }
94                    _ => (),
95                }
96
97                if item.is_generic() {
98                    context.in_generic = in_generic;
99                }
100            }
101        }
102
103        Ok(ir::Ir { components })
104    }
105}
106
107fn conv_global_function(context: &mut Context, value: &FunctionDeclaration) {
108    let upper_context = context;
109    let mut context = Context::default();
110    context.inherit(upper_context);
111
112    context.in_global_func = Some(value.identifier.identifier_token.token);
113    let _: IrResult<()> = Conv::conv(&mut context, value);
114    context.in_global_func = None;
115
116    upper_context.inherit(&mut context);
117}
118
119impl Conv<&ModuleDeclaration> for ir::Module {
120    fn conv(context: &mut Context, value: &ModuleDeclaration) -> IrResult<Self> {
121        let mut declarations = vec![];
122
123        // each top-level component has independent context
124        let upper_context = context;
125        let mut context = Context::default();
126        context.inherit(upper_context);
127
128        // pop_affiliation is not necessary because the local `context` will be dropped
129        context.push_affiliation(Affiliation::Module);
130
131        if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
132            && let SymbolKind::Module(x) = &symbol.found.kind
133        {
134            context.push_namespace(symbol.found.inner_namespace());
135            context.in_test_module = x.test.is_some();
136            if let Some(x) = x.default_clock {
137                let path = VarPath::new(symbol_table::get(x).unwrap().token.text);
138                context.set_default_clock(path, x);
139            }
140            if let Some(x) = x.default_reset {
141                let path = VarPath::new(symbol_table::get(x).unwrap().token.text);
142                context.set_default_reset(path, x);
143            }
144        } else {
145            let token: TokenRange = value.identifier.as_ref().into();
146            return Err(ir_error!(token));
147        }
148
149        if let Some(x) = &value.module_declaration_opt {
150            check_generic_bound(&mut context, &x.with_generic_parameter);
151            let items: Vec<_> = x
152                .with_generic_parameter
153                .with_generic_parameter_list
154                .as_ref()
155                .into();
156            for item in items {
157                let _ret: IrResult<()> = Conv::conv(&mut context, item);
158            }
159        }
160
161        if let Some(x) = &value.module_declaration_opt0 {
162            check_proto(&mut context, &value.identifier, &x.scoped_identifier);
163        }
164
165        if let Some(x) = &value.module_declaration_opt1
166            && let Some(x) = &x.with_parameter.with_parameter_opt
167        {
168            let items: Vec<_> = x.with_parameter_list.as_ref().into();
169            for item in items {
170                let _ret: IrResult<()> = Conv::conv(&mut context, item);
171            }
172        }
173
174        if let Some(x) = &value.module_declaration_opt2
175            && let Some(x) = &x.port_declaration.port_declaration_opt
176        {
177            let items: Vec<_> = x.port_declaration_list.as_ref().into();
178            for item in items {
179                let _ret: IrResult<()> = Conv::conv(&mut context, item);
180            }
181        }
182
183        for x in &value.module_declaration_list {
184            let items: Vec<_> = x.module_group.as_ref().into();
185            for item in &items {
186                let ret: IrResult<ir::DeclarationBlock> =
187                    Conv::conv(&mut context, item.generate_item.as_ref());
188
189                if let Ok(mut block) = ret {
190                    declarations.append(&mut block.0);
191                }
192            }
193        }
194
195        // This check must be after default clock/reset are registered in context
196        if let (Some(clock), Some(reset)) =
197            (context.get_default_clock(), context.get_default_reset())
198        {
199            check_clock_domain(
200                &mut context,
201                &clock.0.comptime,
202                &reset.0.comptime,
203                &value.module.module_token.token,
204            );
205        }
206
207        declarations.retain(|x| !x.is_null());
208        let port_types = context.drain_port_types();
209        let variables = context.drain_variables();
210        let functions = context.drain_functions();
211
212        let mut ports = HashMap::default();
213
214        for (id, var) in &variables {
215            if var.kind.is_port() {
216                ports.insert(var.path.clone(), *id);
217            }
218        }
219
220        context.pop_namespace();
221        upper_context.inherit(&mut context);
222
223        Ok(ir::Module {
224            name: value.identifier.text(),
225            token: value.identifier.as_ref().into(),
226            ports,
227            port_types,
228            variables,
229            functions,
230            declarations,
231            suppress_unassigned: false,
232        })
233    }
234}
235
236impl Conv<&InterfaceDeclaration> for ir::Interface {
237    fn conv(context: &mut Context, value: &InterfaceDeclaration) -> IrResult<Self> {
238        // each top-level component has independent context
239        let upper_context = context;
240        let mut context = Context::default();
241        context.inherit(upper_context);
242
243        // pop_affiliation is not necessary because the local `context` will be dropped
244        context.push_affiliation(Affiliation::Interface);
245
246        if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
247            && matches!(symbol.found.kind, SymbolKind::Interface(_))
248        {
249            context.push_namespace(symbol.found.inner_namespace());
250        } else {
251            let token: TokenRange = value.identifier.as_ref().into();
252            return Err(ir_error!(token));
253        }
254
255        if let Some(x) = &value.interface_declaration_opt {
256            check_generic_bound(&mut context, &x.with_generic_parameter);
257            let items: Vec<_> = x
258                .with_generic_parameter
259                .with_generic_parameter_list
260                .as_ref()
261                .into();
262            for item in items {
263                let _ret: IrResult<()> = Conv::conv(&mut context, item);
264            }
265        }
266
267        if let Some(x) = &value.interface_declaration_opt0 {
268            check_proto(&mut context, &value.identifier, &x.scoped_identifier);
269        }
270
271        if let Some(x) = &value.interface_declaration_opt1
272            && let Some(x) = &x.with_parameter.with_parameter_opt
273        {
274            let items: Vec<_> = x.with_parameter_list.as_ref().into();
275            for item in items {
276                let _ret: IrResult<()> = Conv::conv(&mut context, item);
277            }
278        }
279
280        for x in &value.interface_declaration_list {
281            let items: Vec<_> = x.interface_group.as_ref().into();
282            for item in items {
283                match item {
284                    InterfaceItem::GenerateItem(x) => {
285                        let _: IrResult<ir::DeclarationBlock> =
286                            Conv::conv(&mut context, x.generate_item.as_ref());
287                    }
288                    InterfaceItem::ModportDeclaration(x) => {
289                        let _: IrResult<()> =
290                            Conv::conv(&mut context, x.modport_declaration.as_ref());
291                    }
292                }
293            }
294        }
295
296        let var_paths = context.drain_var_paths();
297        let func_paths = context.drain_func_paths();
298        let mut variables = context.drain_variables();
299        let functions = context.drain_functions();
300        let modports = context.drain_modports();
301
302        let variables = variables
303            .extract_if(|_, v| v.affiliation != Affiliation::Function)
304            .collect();
305
306        context.pop_namespace();
307        upper_context.inherit(&mut context);
308
309        Ok(ir::Interface {
310            name: value.identifier.text(),
311            var_paths,
312            func_paths,
313            variables,
314            functions,
315            modports,
316        })
317    }
318}
319
320impl Conv<&PackageDeclaration> for () {
321    fn conv(context: &mut Context, value: &PackageDeclaration) -> IrResult<Self> {
322        // each top-level component has independent context
323        let upper_context = context;
324        let mut context = Context::default();
325        context.inherit(upper_context);
326
327        // pop_affiliation is not necessary because the local `context` will be dropped
328        context.push_affiliation(Affiliation::Package);
329
330        if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
331            && matches!(symbol.found.kind, SymbolKind::Package(_))
332        {
333            context.push_namespace(symbol.found.inner_namespace());
334        } else {
335            let token: TokenRange = value.identifier.as_ref().into();
336            return Err(ir_error!(token));
337        }
338
339        if let Some(x) = &value.package_declaration_opt {
340            check_generic_bound(&mut context, &x.with_generic_parameter);
341        }
342
343        if let Some(x) = &value.package_declaration_opt0 {
344            check_proto(&mut context, &value.identifier, &x.scoped_identifier);
345        }
346
347        for x in &value.package_declaration_list {
348            let items: Vec<_> = x.package_group.as_ref().into();
349            for item in items {
350                match item {
351                    PackageItem::ConstDeclaration(x) => {
352                        let _: IrResult<ir::Declaration> =
353                            Conv::conv(&mut context, x.const_declaration.as_ref());
354                    }
355                    PackageItem::FunctionDeclaration(x) => {
356                        let _: IrResult<()> =
357                            Conv::conv(&mut context, x.function_declaration.as_ref());
358                    }
359                    PackageItem::StructUnionDeclaration(x) => {
360                        let _: IrResult<()> =
361                            Conv::conv(&mut context, x.struct_union_declaration.as_ref());
362                    }
363                    _ => (),
364                }
365            }
366        }
367
368        context.pop_namespace();
369        upper_context.inherit(&mut context);
370
371        Ok(())
372    }
373}
374
375impl Conv<&ProtoModuleDeclaration> for ir::Module {
376    fn conv(context: &mut Context, value: &ProtoModuleDeclaration) -> IrResult<Self> {
377        // each top-level component has independent context
378        let upper_context = context;
379        let mut context = Context::default();
380        context.inherit(upper_context);
381
382        // pop_affiliation is not necessary because the local `context` will be dropped
383        context.push_affiliation(Affiliation::ProtoModule);
384
385        if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
386            && matches!(symbol.found.kind, SymbolKind::ProtoModule(_))
387        {
388            context.push_namespace(symbol.found.inner_namespace());
389        } else {
390            let token: TokenRange = value.identifier.as_ref().into();
391            return Err(ir_error!(token));
392        }
393
394        if let Some(x) = &value.proto_module_declaration_opt
395            && let Some(x) = &x.with_parameter.with_parameter_opt
396        {
397            let items: Vec<_> = x.with_parameter_list.as_ref().into();
398            for item in items {
399                let _ret: IrResult<()> = Conv::conv(&mut context, item);
400            }
401        }
402
403        if let Some(x) = &value.proto_module_declaration_opt0
404            && let Some(x) = &x.port_declaration.port_declaration_opt
405        {
406            let items: Vec<_> = x.port_declaration_list.as_ref().into();
407            for item in items {
408                let _ret: IrResult<()> = Conv::conv(&mut context, item);
409            }
410        }
411
412        let port_types = context.drain_port_types();
413        let variables = context.drain_variables();
414
415        let mut ports = HashMap::default();
416
417        for (id, var) in &variables {
418            if var.kind.is_port() {
419                ports.insert(var.path.clone(), *id);
420            }
421        }
422
423        context.pop_namespace();
424        upper_context.inherit(&mut context);
425
426        Ok(ir::Module {
427            name: value.identifier.text(),
428            token: value.identifier.as_ref().into(),
429            ports,
430            port_types,
431            variables,
432            functions: HashMap::default(),
433            declarations: vec![],
434            suppress_unassigned: false,
435        })
436    }
437}
438
439impl Conv<&ProtoInterfaceDeclaration> for () {
440    fn conv(context: &mut Context, value: &ProtoInterfaceDeclaration) -> IrResult<Self> {
441        context.push_affiliation(Affiliation::ProtoInterface);
442
443        if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
444            && matches!(symbol.found.kind, SymbolKind::ProtoInterface(_))
445        {
446            context.push_namespace(symbol.found.inner_namespace());
447        } else {
448            let token: TokenRange = value.identifier.as_ref().into();
449            return Err(ir_error!(token));
450        }
451
452        for x in &value.proto_interface_declaration_list {
453            if let ProtoInterfaceItem::ProtoAliasDeclaration(x) = x.proto_interface_item.as_ref() {
454                let r#type = match x
455                    .proto_alias_declaration
456                    .proto_alias_declaration_group
457                    .as_ref()
458                {
459                    ProtoAliasDeclarationGroup::Module(_) => AliasType::ProtoModule,
460                    ProtoAliasDeclarationGroup::Interface(_) => AliasType::ProtoInterface,
461                    ProtoAliasDeclarationGroup::Package(_) => AliasType::ProtoPackage,
462                };
463                check_alias_target(
464                    context,
465                    &x.proto_alias_declaration.scoped_identifier,
466                    r#type,
467                );
468            }
469        }
470
471        context.pop_affiliation();
472        context.pop_namespace();
473        Ok(())
474    }
475}
476
477impl Conv<&ProtoPackageDeclaration> for () {
478    fn conv(context: &mut Context, value: &ProtoPackageDeclaration) -> IrResult<Self> {
479        context.push_affiliation(Affiliation::ProtoPackage);
480
481        if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
482            && matches!(symbol.found.kind, SymbolKind::ProtoPackage(_))
483        {
484            context.push_namespace(symbol.found.inner_namespace());
485        } else {
486            let token: TokenRange = value.identifier.as_ref().into();
487            return Err(ir_error!(token));
488        }
489
490        for x in &value.proto_package_declaration_list {
491            if let ProtoPacakgeItem::ProtoAliasDeclaration(x) = x.proto_pacakge_item.as_ref() {
492                let r#type = match x
493                    .proto_alias_declaration
494                    .proto_alias_declaration_group
495                    .as_ref()
496                {
497                    ProtoAliasDeclarationGroup::Module(_) => AliasType::ProtoModule,
498                    ProtoAliasDeclarationGroup::Interface(_) => AliasType::ProtoInterface,
499                    ProtoAliasDeclarationGroup::Package(_) => AliasType::ProtoPackage,
500                };
501                check_alias_target(
502                    context,
503                    &x.proto_alias_declaration.scoped_identifier,
504                    r#type,
505                );
506            }
507        }
508
509        context.pop_affiliation();
510        context.pop_namespace();
511        Ok(())
512    }
513}