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 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 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 let upper_context = context;
125 let mut context = Context::default();
126 context.inherit(upper_context);
127
128 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 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 let upper_context = context;
240 let mut context = Context::default();
241 context.inherit(upper_context);
242
243 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 let upper_context = context;
324 let mut context = Context::default();
325 context.inherit(upper_context);
326
327 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 let upper_context = context;
379 let mut context = Context::default();
380 context.inherit(upper_context);
381
382 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}