1use crate::BigUint;
2use crate::analyzer_error::{AnalyzerError, InvalidSelectKind};
3use crate::conv::Context;
4use crate::conv::utils::eval_width_select;
5use crate::ir::{
6 AssignDestination, Comptime, Expression, Factor, Op, Shape, ShapeRef, Type, TypeKind,
7};
8use crate::symbol::Affiliation;
9use crate::value::{Value, ValueBigUint};
10use std::fmt;
11use veryl_parser::resource_table::{self, StrId};
12use veryl_parser::token_range::TokenRange;
13
14#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug, Default)]
15pub struct VarId(u32);
16
17impl VarId {
18 pub const SYNTHETIC: VarId = VarId(u32::MAX);
20
21 pub fn inc(&mut self) {
22 self.0 += 1;
23 }
24}
25
26impl fmt::Display for VarId {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 let ret = format!("var{}", self.0);
29 ret.fmt(f)
30 }
31}
32
33#[derive(Clone, Debug, Default)]
34pub struct VarPathSelect(pub VarPath, pub VarSelect, pub TokenRange);
35
36impl VarPathSelect {
37 pub fn to_assign_destination(
38 self,
39 context: &mut Context,
40 ignore_error: bool,
41 ) -> Option<AssignDestination> {
42 let (path, select, token) = self.into();
43
44 if let Some((id, mut comptime)) = context.find_path(&path) {
45 if let Some(part_select) = &comptime.part_select {
46 comptime.r#type = part_select.base.clone();
47 }
48
49 let (array_select, width_select) = select.split(comptime.r#type.array.dims());
50 comptime.r#type.array.drain(0..array_select.dimension());
51
52 if let Some(variable) = context.variables.get(&id)
53 && !variable.is_assignable()
54 && !ignore_error
55 {
56 context.insert_error(AnalyzerError::invalid_assignment(
57 &path.to_string(),
58 &variable.kind.description(),
59 &token,
60 ));
61 }
62
63 let width_select = if let Some(part_select) = &comptime.part_select {
64 part_select.to_base_select(context, &width_select)?
65 } else {
66 eval_width_select(context, &path, &comptime.r#type, width_select)?
67 };
68
69 if array_select.is_range() {
72 None
74 } else {
75 Some(AssignDestination {
76 id,
77 path,
78 index: array_select.to_index(),
79 select: width_select,
80 comptime,
81 token,
82 })
83 }
84 } else {
85 let base = VarPath::new(path.first());
87 if let Some((id, mut comptime)) = context.find_path(&base)
88 && comptime.r#type.kind == TypeKind::SystemVerilog
89 {
90 let (array_select, _) = select.split(comptime.r#type.array.dims());
91 comptime.r#type.array.drain(0..array_select.dimension());
92
93 Some(AssignDestination {
94 id,
95 path,
96 index: array_select.to_index(),
97 select: VarSelect::default(),
98 comptime,
99 token,
100 })
101 } else {
102 None
103 }
104 }
105 }
106
107 pub fn to_assign_destinations(
110 self,
111 context: &mut Context,
112 ignore_error: bool,
113 ) -> Vec<AssignDestination> {
114 let (path, select, token) = self.clone().into();
115
116 let Some((id, mut base_comptime)) = context.find_path(&path) else {
117 return self
118 .to_assign_destination(context, ignore_error)
119 .into_iter()
120 .collect();
121 };
122 if let Some(part_select) = &base_comptime.part_select {
123 base_comptime.r#type = part_select.base.clone();
124 }
125
126 let (array_select, _) = select.clone().split(base_comptime.r#type.array.dims());
127 if !array_select.is_range() {
128 return self
129 .to_assign_destination(context, ignore_error)
130 .into_iter()
131 .collect();
132 }
133
134 let Some((beg, end)) = array_select.eval_value(context, &base_comptime.r#type, true) else {
135 return vec![];
136 };
137
138 if let Some(variable) = context.variables.get(&id)
139 && !variable.is_assignable()
140 && !ignore_error
141 {
142 context.insert_error(AnalyzerError::invalid_assignment(
143 &path.to_string(),
144 &variable.kind.description(),
145 &token,
146 ));
147 }
148
149 let mut comptime = base_comptime.clone();
150 comptime.r#type.array.drain(0..array_select.dimension());
151
152 let width_select = VarSelect::default();
153
154 let array_shape = base_comptime.r#type.array.clone();
155 (beg..=end)
156 .map(|i| AssignDestination {
157 id,
158 path: path.clone(),
159 index: VarIndex::from_index(i, &array_shape),
160 select: width_select.clone(),
161 comptime: comptime.clone(),
162 token,
163 })
164 .collect()
165 }
166
167 pub fn to_expression(self, context: &Context) -> Option<Expression> {
168 let (path, select, token) = self.into();
169
170 if let Some((id, mut comptime)) = context.find_path(&path) {
171 let (array_select, width_select) = select.split(comptime.r#type.array.dims());
172 comptime.r#type.array.drain(0..array_select.dimension());
173
174 comptime.token = token;
175 let src = Factor::Variable(id, array_select.to_index(), width_select, comptime);
176 Some(Expression::Term(Box::new(src)))
177 } else {
178 None
179 }
180 }
181}
182
183impl From<VarPathSelect> for (VarPath, VarSelect, TokenRange) {
184 fn from(value: VarPathSelect) -> Self {
185 (value.0, value.1, value.2)
186 }
187}
188
189#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
190pub struct VarPath(pub Vec<StrId>);
191
192impl VarPath {
193 pub fn new(x: StrId) -> Self {
194 Self(vec![x])
195 }
196 pub fn from_slice(x: &[StrId]) -> Self {
197 Self(x.to_vec())
198 }
199 pub fn push(&mut self, x: StrId) {
200 self.0.push(x)
201 }
202 pub fn pop(&mut self) {
203 self.0.pop();
204 }
205 pub fn append(&mut self, x: &[StrId]) {
206 for x in x {
207 self.0.push(*x)
208 }
209 }
210 pub fn add_prelude(&mut self, x: &[StrId]) {
211 let mut ret = x.to_vec();
212 ret.append(&mut self.0);
213 self.0 = ret;
214 }
215 pub fn remove_prelude(&mut self, x: &[StrId]) {
216 if self.starts_with(x) {
217 for _ in 0..x.len() {
218 self.0.remove(0);
219 }
220 }
221 }
222 pub fn starts_with(&self, x: &[StrId]) -> bool {
223 self.0.starts_with(x)
224 }
225 pub fn first(&self) -> StrId {
226 self.0[0]
227 }
228}
229
230impl fmt::Display for VarPath {
231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232 let mut ret = String::new();
233
234 for id in &self.0 {
235 ret.push('.');
236 ret.push_str(&format!("{id}"));
237 }
238
239 ret[1..].fmt(f)
240 }
241}
242
243impl std::str::FromStr for VarPath {
244 type Err = ();
245 fn from_str(s: &str) -> Result<Self, Self::Err> {
246 let id = resource_table::insert_str(s);
247 Ok(Self::new(id))
248 }
249}
250
251#[derive(Clone, Debug, Default)]
252pub struct VarIndex(pub Vec<Expression>);
253
254impl VarIndex {
255 pub fn from_index(index: usize, array: &ShapeRef) -> Self {
256 let mut remaining = index;
257 let mut ret = vec![];
258 for a in array.iter().rev() {
259 let a = a.unwrap_or(1);
260 ret.push(remaining % a);
261 remaining /= a;
262 }
263
264 let token = TokenRange::default();
265 let ret: Vec<_> = ret
266 .into_iter()
267 .rev()
268 .map(|x| Expression::create_value(Value::new(x as u64, 32, false), token))
269 .collect();
270 Self(ret)
271 }
272
273 pub fn push(&mut self, x: Expression) {
274 self.0.push(x)
275 }
276
277 pub fn dimension(&self) -> usize {
278 self.0.len()
279 }
280
281 pub fn add_prelude(&mut self, x: &VarIndex) {
282 let mut x = x.clone();
283 for e in self.0.drain(..) {
284 x.push(e);
285 }
286 self.0 = x.0;
287 }
288
289 pub fn append(&mut self, x: &VarIndex) {
290 for x in &x.0 {
291 self.0.push(x.clone());
292 }
293 }
294
295 pub fn is_const(&self) -> bool {
296 let mut ret = true;
297
298 for x in &self.0 {
299 ret &= x.comptime().is_const;
300 }
301
302 ret
303 }
304
305 pub fn eval_value(&self, context: &mut Context) -> Option<Vec<usize>> {
306 let mut ret = vec![];
307 for x in &self.0 {
308 if let Some(x) = x.eval_value(context) {
309 ret.push(x.to_usize().unwrap_or(0))
310 } else {
311 return None;
312 }
313 }
314 Some(ret)
315 }
316
317 pub fn to_select(self) -> VarSelect {
318 VarSelect(self.0, None)
319 }
320}
321
322impl fmt::Display for VarIndex {
323 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324 let mut ret = String::new();
325 for i in &self.0 {
326 ret.push_str(&format!("[{i}]"));
327 }
328 ret.fmt(f)
329 }
330}
331
332#[derive(Clone, Debug)]
333pub enum VarSelectOp {
334 Colon,
335 PlusColon,
336 MinusColon,
337 Step,
338}
339
340impl fmt::Display for VarSelectOp {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342 match self {
343 VarSelectOp::Colon => ":".fmt(f),
344 VarSelectOp::PlusColon => "+:".fmt(f),
345 VarSelectOp::MinusColon => "-:".fmt(f),
346 VarSelectOp::Step => " step ".fmt(f),
347 }
348 }
349}
350
351impl VarSelectOp {
352 pub fn eval_expr(&self, beg: &Expression, end: &Expression) -> (Expression, Expression) {
353 let comptime = Box::new(Comptime::create_unknown(TokenRange::default()));
354 match self {
355 VarSelectOp::Colon => (beg.clone(), end.clone()),
356 VarSelectOp::PlusColon => {
357 let expr = Expression::Binary(
358 Box::new(beg.clone()),
359 Op::Add,
360 Box::new(end.clone()),
361 comptime.clone(),
362 );
363 let minus_one = Expression::Unary(
364 Op::Sub,
365 Box::new(Expression::create_value(
366 Value::new(1, 32, false),
367 TokenRange::default(),
368 )),
369 comptime.clone(),
370 );
371 let expr =
372 Expression::Binary(Box::new(expr), Op::Add, Box::new(minus_one), comptime);
373 (expr, beg.clone())
374 }
375 VarSelectOp::MinusColon => {
376 let expr = Expression::Unary(Op::Sub, Box::new(end.clone()), comptime.clone());
377 let expr = Expression::Binary(
378 Box::new(beg.clone()),
379 Op::Add,
380 Box::new(expr),
381 comptime.clone(),
382 );
383 let expr = Expression::Binary(
384 Box::new(expr),
385 Op::Add,
386 Box::new(Expression::create_value(
387 Value::new(1, 32, false),
388 TokenRange::default(),
389 )),
390 comptime,
391 );
392 (beg.clone(), expr)
393 }
394 VarSelectOp::Step => {
395 let mul = Expression::Binary(
396 Box::new(beg.clone()),
397 Op::Mul,
398 Box::new(end.clone()),
399 comptime.clone(),
400 );
401 let expr = Expression::Binary(
402 Box::new(mul.clone()),
403 Op::Add,
404 Box::new(end.clone()),
405 comptime.clone(),
406 );
407 let minus_one = Expression::Unary(
408 Op::Sub,
409 Box::new(Expression::create_value(
410 Value::new(1, 32, false),
411 TokenRange::default(),
412 )),
413 comptime.clone(),
414 );
415 let expr =
416 Expression::Binary(Box::new(expr), Op::Add, Box::new(minus_one), comptime);
417 (expr, mul)
418 }
419 }
420 }
421
422 pub fn eval_value(&self, beg: usize, end: usize, is_array: bool) -> (usize, usize) {
423 let (beg, end, swap) = match self {
424 VarSelectOp::Colon => (beg, end, false),
425 VarSelectOp::PlusColon => ((beg + end).saturating_sub(1), beg, is_array),
426 VarSelectOp::MinusColon => (beg, beg.saturating_sub(end) + 1, is_array),
427 VarSelectOp::Step => ((beg * end + end).saturating_sub(1), beg * end, is_array),
428 };
429 if swap { (end, beg) } else { (beg, end) }
430 }
431}
432
433#[derive(Clone, Debug, Default)]
434pub struct VarSelect(pub Vec<Expression>, pub Option<(VarSelectOp, Expression)>);
435
436impl VarSelect {
437 pub fn set_index(&mut self, index: &VarIndex) {
438 for x in &mut self.0 {
439 x.set_index(index);
440 }
441
442 if let Some((_, x)) = &mut self.1 {
443 x.set_index(index);
444 }
445 }
446
447 pub fn push(&mut self, x: Expression) {
448 self.0.push(x)
449 }
450
451 pub fn append(&mut self, mut x: VarSelect) {
452 self.0.append(&mut x.0);
453 self.1 = x.1;
454 }
455
456 pub fn split(mut self, i: usize) -> (Self, Self) {
457 if self.0.len() <= i {
458 (self, VarSelect::default())
459 } else {
460 let x = self.0.drain(0..i).collect();
461 (VarSelect(x, None), self)
462 }
463 }
464
465 pub fn dimension(&self) -> usize {
466 self.0.len()
467 }
468
469 pub fn is_range(&self) -> bool {
470 self.1.is_some()
471 }
472
473 pub fn is_empty(&self) -> bool {
474 self.0.is_empty()
475 }
476
477 pub fn is_const(&self) -> bool {
478 let mut ret = true;
479
480 for x in &self.0 {
481 ret &= x.comptime().is_const;
482 }
483
484 ret
485 }
486
487 pub fn to_index(self) -> VarIndex {
488 VarIndex(self.0)
489 }
490
491 pub fn token_range(&self) -> TokenRange {
492 if let Some(x) = self.0.first() {
493 let beg = x.token_range();
494
495 let end = if let Some(x) = &self.1 {
496 x.1.token_range()
497 } else {
498 self.0.last().unwrap().token_range()
499 };
500 TokenRange {
501 beg: beg.beg,
502 end: end.end,
503 }
504 } else {
505 TokenRange::default()
506 }
507 }
508
509 pub fn eval_comptime(
510 &self,
511 context: &mut Context,
512 r#type: &Type,
513 is_array: bool,
514 ) -> Option<Shape> {
515 if r#type.is_unknown() {
516 None
517 } else {
518 let r#type = if is_array {
519 &r#type.array
520 } else {
521 r#type.width()
522 };
523
524 if self.is_empty() {
525 Some(r#type.to_owned())
526 } else {
527 let dim = self.dimension();
528 let beg = self.0.last().unwrap();
529 let mut range = beg.token_range();
530 let beg = beg.eval_value(context);
531
532 let beg = if let Some(beg) = beg {
533 beg.to_usize().unwrap_or(0)
534 } else {
535 if self.1.is_none() {
537 let mut ret = r#type.to_owned();
538 ret.drain(0..dim);
539 let ret = if !is_array && ret.is_empty() {
540 Some(Shape::new(vec![Some(1)]))
541 } else {
542 Some(ret)
543 };
544 return ret;
545 } else {
546 return None;
547 }
548 };
549
550 let (beg, end) = if let Some((op, x)) = &self.1 {
551 range.set_end(x.token_range());
552 let end = x.eval_value(context)?.to_usize().unwrap_or(0);
553 op.eval_value(beg, end, is_array)
554 } else {
555 (beg, beg)
556 };
557
558 if r#type.dims() < dim {
559 if dim == 1 && r#type.dims() == 0 && !is_array {
560 let width = beg - end + 1;
561 return Some(Shape::new(vec![Some(width)]));
562 } else {
563 context.insert_error(AnalyzerError::invalid_select(
564 &InvalidSelectKind::OutOfDimension {
565 dim,
566 size: r#type.dims(),
567 },
568 &range,
569 &[],
570 ));
571 return None;
572 }
573 }
574
575 let wrong_order = if is_array { beg > end } else { beg < end };
576 if wrong_order {
577 context.insert_error(AnalyzerError::invalid_select(
578 &InvalidSelectKind::WrongOrder { beg, end },
579 &range,
580 &[],
581 ));
582 return None;
583 }
584
585 for (i, beg) in self.0.iter().enumerate() {
586 if let Some(size) = r#type.get(i)
587 && let Some(size) = size
588 {
589 let size = *size;
590 let beg = beg.eval_value(context)?;
591
592 if beg.is_xz() {
593 continue;
595 }
596
597 let beg = beg.to_usize().unwrap_or(0);
598 let mut out_of_range = beg >= size;
599
600 if i == dim - 1 {
601 out_of_range |= end >= size;
602 }
603
604 if out_of_range {
605 context.insert_error(AnalyzerError::invalid_select(
606 &InvalidSelectKind::OutOfRange { beg, end, size },
607 &range,
608 &[],
609 ));
610 return None;
611 }
612 }
613 }
614
615 let width = if is_array {
616 end - beg + 1
617 } else {
618 beg - end + 1
619 };
620
621 let mut ret = r#type.to_owned();
622
623 if width == 1 {
624 ret.drain(0..dim);
625 } else {
626 ret.drain(0..(dim - 1));
627 let first = ret.first_mut().unwrap();
628 *first = Some(width);
629 }
630
631 if !is_array && ret.is_empty() {
632 Some(Shape::new(vec![Some(1)]))
633 } else {
634 Some(ret)
635 }
636 }
637 }
638 }
639
640 pub fn eval_value(
641 &self,
642 context: &mut Context,
643 r#type: &Type,
644 is_array: bool,
645 ) -> Option<(usize, usize)> {
646 if self.0.is_empty() {
647 let total_width: usize = if is_array {
648 r#type.total_array()?
649 } else {
650 r#type.total_width()?
651 };
652 return Some((total_width.saturating_sub(1), 0));
653 }
654
655 let r#type = if is_array {
656 &r#type.array
657 } else {
658 r#type.width()
659 };
660
661 let mut beg = 0;
662 let mut end = 0;
663 let mut base = 1;
664
665 let dim = self.dimension();
666 if r#type.dims() < dim {
667 if dim == 1 && r#type.dims() == 0 && !is_array {
668 let x = &self.0[0];
669 let x = x.eval_value(context)?.to_usize().unwrap_or(0);
670 let (x, y) = if let Some((op, y)) = &self.1 {
671 let y = y.eval_value(context)?.to_usize().unwrap_or(0);
672 op.eval_value(x, y, is_array)
673 } else {
674 (x, x)
675 };
676 return Some((x, y));
677 } else {
678 return None;
679 }
680 }
681 let skip = r#type.dims() - dim;
682 for (i, w) in r#type.iter().rev().enumerate() {
683 if let Some(w) = w {
684 if i == skip {
685 let x = self.0.get(dim - (i - skip) - 1)?;
686 let x = x.eval_value(context)?.to_usize().unwrap_or(0);
687
688 let (x, y) = if let Some((op, y)) = &self.1 {
689 let y = y.eval_value(context)?.to_usize().unwrap_or(0);
690 op.eval_value(x, y, is_array)
691 } else {
692 (x, x)
693 };
694
695 if is_array {
696 beg += x * base;
697 end += (y + 1) * base - 1;
698 } else {
699 beg += (x + 1) * base - 1;
700 end += y * base;
701 }
702 } else if i > skip {
703 let x = self.0.get(dim - (i - skip) - 1)?;
704 let x = x.eval_value(context)?.to_usize().unwrap_or(0);
705
706 beg += x * base;
707 end += x * base;
708 }
709 base *= w;
710 } else {
711 return None;
712 }
713 }
714
715 let token = self.token_range();
716 let beg = context.check_size(beg, token)?;
717 let end = context.check_size(end, token)?;
718
719 Some((beg, end))
720 }
721}
722
723impl fmt::Display for VarSelect {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725 let mut ret = String::new();
726 let len = self.0.len();
727 for (i, x) in self.0.iter().enumerate() {
728 if i == len - 1 {
729 if let Some((op, y)) = &self.1 {
730 ret.push_str(&format!("[{x}{op}{y}]"));
731 } else {
732 ret.push_str(&format!("[{x}]"));
733 }
734 } else {
735 ret.push_str(&format!("[{x}]"));
736 }
737 }
738 ret.fmt(f)
739 }
740}
741
742#[derive(Copy, Clone, PartialEq, Eq)]
743pub enum VarKind {
744 Param,
745 Const,
746 Input,
747 Output,
748 Inout,
749 Variable,
750 Let,
751}
752
753impl VarKind {
754 pub fn is_param(&self) -> bool {
755 matches!(self, VarKind::Param)
756 }
757
758 pub fn is_port(&self) -> bool {
759 matches!(self, VarKind::Input | VarKind::Output | VarKind::Inout)
760 }
761
762 pub fn description(&self) -> String {
763 let ret = match self {
764 VarKind::Param => "parameter",
765 VarKind::Const => "constant",
766 VarKind::Input => "input",
767 VarKind::Output => "output",
768 VarKind::Inout => "inout",
769 VarKind::Variable => "variable",
770 VarKind::Let => "let-bounded variable",
771 };
772 ret.to_string()
773 }
774}
775
776impl fmt::Display for VarKind {
777 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778 let ret = match self {
779 VarKind::Param => "param",
780 VarKind::Const => "const",
781 VarKind::Input => "input",
782 VarKind::Output => "output",
783 VarKind::Inout => "inout",
784 VarKind::Variable => "var",
785 VarKind::Let => "let",
786 };
787 ret.fmt(f)
788 }
789}
790
791#[derive(Clone)]
792pub struct Variable {
793 pub id: VarId,
794 pub path: VarPath,
795 pub kind: VarKind,
796 pub r#type: Type,
797 pub value: Vec<Value>,
798 pub assigned: Vec<BigUint>,
799 pub affiliation: Affiliation,
800 pub token: TokenRange,
801}
802
803impl Variable {
804 #[allow(clippy::too_many_arguments)]
805 pub fn new(
806 id: VarId,
807 path: VarPath,
808 kind: VarKind,
809 r#type: Type,
810 value: Vec<Value>,
811 affiliation: Affiliation,
812 token: &TokenRange,
813 array_limit: usize,
814 ) -> Self {
815 let total_array = r#type.total_array().unwrap_or(value.len()).max(value.len());
821 let assigned: Vec<BigUint> = if total_array > array_limit {
822 Vec::new()
823 } else {
824 vec![0u32.into(); total_array]
825 };
826
827 Self {
828 id,
829 path,
830 kind,
831 r#type,
832 value,
833 assigned,
834 affiliation,
835 token: *token,
836 }
837 }
838
839 pub fn get_value(&self, index: &[usize]) -> Option<&Value> {
840 let index = self.r#type.array.calc_index(index)?;
841 self.value.get(index)
842 }
843
844 pub fn set_value(
845 &mut self,
846 index: &[usize],
847 mut value: Value,
848 range: Option<(usize, usize)>,
849 ) -> bool {
850 let Some(index) = self.r#type.array.calc_index(index) else {
851 return false;
852 };
853 if let Some(total_width) = self.total_width() {
854 let value_width = value.width();
855 let value = if value_width >= total_width {
856 value.trunc(total_width);
857 value
858 } else {
859 value.expand(total_width, true).into_owned()
860 };
861
862 if let Some(x) = self.value.get_mut(index) {
863 if let Some((beg, end)) = range {
864 x.assign(value, beg, end);
865 } else {
866 *x = value;
867 }
868 true
869 } else {
870 false
871 }
872 } else {
873 false
874 }
875 }
876
877 pub fn set_assigned(&mut self, index: usize, value: BigUint) -> bool {
878 if let Some(x) = self.assigned.get_mut(index) {
879 *x = value;
880 true
881 } else {
882 false
883 }
884 }
885
886 pub fn unassigned(&self) -> Vec<usize> {
887 let mut ret = vec![];
888 if let Some(total_width) = self.total_width() {
889 let mask = ValueBigUint::gen_mask(total_width);
890
891 for (i, assigned) in self.assigned.iter().enumerate() {
892 if *assigned != mask {
893 ret.push(i);
894 }
895 }
896 }
897
898 ret
899 }
900
901 pub fn is_assignable(&self) -> bool {
902 matches!(
903 self.kind,
904 VarKind::Output | VarKind::Inout | VarKind::Variable
905 )
906 }
907
908 pub fn total_width(&self) -> Option<usize> {
909 self.r#type.total_width()
910 }
911
912 pub fn prepend_array(&mut self, array: &ShapeRef) {
913 if !array.is_empty()
914 && let Some(total_array) = array.total()
915 {
916 let value = self.value.clone();
917 let assigned = self.assigned.clone();
918 for _ in 0..total_array.saturating_sub(1) {
919 self.value.append(&mut value.clone());
920 self.assigned.append(&mut assigned.clone());
921 }
922 self.r#type.prepend_array(array);
923 }
924 }
925}
926
927impl fmt::Display for Variable {
928 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
929 let mut ret = String::new();
930
931 let mut r#type = self.r#type.clone();
933 if r#type.width().as_shape_ref() == ShapeRef::new(&[Some(1)]) {
934 r#type.clear_width();
935 }
936 r#type.array.clear();
937
938 let type_len = self.r#type.total_array();
942 let is_template = self.value.len() == 1 && matches!(type_len, Some(n) if n > 1);
943 let display_len = if is_template {
944 type_len.unwrap()
945 } else {
946 self.value.len()
947 };
948 let is_array = display_len != 1;
949 for i in 0..display_len {
950 let value = if is_template {
951 &self.value[0]
952 } else {
953 &self.value[i]
954 };
955 if is_array {
956 ret.push_str(&format!(
957 "{} {}[{}]({}): ",
958 self.kind, self.id, i, self.path
959 ));
960 } else {
961 ret.push_str(&format!("{} {}({}): ", self.kind, self.id, self.path));
962 }
963 ret.push_str(&format!("{}", r#type));
964
965 ret.push_str(&format!(" = {:x};\n", value));
966 }
967 ret.trim_end().fmt(f)
968 }
969}
970
971#[derive(Clone)]
972pub struct VariableInfo {
973 pub id: VarId,
974 pub path: VarPath,
975 pub kind: VarKind,
976 pub r#type: Type,
977 pub affiliation: Affiliation,
978 pub token: TokenRange,
979}
980
981impl VariableInfo {
982 pub fn new(x: &Variable) -> Self {
983 Self {
984 id: x.id,
985 path: x.path.clone(),
986 kind: x.kind,
987 r#type: x.r#type.clone(),
988 affiliation: x.affiliation,
989 token: x.token,
990 }
991 }
992
993 pub fn total_width(&self) -> Option<usize> {
994 self.r#type.total_width()
995 }
996}
997
998#[cfg(test)]
999mod tests {
1000 use super::*;
1001 use crate::ir::TypeKind;
1002 use veryl_parser::token_range::TokenRange;
1003
1004 fn gen_var_select(x: &[u32], y: Option<u32>) -> VarSelect {
1005 let mut ret = VarSelect::default();
1006
1007 for x in x {
1008 let token = TokenRange::default();
1009 let expr = Expression::create_value(Value::new(*x as u64, 8, false), token);
1010 ret.push(expr);
1011 }
1012
1013 if let Some(y) = y {
1014 let token = TokenRange::default();
1015 let expr = Expression::create_value(Value::new(y as u64, 8, false), token);
1016 let op = VarSelectOp::Colon;
1017 ret.1 = Some((op, expr));
1018 }
1019
1020 ret
1021 }
1022
1023 #[test]
1024 fn var_select_array() {
1025 let mut context = Context::default();
1026
1027 let x0 = gen_var_select(&[2, 3, 4], None);
1028 let x1 = gen_var_select(&[2, 3, 4], Some(5));
1029 let x2 = gen_var_select(&[2, 3], None);
1030 let x3 = gen_var_select(&[2, 3], Some(4));
1031 let x4 = gen_var_select(&[2], None);
1032 let x5 = gen_var_select(&[2], Some(3));
1033
1034 assert_eq!(x0.to_string(), "[8'h02][8'h03][8'h04]");
1035 assert_eq!(x1.to_string(), "[8'h02][8'h03][8'h04:8'h05]");
1036 assert_eq!(x2.to_string(), "[8'h02][8'h03]");
1037 assert_eq!(x3.to_string(), "[8'h02][8'h03:8'h04]");
1038 assert_eq!(x4.to_string(), "[8'h02]");
1039 assert_eq!(x5.to_string(), "[8'h02:8'h03]");
1040
1041 let array = Shape::new(vec![Some(4), Some(5), Some(6)]);
1042
1043 let mut r#type = Type::new(TypeKind::Logic);
1044 r#type.array = array.clone();
1045
1046 let y0 = x0.eval_comptime(&mut context, &r#type, true).unwrap();
1047 let y1 = x1.eval_comptime(&mut context, &r#type, true).unwrap();
1048 let y2 = x2.eval_comptime(&mut context, &r#type, true).unwrap();
1049 let y3 = x3.eval_comptime(&mut context, &r#type, true).unwrap();
1050 let y4 = x4.eval_comptime(&mut context, &r#type, true).unwrap();
1051 let y5 = x5.eval_comptime(&mut context, &r#type, true).unwrap();
1052
1053 assert_eq!(&y0, ShapeRef::new(&[]));
1054 assert_eq!(&y1, ShapeRef::new(&[Some(2)]));
1055 assert_eq!(&y2, ShapeRef::new(&[Some(6)]));
1056 assert_eq!(&y3, ShapeRef::new(&[Some(2), Some(6)]));
1057 assert_eq!(&y4, ShapeRef::new(&[Some(5), Some(6)]));
1058 assert_eq!(&y5, ShapeRef::new(&[Some(2), Some(5), Some(6)]));
1059
1060 let mut context = Context::default();
1061
1062 let z0 = x0.eval_value(&mut context, &r#type, true).unwrap();
1063 let z1 = x1.eval_value(&mut context, &r#type, true).unwrap();
1064 let z2 = x2.eval_value(&mut context, &r#type, true).unwrap();
1065 let z3 = x3.eval_value(&mut context, &r#type, true).unwrap();
1066 let z4 = x4.eval_value(&mut context, &r#type, true).unwrap();
1067 let z5 = x5.eval_value(&mut context, &r#type, true).unwrap();
1068
1069 assert_eq!(z0, (82, 82));
1070 assert_eq!(z1, (82, 83));
1071 assert_eq!(z2, (78, 83));
1072 assert_eq!(z3, (78, 89));
1073 assert_eq!(z4, (60, 89));
1074 assert_eq!(z5, (60, 119));
1075 }
1076
1077 #[test]
1078 fn var_select_width() {
1079 let mut context = Context::default();
1080
1081 let x0 = gen_var_select(&[2, 3, 4], None);
1082 let x1 = gen_var_select(&[2, 3, 5], Some(4));
1083 let x2 = gen_var_select(&[2, 3], None);
1084 let x3 = gen_var_select(&[2, 4], Some(3));
1085 let x4 = gen_var_select(&[2], None);
1086 let x5 = gen_var_select(&[3], Some(2));
1087 let x6 = gen_var_select(&[], None);
1088
1089 assert_eq!(x0.to_string(), "[8'h02][8'h03][8'h04]");
1090 assert_eq!(x1.to_string(), "[8'h02][8'h03][8'h05:8'h04]");
1091 assert_eq!(x2.to_string(), "[8'h02][8'h03]");
1092 assert_eq!(x3.to_string(), "[8'h02][8'h04:8'h03]");
1093 assert_eq!(x4.to_string(), "[8'h02]");
1094 assert_eq!(x5.to_string(), "[8'h03:8'h02]");
1095 assert_eq!(x6.to_string(), "");
1096
1097 let width = Shape::new(vec![Some(4), Some(5), Some(6)]);
1098
1099 let mut r#type = Type::new(TypeKind::Logic);
1100 r#type.set_concrete_width(width.clone());
1101
1102 let y0 = x0.eval_comptime(&mut context, &r#type, false).unwrap();
1103 let y1 = x1.eval_comptime(&mut context, &r#type, false).unwrap();
1104 let y2 = x2.eval_comptime(&mut context, &r#type, false).unwrap();
1105 let y3 = x3.eval_comptime(&mut context, &r#type, false).unwrap();
1106 let y4 = x4.eval_comptime(&mut context, &r#type, false).unwrap();
1107 let y5 = x5.eval_comptime(&mut context, &r#type, false).unwrap();
1108 let y6 = x6.eval_comptime(&mut context, &r#type, false).unwrap();
1109
1110 assert_eq!(&y0, ShapeRef::new(&[Some(1)]));
1111 assert_eq!(&y1, ShapeRef::new(&[Some(2)]));
1112 assert_eq!(&y2, ShapeRef::new(&[Some(6)]));
1113 assert_eq!(&y3, ShapeRef::new(&[Some(2), Some(6)]));
1114 assert_eq!(&y4, ShapeRef::new(&[Some(5), Some(6)]));
1115 assert_eq!(&y5, ShapeRef::new(&[Some(2), Some(5), Some(6)]));
1116 assert_eq!(&y6, ShapeRef::new(&[Some(4), Some(5), Some(6)]));
1117
1118 let mut context = Context::default();
1119
1120 let z0 = x0.eval_value(&mut context, &r#type, false).unwrap();
1121 let z1 = x1.eval_value(&mut context, &r#type, false).unwrap();
1122 let z2 = x2.eval_value(&mut context, &r#type, false).unwrap();
1123 let z3 = x3.eval_value(&mut context, &r#type, false).unwrap();
1124 let z4 = x4.eval_value(&mut context, &r#type, false).unwrap();
1125 let z5 = x5.eval_value(&mut context, &r#type, false).unwrap();
1126 let z6 = x6.eval_value(&mut context, &r#type, false).unwrap();
1127
1128 assert_eq!(z0, (82, 82));
1129 assert_eq!(z1, (83, 82));
1130 assert_eq!(z2, (83, 78));
1131 assert_eq!(z3, (89, 78));
1132 assert_eq!(z4, (89, 60));
1133 assert_eq!(z5, (119, 60));
1134 assert_eq!(z6, (119, 0));
1135 }
1136
1137 #[test]
1138 fn var_index_from_index() {
1139 let array = Shape::new(vec![Some(2), Some(3), Some(4)]);
1140
1141 let x00 = VarIndex::from_index(0, &array);
1142 let x01 = VarIndex::from_index(1, &array);
1143 let x02 = VarIndex::from_index(2, &array);
1144 let x03 = VarIndex::from_index(3, &array);
1145 let x04 = VarIndex::from_index(4, &array);
1146 let x05 = VarIndex::from_index(5, &array);
1147 let x06 = VarIndex::from_index(6, &array);
1148 let x07 = VarIndex::from_index(7, &array);
1149 let x08 = VarIndex::from_index(8, &array);
1150 let x09 = VarIndex::from_index(9, &array);
1151 let x10 = VarIndex::from_index(10, &array);
1152 let x11 = VarIndex::from_index(11, &array);
1153 let x12 = VarIndex::from_index(12, &array);
1154 let x13 = VarIndex::from_index(13, &array);
1155 let x14 = VarIndex::from_index(14, &array);
1156 let x15 = VarIndex::from_index(15, &array);
1157 let x16 = VarIndex::from_index(16, &array);
1158 let x17 = VarIndex::from_index(17, &array);
1159 let x18 = VarIndex::from_index(18, &array);
1160 let x19 = VarIndex::from_index(19, &array);
1161 let x20 = VarIndex::from_index(20, &array);
1162 let x21 = VarIndex::from_index(21, &array);
1163 let x22 = VarIndex::from_index(22, &array);
1164 let x23 = VarIndex::from_index(23, &array);
1165
1166 assert_eq!(
1167 x00.to_string(),
1168 "[32'h00000000][32'h00000000][32'h00000000]"
1169 );
1170 assert_eq!(
1171 x01.to_string(),
1172 "[32'h00000000][32'h00000000][32'h00000001]"
1173 );
1174 assert_eq!(
1175 x02.to_string(),
1176 "[32'h00000000][32'h00000000][32'h00000002]"
1177 );
1178 assert_eq!(
1179 x03.to_string(),
1180 "[32'h00000000][32'h00000000][32'h00000003]"
1181 );
1182 assert_eq!(
1183 x04.to_string(),
1184 "[32'h00000000][32'h00000001][32'h00000000]"
1185 );
1186 assert_eq!(
1187 x05.to_string(),
1188 "[32'h00000000][32'h00000001][32'h00000001]"
1189 );
1190 assert_eq!(
1191 x06.to_string(),
1192 "[32'h00000000][32'h00000001][32'h00000002]"
1193 );
1194 assert_eq!(
1195 x07.to_string(),
1196 "[32'h00000000][32'h00000001][32'h00000003]"
1197 );
1198 assert_eq!(
1199 x08.to_string(),
1200 "[32'h00000000][32'h00000002][32'h00000000]"
1201 );
1202 assert_eq!(
1203 x09.to_string(),
1204 "[32'h00000000][32'h00000002][32'h00000001]"
1205 );
1206 assert_eq!(
1207 x10.to_string(),
1208 "[32'h00000000][32'h00000002][32'h00000002]"
1209 );
1210 assert_eq!(
1211 x11.to_string(),
1212 "[32'h00000000][32'h00000002][32'h00000003]"
1213 );
1214 assert_eq!(
1215 x12.to_string(),
1216 "[32'h00000001][32'h00000000][32'h00000000]"
1217 );
1218 assert_eq!(
1219 x13.to_string(),
1220 "[32'h00000001][32'h00000000][32'h00000001]"
1221 );
1222 assert_eq!(
1223 x14.to_string(),
1224 "[32'h00000001][32'h00000000][32'h00000002]"
1225 );
1226 assert_eq!(
1227 x15.to_string(),
1228 "[32'h00000001][32'h00000000][32'h00000003]"
1229 );
1230 assert_eq!(
1231 x16.to_string(),
1232 "[32'h00000001][32'h00000001][32'h00000000]"
1233 );
1234 assert_eq!(
1235 x17.to_string(),
1236 "[32'h00000001][32'h00000001][32'h00000001]"
1237 );
1238 assert_eq!(
1239 x18.to_string(),
1240 "[32'h00000001][32'h00000001][32'h00000002]"
1241 );
1242 assert_eq!(
1243 x19.to_string(),
1244 "[32'h00000001][32'h00000001][32'h00000003]"
1245 );
1246 assert_eq!(
1247 x20.to_string(),
1248 "[32'h00000001][32'h00000002][32'h00000000]"
1249 );
1250 assert_eq!(
1251 x21.to_string(),
1252 "[32'h00000001][32'h00000002][32'h00000001]"
1253 );
1254 assert_eq!(
1255 x22.to_string(),
1256 "[32'h00000001][32'h00000002][32'h00000002]"
1257 );
1258 assert_eq!(
1259 x23.to_string(),
1260 "[32'h00000001][32'h00000002][32'h00000003]"
1261 );
1262 }
1263}