Skip to main content

veryl_analyzer/ir/
variable.rs

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    /// Sentinel value for synthetic events (no corresponding variable in storage).
19    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            // TODO invalid_select
70
71            if array_select.is_range() {
72                // Range selects are expanded by `to_assign_destinations`.
73                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            // If base path is SystemVerilog, valid AssignDestination should be generated.
86            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    /// Like `to_assign_destination` but expands an array range select
108    /// (e.g., `w_arr[2*n+:2]`) into one destination per covered element.
109    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                    // Even if beg is unknown, single select can be determined
536                    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                            // skip out_of_range check
594                            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        // `assigned` tracks per-element coverage and must match the full
816        // array length (not `value.len()`, since `value` may hold a single
817        // template entry for all-same init). `set_assigned` / `unassigned()`
818        // callers gate on `> array_limit` before touching `assigned`, so
819        // arrays past the limit can leave the vec empty.
820        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        // adjust type format
932        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        // Template form (`value.len() == 1 && total_array > 1`) means every
939        // element shares value[0]; otherwise treat value.len() as the
940        // effective element count.
941        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}