1use crate::analyzer_error::{AnalyzerError, MismatchTypeKind, UnevaluableValueKind};
2use crate::attribute::{AllowItem, Attribute};
3use crate::attribute_table;
4use crate::conv::checker::alias::{AliasType, check_alias_target};
5use crate::conv::checker::bind::check_bind_target;
6use crate::conv::checker::clock_domain::check_clock_domain;
7use crate::conv::checker::generic::{
8 check_generic_bound, check_generic_bound_item, check_generic_expression,
9 check_generic_refereence,
10};
11use crate::conv::checker::import::check_import;
12use crate::conv::checker::inst::check_inst;
13use crate::conv::checker::modport::{check_modport, check_modport_default, check_modport_in_port};
14use crate::conv::checker::port::{check_direction, check_port_default_value, check_port_direction};
15use crate::conv::utils::{
16 TypePosition, eval_assign_statement, eval_clock, eval_const_assign, eval_expr,
17 eval_generate_for_range, eval_reset, eval_size, eval_type, eval_variable, expand_connect,
18 expand_connect_const, get_component, get_overridden_params, get_port_connects, get_return_str,
19 insert_port_connect, try_infer_decl_type, try_infer_var_assign, var_path_to_assign_destination,
20};
21use crate::conv::{Affiliation, Context, Conv};
22use crate::ir::{
23 self, Comptime, FuncArg, FuncPath, InstanceKind, IrResult, Shape, Signature, TypeKind,
24 ValueVariant, VarId, VarIndex, VarKind, VarPath, VarPathSelect, VarSelect, Variable,
25};
26use crate::namespace::DefineContext;
27use crate::symbol::{
28 ClockDomain, Direction, GenericBoundKind, Symbol, SymbolKind, TbComponentKind,
29};
30use crate::symbol_path::{GenericSymbolPath, SymbolPathNamespace};
31use crate::symbol_table;
32use crate::value::Value;
33use crate::{HashMap, ir_error};
34use std::sync::Arc;
35use veryl_parser::resource_table::{self, StrId};
36use veryl_parser::token_range::TokenRange;
37use veryl_parser::veryl_grammar_trait::*;
38
39impl Conv<&GenerateItem> for ir::DeclarationBlock {
40 fn conv(context: &mut Context, value: &GenerateItem) -> IrResult<Self> {
41 match value {
42 GenerateItem::LetDeclaration(x) => Ok(ir::DeclarationBlock::new(Conv::conv(
43 context,
44 x.let_declaration.as_ref(),
45 )?)),
46 GenerateItem::VarDeclaration(x) => Ok(ir::DeclarationBlock::new(Conv::conv(
47 context,
48 x.var_declaration.as_ref(),
49 )?)),
50 GenerateItem::AlwaysFfDeclaration(x) => {
51 let token: TokenRange = x.always_ff_declaration.as_ref().into();
52 match Conv::conv(context, x.always_ff_declaration.as_ref()) {
53 Ok(decl) => Ok(ir::DeclarationBlock::new(decl)),
54 Err(_) if context.in_generic => Ok(ir::DeclarationBlock::default()),
55 Err(_) => Ok(ir::DeclarationBlock::new(ir::Declaration::Unsupported(
56 token,
57 ))),
58 }
59 }
60 GenerateItem::AlwaysCombDeclaration(x) => {
61 let token: TokenRange = x.always_comb_declaration.as_ref().into();
62 match Conv::conv(context, x.always_comb_declaration.as_ref()) {
63 Ok(decl) => Ok(ir::DeclarationBlock::new(decl)),
64 Err(_) if context.in_generic => Ok(ir::DeclarationBlock::default()),
65 Err(_) => Ok(ir::DeclarationBlock::new(ir::Declaration::Unsupported(
66 token,
67 ))),
68 }
69 }
70 GenerateItem::GenerateIfDeclaration(x) => {
71 Conv::conv(context, x.generate_if_declaration.as_ref())
72 }
73 GenerateItem::GenerateForDeclaration(x) => {
74 Conv::conv(context, x.generate_for_declaration.as_ref())
75 }
76 GenerateItem::GenerateBlockDeclaration(x) => Conv::conv(
77 context,
78 x.generate_block_declaration.generate_named_block.as_ref(),
79 ),
80 GenerateItem::ConstDeclaration(x) => Ok(ir::DeclarationBlock::new(Conv::conv(
81 context,
82 x.const_declaration.as_ref(),
83 )?)),
84 GenerateItem::GenDeclaration(x) => Ok(ir::DeclarationBlock::new(Conv::conv(
85 context,
86 x.gen_declaration.as_ref(),
87 )?)),
88 GenerateItem::AssignDeclaration(x) => {
89 let token: TokenRange = x.assign_declaration.as_ref().into();
90 match Conv::conv(context, x.assign_declaration.as_ref()) {
91 Ok(decl) => Ok(ir::DeclarationBlock::new(decl)),
92 Err(_) if context.in_generic => Ok(ir::DeclarationBlock::default()),
93 Err(_) => Ok(ir::DeclarationBlock::new(ir::Declaration::Unsupported(
94 token,
95 ))),
96 }
97 }
98 GenerateItem::FunctionDeclaration(x) => {
99 let in_generic = context.in_generic;
100 if x.function_declaration.function_declaration_opt.is_some() {
101 context.in_generic = true;
102 }
103
104 let ret: IrResult<()> = Conv::conv(context, x.function_declaration.as_ref());
105
106 if x.function_declaration.function_declaration_opt.is_some() {
107 context.in_generic = in_generic;
108 }
109
110 ret?;
111 Ok(ir::DeclarationBlock::default())
112 }
113 GenerateItem::StructUnionDeclaration(x) => {
114 let in_generic = context.in_generic;
115 if x.struct_union_declaration
116 .struct_union_declaration_opt
117 .is_some()
118 {
119 context.in_generic = true;
120 }
121
122 let ret: IrResult<()> = Conv::conv(context, x.struct_union_declaration.as_ref());
123
124 if x.struct_union_declaration
125 .struct_union_declaration_opt
126 .is_some()
127 {
128 context.in_generic = in_generic;
129 }
130
131 ret?;
132 Ok(ir::DeclarationBlock::default())
133 }
134 GenerateItem::EnumDeclaration(x) => {
135 let _: () = Conv::conv(context, x.enum_declaration.as_ref())?;
136 Ok(ir::DeclarationBlock::default())
137 }
138 GenerateItem::InitialDeclaration(x) => {
139 let token: TokenRange = x.initial_declaration.as_ref().into();
140 match Conv::conv(context, x.initial_declaration.as_ref()) {
141 Ok(decl) => Ok(ir::DeclarationBlock::new(decl)),
142 Err(_) if context.in_generic => Ok(ir::DeclarationBlock::default()),
143 Err(_) => Ok(ir::DeclarationBlock::new(ir::Declaration::Unsupported(
144 token,
145 ))),
146 }
147 }
148 GenerateItem::FinalDeclaration(x) => {
149 let token: TokenRange = x.final_declaration.as_ref().into();
150 match Conv::conv(context, x.final_declaration.as_ref()) {
151 Ok(decl) => Ok(ir::DeclarationBlock::new(decl)),
152 Err(_) if context.in_generic => Ok(ir::DeclarationBlock::default()),
153 Err(_) => Ok(ir::DeclarationBlock::new(ir::Declaration::Unsupported(
154 token,
155 ))),
156 }
157 }
158 GenerateItem::InstDeclaration(x) => {
159 let token: TokenRange = x.inst_declaration.as_ref().into();
160 match Conv::conv(context, x.inst_declaration.as_ref()) {
161 Ok(decl) => Ok(ir::DeclarationBlock::new(decl)),
162 Err(_) if context.in_generic => Ok(ir::DeclarationBlock::default()),
163 Err(_) => Ok(ir::DeclarationBlock::new(ir::Declaration::Unsupported(
164 token,
165 ))),
166 }
167 }
168 GenerateItem::ConnectDeclaration(x) => {
169 Conv::conv(context, x.connect_declaration.as_ref())
170 }
171 GenerateItem::UnsafeBlock(x) => Conv::conv(context, x.unsafe_block.as_ref()),
172 GenerateItem::ImportDeclaration(x) => {
173 Conv::conv(context, x.import_declaration.as_ref())
174 }
175 GenerateItem::BindDeclaration(x) => {
176 let _: () = Conv::conv(context, x.bind_declaration.as_ref())?;
177 Ok(ir::DeclarationBlock::default())
178 }
179 GenerateItem::AliasDeclaration(x) => {
180 let _: () = Conv::conv(context, x.alias_declaration.as_ref())?;
181 Ok(ir::DeclarationBlock::default())
182 }
183 GenerateItem::TypeDefDeclaration(x) => {
184 let _: () = Conv::conv(context, x.type_def_declaration.as_ref())?;
185 Ok(ir::DeclarationBlock::default())
186 }
187 GenerateItem::EmbedDeclaration(x) => {
188 let _: () = Conv::conv(context, x.embed_declaration.as_ref())?;
189 Ok(ir::DeclarationBlock::default())
190 }
191 }
192 }
193}
194
195fn get_label(block: &GenerateOptionalNamedBlock, default: StrId) -> StrId {
196 if let Some(x) = &block.generate_optional_named_block_opt {
197 x.identifier.text()
198 } else {
199 default
200 }
201}
202
203impl Conv<&GenerateIfDeclaration> for ir::DeclarationBlock {
204 fn conv(context: &mut Context, value: &GenerateIfDeclaration) -> IrResult<Self> {
205 let label = value.generate_named_block.identifier.text();
206
207 let (comptime, _) = eval_expr(context, None, value.expression.as_ref(), false)?;
208 let cond = comptime.get_value()?;
209
210 if cond.to_usize().unwrap_or(0) != 0 {
211 context.push_hierarchy(label);
212
213 let block = context.block(|c| {
214 let block: ir::DeclarationBlock =
215 Conv::conv(c, value.generate_named_block.as_ref())?;
216 Ok(block)
217 });
218
219 context.pop_hierarchy();
220 block
221 } else {
222 for x in &value.generate_if_declaration_list {
223 let (comptime, _) = eval_expr(context, None, x.expression.as_ref(), false)?;
224
225 let cond = comptime.get_value()?;
226
227 if cond.to_usize().unwrap_or(0) != 0 {
228 let label = get_label(&x.generate_optional_named_block, label);
229
230 context.push_hierarchy(label);
231
232 let block = context.block(|c| {
233 let block: ir::DeclarationBlock =
234 Conv::conv(c, x.generate_optional_named_block.as_ref())?;
235 Ok(block)
236 });
237
238 context.pop_hierarchy();
239 return block;
240 }
241 }
242
243 if let Some(x) = &value.generate_if_declaration_opt {
244 let label = get_label(&x.generate_optional_named_block, label);
245
246 context.push_hierarchy(label);
247
248 let block = context.block(|c| {
249 let block: ir::DeclarationBlock =
250 Conv::conv(c, x.generate_optional_named_block.as_ref())?;
251 Ok(block)
252 });
253
254 context.pop_hierarchy();
255 block
256 } else {
257 Ok(ir::DeclarationBlock::default())
258 }
259 }
260 }
261}
262
263impl Conv<&GenerateNamedBlock> for ir::DeclarationBlock {
264 fn conv(context: &mut Context, value: &GenerateNamedBlock) -> IrResult<Self> {
265 let mut ret = vec![];
266 for x in &value.generate_named_block_list {
267 let items: Vec<_> = x.generate_group.as_ref().into();
268 for item in items {
269 let item: IrResult<ir::DeclarationBlock> = Conv::conv(context, item);
270
271 if let Ok(mut item) = item {
272 ret.append(&mut item.0);
273 }
274 }
275 }
276 Ok(ir::DeclarationBlock(ret))
277 }
278}
279
280impl Conv<&GenerateOptionalNamedBlock> for ir::DeclarationBlock {
281 fn conv(context: &mut Context, value: &GenerateOptionalNamedBlock) -> IrResult<Self> {
282 let mut ret = vec![];
283 for x in &value.generate_optional_named_block_list {
284 let items: Vec<_> = x.generate_group.as_ref().into();
285 for item in items {
286 let item: IrResult<ir::DeclarationBlock> = Conv::conv(context, item);
287
288 if let Ok(mut item) = item {
289 ret.append(&mut item.0);
290 }
291 }
292 }
293 Ok(ir::DeclarationBlock(ret))
294 }
295}
296
297impl Conv<&GenerateForDeclaration> for ir::DeclarationBlock {
298 fn conv(context: &mut Context, value: &GenerateForDeclaration) -> IrResult<Self> {
299 let token: TokenRange = (&value.identifier.identifier_token).into();
300 let label = value.generate_named_block.identifier.text();
301
302 let rev = value.generate_for_declaration_opt.is_some();
303 let step = value
304 .generate_for_declaration_opt0
305 .as_ref()
306 .map(|x| (x.assignment_operator.as_ref(), x.expression.as_ref()));
307
308 let range = eval_generate_for_range(context, &value.range, rev, step, token)?;
309
310 let mut ret = ir::DeclarationBlock::default();
311
312 for i in range {
313 let label = format!("{}[{}]", label, i);
314 let label = resource_table::insert_str(&label);
315
316 let index = value.identifier.text();
317 let path = VarPath::new(index);
318 let kind = VarKind::Const;
319 let comptime = Comptime::create_value(Value::new(i as u64, 32, false), token);
320
321 context.push_hierarchy(label);
322
323 let block = context.block(|c| {
324 let id = c.insert_var_path(path.clone(), comptime.clone());
325 let array_limit = c.config.evaluate_array_limit;
326 let variable = Variable::new(
327 id,
328 path,
329 kind,
330 comptime.r#type.clone(),
331 vec![comptime.get_value().unwrap().clone()],
332 c.get_affiliation(),
333 &token,
334 array_limit,
335 );
336 c.insert_variable(id, variable);
337
338 let block: IrResult<ir::DeclarationBlock> =
339 Conv::conv(c, value.generate_named_block.as_ref());
340 block
341 });
342
343 context.pop_hierarchy();
344
345 if let Ok(mut block) = block {
346 ret.0.append(&mut block.0);
347 }
348 }
349
350 Ok(ret)
351 }
352}
353
354impl Conv<&WithGenericParameterItem> for () {
355 fn conv(context: &mut Context, value: &WithGenericParameterItem) -> IrResult<Self> {
356 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
357 && let SymbolKind::GenericParameter(x) = &symbol.found.kind
358 {
359 check_generic_bound_item(context, &x.bound, &symbol.found.namespace);
360 if let Some(y) = &value.with_generic_parameter_item_opt {
361 let token: TokenRange = y.with_generic_argument_item.as_ref().into();
362
363 match y.with_generic_argument_item.as_ref() {
364 WithGenericArgumentItem::Number(_)
365 | WithGenericArgumentItem::BooleanLiteral(_) => {
366 if !matches!(x.bound, GenericBoundKind::Proto(_)) {
367 context.insert_error(AnalyzerError::mismatch_assignment(
368 "number",
369 &x.bound.to_string(),
370 &token,
371 &[],
372 ));
373 }
374 }
375 WithGenericArgumentItem::FixedType(_) => {
376 if !matches!(x.bound, GenericBoundKind::Type) {
377 context.insert_error(AnalyzerError::mismatch_assignment(
378 "type",
379 &x.bound.to_string(),
380 &token,
381 &[],
382 ));
383 }
384 }
385 WithGenericArgumentItem::GenericArgIdentifier(_) => {
386 }
388 }
389 }
390 Ok(())
391 } else {
392 let token: TokenRange = value.identifier.as_ref().into();
393 Err(ir_error!(token))
394 }
395 }
396}
397
398impl Conv<&WithParameterItem> for () {
399 fn conv(context: &mut Context, value: &WithParameterItem) -> IrResult<Self> {
400 let define_context: DefineContext = (&value.colon.colon_token).into();
401 if !define_context.is_default() {
402 return Ok(());
403 }
404
405 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
406 && let SymbolKind::Parameter(x) = &symbol.found.kind
407 {
408 let path = VarPath::new(symbol.found.token.text);
409 let kind: VarKind = (&x.kind).into();
410 let token: TokenRange = value.into();
411 let variable_token: TokenRange = (&value.identifier.identifier_token).into();
412
413 let r#type = x.r#type.to_ir_type(context, TypePosition::Variable)?;
414
415 let expr = if context.is_affiliated(Affiliation::ProtoModule) {
417 let comptime = Comptime::create_unknown(token);
418 let expr = ir::Expression::Term(Box::new(ir::Factor::Unknown(comptime.clone())));
419 (comptime, expr)
420 } else {
421 let Some(expr) = &x.value else {
422 context.insert_error(AnalyzerError::missing_default_argument(
423 &value.identifier.text().to_string(),
424 &value.identifier.as_ref().into(),
425 ));
426 return Err(ir_error!(token));
427 };
428
429 eval_expr(context, Some(r#type.clone()), expr, false)?
430 };
431
432 let mut expr = context.get_override(&path).cloned().unwrap_or(expr);
434
435 let dst = ir::AssignDestination {
436 id: VarId::default(),
437 path: path.clone(),
438 index: VarIndex::default(),
439 select: VarSelect::default(),
440 comptime: Comptime::from_type(r#type, ClockDomain::None, TokenRange::default()),
441 token: variable_token,
442 };
443
444 eval_const_assign(context, kind, &dst, &mut expr)?;
445
446 Ok(())
447 } else {
448 let token: TokenRange = value.identifier.as_ref().into();
449 Err(ir_error!(token))
450 }
451 }
452}
453
454impl Conv<&PortDeclarationItem> for () {
455 fn conv(context: &mut Context, value: &PortDeclarationItem) -> IrResult<Self> {
456 let define_context: DefineContext = (&value.colon.colon_token).into();
457 if !define_context.is_default() {
458 return Ok(());
459 }
460
461 let token: TokenRange = value.into();
462
463 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
464 && let SymbolKind::Port(x) = &symbol.found.kind
465 {
466 check_modport_in_port(context, value);
467 check_port_direction(context, value);
468
469 let path = VarPath::new(symbol.found.token.text);
470 let variable_token: TokenRange = (&value.identifier.identifier_token).into();
471
472 let pos = match x.direction {
473 Direction::Modport => TypePosition::Modport,
474 _ => TypePosition::Variable,
475 };
476
477 let r#type = x.r#type.to_ir_type(context, pos)?;
478 let clock_domain = x.clock_domain;
479
480 if !context.is_affiliated(Affiliation::Function) {
483 context.insert_port_type(path.clone(), r#type.clone(), clock_domain);
484 }
485
486 let kind = match x.direction {
487 Direction::Input => VarKind::Input,
488 Direction::Output => VarKind::Output,
489 Direction::Inout => VarKind::Inout,
490 Direction::Modport => {
491 match &r#type.kind {
492 ir::TypeKind::Modport(sig, name) => {
493 let component = get_component(context, sig, token)?;
494 let base = value.identifier.text();
495 let ir::Component::Interface(component) = component.as_ref() else {
496 return Err(ir_error!(token));
497 };
498 let component = component.clone();
499 context.extract_interface_member(
500 base,
501 &r#type.array,
502 component,
503 Some(*name),
504 clock_domain,
505 variable_token,
506 );
507
508 let path = VarPath::new(value.identifier.text());
510 let r#type = {
511 let mut t = ir::Type::new(TypeKind::Modport(sig.clone(), *name));
512 t.array = r#type.array;
513 t
514 };
515
516 let comptime =
517 Comptime::from_type(r#type.clone(), clock_domain, variable_token);
518 context.insert_var_path(path.clone(), comptime);
519 }
520 ir::TypeKind::SystemVerilog => (),
521 _ => {
522 context.insert_error(AnalyzerError::mismatch_type(
523 MismatchTypeKind::SymbolKind {
524 name: symbol.found.token.to_string(),
525 expected: "modport".to_string(),
526 actual: symbol.found.kind.to_kind_name(),
527 },
528 &variable_token,
529 ));
530 }
531 }
532 return Ok(());
534 }
535 Direction::Interface => {
536 if let ir::TypeKind::AbstractInterface(_) = &r#type.kind {
537 let path = VarPath::new(value.identifier.text());
538 let comptime =
539 Comptime::from_type(r#type.clone(), clock_domain, variable_token);
540 context.insert_var_path(path.clone(), comptime);
541 }
542 return Ok(());
543 }
544 _ => {
545 return Err(ir_error!(token));
546 }
547 };
548
549 let default_value = if let Some(x) = &x.default_value {
550 let allow_anonymous = kind == VarKind::Output;
551 let default_value = eval_expr(context, Some(r#type.clone()), x, allow_anonymous);
552
553 check_port_default_value(context, value, &default_value, kind, x);
554
555 let (comptime, _) = default_value?;
556
557 if x.is_anonymous_expression() {
558 None
559 } else {
560 let value = comptime.get_value()?.clone();
561 Some((value, comptime))
562 }
563 } else {
564 None
565 };
566
567 if let Some((value, comptime)) = default_value {
568 let mut comptime = comptime.clone();
569 comptime.value = ValueVariant::Numeric(value.clone());
570 comptime.r#type = r#type.clone();
571
572 let id = context.insert_var_path(path.clone(), comptime);
574 let array_limit = context.config.evaluate_array_limit;
575 let variable = Variable::new(
576 id,
577 path,
578 kind,
579 r#type,
580 vec![value.clone()],
581 context.get_affiliation(),
582 &variable_token,
583 array_limit,
584 );
585 context.insert_variable(id, variable);
586 } else {
587 eval_variable(context, &path, kind, &r#type, clock_domain, variable_token);
588 }
589 Ok(())
590 } else {
591 Err(ir_error!(token))
592 }
593 }
594}
595
596impl Conv<&AlwaysFfDeclaration> for ir::Declaration {
597 fn conv(context: &mut Context, value: &AlwaysFfDeclaration) -> IrResult<Self> {
598 let clock = eval_clock(context, value)?;
599 let reset = eval_reset(context, value)?;
600
601 if let Some(reset) = &reset {
602 check_clock_domain(
603 context,
604 &clock.comptime,
605 &reset.comptime,
606 &value.always_ff.always_ff_token.token,
607 );
608 }
609
610 context.current_clock = Some(clock.comptime.clone());
611
612 context.push_affiliation(Affiliation::AlwaysFf);
613
614 let statements: IrResult<ir::StatementBlock> =
615 context.block(|c| Conv::conv(c, value.statement_block.as_ref()));
616
617 context.pop_affiliation();
618
619 Ok(ir::Declaration::new_ff(clock, reset, statements?.0))
620 }
621}
622
623impl Conv<&AlwaysCombDeclaration> for ir::Declaration {
624 fn conv(context: &mut Context, value: &AlwaysCombDeclaration) -> IrResult<Self> {
625 context.push_affiliation(Affiliation::AlwaysComb);
626
627 let statements: IrResult<ir::StatementBlock> =
628 context.block(|c| Conv::conv(c, value.statement_block.as_ref()));
629
630 context.pop_affiliation();
631
632 Ok(ir::Declaration::new_comb(statements?.0))
633 }
634}
635
636impl Conv<&VarDeclaration> for ir::Declaration {
637 fn conv(context: &mut Context, value: &VarDeclaration) -> IrResult<Self> {
638 let define_context: DefineContext = (&value.var.var_token).into();
639 if !define_context.is_default() {
640 return Ok(ir::Declaration::Null);
641 }
642
643 let token: TokenRange = value.into();
644
645 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
646 && let SymbolKind::Variable(x) = &symbol.found.kind
647 {
648 let path = VarPath::new(symbol.found.token.text);
649 let kind = VarKind::Variable;
650 let variable_token: TokenRange = (&value.identifier.identifier_token).into();
651
652 let r#type = x.r#type.to_ir_type(context, TypePosition::Variable)?;
653 let clock_domain = x.clock_domain;
654
655 eval_variable(context, &path, kind, &r#type, clock_domain, variable_token);
656 Ok(ir::Declaration::Null)
657 } else {
658 Err(ir_error!(token))
659 }
660 }
661}
662
663impl Conv<&LetDeclaration> for ir::Declaration {
664 fn conv(context: &mut Context, value: &LetDeclaration) -> IrResult<Self> {
665 let define_context: DefineContext = (&value.r#let.let_token).into();
666 if !define_context.is_default() {
667 return Ok(ir::Declaration::Null);
668 }
669
670 let token: TokenRange = value.into();
671
672 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
673 && let SymbolKind::Variable(x) = &symbol.found.kind
674 {
675 let path = VarPath::new(symbol.found.token.text);
676 let kind = VarKind::Let;
677 let variable_token: TokenRange = (&value.identifier.identifier_token).into();
678
679 let inferred = try_infer_decl_type(
680 context,
681 &x.r#type,
682 &value.expression,
683 value.identifier.identifier_token.token.id,
684 token,
685 )?;
686 let r#type = if let Some((ref comptime, _)) = inferred {
687 comptime.r#type.clone()
688 } else {
689 x.r#type.to_ir_type(context, TypePosition::Variable)?
690 };
691 let clock_domain = x.clock_domain;
692
693 eval_variable(context, &path, kind, &r#type, clock_domain, variable_token);
694
695 let (id, comptime) = context.find_path(&path).ok_or_else(|| ir_error!(token))?;
696
697 let mut dst = ir::AssignDestination {
698 id,
699 path,
700 index: VarIndex::default(),
701 select: VarSelect::default(),
702 comptime,
703 token: variable_token,
704 };
705
706 let mut expr = if let Some(inferred) = inferred {
707 inferred
708 } else {
709 eval_expr(context, Some(r#type.clone()), &value.expression, false)?
710 };
711
712 let statements = eval_assign_statement(context, &mut dst, &mut expr, token)?;
713 Ok(ir::Declaration::new_comb(statements))
714 } else {
715 Err(ir_error!(token))
716 }
717 }
718}
719
720impl Conv<&ConstDeclaration> for ir::Declaration {
721 fn conv(context: &mut Context, value: &ConstDeclaration) -> IrResult<Self> {
722 let define_context: DefineContext = (&value.r#const.const_token).into();
723 if !define_context.is_default() {
724 return Ok(ir::Declaration::Null);
725 }
726
727 let token: TokenRange = value.into();
728
729 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
730 && let SymbolKind::Parameter(x) = &symbol.found.kind
731 {
732 let path = VarPath::new(symbol.found.token.text);
733 let kind: VarKind = (&x.kind).into();
734 let variable_token: TokenRange = (&value.identifier.identifier_token).into();
735
736 let inferred = try_infer_decl_type(
737 context,
738 &x.r#type,
739 &value.expression,
740 value.identifier.identifier_token.token.id,
741 token,
742 )?;
743 let r#type = if let Some((ref comptime, _)) = inferred {
744 comptime.r#type.clone()
745 } else {
746 x.r#type.to_ir_type(context, TypePosition::Variable)?
747 };
748
749 let Some(expr) = &x.value else {
750 context.insert_error(AnalyzerError::missing_default_argument(
751 &value.identifier.text().to_string(),
752 &value.identifier.as_ref().into(),
753 ));
754 return Err(ir_error!(token));
755 };
756
757 let (comptime, expr) = if let Some(inferred) = inferred {
758 inferred
759 } else {
760 eval_expr(context, Some(r#type.clone()), expr, false)?
761 };
762 if !comptime.is_const {
763 context.insert_error(AnalyzerError::unevaluable_value(
764 UnevaluableValueKind::ConstValue,
765 &expr.token_range(),
766 ));
767 }
768
769 let dst = ir::AssignDestination {
770 id: VarId::default(),
771 path: path.clone(),
772 index: VarIndex::default(),
773 select: VarSelect::default(),
774 comptime: Comptime::from_type(r#type, ClockDomain::None, TokenRange::default()),
775 token: variable_token,
776 };
777
778 eval_const_assign(context, kind, &dst, &mut (comptime, expr))?;
779
780 Ok(ir::Declaration::Null)
781 } else {
782 Err(ir_error!(token))
783 }
784 }
785}
786
787impl Conv<&GenDeclaration> for ir::Declaration {
788 fn conv(context: &mut Context, value: &GenDeclaration) -> IrResult<Self> {
789 let define_context: DefineContext = (&value.r#gen.gen_token).into();
790 if !define_context.is_default() {
791 return Ok(ir::Declaration::Null);
792 }
793
794 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
795 && let SymbolKind::GenericConst(x) = &symbol.found.kind
796 {
797 check_generic_bound_item(context, &x.bound, &symbol.found.namespace);
798 check_generic_expression(
799 context,
800 &x.value,
801 &x.bound,
802 None,
803 value.identifier.as_ref().into(),
804 );
805 Ok(ir::Declaration::Null)
806 } else {
807 Err(ir_error!(value.into()))
808 }
809 }
810}
811
812impl Conv<&AssignDeclaration> for ir::Declaration {
813 fn conv(context: &mut Context, value: &AssignDeclaration) -> IrResult<Self> {
814 let define_context: DefineContext = (&value.assign.assign_token).into();
815 if !define_context.is_default() {
816 return Ok(ir::Declaration::Null);
817 }
818
819 let token: TokenRange = value.into();
820
821 match value.assign_destination.as_ref() {
822 AssignDestination::HierarchicalIdentifier(x) => {
823 let ident = x.hierarchical_identifier.as_ref();
824
825 let inferred =
826 if let Ok(symbol) = symbol_table::resolve(x.hierarchical_identifier.as_ref()) {
827 try_infer_var_assign(context, &symbol.found, &value.expression, token)?
828 } else {
829 None
830 };
831
832 let dst: VarPathSelect = Conv::conv(context, ident)?;
833
834 if let Some(mut dst) = dst.to_assign_destination(context, false) {
835 let mut expr = if let Some(inferred) = inferred {
836 inferred
837 } else {
838 eval_expr(
839 context,
840 Some(dst.comptime.r#type.clone()),
841 &value.expression,
842 false,
843 )?
844 };
845
846 let statements = eval_assign_statement(context, &mut dst, &mut expr, token)?;
847
848 Ok(ir::Declaration::new_comb(statements))
849 } else {
850 if let Ok(symbol) = symbol_table::resolve(x.hierarchical_identifier.as_ref())
851 && let SymbolKind::Variable(x) = &symbol.found.kind
852 && x.affiliation == Affiliation::Module
853 {
854 let ident_token = ident.identifier.identifier_token.token;
855 context.insert_error(AnalyzerError::referring_before_definition(
856 &ident_token.text.to_string(),
857 &ident_token.into(),
858 ));
859 }
860 Err(ir_error!(token))
861 }
862 }
863 AssignDestination::LBraceAssignConcatenationListRBrace(x) => {
864 let items: Vec<_> = x.assign_concatenation_list.as_ref().into();
865
866 let mut dst = vec![];
867 for item in items {
868 let ident = item.hierarchical_identifier.as_ref();
869 let x: VarPathSelect = Conv::conv(context, ident)?;
870 if let Some(x) = x.to_assign_destination(context, false) {
871 dst.push(x);
872 } else {
873 if let Ok(symbol) =
874 symbol_table::resolve(item.hierarchical_identifier.as_ref())
875 && let SymbolKind::Variable(x) = &symbol.found.kind
876 && x.affiliation == Affiliation::Module
877 {
878 let ident_token = ident.identifier.identifier_token.token;
879 context.insert_error(AnalyzerError::referring_before_definition(
880 &ident_token.text.to_string(),
881 &ident_token.into(),
882 ));
883 }
884 return Err(ir_error!(token));
885 }
886 }
887
888 let mut width = Some(0);
889 for x in &dst {
890 if let Some(x) = x.total_width(context)
891 && let Some(width) = &mut width
892 {
893 *width += x;
894 } else {
895 width = None;
896 }
897 }
898 if let Some(x) = width {
899 width = context.check_size(x, token);
900 }
901
902 let r#type = {
903 let mut t = ir::Type::new(TypeKind::Logic);
904 t.set_concrete_width(Shape::new(vec![width]));
905 t
906 };
907
908 let (_, expr) = eval_expr(context, Some(r#type), &value.expression, false)?;
909 let statement = ir::Statement::Assign(ir::AssignStatement {
910 dst,
911 width,
912 expr,
913 token,
914 });
915 Ok(ir::Declaration::Comb(ir::CombDeclaration {
916 statements: vec![statement],
917 }))
918 }
919 }
920 }
921}
922
923impl Conv<(&FunctionDeclaration, Option<&FuncPath>)> for () {
924 fn conv(
925 context: &mut Context,
926 value: (&FunctionDeclaration, Option<&FuncPath>),
927 ) -> IrResult<Self> {
928 let (func_def, path) = value;
929 let token: TokenRange = (&func_def.identifier.identifier_token).into();
930
931 if let Some(x) = &func_def.function_declaration_opt {
932 check_generic_bound(context, &x.with_generic_parameter);
933 }
934
935 if let Ok(symbol) = symbol_table::resolve(func_def.identifier.as_ref())
936 && let SymbolKind::Function(_) = &symbol.found.kind
937 {
938 let port_declaration = func_def
939 .function_declaration_opt0
940 .as_ref()
941 .map(|x| x.port_declaration.as_ref());
942 let statement_block = Some(func_def.statement_block.as_ref());
943 conv_function(
944 context,
945 path,
946 &symbol.found,
947 port_declaration,
948 statement_block,
949 token,
950 )
951 } else {
952 Err(ir_error!(token))
953 }
954 }
955}
956
957impl Conv<&FunctionDeclaration> for () {
958 fn conv(context: &mut Context, value: &FunctionDeclaration) -> IrResult<Self> {
959 if value.function_declaration_opt.is_some() {
961 context.ignore_var_func = true;
962 }
963
964 let ret = Conv::conv(context, (value, None));
965
966 if value.function_declaration_opt.is_some() {
967 context.ignore_var_func = false;
968 Ok(())
969 } else {
970 ret
971 }
972 }
973}
974
975impl Conv<(&ProtoFunctionDeclaration, Option<&FuncPath>)> for () {
976 fn conv(
977 context: &mut Context,
978 value: (&ProtoFunctionDeclaration, Option<&FuncPath>),
979 ) -> IrResult<Self> {
980 let (func_def, path) = value;
981 let token: TokenRange = (&func_def.identifier.identifier_token).into();
982
983 if let Some(x) = &func_def.proto_function_declaration_opt {
984 check_generic_bound(context, &x.with_generic_parameter);
985 }
986
987 if let Ok(symbol) = symbol_table::resolve(func_def.identifier.as_ref())
988 && let SymbolKind::ProtoFunction(_) = &symbol.found.kind
989 {
990 let port_declaration = func_def
991 .proto_function_declaration_opt0
992 .as_ref()
993 .map(|x| x.port_declaration.as_ref());
994 conv_function(context, path, &symbol.found, port_declaration, None, token)
995 } else {
996 Err(ir_error!(token))
997 }
998 }
999}
1000
1001fn conv_function(
1002 context: &mut Context,
1003 path: Option<&FuncPath>,
1004 symbol: &Symbol,
1005 port_declaratoin: Option<&PortDeclaration>,
1006 statement_block: Option<&StatementBlock>,
1007 token: TokenRange,
1008) -> IrResult<()> {
1009 let (path, name, namespace) = if let Some(path) = path {
1012 let name = resource_table::insert_str(&path.sig.to_string());
1013 (path.clone(), name, path.sig.namespace())
1014 } else {
1015 let path = FuncPath::new(symbol.id);
1016 (path, symbol.token.text, symbol.inner_namespace())
1017 };
1018
1019 if context.func_paths.contains_key(&path) {
1020 return Ok(());
1022 }
1023 let id = context.insert_func_path(path.clone());
1024
1025 let proeprty = match &symbol.kind {
1026 SymbolKind::Function(x) => x,
1027 SymbolKind::ProtoFunction(x) => x,
1028 _ => unreachable!(),
1029 };
1030
1031 let ret_type = if let Some(ret_type) = proeprty.ret.as_ref() {
1032 let mut r#type = ret_type.to_ir_type(context, TypePosition::Variable)?;
1033 if r#type.is_struct() {
1034 r#type.set_concrete_width(Shape::new(vec![r#type.total_width()]));
1035 r#type.kind = if r#type.is_2state() {
1036 TypeKind::Bit
1037 } else {
1038 TypeKind::Logic
1039 };
1040 }
1041 Comptime::from_type(r#type, ClockDomain::None, token)
1042 } else {
1043 let r#type = ir::Type::new(TypeKind::Void);
1044 Comptime::from_type(r#type, ClockDomain::None, token)
1045 };
1046
1047 let mut args = vec![];
1048 let ports: Vec<_> = if let Some(port_declaratoin) = port_declaratoin
1049 && let Some(ref x) = port_declaratoin.port_declaration_opt
1050 {
1051 x.port_declaration_list.as_ref().into()
1052 } else {
1053 vec![]
1054 };
1055 let arity = ports.len();
1056
1057 context.push_affiliation(Affiliation::Function);
1058 context.push_hierarchy(name);
1059 context.push_namespace(namespace);
1060
1061 let token: TokenRange = symbol.token.into();
1062 let func = context.block(|c| {
1063 let ret_id = if ret_type.r#type.kind != TypeKind::Void {
1064 let path = VarPath::new(get_return_str());
1065 let kind = VarKind::Variable;
1066 let r#type = ret_type.r#type.clone();
1067
1068 if let Some(_total_array) = r#type.total_array()
1070 && let Some(total_width) = r#type.total_width()
1071 {
1072 let values = vec![Value::new_x(total_width, false)];
1077
1078 let ret_id = c.insert_var_path(path.clone(), ret_type.clone());
1079 let array_limit = c.config.evaluate_array_limit;
1080 let variable = Variable::new(
1081 ret_id,
1082 path,
1083 kind,
1084 r#type,
1085 values,
1086 c.get_affiliation(),
1087 &token,
1088 array_limit,
1089 );
1090 c.insert_variable(ret_id, variable);
1091 Some(ret_id)
1092 } else {
1093 None
1094 }
1095 } else {
1096 None
1097 };
1098
1099 let mut arg_map = HashMap::default();
1100 for port in ports {
1101 let _: IrResult<()> = Conv::conv(c, port);
1102
1103 let name = port.identifier.text();
1104 let path = VarPath::new(name);
1105 if let Some((_, comptime)) = c.var_paths.get(&path).cloned() {
1106 let modport_members = comptime.r#type.expand_modport(c, &path, token)?;
1107 if modport_members.is_empty() {
1108 let mut members = vec![];
1109 if let Some((id, comptime)) = c.var_paths.get(&path).cloned() {
1110 let variable = c.variables.get(&id).ok_or_else(|| ir_error!(token))?;
1111 let direction = match variable.kind {
1112 VarKind::Input => Direction::Input,
1113 VarKind::Output => Direction::Output,
1114 _ => unreachable!(),
1115 };
1116
1117 arg_map.insert(path.clone(), id);
1118 members.push((path.clone(), comptime, direction));
1119 }
1120 let arg = FuncArg {
1121 name: path.first(),
1122 comptime,
1123 members,
1124 };
1125 args.push(arg);
1126 } else {
1127 let mut members = vec![];
1128 for (path, direction) in modport_members {
1129 if let Some((id, comptime)) = c.var_paths.get(&path) {
1130 arg_map.insert(path.clone(), *id);
1131 members.push((path, comptime.clone(), direction));
1132 }
1133 }
1134 let arg = FuncArg {
1135 name: path.first(),
1136 comptime,
1137 members,
1138 };
1139 args.push(arg);
1140 }
1141 }
1142 }
1143
1144 let body = if let Some(block) = statement_block {
1145 let disable_const_opt = c.disalbe_const_opt;
1146 c.disalbe_const_opt = true;
1147 let statements: IrResult<ir::StatementBlock> = Conv::conv(c, block);
1148 c.disalbe_const_opt = disable_const_opt;
1149
1150 vec![ir::FunctionBody {
1151 ret: ret_id,
1152 arg_map,
1153 statements: statements?.0,
1154 }]
1155 } else {
1156 vec![]
1157 };
1158
1159 Ok((args, body))
1160 });
1161
1162 context.pop_affiliation();
1163 context.pop_hierarchy();
1164 context.pop_namespace();
1165
1166 let (args, body) = func?;
1167 let func = ir::Function {
1168 name,
1169 id,
1170 path,
1171 r#type: ret_type,
1172 array: Shape::default(),
1173 arity,
1174 args,
1175 is_const: proeprty.constantable.unwrap(),
1176 functions: body,
1177 token,
1178 };
1179
1180 context.insert_function(id, func);
1182 Ok(())
1183}
1184
1185impl Conv<&StructUnionDeclaration> for () {
1186 fn conv(context: &mut Context, value: &StructUnionDeclaration) -> IrResult<Self> {
1187 eval_type(
1188 context,
1189 &value.identifier.as_ref().into(),
1190 TypePosition::TypeDef,
1191 )?;
1192
1193 if let Some(x) = &value.struct_union_declaration_opt {
1194 check_generic_bound(context, &x.with_generic_parameter);
1195 }
1196
1197 if context.is_affiliated(Affiliation::Interface) {
1198 let kind = match value.struct_union.as_ref() {
1199 StructUnion::Struct(_) => "struct",
1200 StructUnion::Union(_) => "union",
1201 };
1202 context.insert_error(AnalyzerError::invalid_type_declaration(kind, &value.into()));
1203 }
1204
1205 Ok(())
1206 }
1207}
1208
1209impl Conv<&EnumDeclaration> for () {
1210 fn conv(context: &mut Context, value: &EnumDeclaration) -> IrResult<Self> {
1211 eval_type(
1212 context,
1213 &value.identifier.as_ref().into(),
1214 TypePosition::TypeDef,
1215 )?;
1216
1217 if context.is_affiliated(Affiliation::Interface) {
1218 context.insert_error(AnalyzerError::invalid_type_declaration(
1219 "enum",
1220 &value.into(),
1221 ));
1222 }
1223
1224 Ok(())
1225 }
1226}
1227
1228impl Conv<&InitialDeclaration> for ir::Declaration {
1229 fn conv(context: &mut Context, value: &InitialDeclaration) -> IrResult<Self> {
1230 let statements: ir::StatementBlock = Conv::conv(context, value.statement_block.as_ref())?;
1231 Ok(ir::Declaration::Initial(ir::InitialDeclaration {
1232 statements: statements.0,
1233 }))
1234 }
1235}
1236
1237impl Conv<&FinalDeclaration> for ir::Declaration {
1238 fn conv(context: &mut Context, value: &FinalDeclaration) -> IrResult<Self> {
1239 let statements: ir::StatementBlock = Conv::conv(context, value.statement_block.as_ref())?;
1240 Ok(ir::Declaration::Final(ir::FinalDeclaration {
1241 statements: statements.0,
1242 }))
1243 }
1244}
1245
1246impl Conv<&InstDeclaration> for ir::Declaration {
1247 fn conv(context: &mut Context, value: &InstDeclaration) -> IrResult<Self> {
1248 let define_context: DefineContext = (&value.inst.inst_token).into();
1249 if !define_context.is_default() {
1250 return Ok(ir::Declaration::Null);
1251 }
1252
1253 let in_module = context.is_affiliated(Affiliation::Module);
1254 let token = value.inst.inst_token.token;
1255 check_inst(context, in_module, &token, &value.component_instantiation);
1256
1257 let path: SymbolPathNamespace = value
1258 .component_instantiation
1259 .scoped_identifier
1260 .as_ref()
1261 .into();
1262 if let Ok(symbol) = symbol_table::resolve(&path)
1263 && let SymbolKind::TbComponent(ref tb_prop) = symbol.found.kind
1264 {
1265 if !context.in_test_module {
1266 let token: TokenRange = value
1267 .component_instantiation
1268 .scoped_identifier
1269 .as_ref()
1270 .into();
1271 context.insert_error(AnalyzerError::invalid_tb_usage(&token));
1272 return Ok(ir::Declaration::Null);
1273 }
1274
1275 let inst_token: TokenRange = value.component_instantiation.identifier.as_ref().into();
1277 let inst_name = value
1278 .component_instantiation
1279 .identifier
1280 .identifier_token
1281 .token
1282 .text;
1283 let var_path = ir::VarPath::new(inst_name);
1284 let type_kind = match tb_prop.kind {
1285 TbComponentKind::ClockGen => ir::TypeKind::Clock,
1286 TbComponentKind::ResetGen => ir::TypeKind::Reset,
1287 };
1288 let ir_type = {
1289 let mut t = ir::Type::new(type_kind);
1290 t.set_concrete_width(ir::Shape::new(vec![Some(1)]));
1291 t
1292 };
1293 eval_variable(
1294 context,
1295 &var_path,
1296 ir::VarKind::Variable,
1297 &ir_type,
1298 ClockDomain::None,
1299 inst_token,
1300 );
1301
1302 attribute_table::insert(inst_token, Attribute::Allow(AllowItem::UnassignVariable));
1304
1305 if let Some(ref opt1) = value.component_instantiation.component_instantiation_opt1
1306 && let Some(ref param_opt) = opt1.inst_parameter.inst_parameter_opt
1307 {
1308 let items: Vec<_> = param_opt.inst_parameter_list.as_ref().into();
1309 for item in items {
1310 let param_name = item.identifier.identifier_token.token.text.to_string();
1311 match (&tb_prop.kind, param_name.as_str()) {
1312 (TbComponentKind::ResetGen, "cycles") => {
1313 if let Some(ref opt) = item.inst_parameter_item_opt {
1314 let (_, expr) = eval_expr(context, None, &opt.expression, false)?;
1315 context.tb_reset_cycles.insert(inst_name, expr);
1316 }
1317 }
1318 (TbComponentKind::ClockGen, "period") => {
1319 if let Some(ref opt) = item.inst_parameter_item_opt {
1320 let (_, expr) = eval_expr(context, None, &opt.expression, false)?;
1321 context.tb_clock_period.insert(inst_name, expr);
1322 }
1323 }
1324 _ => {}
1325 }
1326 }
1327 }
1328
1329 let mut connected_clk: Option<StrId> = None;
1330 if let Some(ref opt2) = value.component_instantiation.component_instantiation_opt2
1331 && let Some(ref port_opt) = opt2.inst_port.inst_port_opt
1332 {
1333 let items: Vec<_> = port_opt.inst_port_list.as_ref().into();
1334 for item in items {
1335 let port_name = item.identifier.identifier_token.token.text;
1336 let port_name_str =
1337 resource_table::get_str_value(port_name).unwrap_or_default();
1338 let port_token: TokenRange = item.identifier.as_ref().into();
1339 match (&tb_prop.kind, port_name_str.as_str()) {
1340 (TbComponentKind::ResetGen, "clk") => {
1341 let signal_name = if let Some(ref x) = item.inst_port_item_opt {
1342 let dst: Vec<VarPathSelect> =
1343 Conv::conv(context, x.expression.as_ref())?;
1344 dst.first().and_then(|p| p.0.0.first().copied())
1345 } else {
1346 Some(port_name)
1347 };
1348 if let Some(name) = signal_name {
1349 connected_clk = Some(name);
1350 }
1351 }
1352 _ => {
1353 let type_name = match tb_prop.kind {
1354 TbComponentKind::ClockGen => "$tb::clock_gen",
1355 TbComponentKind::ResetGen => "$tb::reset_gen",
1356 };
1357 context.insert_error(AnalyzerError::unknown_tb_port(
1358 type_name,
1359 &port_name_str,
1360 &port_token,
1361 ));
1362 }
1363 }
1364 }
1365 }
1366
1367 if matches!(tb_prop.kind, TbComponentKind::ResetGen) {
1368 if let Some(clk) = connected_clk {
1369 context.tb_reset_clock.insert(inst_name, clk);
1370 } else {
1371 let type_name: TokenRange = value
1372 .component_instantiation
1373 .scoped_identifier
1374 .as_ref()
1375 .into();
1376 context.insert_error(AnalyzerError::missing_tb_port(
1377 "$tb::reset_gen",
1378 "clk",
1379 &type_name,
1380 ));
1381 }
1382 }
1383
1384 return Ok(ir::Declaration::Null);
1385 }
1386
1387 let clock_domain = if let Ok(symbol) =
1388 symbol_table::resolve(value.component_instantiation.identifier.as_ref())
1389 && let SymbolKind::Instance(x) = &symbol.found.kind
1390 {
1391 x.clock_domain
1392 } else {
1393 ClockDomain::None
1394 };
1395
1396 let value = value.component_instantiation.as_ref();
1397 let token: TokenRange = value.identifier.as_ref().into();
1398 let generic_path: GenericSymbolPath = value.scoped_identifier.as_ref().into();
1399
1400 check_generic_refereence(context, &generic_path);
1401
1402 let mut sig =
1403 Signature::from_path(context, generic_path).ok_or_else(|| ir_error!(token))?;
1404 let symbol = symbol_table::get(sig.symbol).unwrap();
1405
1406 let parameters = symbol.kind.get_parameters();
1407 let overridden_params = get_overridden_params(context, value)?;
1408 for x in parameters {
1409 let path = VarPath::new(x.name);
1410 if let Some(value) = overridden_params.get(&path) {
1411 sig.add_parameter(x.name, value.0.value.clone());
1412 }
1413 }
1414
1415 context.push_override(overridden_params);
1416
1417 let component = context.block(|c| get_component(c, &sig, token));
1418
1419 context.pop_override();
1420
1421 let component_arc = component?;
1422 match component_arc.as_ref() {
1423 ir::Component::Module(component) => {
1424 let mut inputs = vec![];
1425 let mut outputs = vec![];
1426 if let Some(x) = &value.component_instantiation_opt2
1427 && let Some(x) = &x.inst_port.inst_port_opt
1428 {
1429 let ports: Vec<_> = x.inst_port_list.as_ref().into();
1430 let mut clock_domain_table = HashMap::default();
1431
1432 for port in ports {
1433 let name = port.identifier.text();
1434 let path = VarPath::new(name);
1435 let token: TokenRange = port.identifier.as_ref().into();
1436 if let Some((dst_type, clock_domain)) = component.port_types.get(&path) {
1437 let connects =
1438 get_port_connects(context, component, port, &path, dst_type, token);
1439 let Ok(connects) = connects else {
1440 continue;
1441 };
1442
1443 let dst_comptime =
1444 Comptime::from_type(dst_type.clone(), *clock_domain, token);
1445
1446 for (path, dst, mut expr) in connects {
1447 if let Some(id) = component.ports.get(&path)
1448 && let Some(variable) = component.variables.get(id)
1449 {
1450 let expr_comptime = expr.eval_comptime(context, None);
1451
1452 if let Some(x) =
1453 clock_domain_table.get(&dst_comptime.clock_domain)
1454 {
1455 check_clock_domain(context, x, expr_comptime, &token.beg);
1456 } else {
1457 clock_domain_table.insert(
1458 dst_comptime.clock_domain,
1459 expr_comptime.clone(),
1460 );
1461 }
1462
1463 insert_port_connect(
1464 context,
1465 variable,
1466 dst,
1467 expr,
1468 &mut inputs,
1469 &mut outputs,
1470 );
1471 }
1472 }
1473 }
1474 }
1475 }
1476
1477 let name = value.identifier.text();
1480 Ok(ir::Declaration::Inst(Box::new(ir::InstDeclaration {
1481 name,
1482 inputs,
1483 outputs,
1484 component: component_arc,
1485 })))
1486 }
1487 ir::Component::Interface(component) => {
1488 let mut array = Shape::default();
1489 if let Some(x) = &value.component_instantiation_opt0 {
1490 let exprs: Vec<_> = x.array.as_ref().into();
1491 for expr in exprs {
1492 let (_, value) = eval_size(context, expr, false)?;
1493 array.push(value)
1494 }
1495 }
1496
1497 let base = value.identifier.text();
1498 context.extract_interface_member(
1499 base,
1500 &array,
1501 component.clone(),
1502 None,
1503 clock_domain,
1504 token,
1505 );
1506
1507 let path = VarPath::new(value.identifier.text());
1509 let r#type = {
1510 let mut t = ir::Type::new(TypeKind::Instance(sig, InstanceKind::Interface));
1511 t.array = array;
1512 t
1513 };
1514
1515 let comptime = Comptime::from_type(r#type.clone(), clock_domain, token);
1516 context.insert_var_path(path.clone(), comptime);
1517
1518 Ok(ir::Declaration::Null)
1519 }
1520 ir::Component::SystemVerilog(component) => {
1521 let mut component = component.clone();
1525 if let Some(x) = &value.component_instantiation_opt2
1526 && let Some(x) = &x.inst_port.inst_port_opt
1527 {
1528 let ports: Vec<_> = x.inst_port_list.as_ref().into();
1529 let mut prev_port = None;
1530 for port in ports {
1531 let dst_paths = if let Some(x) = &port.inst_port_item_opt {
1532 let dst: Vec<VarPathSelect> =
1533 Conv::conv(context, x.expression.as_ref())?;
1534 dst
1535 } else {
1536 let name = port.identifier.text();
1537 let path = VarPath::new(name);
1538 let path = VarPathSelect(
1539 path,
1540 VarSelect::default(),
1541 port.identifier.identifier_token.token.into(),
1542 );
1543 vec![path]
1544 };
1545
1546 let mut expanded_paths = vec![];
1547 for dst_path in dst_paths {
1548 if let Some((_, comptime)) = context.find_path(&dst_path.0) {
1549 if comptime.r#type.is_interface() {
1550 let paths = comptime.r#type.expand_interface(
1551 context,
1552 &dst_path.0,
1553 comptime.token,
1554 )?;
1555 for x in paths {
1556 let path =
1557 VarPathSelect(x.0, dst_path.1.clone(), dst_path.2);
1558 expanded_paths.push(path);
1559 }
1560 } else {
1561 expanded_paths.push(dst_path);
1562 }
1563 }
1564 }
1565
1566 let mut dst_paths =
1567 var_path_to_assign_destination(context, expanded_paths, true);
1568
1569 for dst_path in &dst_paths {
1570 if let Some((_, comptime)) = context.find_path(&dst_path.path) {
1571 if let Some(prev) = &prev_port {
1573 check_clock_domain(context, &comptime, prev, &token.beg);
1574 }
1575
1576 if comptime.r#type.is_reset()
1578 && !comptime.r#type.is_explicit_reset()
1579 {
1580 context.insert_error(AnalyzerError::sv_with_implicit_reset(
1581 &token,
1582 ));
1583 }
1584
1585 prev_port = Some(comptime);
1586 }
1587 }
1588
1589 component.connects.append(&mut dst_paths);
1590 }
1591 }
1592 let name = value.identifier.text();
1593 let component = Arc::new(ir::Component::SystemVerilog(component));
1594 Ok(ir::Declaration::Inst(Box::new(ir::InstDeclaration {
1595 name,
1596 inputs: vec![],
1597 outputs: vec![],
1598 component,
1599 })))
1600 }
1601 }
1602 }
1603}
1604
1605impl Conv<&ConnectDeclaration> for ir::DeclarationBlock {
1606 fn conv(context: &mut Context, value: &ConnectDeclaration) -> IrResult<Self> {
1607 let token: TokenRange = value.into();
1608
1609 let lhs: VarPathSelect = Conv::conv(context, value.hierarchical_identifier.as_ref())?;
1610 let rhs: Vec<VarPathSelect> = Conv::conv(context, value.expression.as_ref())?;
1611
1612 let (comptime, _) = eval_expr(context, None, value.expression.as_ref(), false)?;
1613
1614 let statements = if comptime.is_const {
1615 expand_connect_const(context, lhs, comptime, token)?
1616 } else {
1617 if rhs.len() != 1 {
1618 context.insert_error(AnalyzerError::mismatch_type(
1619 MismatchTypeKind::ConnectMultipleExpression,
1620 &token,
1621 ));
1622 return Err(ir_error!(token));
1623 }
1624
1625 let rhs = rhs[0].clone();
1626
1627 expand_connect(context, lhs, rhs, token)?
1628 };
1629
1630 let ret = ir::CombDeclaration { statements };
1631 let ret = ir::Declaration::Comb(ret);
1632 Ok(ir::DeclarationBlock(vec![ret]))
1633 }
1634}
1635
1636impl Conv<&UnsafeBlock> for ir::DeclarationBlock {
1637 fn conv(context: &mut Context, value: &UnsafeBlock) -> IrResult<Self> {
1638 let mut ret = vec![];
1639 for x in &value.unsafe_block_list {
1640 let items: Vec<_> = x.generate_group.as_ref().into();
1641 for item in items {
1642 let item: IrResult<ir::DeclarationBlock> = Conv::conv(context, item);
1643
1644 if let Ok(mut item) = item {
1645 ret.append(&mut item.0);
1646 }
1647 }
1648 }
1649 Ok(ir::DeclarationBlock(ret))
1650 }
1651}
1652
1653impl Conv<&ImportDeclaration> for ir::DeclarationBlock {
1654 fn conv(context: &mut Context, value: &ImportDeclaration) -> IrResult<Self> {
1655 check_import(context, value);
1656 Ok(ir::DeclarationBlock::default())
1657 }
1658}
1659
1660impl Conv<&BindDeclaration> for () {
1661 fn conv(context: &mut Context, value: &BindDeclaration) -> IrResult<Self> {
1662 if let Ok(symbol) = symbol_table::resolve(value.scoped_identifier.as_ref()) {
1663 if !check_bind_target(context, &value.scoped_identifier, &symbol.found) {
1664 return Ok(());
1665 }
1666
1667 let in_module = symbol.found.is_module(true);
1668 let token = value.bind.bind_token.token;
1669 check_inst(context, in_module, &token, &value.component_instantiation);
1670 }
1671
1672 Ok(())
1673 }
1674}
1675
1676impl Conv<&EmbedDeclaration> for () {
1677 fn conv(context: &mut Context, value: &EmbedDeclaration) -> IrResult<Self> {
1678 for x in &value.embed_content.embed_content_list {
1679 if let EmbedItem::EmbedScopedIdentifier(x) = x.embed_item.as_ref() {
1680 let path = x.embed_scoped_identifier.scoped_identifier.as_ref();
1681
1682 let token: TokenRange = path.identifier().into();
1683 let generic_path: GenericSymbolPath = path.into();
1684
1685 if let Ok(symbol) = symbol_table::resolve(path)
1687 && matches!(
1688 symbol.found.kind,
1689 SymbolKind::Module(_) | SymbolKind::Interface(_)
1690 )
1691 {
1692 let sig = Signature::from_path(context, generic_path)
1693 .ok_or_else(|| ir_error!(token))?;
1694 let _component = context.block(|c| get_component(c, &sig, token));
1695 }
1696 }
1697 }
1698
1699 Ok(())
1700 }
1701}
1702
1703impl Conv<&AliasDeclaration> for () {
1704 fn conv(context: &mut Context, value: &AliasDeclaration) -> IrResult<Self> {
1705 let r#type = match value.alias_declaration_group.as_ref() {
1706 AliasDeclarationGroup::Module(_) => AliasType::Module,
1707 AliasDeclarationGroup::Interface(_) => AliasType::Interface,
1708 AliasDeclarationGroup::Package(_) => AliasType::Package,
1709 };
1710
1711 check_alias_target(context, &value.scoped_identifier, r#type);
1712
1713 Ok(())
1714 }
1715}
1716
1717impl Conv<&TypeDefDeclaration> for () {
1718 fn conv(context: &mut Context, value: &TypeDefDeclaration) -> IrResult<Self> {
1719 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
1720 && let SymbolKind::TypeDef(x) = &symbol.found.kind
1721 {
1722 x.r#type.to_ir_type(context, TypePosition::TypeDef)?;
1723 }
1724
1725 Ok(())
1726 }
1727}
1728
1729impl Conv<&ModportDeclaration> for () {
1730 fn conv(context: &mut Context, value: &ModportDeclaration) -> IrResult<Self> {
1731 context.push_affiliation(Affiliation::Modport);
1732
1733 let ret = context.block(|c| {
1734 if let Some(x) = &value.modport_declaration_opt {
1735 let items: Vec<_> = x.modport_list.as_ref().into();
1736 for item in &items {
1737 check_modport(c, item);
1738 check_direction(c, &item.direction);
1739 }
1740 }
1741
1742 if let Some(x) = &value.modport_declaration_opt0 {
1743 check_modport_default(c, x.modport_default.as_ref(), value.identifier.text());
1744 }
1745
1746 if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
1747 && let SymbolKind::Modport(x) = &symbol.found.kind
1748 {
1749 let sig = if let Some(x) = c.get_current_signature() {
1750 x.clone()
1751 } else {
1752 Signature::new(x.interface)
1753 };
1754
1755 let name = value.identifier.text();
1756 let path = VarPath::new(name);
1757 let r#type = ir::Type::new(ir::TypeKind::Modport(sig, symbol.found.token.text));
1758 let token: TokenRange = value.identifier.as_ref().into();
1759
1760 let comptime = Comptime::from_type(r#type, ClockDomain::None, token);
1761 c.insert_var_path(path, comptime);
1762
1763 let mut members = vec![];
1764 for x in &x.members {
1765 let symbol = symbol_table::get(*x).unwrap();
1766 match &symbol.kind {
1767 SymbolKind::ModportVariableMember(x) => {
1768 members.push((symbol.token.text, x.direction));
1769 }
1770 SymbolKind::ModportFunctionMember(_) => {
1771 members.push((symbol.token.text, Direction::Import));
1772 }
1773 _ => (),
1774 }
1775 }
1776 c.insert_modport(name, members);
1777 }
1778 Ok(())
1779 });
1780
1781 context.pop_affiliation();
1782 ret
1783 }
1784}