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, get_component};
6use crate::conv::{Affiliation, Context, Conv};
7use crate::ir::{self, IrResult, VarKind, VarPath, Variable};
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
14fn top_level_memo_sig(context: &Context, identifier: &Identifier) -> Option<ir::Signature> {
18 if context.config.retain_component_body && !context.in_generic {
19 symbol_table::resolve(identifier).ok().map(|s| {
20 let mut sig = ir::Signature::new(s.found.id);
21 sig.normalize();
22 sig
23 })
24 } else {
25 None
26 }
27}
28
29impl Conv<&Veryl> for ir::Ir {
30 fn conv(context: &mut Context, value: &Veryl) -> IrResult<Self> {
31 let mut components = vec![];
32
33 for x in &value.veryl_list {
34 let items: Vec<&DescriptionItem> = if context.in_dependency {
37 crate::attribute::description_items_excluding_tests(&x.description_group)
38 } else {
39 x.description_group.as_ref().into()
40 };
41 for item in &items {
42 let in_generic = context.in_generic;
44 if item.is_generic() {
45 context.in_generic = true;
46 }
47
48 match item {
49 DescriptionItem::DescriptionItemOptPublicDescriptionItem(x) => {
50 match x.public_description_item.as_ref() {
51 PublicDescriptionItem::ModuleDeclaration(x) => {
52 let decl = x.module_declaration.as_ref();
53 if let Some(sig) =
54 top_level_memo_sig(context, decl.identifier.as_ref())
55 {
56 let token: TokenRange = decl.identifier.as_ref().into();
57 if let Ok(component) = get_component(context, &sig, token)
58 && let ir::Component::Module(m) = component.as_ref()
59 {
60 let mut component = m.clone();
61 if check_module_with_unevaluable_generic_parameters(
62 &decl.identifier,
63 ) {
64 component.suppress_unassigned = true;
65 }
66 components.push(ir::Component::Module(component));
67 }
68 } else {
69 let ret: IrResult<ir::Module> = Conv::conv(context, decl);
70 if let Ok(mut component) = ret {
71 if check_module_with_unevaluable_generic_parameters(
73 &decl.identifier,
74 ) {
75 component.suppress_unassigned = true;
76 }
77 components.push(ir::Component::Module(component));
78 }
79 }
80 }
81 PublicDescriptionItem::InterfaceDeclaration(x) => {
82 let decl = x.interface_declaration.as_ref();
83 if let Some(sig) =
84 top_level_memo_sig(context, decl.identifier.as_ref())
85 {
86 let token: TokenRange = decl.identifier.as_ref().into();
87 let _ = get_component(context, &sig, token);
88 } else {
89 let _: IrResult<ir::Interface> = Conv::conv(context, decl);
90 }
91 }
92 PublicDescriptionItem::PackageDeclaration(x) => {
93 let _: IrResult<()> =
94 Conv::conv(context, x.package_declaration.as_ref());
95 }
96 PublicDescriptionItem::ProtoDeclaration(x) => {
97 match x.proto_declaration.proto_declaration_group.as_ref() {
98 ProtoDeclarationGroup::ProtoModuleDeclaration(x) => {
99 let _: IrResult<ir::Module> = Conv::conv(
100 context,
101 x.proto_module_declaration.as_ref(),
102 );
103 }
104 ProtoDeclarationGroup::ProtoInterfaceDeclaration(x) => {
105 let _: IrResult<()> = Conv::conv(
106 context,
107 x.proto_interface_declaration.as_ref(),
108 );
109 }
110 ProtoDeclarationGroup::ProtoPackageDeclaration(x) => {
111 let _: IrResult<()> = Conv::conv(
112 context,
113 x.proto_package_declaration.as_ref(),
114 );
115 }
116 }
117 }
118 PublicDescriptionItem::AliasDeclaration(x) => {
119 let _: IrResult<()> =
120 Conv::conv(context, x.alias_declaration.as_ref());
121 }
122 PublicDescriptionItem::FunctionDeclaration(x) => {
123 conv_global_function(context, x.function_declaration.as_ref());
124 }
125 }
126 }
127 DescriptionItem::BindDeclaration(x) => {
128 let _: IrResult<()> = Conv::conv(context, x.bind_declaration.as_ref());
129 }
130 DescriptionItem::EmbedDeclaration(x) => {
131 let _: IrResult<()> = Conv::conv(context, x.embed_declaration.as_ref());
132 }
133 DescriptionItem::ImportDeclaration(x) => {
134 let _: IrResult<ir::DeclarationBlock> =
135 Conv::conv(context, x.import_declaration.as_ref());
136 }
137 _ => (),
138 }
139
140 if item.is_generic() {
141 context.in_generic = in_generic;
142 }
143 }
144 }
145
146 Ok(ir::Ir { components })
147 }
148}
149
150fn conv_global_function(context: &mut Context, value: &FunctionDeclaration) {
151 let upper_context = context;
152 let mut context = Context::default();
153 context.inherit(upper_context);
154
155 context.in_global_func = Some(value.identifier.identifier_token.token);
156 let _: IrResult<()> = Conv::conv(&mut context, value);
157 context.in_global_func = None;
158
159 upper_context.inherit(&mut context);
160}
161
162fn collect_interface_members(context: &Context) -> HashMap<ir::VarId, Variable> {
163 let modport_ports: Vec<(&VarPath, usize)> = context
166 .port_types
167 .iter()
168 .filter(|(_, (r#type, _))| matches!(r#type.kind, ir::TypeKind::Modport(_, _)))
169 .map(|(port, (r#type, _))| (port, r#type.array.dims()))
170 .collect();
171 if modport_ports.is_empty() {
172 return HashMap::default();
173 }
174
175 context
176 .var_paths
177 .iter()
178 .filter_map(|(path, (id, comptime))| {
179 if context.variables.contains_key(id) {
180 return None;
181 }
182 let (port, port_dimensions) = modport_ports
183 .iter()
184 .filter(|(port, _)| path.0.len() > port.0.len() && path.starts_with(&port.0))
185 .max_by_key(|(port, _)| port.0.len())?;
186 let mut variable = Variable::new(
187 *id,
188 path.clone(),
189 VarKind::Variable,
190 comptime.r#type.clone(),
191 vec![],
192 Affiliation::Module,
193 &comptime.token,
194 0,
195 );
196 variable.set_leading_array_path_offset(*port_dimensions, path.0.len() - port.0.len());
197 Some((*id, variable))
198 })
199 .collect()
200}
201
202impl Conv<&ModuleDeclaration> for ir::Module {
203 fn conv(context: &mut Context, value: &ModuleDeclaration) -> IrResult<Self> {
204 Conv::conv(context, (value, false))
205 }
206}
207
208impl Conv<(&ModuleDeclaration, bool)> for ir::Module {
209 fn conv(context: &mut Context, value: (&ModuleDeclaration, bool)) -> IrResult<Self> {
210 let (module_declaration, header_only) = value;
211
212 let mut declarations = vec![];
213
214 let upper_context = context;
216 let mut context = Context::default();
217 context.inherit(upper_context);
218
219 let _guard = context.conv_profile_guard(module_declaration.identifier.text());
220
221 context.push_affiliation(Affiliation::Module);
223
224 let signature = if let Ok(symbol) =
225 symbol_table::resolve(module_declaration.identifier.as_ref())
226 && let SymbolKind::Module(x) = &symbol.found.kind
227 && !x.is_proto
228 {
229 context.push_namespace(symbol.found.inner_namespace());
230 context.in_test_module = x.test.is_some();
231 if let Some(x) = x.default_clock {
232 let path = VarPath::new(symbol_table::get(x).unwrap().token.text);
233 context.set_default_clock(path, x);
234 }
235 if let Some(x) = x.default_reset {
236 let path = VarPath::new(symbol_table::get(x).unwrap().token.text);
237 context.set_default_reset(path, x);
238 }
239 ir::Signature::new(symbol.found.id)
240 } else {
241 let token: TokenRange = module_declaration.identifier.as_ref().into();
242 return Err(ir_error!(token));
243 };
244
245 if let Some(x) = &module_declaration.module_declaration_opt {
246 check_generic_bound(&mut context, &x.with_generic_parameter);
247 let items: Vec<_> = x
248 .with_generic_parameter
249 .with_generic_parameter_list
250 .as_ref()
251 .into();
252 for item in items {
253 let _ret: IrResult<()> = Conv::conv(&mut context, item);
254 }
255 }
256
257 if let Some(x) = &module_declaration.module_declaration_opt0 {
258 check_proto(
259 &mut context,
260 &module_declaration.identifier,
261 &x.scoped_identifier,
262 );
263 }
264
265 if let Some(x) = &module_declaration.module_declaration_opt1
266 && let Some(x) = &x.with_parameter.with_parameter_opt
267 {
268 let items: Vec<_> = x.with_parameter_list.as_ref().into();
269 for item in items {
270 let _ret: IrResult<()> = Conv::conv(&mut context, item);
271 }
272 }
273
274 if let Some(x) = &module_declaration.module_declaration_opt2
275 && let Some(x) = &x.port_declaration.port_declaration_opt
276 {
277 let items: Vec<_> = x.port_declaration_list.as_ref().into();
278 for item in items {
279 let _ret: IrResult<()> = Conv::conv(&mut context, item);
280 }
281 }
282
283 if !header_only {
284 let mut items = vec![];
285 for x in &module_declaration.module_declaration_list {
286 let group: Vec<_> = x.module_group.as_ref().into();
287 items.extend(group);
288 }
289
290 let is_tb_block = |item: &&ModuleItem| {
296 matches!(
297 item.generate_item.as_ref(),
298 GenerateItem::InitialDeclaration(_) | GenerateItem::FinalDeclaration(_)
299 )
300 };
301 let mut blocks: Vec<Vec<ir::Declaration>> = Vec::new();
302 blocks.resize_with(items.len(), Vec::new);
303 for deferred in [false, true] {
304 for (i, item) in items.iter().enumerate() {
305 if is_tb_block(item) != deferred {
306 continue;
307 }
308 let ret: IrResult<ir::DeclarationBlock> =
309 Conv::conv(&mut context, item.generate_item.as_ref());
310
311 if let Ok(block) = ret {
312 blocks[i] = block.0;
313 }
314 }
315 }
316 for mut block in blocks {
317 declarations.append(&mut block);
318 }
319 }
320
321 if let (Some(clock), Some(reset)) =
323 (context.get_default_clock(), context.get_default_reset())
324 {
325 check_clock_domain(
326 &mut context,
327 &clock.0.comptime,
328 &reset.0.comptime,
329 &module_declaration.module.module_token.token,
330 );
331 }
332
333 declarations.retain(|x| !x.is_null());
334 let interface_members = collect_interface_members(&context);
335 let port_types = context.drain_port_types();
336 let variables = context.drain_variables();
337 let functions = context.drain_functions();
338
339 let mut ports = HashMap::default();
340
341 for (id, var) in &variables {
342 if var.kind.is_port() {
343 ports.insert(var.path.clone(), *id);
344 }
345 }
346
347 context.pop_namespace();
348 upper_context.inherit(&mut context);
349
350 Ok(ir::Module {
351 name: module_declaration.identifier.text(),
352 signature,
353 token: module_declaration.identifier.as_ref().into(),
354 ports,
355 port_types,
356 variables,
357 functions,
358 interface_members,
359 declarations,
360 suppress_unassigned: false,
361 per_decl_refs: HashMap::default(),
362 assign_tokens: HashMap::default(),
363 ff_table: ir::FfTable::default(),
364 })
365 }
366}
367
368impl Conv<&InterfaceDeclaration> for () {
369 fn conv(context: &mut Context, value: &InterfaceDeclaration) -> IrResult<Self> {
370 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
371 && matches!(symbol.found.kind, SymbolKind::Interface(ref x) if !x.is_proto)
372 {
373 context.push_namespace(symbol.found.inner_namespace());
374 } else {
375 let token: TokenRange = value.identifier.as_ref().into();
376 return Err(ir_error!(token));
377 }
378
379 if let Some(x) = &value.interface_declaration_opt {
380 check_generic_bound(context, &x.with_generic_parameter);
381 let items: Vec<_> = x
382 .with_generic_parameter
383 .with_generic_parameter_list
384 .as_ref()
385 .into();
386 for item in items {
387 let _ret: IrResult<()> = Conv::conv(context, item);
388 }
389 }
390
391 if let Some(x) = &value.interface_declaration_opt0 {
392 check_proto(context, &value.identifier, &x.scoped_identifier);
393 }
394
395 if let Some(x) = &value.interface_declaration_opt1
396 && let Some(x) = &x.with_parameter.with_parameter_opt
397 {
398 let items: Vec<_> = x.with_parameter_list.as_ref().into();
399 for item in items {
400 let _ret: IrResult<()> = Conv::conv(context, item);
401 }
402 }
403
404 for x in &value.interface_declaration_list {
405 let items: Vec<_> = x.interface_group.as_ref().into();
406 for item in items {
407 match item {
408 InterfaceItem::GenerateItem(x) => {
409 let _: IrResult<ir::DeclarationBlock> =
410 Conv::conv(context, x.generate_item.as_ref());
411 }
412 InterfaceItem::MixinDeclaration(x) => {
413 let _: IrResult<()> = Conv::conv(context, x.mixin_declaration.as_ref());
414 }
415 InterfaceItem::ModportDeclaration(x) => {
416 let _: IrResult<()> = Conv::conv(context, x.modport_declaration.as_ref());
417 }
418 }
419 }
420 }
421
422 context.pop_namespace();
423
424 Ok(())
425 }
426}
427
428impl Conv<&InterfaceDeclaration> for ir::Interface {
429 fn conv(context: &mut Context, value: &InterfaceDeclaration) -> IrResult<Self> {
430 let upper_context = context;
432 let mut context = Context::default();
433 context.inherit(upper_context);
434
435 let _guard = context.conv_profile_guard(value.identifier.text());
436
437 context.push_affiliation(Affiliation::Interface);
439
440 let ret: IrResult<()> = Conv::conv(&mut context, value);
441
442 let var_paths = context.drain_var_paths();
443 let func_paths = context.drain_func_paths();
444 let mut variables = context.drain_variables();
445 let functions = context.drain_functions();
446 let modports = context.drain_modports();
447
448 let variables = variables
449 .extract_if(|_, v| v.affiliation != Affiliation::Function)
450 .collect();
451
452 context.pop_namespace();
453 upper_context.inherit(&mut context);
454
455 ret?;
456
457 Ok(ir::Interface {
458 name: value.identifier.text(),
459 var_paths,
460 func_paths,
461 variables,
462 functions,
463 modports,
464 })
465 }
466}
467
468impl Conv<&PackageDeclaration> for () {
469 fn conv(context: &mut Context, value: &PackageDeclaration) -> IrResult<Self> {
470 let upper_context = context;
472 let mut context = Context::default();
473 context.inherit(upper_context);
474
475 let _guard = context.conv_profile_guard(value.identifier.text());
476
477 context.push_affiliation(Affiliation::Package);
479
480 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
481 && matches!(symbol.found.kind, SymbolKind::Package(ref x) if !x.is_proto)
482 {
483 context.push_namespace(symbol.found.inner_namespace());
484 } else {
485 let token: TokenRange = value.identifier.as_ref().into();
486 return Err(ir_error!(token));
487 }
488
489 if let Some(x) = &value.package_declaration_opt {
490 check_generic_bound(&mut context, &x.with_generic_parameter);
491 }
492
493 if let Some(x) = &value.package_declaration_opt0 {
494 check_proto(&mut context, &value.identifier, &x.scoped_identifier);
495 }
496
497 for x in &value.package_declaration_list {
498 let items: Vec<_> = x.package_group.as_ref().into();
499 for item in items {
500 match item {
501 PackageItem::ConstDeclaration(x) => {
502 let _: IrResult<ir::Declaration> =
503 Conv::conv(&mut context, x.const_declaration.as_ref());
504 }
505 PackageItem::FunctionDeclaration(x) => {
506 let _: IrResult<()> =
507 Conv::conv(&mut context, x.function_declaration.as_ref());
508 }
509 PackageItem::StructUnionDeclaration(x) => {
510 let _: IrResult<()> =
511 Conv::conv(&mut context, x.struct_union_declaration.as_ref());
512 }
513 _ => (),
514 }
515 }
516 }
517
518 context.pop_namespace();
519 upper_context.inherit(&mut context);
520
521 Ok(())
522 }
523}
524
525impl Conv<&ProtoModuleDeclaration> for ir::Module {
526 fn conv(context: &mut Context, value: &ProtoModuleDeclaration) -> IrResult<Self> {
527 let upper_context = context;
529 let mut context = Context::default();
530 context.inherit(upper_context);
531
532 context.push_affiliation(Affiliation::ProtoModule);
534
535 let signature = if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
536 && matches!(symbol.found.kind, SymbolKind::Module(ref x) if x.is_proto)
537 {
538 context.push_namespace(symbol.found.inner_namespace());
539 ir::Signature::new(symbol.found.id)
540 } else {
541 let token: TokenRange = value.identifier.as_ref().into();
542 return Err(ir_error!(token));
543 };
544
545 if let Some(x) = &value.proto_module_declaration_opt
546 && let Some(x) = &x.with_parameter.with_parameter_opt
547 {
548 let items: Vec<_> = x.with_parameter_list.as_ref().into();
549 for item in items {
550 let _ret: IrResult<()> = Conv::conv(&mut context, item);
551 }
552 }
553
554 if let Some(x) = &value.proto_module_declaration_opt0
555 && let Some(x) = &x.port_declaration.port_declaration_opt
556 {
557 let items: Vec<_> = x.port_declaration_list.as_ref().into();
558 for item in items {
559 let _ret: IrResult<()> = Conv::conv(&mut context, item);
560 }
561 }
562
563 let interface_members = collect_interface_members(&context);
564 let port_types = context.drain_port_types();
565 let variables = context.drain_variables();
566
567 let mut ports = HashMap::default();
568
569 for (id, var) in &variables {
570 if var.kind.is_port() {
571 ports.insert(var.path.clone(), *id);
572 }
573 }
574
575 context.pop_namespace();
576 upper_context.inherit(&mut context);
577
578 Ok(ir::Module {
579 name: value.identifier.text(),
580 signature,
581 token: value.identifier.as_ref().into(),
582 ports,
583 port_types,
584 variables,
585 functions: HashMap::default(),
586 interface_members,
587 declarations: vec![],
588 suppress_unassigned: false,
589 per_decl_refs: HashMap::default(),
590 assign_tokens: HashMap::default(),
591 ff_table: ir::FfTable::default(),
592 })
593 }
594}
595
596impl Conv<&ProtoInterfaceDeclaration> for () {
597 fn conv(context: &mut Context, value: &ProtoInterfaceDeclaration) -> IrResult<Self> {
598 context.push_affiliation(Affiliation::ProtoInterface);
599
600 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
601 && matches!(symbol.found.kind, SymbolKind::Interface(ref x) if x.is_proto)
602 {
603 context.push_namespace(symbol.found.inner_namespace());
604 } else {
605 let token: TokenRange = value.identifier.as_ref().into();
606 return Err(ir_error!(token));
607 }
608
609 for x in &value.proto_interface_declaration_list {
610 if let ProtoInterfaceItem::ProtoAliasDeclaration(x) = x.proto_interface_item.as_ref() {
611 let r#type = match x
612 .proto_alias_declaration
613 .proto_alias_declaration_group
614 .as_ref()
615 {
616 ProtoAliasDeclarationGroup::Module(_) => AliasType::ProtoModule,
617 ProtoAliasDeclarationGroup::Interface(_) => AliasType::ProtoInterface,
618 ProtoAliasDeclarationGroup::Package(_) => AliasType::ProtoPackage,
619 };
620 check_alias_target(
621 context,
622 &x.proto_alias_declaration.scoped_identifier,
623 r#type,
624 );
625 }
626 }
627
628 context.pop_affiliation();
629 context.pop_namespace();
630 Ok(())
631 }
632}
633
634impl Conv<&ProtoPackageDeclaration> for () {
635 fn conv(context: &mut Context, value: &ProtoPackageDeclaration) -> IrResult<Self> {
636 context.push_affiliation(Affiliation::ProtoPackage);
637
638 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
639 && matches!(symbol.found.kind, SymbolKind::Package(ref x) if x.is_proto)
640 {
641 context.push_namespace(symbol.found.inner_namespace());
642 } else {
643 let token: TokenRange = value.identifier.as_ref().into();
644 return Err(ir_error!(token));
645 }
646
647 for x in &value.proto_package_declaration_list {
648 if let ProtoPacakgeItem::ProtoAliasDeclaration(x) = x.proto_pacakge_item.as_ref() {
649 let r#type = match x
650 .proto_alias_declaration
651 .proto_alias_declaration_group
652 .as_ref()
653 {
654 ProtoAliasDeclarationGroup::Module(_) => AliasType::ProtoModule,
655 ProtoAliasDeclarationGroup::Interface(_) => AliasType::ProtoInterface,
656 ProtoAliasDeclarationGroup::Package(_) => AliasType::ProtoPackage,
657 };
658 check_alias_target(
659 context,
660 &x.proto_alias_declaration.scoped_identifier,
661 r#type,
662 );
663 }
664 }
665
666 context.pop_affiliation();
667 context.pop_namespace();
668 Ok(())
669 }
670}