Skip to main content

veryl_analyzer/ir/
comptime.rs

1use crate::conv::Context;
2use crate::conv::utils::get_component;
3use crate::ir::{
4    Component, Expression, IrResult, Op, Shape, ShapeRef, Signature, VarIndex, VarPath, VarSelect,
5    VarSelectOp,
6};
7use crate::ir_error;
8use crate::literal::TypeLiteral;
9use crate::symbol::ClockDomain;
10use crate::symbol::{Direction, SymbolId};
11use crate::value::Value;
12use std::fmt;
13use veryl_parser::resource_table::StrId;
14use veryl_parser::token_range::TokenRange;
15
16#[derive(Clone, Default, Debug)]
17pub struct PartSelect {
18    pub pos: usize,
19    pub r#type: Type,
20}
21
22impl fmt::Display for PartSelect {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        format!("{}: {}", self.pos, self.r#type).fmt(f)
25    }
26}
27
28#[derive(Clone, Debug)]
29pub struct PartSelectPath {
30    pub base: Type,
31    pub path: VarPath,
32    pub part_select: Vec<PartSelect>,
33}
34
35impl PartSelectPath {
36    pub fn to_base_select(&self, context: &mut Context, select: &VarSelect) -> Option<VarSelect> {
37        let mut pos_width: Option<(Expression, usize, Option<usize>)> = None;
38
39        let range_select = if let Some((op, end)) = &select.1 {
40            let (beg, end) = op.eval_expr(select.0.last().unwrap(), end);
41            Some((beg, end))
42        } else {
43            None
44        };
45
46        let mut select = select.0.as_slice();
47        if range_select.is_some() {
48            select = &select[0..select.len() - 1];
49        }
50
51        let token = TokenRange::default();
52        let comptime = Box::new(Comptime::create_unknown(token));
53
54        let base_select = [PartSelect {
55            pos: 0,
56            r#type: self.base.clone(),
57        }];
58        let part_select = itertools::chain(&base_select, self.part_select.iter());
59        let len = self.part_select.len() + 1;
60
61        for (i, x) in part_select.enumerate() {
62            let has_sub_part = i != (len - 1);
63            let dims = x.r#type.width.dims();
64            let select_dims = select.len().min(dims);
65            let remaining_dims = dims - select_dims;
66            let is_select = !select.is_empty();
67
68            // check remaining dimension before the next parts
69            if has_sub_part && dims > select.len() {
70                return None;
71            }
72
73            let index = if is_select {
74                let sel = &select[0..select_dims];
75                select = &select[select_dims..];
76
77                // If select dimension doesn't satisfy type dimension,
78                // additional select is necessary
79                if remaining_dims != 0 {
80                    let mut sel = sel.to_vec();
81                    for _ in 0..remaining_dims {
82                        sel.push(Expression::create_value(Value::new(0, 32, false), token));
83                    }
84                    x.r#type.width.calc_index_expr(&sel)?
85                } else {
86                    x.r#type.width.calc_index_expr(sel)?
87                }
88            } else {
89                Expression::create_value(Value::new(0, 32, false), TokenRange::default())
90            };
91
92            let remaining_width = x.r#type.width.as_shape_ref();
93            let remaining_width = ShapeRef::new(&remaining_width[select_dims..]);
94
95            let width = if is_select {
96                let mut r#type = x.r#type.clone();
97                r#type.set_concrete_width(remaining_width.to_owned());
98                r#type.total_width()?
99            } else {
100                x.r#type.total_width()?
101            };
102
103            let range_width = if let Some(x) = remaining_width.first() {
104                let x = (*x)?;
105                Some(width / x)
106            } else {
107                None
108            };
109
110            // pos += x.pos + width * index;
111            let x_pos = Expression::create_value(Value::new(x.pos as u64, 32, false), token);
112
113            let expr = if remaining_dims != 0 {
114                // If remaining_dims exists, width is already considered by index
115                Expression::Binary(Box::new(x_pos), Op::Add, Box::new(index), comptime.clone())
116            } else {
117                let expr = Expression::create_value(Value::new(width as u64, 32, false), token);
118                let expr =
119                    Expression::Binary(Box::new(expr), Op::Mul, Box::new(index), comptime.clone());
120                Expression::Binary(Box::new(x_pos), Op::Add, Box::new(expr), comptime.clone())
121            };
122
123            if let Some((pos, _, _)) = pos_width {
124                let expr =
125                    Expression::Binary(Box::new(pos), Op::Add, Box::new(expr), comptime.clone());
126                pos_width = Some((expr, width, range_width));
127            } else {
128                pos_width = Some((expr, width, range_width));
129            }
130        }
131
132        if let Some((pos, width, range_width)) = pos_width {
133            let single = width == 1;
134            let width = Expression::create_value(Value::new(width as u64, 32, false), token);
135
136            // beg = pos + width - 1
137            // end = pos
138            let one = Expression::create_value(Value::new(1, 32, false), token);
139            let minus_one = Expression::Unary(Op::Sub, Box::new(one.clone()), comptime.clone());
140            let expr = Expression::Binary(
141                Box::new(pos.clone()),
142                Op::Add,
143                Box::new(width.clone()),
144                comptime.clone(),
145            );
146            let expr = Expression::Binary(
147                Box::new(expr),
148                Op::Add,
149                Box::new(minus_one.clone()),
150                comptime.clone(),
151            );
152            let mut beg = expr;
153            let mut end = pos;
154
155            // beg = end + (range_beg + 1) * range_width - 1
156            // end = end + range_end * range_width
157            if let Some((range_beg, range_end)) = range_select {
158                let range_width =
159                    Expression::create_value(Value::new(range_width? as u64, 32, false), token);
160
161                let expr = Expression::Binary(
162                    Box::new(range_beg),
163                    Op::Add,
164                    Box::new(one.clone()),
165                    comptime.clone(),
166                );
167                let expr = Expression::Binary(
168                    Box::new(expr),
169                    Op::Mul,
170                    Box::new(range_width.clone()),
171                    comptime.clone(),
172                );
173                let expr = Expression::Binary(
174                    Box::new(expr),
175                    Op::Add,
176                    Box::new(minus_one),
177                    comptime.clone(),
178                );
179                beg = Expression::Binary(
180                    Box::new(end.clone()),
181                    Op::Add,
182                    Box::new(expr),
183                    comptime.clone(),
184                );
185
186                let expr = Expression::Binary(
187                    Box::new(range_end),
188                    Op::Mul,
189                    Box::new(range_width),
190                    comptime.clone(),
191                );
192                end = Expression::Binary(Box::new(end), Op::Add, Box::new(expr), comptime);
193            }
194
195            beg.eval_comptime(context, None);
196            end.eval_comptime(context, None);
197
198            if single {
199                Some(VarSelect(vec![beg], None))
200            } else {
201                Some(VarSelect(vec![beg], Some((VarSelectOp::Colon, end))))
202            }
203        } else {
204            None
205        }
206    }
207}
208
209impl fmt::Display for PartSelectPath {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211        let mut ret = format!("{}: ", self.path);
212
213        for x in &self.part_select {
214            ret.push_str(&format!("[{x}]"));
215        }
216
217        ret.fmt(f)
218    }
219}
220
221#[derive(Copy, Clone, Default, Debug)]
222pub struct ExpressionContext {
223    pub width: usize,
224    pub signed: bool,
225    pub is_const: bool,
226    pub is_global: bool,
227}
228
229impl ExpressionContext {
230    pub fn merge(&self, other: ExpressionContext) -> ExpressionContext {
231        ExpressionContext {
232            width: self.width.max(other.width),
233            signed: self.signed & other.signed,
234            is_const: self.is_const & other.is_const,
235            is_global: self.is_global & other.is_global,
236        }
237    }
238}
239
240#[derive(Clone, Default, Debug)]
241pub struct Comptime {
242    pub value: ValueVariant,
243    pub r#type: Type,
244    pub is_const: bool,
245    pub is_global: bool,
246    pub part_select: Option<PartSelectPath>,
247    pub clock_domain: ClockDomain,
248    pub expr_context: ExpressionContext,
249    pub evaluated: bool,
250    pub token: TokenRange,
251}
252
253impl Comptime {
254    pub fn create_unknown(token: TokenRange) -> Self {
255        Self {
256            value: ValueVariant::Unknown,
257            r#type: Type {
258                kind: TypeKind::Unknown,
259                ..Default::default()
260            },
261            token,
262            ..Default::default()
263        }
264    }
265
266    pub fn create_value(value: Value, token: TokenRange) -> Self {
267        let width = value.width();
268        Self {
269            value: ValueVariant::Numeric(value),
270            r#type: Type {
271                kind: TypeKind::Bit,
272                width: Shape::new(vec![Some(width)]),
273                ..Default::default()
274            },
275            is_const: true,
276            is_global: true,
277            token,
278            ..Default::default()
279        }
280    }
281
282    pub fn from_type(r#type: Type, clock_domain: ClockDomain, token: TokenRange) -> Self {
283        Self {
284            r#type,
285            clock_domain,
286            token,
287            ..Default::default()
288        }
289    }
290
291    pub fn get_value(&self) -> IrResult<&Value> {
292        if let ValueVariant::Numeric(x) = &self.value {
293            Ok(x)
294        } else {
295            Err(ir_error!(self.token))
296        }
297    }
298}
299
300#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
301pub enum ValueVariant {
302    Numeric(Value),
303    NumericArray(Vec<Value>),
304    Type(Type),
305    #[default]
306    Unknown,
307}
308
309impl ValueVariant {
310    pub fn expand_value(&mut self, width: usize) {
311        if let ValueVariant::Numeric(x) = self {
312            x.expand(width, false);
313        }
314    }
315
316    pub fn is_unknown(&self) -> bool {
317        matches!(self, ValueVariant::Unknown)
318    }
319}
320
321#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
322pub struct Type {
323    pub kind: TypeKind,
324    pub signed: bool,
325    pub is_positive: bool,
326    pub array: Shape,
327    width: Shape,
328    width_expr: Vec<crate::ir::WidthExpr>,
329}
330
331impl Type {
332    pub fn width(&self) -> &Shape {
333        &self.width
334    }
335
336    pub fn width_mut(&mut self) -> &mut Shape {
337        &mut self.width
338    }
339
340    pub fn width_expr(&self) -> &[crate::ir::WidthExpr] {
341        &self.width_expr
342    }
343
344    pub fn new(kind: TypeKind) -> Type {
345        Type {
346            kind,
347            ..Default::default()
348        }
349    }
350
351    pub fn create_unknown() -> Type {
352        Type {
353            kind: TypeKind::Unknown,
354            ..Default::default()
355        }
356    }
357
358    pub fn set_concrete_width(&mut self, shape: Shape) {
359        self.width_expr = crate::ir::WidthExpr::from_shape(&shape);
360        self.width = shape;
361    }
362
363    pub fn set_parametric_width(&mut self, shape: Shape, width_expr: Vec<crate::ir::WidthExpr>) {
364        debug_assert_eq!(
365            shape.as_slice().len(),
366            width_expr.len(),
367            "shape and width_expr length mismatch"
368        );
369        self.width = shape;
370        self.width_expr = width_expr;
371    }
372
373    pub fn clear_width(&mut self) {
374        self.width = Shape::default();
375        self.width_expr.clear();
376    }
377
378    pub fn to_sv_type_name(&self) -> Option<&'static str> {
379        match &self.kind {
380            TypeKind::Bit => Some("bit"),
381            TypeKind::Logic => Some("logic"),
382            TypeKind::F32 => Some("shortreal"),
383            TypeKind::F64 => Some("real"),
384            TypeKind::String => Some("string"),
385            TypeKind::Clock | TypeKind::ClockPosedge | TypeKind::ClockNegedge => Some("logic"),
386            TypeKind::Reset
387            | TypeKind::ResetAsyncHigh
388            | TypeKind::ResetAsyncLow
389            | TypeKind::ResetSyncHigh
390            | TypeKind::ResetSyncLow => Some("logic"),
391            _ => None,
392        }
393    }
394
395    pub fn to_sv_width(&self) -> String {
396        if self.width_expr.is_empty() {
397            return String::new();
398        }
399        let mut s = String::new();
400        for dim in &self.width_expr {
401            s.push_str(&dim.to_sv_width_string());
402        }
403        s
404    }
405
406    pub fn is_4state(&self) -> bool {
407        match &self.kind {
408            TypeKind::Struct(x) => x.is_4state(),
409            TypeKind::Union(x) => x.is_4state(),
410            TypeKind::Enum(x) => x.is_4state(),
411            _ => matches!(self.kind, TypeKind::Logic) | self.is_clock() | self.is_reset(),
412        }
413    }
414
415    pub fn is_2state(&self) -> bool {
416        match &self.kind {
417            TypeKind::Struct(x) => x.is_2state(),
418            TypeKind::Union(x) => x.is_2state(),
419            TypeKind::Enum(x) => x.is_2state(),
420            _ => {
421                matches!(self.kind, TypeKind::Bit | TypeKind::F32 | TypeKind::F64)
422            }
423        }
424    }
425
426    pub fn is_clock(&self) -> bool {
427        matches!(
428            self.kind,
429            TypeKind::Clock | TypeKind::ClockPosedge | TypeKind::ClockNegedge
430        )
431    }
432
433    pub fn is_reset(&self) -> bool {
434        matches!(
435            self.kind,
436            TypeKind::Reset
437                | TypeKind::ResetAsyncHigh
438                | TypeKind::ResetAsyncLow
439                | TypeKind::ResetSyncHigh
440                | TypeKind::ResetSyncLow
441        )
442    }
443
444    pub fn is_explicit_reset(&self) -> bool {
445        matches!(
446            self.kind,
447            TypeKind::ResetAsyncHigh
448                | TypeKind::ResetAsyncLow
449                | TypeKind::ResetSyncHigh
450                | TypeKind::ResetSyncLow
451        )
452    }
453
454    pub fn is_type(&self) -> bool {
455        matches!(self.kind, TypeKind::Type)
456    }
457
458    pub fn is_unknown(&self) -> bool {
459        matches!(self.kind, TypeKind::Unknown)
460    }
461
462    pub fn is_array(&self) -> bool {
463        !self.array.is_empty()
464    }
465
466    pub fn is_binary(&self) -> bool {
467        self.total_width() == Some(1)
468    }
469
470    pub fn is_struct(&self) -> bool {
471        matches!(&self.kind, TypeKind::Struct(_))
472    }
473
474    pub fn is_union(&self) -> bool {
475        matches!(&self.kind, TypeKind::Union(_))
476    }
477
478    pub fn is_struct_union(&self) -> bool {
479        matches!(&self.kind, TypeKind::Struct(_) | TypeKind::Union(_))
480    }
481
482    pub fn is_interface(&self) -> bool {
483        match &self.kind {
484            TypeKind::Instance(_, kind) => *kind == InstanceKind::Interface,
485            TypeKind::Modport(_, _) | TypeKind::AbstractInterface(_) => true,
486            _ => false,
487        }
488    }
489
490    pub fn is_interface_instance(&self) -> bool {
491        match &self.kind {
492            TypeKind::Instance(_, kind) => *kind == InstanceKind::Interface,
493            _ => false,
494        }
495    }
496
497    pub fn is_string(&self) -> bool {
498        matches!(&self.kind, TypeKind::String)
499    }
500
501    pub fn is_systemverilog(&self) -> bool {
502        matches!(&self.kind, TypeKind::SystemVerilog)
503    }
504
505    pub fn get_member_type(&self, name: StrId) -> Option<Type> {
506        if let TypeKind::Struct(x) = &self.kind {
507            for x in &x.members {
508                if x.name == name {
509                    return Some(x.r#type.clone());
510                }
511            }
512        }
513        None
514    }
515
516    pub fn is_inferable_width(&self) -> bool {
517        self.width.dims() == 1 && self.width.last().unwrap().is_none()
518    }
519
520    pub fn total_width(&self) -> Option<usize> {
521        Some(self.kind.width()? * self.width.total()?)
522    }
523
524    pub fn total_array(&self) -> Option<usize> {
525        self.array.total()
526    }
527
528    pub fn compatible(&self, src: &Comptime) -> bool {
529        // TODO type compatible check
530        if self.is_unknown()
531            | self.is_systemverilog()
532            | src.r#type.is_unknown()
533            | src.r#type.is_systemverilog()
534        {
535            true
536        } else if let Some(mut dst_sig) = self.kind.signature() {
537            dst_sig.parameters.clear();
538            if let Some(mut src_sig) = src.r#type.kind.signature() {
539                src_sig.parameters.clear();
540                dst_sig.to_string() == src_sig.to_string()
541            } else {
542                false
543            }
544        } else if self.is_type() || src.r#type.is_type() {
545            self.is_type() && src.r#type.is_type()
546        } else if self.is_2state() {
547            src.r#type.is_2state()
548        } else if self.is_array() || src.r#type.is_array() {
549            array_compatible(&self.array, &src.r#type.array)
550        } else if self.is_clock() {
551            src.r#type.is_clock() || src.is_const
552        } else if self.is_reset() {
553            !src.r#type.is_clock() || src.is_const
554        } else {
555            // TODO width array check
556            true
557        }
558    }
559
560    pub fn expand_struct_union(
561        &self,
562        path: &VarPath,
563        part_select: &[PartSelect],
564        base: Option<&Type>,
565    ) -> Vec<PartSelectPath> {
566        let base = if base.is_some() { base } else { Some(self) };
567        match &self.kind {
568            TypeKind::Struct(x) => x.expand_struct_union(path, part_select, base),
569            TypeKind::Union(x) => x.expand_struct_union(path, part_select, base),
570            _ => vec![],
571        }
572    }
573
574    pub fn expand_interface(
575        &self,
576        context: &mut Context,
577        path: &VarPath,
578        token: TokenRange,
579    ) -> IrResult<Vec<(VarPath, Type)>> {
580        let mut ret = vec![];
581        match &self.kind {
582            TypeKind::Modport(sig, name) => {
583                let component = get_component(context, sig, token)?;
584                let Component::Interface(component) = component.as_ref() else {
585                    unreachable!();
586                };
587
588                let modport_members = component.get_modport(name);
589
590                let mut temp = vec![];
591                for (id, variable) in &component.variables {
592                    if modport_members.contains_key(&variable.path.first()) {
593                        let mut member_path = variable.path.clone();
594                        member_path.add_prelude(&path.0);
595                        temp.push((id, member_path, variable.r#type.clone()));
596                    }
597                }
598                temp.sort_by_key(|x| x.0);
599                ret = temp.into_iter().map(|x| (x.1, x.2)).collect();
600            }
601            TypeKind::Instance(sig, kind) if *kind == InstanceKind::Interface => {
602                let component = get_component(context, sig, token)?;
603                let Component::Interface(component) = component.as_ref() else {
604                    unreachable!();
605                };
606                let mut temp = vec![];
607                for (id, variable) in &component.variables {
608                    let mut member_path = variable.path.clone();
609                    member_path.add_prelude(&path.0);
610                    temp.push((id, member_path, variable.r#type.clone()));
611                }
612                temp.sort_by_key(|x| x.0);
613                ret = temp.into_iter().map(|x| (x.1, x.2)).collect();
614            }
615            _ => (),
616        }
617        Ok(ret)
618    }
619
620    pub fn expand_modport(
621        &self,
622        context: &mut Context,
623        path: &VarPath,
624        token: TokenRange,
625    ) -> IrResult<Vec<(VarPath, Direction)>> {
626        let mut ret = vec![];
627        if let TypeKind::Modport(sig, name) = &self.kind {
628            let component = get_component(context, sig, token)?;
629            let Component::Interface(component) = component.as_ref() else {
630                unreachable!();
631            };
632
633            let modport_members = component.get_modport(name);
634
635            let mut temp = vec![];
636            for (id, variable) in &component.variables {
637                if let Some(x) = modport_members.get(&variable.path.first()) {
638                    let mut member_path = variable.path.clone();
639                    member_path.add_prelude(&path.0);
640                    temp.push((id, member_path, *x));
641                }
642            }
643            temp.sort_by_key(|x| x.0);
644            ret = temp.into_iter().map(|x| (x.1, x.2)).collect();
645        }
646        Ok(ret)
647    }
648
649    pub fn flatten_struct_union_enum(&mut self) {
650        match self.kind.clone() {
651            TypeKind::Struct(_) => {
652                let width = self.total_width();
653                self.kind = if self.is_2state() {
654                    TypeKind::Bit
655                } else {
656                    TypeKind::Logic
657                };
658                self.signed = false;
659                self.set_concrete_width(Shape::new(vec![width]));
660            }
661            TypeKind::Union(_) => {
662                let width = self.total_width();
663                self.kind = if self.is_2state() {
664                    TypeKind::Bit
665                } else {
666                    TypeKind::Logic
667                };
668                self.signed = false;
669                self.set_concrete_width(Shape::new(vec![width]));
670            }
671            TypeKind::Enum(x) => {
672                self.kind = x.r#type.kind;
673                self.signed = x.r#type.signed;
674                let mut array = x.r#type.array;
675                let mut width = x.r#type.width;
676                array.append(&mut self.array);
677                width.append(&mut self.width);
678                self.array = array;
679                self.set_concrete_width(width);
680            }
681            _ => (),
682        }
683    }
684
685    pub fn prepend_array(&mut self, array: &ShapeRef) {
686        if !array.is_empty() {
687            let mut array = array.to_owned();
688            array.append(&mut self.array);
689            self.array = array;
690        }
691    }
692
693    pub fn selected_dimension(&self, index: &VarIndex, select: &VarSelect) -> (usize, usize) {
694        let array_dim = self.array.dims();
695        let width_dim = self.width.dims();
696
697        let array_dim = array_dim.saturating_sub(index.dimension());
698        let width_dim = width_dim.saturating_sub(select.dimension());
699
700        if self.total_width() == Some(1) {
701            (array_dim, 0)
702        } else {
703            (array_dim, width_dim)
704        }
705    }
706}
707
708/// Compare array shapes with `None` (e.g. a dimension from a `$sv::`
709/// constant that Veryl can't evaluate) treated as a wildcard.
710fn array_compatible(a: &Shape, b: &Shape) -> bool {
711    a.dims() == b.dims()
712        && a.iter().zip(b.iter()).all(|(x, y)| match (x, y) {
713            (None, _) | (_, None) => true,
714            (Some(x), Some(y)) => x == y,
715        })
716}
717
718impl From<&TypeLiteral> for Type {
719    fn from(value: &TypeLiteral) -> Self {
720        let kind = match value {
721            TypeLiteral::Bit => TypeKind::Bit,
722            TypeLiteral::BBool => TypeKind::Bit,
723            TypeLiteral::LBool => TypeKind::Logic,
724            TypeLiteral::Clock => TypeKind::Clock,
725            TypeLiteral::ClockPosedge => TypeKind::ClockPosedge,
726            TypeLiteral::ClockNegedge => TypeKind::ClockNegedge,
727            TypeLiteral::F32 => TypeKind::F32,
728            TypeLiteral::F64 => TypeKind::F64,
729            TypeLiteral::I8 => TypeKind::Bit,
730            TypeLiteral::I16 => TypeKind::Bit,
731            TypeLiteral::I32 => TypeKind::Bit,
732            TypeLiteral::I64 => TypeKind::Bit,
733            TypeLiteral::Logic => TypeKind::Logic,
734            TypeLiteral::Reset => TypeKind::Reset,
735            TypeLiteral::ResetAsyncHigh => TypeKind::ResetAsyncHigh,
736            TypeLiteral::ResetAsyncLow => TypeKind::ResetAsyncLow,
737            TypeLiteral::ResetSyncHigh => TypeKind::ResetSyncHigh,
738            TypeLiteral::ResetSyncLow => TypeKind::ResetSyncLow,
739            TypeLiteral::String => TypeKind::Unknown,
740            TypeLiteral::U8 => TypeKind::Bit,
741            TypeLiteral::U16 => TypeKind::Bit,
742            TypeLiteral::U32 => TypeKind::Bit,
743            TypeLiteral::U64 => TypeKind::Bit,
744        };
745
746        let signed = matches!(
747            value,
748            TypeLiteral::F32
749                | TypeLiteral::F64
750                | TypeLiteral::I8
751                | TypeLiteral::I16
752                | TypeLiteral::I32
753                | TypeLiteral::I64
754        );
755
756        let width = match value {
757            TypeLiteral::Bit
758            | TypeLiteral::BBool
759            | TypeLiteral::LBool
760            | TypeLiteral::Clock
761            | TypeLiteral::ClockPosedge
762            | TypeLiteral::ClockNegedge
763            | TypeLiteral::Logic
764            | TypeLiteral::Reset
765            | TypeLiteral::ResetAsyncHigh
766            | TypeLiteral::ResetAsyncLow
767            | TypeLiteral::ResetSyncHigh
768            | TypeLiteral::ResetSyncLow
769            | TypeLiteral::String => Shape::new(vec![Some(1)]),
770            TypeLiteral::F32 => Shape::new(vec![Some(32)]),
771            TypeLiteral::F64 => Shape::new(vec![Some(64)]),
772            TypeLiteral::I8 => Shape::new(vec![Some(8)]),
773            TypeLiteral::I16 => Shape::new(vec![Some(16)]),
774            TypeLiteral::I32 => Shape::new(vec![Some(32)]),
775            TypeLiteral::I64 => Shape::new(vec![Some(64)]),
776            TypeLiteral::U8 => Shape::new(vec![Some(8)]),
777            TypeLiteral::U16 => Shape::new(vec![Some(16)]),
778            TypeLiteral::U32 => Shape::new(vec![Some(32)]),
779            TypeLiteral::U64 => Shape::new(vec![Some(64)]),
780        };
781
782        Type {
783            kind,
784            signed,
785            width,
786            ..Default::default()
787        }
788    }
789}
790
791impl fmt::Display for Type {
792    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
793        let mut ret = if self.signed {
794            "signed ".to_string()
795        } else {
796            String::new()
797        };
798        ret.push_str(&self.kind.to_string());
799
800        if !self.width.is_empty() {
801            ret.push_str(&format!("<{}>", self.width));
802        }
803
804        if !self.array.is_empty() {
805            ret.push_str(&format!("[{}]", self.array));
806        }
807
808        ret.fmt(f)
809    }
810}
811
812#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
813pub enum InstanceKind {
814    #[default]
815    Module,
816    Interface,
817    SystemVerilog,
818}
819
820#[derive(Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
821pub enum TypeKind {
822    Clock,
823    ClockPosedge,
824    ClockNegedge,
825    Reset,
826    ResetAsyncHigh,
827    ResetAsyncLow,
828    ResetSyncHigh,
829    ResetSyncLow,
830    Bit,
831    F32,
832    F64,
833    Logic,
834    Struct(TypeKindStruct),
835    Union(TypeKindUnion),
836    Enum(TypeKindEnum),
837    Module(Signature),
838    Interface(Signature),
839    Modport(Signature, StrId),
840    Package(Signature),
841    Instance(Signature, InstanceKind),
842    AbstractInterface(Option<StrId>),
843    Type,
844    String,
845    SystemVerilog,
846    Void,
847    #[default]
848    Unknown,
849}
850
851impl TypeKind {
852    pub fn width(&self) -> Option<usize> {
853        match self {
854            TypeKind::Clock
855            | TypeKind::ClockPosedge
856            | TypeKind::ClockNegedge
857            | TypeKind::Reset
858            | TypeKind::ResetAsyncHigh
859            | TypeKind::ResetAsyncLow
860            | TypeKind::ResetSyncHigh
861            | TypeKind::ResetSyncLow
862            | TypeKind::Bit
863            | TypeKind::F32
864            | TypeKind::F64
865            | TypeKind::Logic
866            | TypeKind::Type
867            | TypeKind::String
868            | TypeKind::Unknown
869            | TypeKind::SystemVerilog
870            | TypeKind::Module(_)
871            | TypeKind::Interface(_)
872            | TypeKind::Modport(_, _)
873            | TypeKind::Package(_)
874            | TypeKind::Instance(_, _)
875            | TypeKind::AbstractInterface(_) => Some(1),
876            TypeKind::Union(x) => x.width(),
877            TypeKind::Struct(x) => x.width(),
878            TypeKind::Enum(x) => x.width(),
879            TypeKind::Void => None,
880        }
881    }
882
883    pub fn is_float(&self) -> bool {
884        matches!(self, TypeKind::F32 | TypeKind::F64)
885    }
886
887    pub fn signature(&self) -> Option<Signature> {
888        match self {
889            TypeKind::Module(x)
890            | TypeKind::Interface(x)
891            | TypeKind::Package(x)
892            | TypeKind::Instance(x, _) => Some(x.clone()),
893            TypeKind::Modport(x, _) => Some(x.clone()),
894            _ => None,
895        }
896    }
897}
898
899impl fmt::Display for TypeKind {
900    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901        match self {
902            TypeKind::Clock => "clock".fmt(f),
903            TypeKind::ClockPosedge => "clock_posedge".fmt(f),
904            TypeKind::ClockNegedge => "clock_negedge".fmt(f),
905            TypeKind::Reset => "reset".fmt(f),
906            TypeKind::ResetAsyncHigh => "reset_async_high".fmt(f),
907            TypeKind::ResetAsyncLow => "reset_async_low".fmt(f),
908            TypeKind::ResetSyncHigh => "reset_sync_high".fmt(f),
909            TypeKind::ResetSyncLow => "reset_sync_low".fmt(f),
910            TypeKind::Bit => "bit".fmt(f),
911            TypeKind::F32 => "f32".fmt(f),
912            TypeKind::F64 => "f64".fmt(f),
913            TypeKind::Logic => "logic".fmt(f),
914            TypeKind::Struct(x) => x.fmt(f),
915            TypeKind::Union(x) => x.fmt(f),
916            TypeKind::Enum(x) => x.fmt(f),
917            TypeKind::Module(x) => format!("module {x}").fmt(f),
918            TypeKind::Interface(x) => format!("interface {x}").fmt(f),
919            TypeKind::Modport(x, _) => format!("modport {x}").fmt(f),
920            TypeKind::Package(x) => format!("package {x}").fmt(f),
921            TypeKind::Instance(x, _) => format!("instance {x}").fmt(f),
922            TypeKind::AbstractInterface(x) => {
923                if let Some(x) = x {
924                    format!("interface::{x}").fmt(f)
925                } else {
926                    "interface".fmt(f)
927                }
928            }
929            TypeKind::Type => "type".fmt(f),
930            TypeKind::String => "string".fmt(f),
931            TypeKind::SystemVerilog => "systemverilog".fmt(f),
932            TypeKind::Unknown => "unknown".fmt(f),
933            TypeKind::Void => "void".fmt(f),
934        }
935    }
936}
937
938#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
939pub struct TypeKindStruct {
940    pub id: SymbolId,
941    pub members: Vec<TypeKindMember>,
942}
943
944impl TypeKindStruct {
945    pub fn is_4state(&self) -> bool {
946        self.members.iter().any(|x| x.r#type.is_4state())
947    }
948
949    pub fn is_2state(&self) -> bool {
950        self.members.iter().all(|x| x.r#type.is_2state())
951    }
952
953    pub fn width(&self) -> Option<usize> {
954        let mut ret = 0;
955        for x in &self.members {
956            ret += x.width()?;
957        }
958        Some(ret)
959    }
960
961    pub fn expand_struct_union(
962        &self,
963        path: &VarPath,
964        part_select: &[PartSelect],
965        base: Option<&Type>,
966    ) -> Vec<PartSelectPath> {
967        let mut ret = vec![];
968        let mut offset = 0;
969        for x in self.members.iter().rev() {
970            let width = x.width().unwrap_or(1);
971            let x = x.expand_struct_union(path, part_select, base);
972            for mut x in x.into_iter().rev() {
973                if let Some(x) = x.part_select.get_mut(part_select.len()) {
974                    x.pos += offset;
975                }
976                ret.push(x);
977            }
978            offset += width;
979        }
980        ret.reverse();
981        ret
982    }
983}
984
985impl fmt::Display for TypeKindStruct {
986    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
987        let mut text = String::new();
988        for x in &self.members {
989            text.push_str(&format!(", {x}"));
990        }
991        let text = if text.is_empty() { &text } else { &text[2..] };
992
993        format!("struct {{{}}}", text).fmt(f)
994    }
995}
996
997#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
998pub struct TypeKindUnion {
999    pub id: SymbolId,
1000    pub members: Vec<TypeKindMember>,
1001}
1002
1003impl TypeKindUnion {
1004    pub fn is_4state(&self) -> bool {
1005        self.members.iter().any(|x| x.r#type.is_4state())
1006    }
1007
1008    pub fn is_2state(&self) -> bool {
1009        self.members.iter().all(|x| x.r#type.is_2state())
1010    }
1011
1012    pub fn width(&self) -> Option<usize> {
1013        self.members.first()?.width()
1014    }
1015
1016    pub fn expand_struct_union(
1017        &self,
1018        path: &VarPath,
1019        part_select: &[PartSelect],
1020        base: Option<&Type>,
1021    ) -> Vec<PartSelectPath> {
1022        let mut ret = vec![];
1023        for x in &self.members {
1024            ret.append(&mut x.expand_struct_union(path, part_select, base));
1025        }
1026        ret
1027    }
1028
1029    pub fn expand_union(&self, path: &VarPath, array: &ShapeRef) -> Vec<(VarPath, Type)> {
1030        let mut ret = vec![];
1031        for x in &self.members {
1032            ret.append(&mut x.expand_union(path, array));
1033        }
1034        ret
1035    }
1036}
1037
1038impl fmt::Display for TypeKindUnion {
1039    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1040        let mut text = String::new();
1041        for x in &self.members {
1042            text.push_str(&format!(", {x}"));
1043        }
1044        let text = if text.is_empty() { &text } else { &text[2..] };
1045
1046        format!("union {{{}}}", text).fmt(f)
1047    }
1048}
1049
1050#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1051pub struct TypeKindMember {
1052    pub name: StrId,
1053    pub r#type: Type,
1054}
1055
1056impl TypeKindMember {
1057    pub fn width(&self) -> Option<usize> {
1058        self.r#type.total_width()
1059    }
1060
1061    pub fn expand_struct_union(
1062        &self,
1063        path: &VarPath,
1064        part_select: &[PartSelect],
1065        base: Option<&Type>,
1066    ) -> Vec<PartSelectPath> {
1067        let mut path = path.clone();
1068        path.push(self.name);
1069
1070        let mut part_select = part_select.to_vec();
1071        part_select.push(PartSelect {
1072            pos: 0,
1073            r#type: self.r#type.clone(),
1074        });
1075
1076        let mut ret = self.r#type.expand_struct_union(&path, &part_select, base);
1077
1078        ret.push(PartSelectPath {
1079            base: base.unwrap().clone(),
1080            path: path.clone(),
1081            part_select,
1082        });
1083
1084        ret
1085    }
1086
1087    pub fn expand_union(&self, path: &VarPath, array: &ShapeRef) -> Vec<(VarPath, Type)> {
1088        let mut path = path.clone();
1089        path.push(self.name);
1090        let mut r#type = self.r#type.clone();
1091        r#type.array = array.to_owned();
1092        vec![(path, r#type)]
1093    }
1094}
1095
1096impl fmt::Display for TypeKindMember {
1097    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1098        format!("{}: {}", self.name, self.r#type).fmt(f)
1099    }
1100}
1101
1102#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1103pub struct TypeKindEnum {
1104    pub id: SymbolId,
1105    pub r#type: Box<Type>,
1106}
1107
1108impl TypeKindEnum {
1109    pub fn is_4state(&self) -> bool {
1110        self.r#type.is_4state()
1111    }
1112
1113    pub fn is_2state(&self) -> bool {
1114        self.r#type.is_2state()
1115    }
1116
1117    pub fn width(&self) -> Option<usize> {
1118        self.r#type.total_width()
1119    }
1120}
1121
1122impl fmt::Display for TypeKindEnum {
1123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1124        format!("enum {{{}}}", self.r#type).fmt(f)
1125    }
1126}
1127
1128#[cfg(test)]
1129mod tests {
1130    use super::*;
1131    use veryl_parser::resource_table;
1132
1133    fn create_logic(width: usize) -> Type {
1134        let mut t = Type {
1135            kind: TypeKind::Logic,
1136            array: Shape::default(),
1137            signed: false,
1138            is_positive: false,
1139            ..Default::default()
1140        };
1141        t.set_concrete_width(Shape::new(vec![Some(width)]));
1142        t
1143    }
1144
1145    fn create_logic_multi_dim(width: &[Option<usize>]) -> Type {
1146        let mut t = Type {
1147            kind: TypeKind::Logic,
1148            array: Shape::default(),
1149            signed: false,
1150            is_positive: false,
1151            ..Default::default()
1152        };
1153        t.set_concrete_width(Shape::new(width.to_vec()));
1154        t
1155    }
1156
1157    fn create_struct(members: &[(&'static str, Type)], width: usize) -> Type {
1158        let members = members
1159            .into_iter()
1160            .map(|(n, t)| TypeKindMember {
1161                name: resource_table::insert_str(n),
1162                r#type: t.clone(),
1163            })
1164            .collect();
1165        let mut t = Type {
1166            kind: TypeKind::Struct(TypeKindStruct {
1167                id: SymbolId::default(),
1168                members,
1169            }),
1170            array: Shape::default(),
1171            signed: false,
1172            is_positive: false,
1173            ..Default::default()
1174        };
1175        t.set_concrete_width(Shape::new(vec![Some(width)]));
1176        t
1177    }
1178
1179    fn create_union(members: &[(&'static str, Type)], width: usize) -> Type {
1180        let members = members
1181            .into_iter()
1182            .map(|(n, t)| TypeKindMember {
1183                name: resource_table::insert_str(n),
1184                r#type: t.clone(),
1185            })
1186            .collect();
1187        let mut t = Type {
1188            kind: TypeKind::Union(TypeKindUnion {
1189                id: SymbolId::default(),
1190                members,
1191            }),
1192            array: Shape::default(),
1193            signed: false,
1194            is_positive: false,
1195            ..Default::default()
1196        };
1197        t.set_concrete_width(Shape::new(vec![Some(width)]));
1198        t
1199    }
1200
1201    #[track_caller]
1202    fn check(
1203        path: &PartSelectPath,
1204        select: &[usize],
1205        end: Option<usize>,
1206        expect: Option<(usize, usize)>,
1207    ) {
1208        let mut expr = vec![];
1209        let token = TokenRange::default();
1210        for x in select {
1211            expr.push(Expression::create_value(
1212                Value::new(*x as u64, 32, false),
1213                token,
1214            ));
1215        }
1216        let end = if let Some(end) = end {
1217            Some((
1218                VarSelectOp::Colon,
1219                Expression::create_value(Value::new(end as u64, 32, false), token),
1220            ))
1221        } else {
1222            None
1223        };
1224        let select = VarSelect(expr, end);
1225
1226        let mut context = Context::default();
1227        let expr = path.to_base_select(&mut context, &select);
1228        let range = if let Some(expr) = expr {
1229            let r#type = Type::default();
1230            expr.eval_value(&mut context, &r#type, false)
1231        } else {
1232            None
1233        };
1234
1235        assert_eq!(range, expect)
1236    }
1237
1238    #[rustfmt::skip]
1239    #[test]
1240    fn expand_struct() {
1241        // struct x0 {
1242        //   a: logic<2>,
1243        //   b: logic<3>,
1244        // }
1245        // struct x1 {
1246        //   c: logic<5>,
1247        //   d: logic<6>,
1248        // }
1249        // struct x2 {
1250        //   e: x0<4>,
1251        //   f: x1<7>,
1252        // }
1253        let x0 = create_struct(&[("a", create_logic(2)), ("b", create_logic(3))], 4);
1254        let x1 = create_struct(&[("c", create_logic(5)), ("d", create_logic(6))], 7);
1255        let x2 = create_struct(&[("e", x0.clone()), ("f", x1.clone())], 8);
1256
1257        let path = VarPath::new(resource_table::insert_str("x"));
1258
1259        let x0 = x0.expand_struct_union(&path, &[], None);
1260        let x1 = x1.expand_struct_union(&path, &[], None);
1261        let x2 = x2.expand_struct_union(&path, &[], None);
1262
1263        assert_eq!(x0[0].to_string(), "x.a: [3: logic<2>]");
1264        assert_eq!(x0[1].to_string(), "x.b: [0: logic<3>]");
1265        assert_eq!(x1[0].to_string(), "x.c: [6: logic<5>]");
1266        assert_eq!(x1[1].to_string(), "x.d: [0: logic<6>]");
1267        assert_eq!(x2[0].to_string(), "x.e.a: [77: struct {a: logic<2>, b: logic<3>}<4>][3: logic<2>]");
1268        assert_eq!(x2[1].to_string(), "x.e.b: [77: struct {a: logic<2>, b: logic<3>}<4>][0: logic<3>]");
1269        assert_eq!(x2[2].to_string(), "x.e: [77: struct {a: logic<2>, b: logic<3>}<4>]");
1270        assert_eq!(x2[3].to_string(), "x.f.c: [0: struct {c: logic<5>, d: logic<6>}<7>][6: logic<5>]");
1271        assert_eq!(x2[4].to_string(), "x.f.d: [0: struct {c: logic<5>, d: logic<6>}<7>][0: logic<6>]");
1272        assert_eq!(x2[5].to_string(), "x.f: [0: struct {c: logic<5>, d: logic<6>}<7>]");
1273
1274        /* x[0].a           */ check(&x0[0], &[0]      , None   , Some((4, 3)));
1275        /* x[0].a[0]        */ check(&x0[0], &[0, 0]   , None   , Some((3, 3)));
1276        /* x[0].a[1:0]      */ check(&x0[0], &[0, 1]   , Some(0), Some((4, 3)));
1277        /* x[0].b           */ check(&x0[1], &[0, ]    , None   , Some((2, 0)));
1278        /* x[0].b[2]        */ check(&x0[1], &[0, 2]   , None   , Some((2, 2)));
1279        /* x[0].b[2:1]      */ check(&x0[1], &[0, 2]   , Some(1), Some((2, 1)));
1280        /* x[0].c           */ check(&x1[0], &[0]      , None   , Some((10, 6)));
1281        /* x[0].d           */ check(&x1[1], &[0]      , None   , Some((5, 0)));
1282        /* x[0].e.a         */ check(&x2[0], &[0]      , None   , None);
1283        /* x[0].e[0].a      */ check(&x2[0], &[0, 0]   , None   , Some((81, 80)));
1284        /* x[0].e[1].a      */ check(&x2[0], &[0, 1]   , None   , Some((86, 85)));
1285        /* x[0].e[2].a      */ check(&x2[0], &[0, 2]   , None   , Some((91, 90)));
1286        /* x[0].e[3].a      */ check(&x2[0], &[0, 3]   , None   , Some((96, 95)));
1287        /* x[0].e.b         */ check(&x2[1], &[0]      , None   , None);
1288        /* x[0].e[0].b      */ check(&x2[1], &[0, 0]   , None   , Some((79, 77)));
1289        /* x[0].e[1].b      */ check(&x2[1], &[0, 1]   , None   , Some((84, 82)));
1290        /* x[0].e[2].b      */ check(&x2[1], &[0, 2]   , None   , Some((89, 87)));
1291        /* x[0].e[3].b      */ check(&x2[1], &[0, 3]   , None   , Some((94, 92)));
1292        /* x[0].e[3].b      */ check(&x2[1], &[0, 3]   , None   , Some((94, 92)));
1293        /* x[0].e[3].b[2]   */ check(&x2[1], &[0, 3, 2], None   , Some((94, 94)));
1294        /* x[0].e[3].b[1:0] */ check(&x2[1], &[0, 3, 1], Some(0), Some((93, 92)));
1295        /* x[0].e           */ check(&x2[2], &[0]      , None   , Some((96, 77)));
1296        /* x[0].e[0]        */ check(&x2[2], &[0, 0]   , None   , Some((81, 77)));
1297        /* x[0].e[1]        */ check(&x2[2], &[0, 1]   , None   , Some((86, 82)));
1298        /* x[0].e[2]        */ check(&x2[2], &[0, 2]   , None   , Some((91, 87)));
1299        /* x[0].e[3]        */ check(&x2[2], &[0, 3]   , None   , Some((96, 92)));
1300        /* x[0].e[2:1]      */ check(&x2[2], &[0, 2]   , Some(1), Some((91, 82)));
1301        /* x[0].f.c         */ check(&x2[3], &[0]      , None   , None);
1302        /* x[0].f[0].c      */ check(&x2[3], &[0, 0]   , None   , Some((10, 6)));
1303        /* x[0].f[1].c      */ check(&x2[3], &[0, 1]   , None   , Some((21, 17)));
1304        /* x[0].f[2].c      */ check(&x2[3], &[0, 2]   , None   , Some((32, 28)));
1305        /* x[0].f[3].c      */ check(&x2[3], &[0, 3]   , None   , Some((43, 39)));
1306        /* x[0].f[4].c      */ check(&x2[3], &[0, 4]   , None   , Some((54, 50)));
1307        /* x[0].f[5].c      */ check(&x2[3], &[0, 5]   , None   , Some((65, 61)));
1308        /* x[0].f[6].c      */ check(&x2[3], &[0, 6]   , None   , Some((76, 72)));
1309        /* x[0].f.d         */ check(&x2[4], &[0]      , None   , None);
1310        /* x[0].f[0].d      */ check(&x2[4], &[0, 0]   , None   , Some((5, 0)));
1311        /* x[0].f[1].d      */ check(&x2[4], &[0, 1]   , None   , Some((16, 11)));
1312        /* x[0].f[2].d      */ check(&x2[4], &[0, 2]   , None   , Some((27, 22)));
1313        /* x[0].f[3].d      */ check(&x2[4], &[0, 3]   , None   , Some((38, 33)));
1314        /* x[0].f[4].d      */ check(&x2[4], &[0, 4]   , None   , Some((49, 44)));
1315        /* x[0].f[5].d      */ check(&x2[4], &[0, 5]   , None   , Some((60, 55)));
1316        /* x[0].f[6].d      */ check(&x2[4], &[0, 6]   , None   , Some((71, 66)));
1317        /* x[0].f           */ check(&x2[5], &[0]      , None   , Some((76, 0)));
1318        /* x[0].f[0]        */ check(&x2[5], &[0, 0]   , None   , Some((10, 0)));
1319        /* x[0].f[1]        */ check(&x2[5], &[0, 1]   , None   , Some((21, 11)));
1320        /* x[0].f[2]        */ check(&x2[5], &[0, 2]   , None   , Some((32, 22)));
1321        /* x[0].f[3]        */ check(&x2[5], &[0, 3]   , None   , Some((43, 33)));
1322        /* x[0].f[4]        */ check(&x2[5], &[0, 4]   , None   , Some((54, 44)));
1323        /* x[0].f[5]        */ check(&x2[5], &[0, 5]   , None   , Some((65, 55)));
1324        /* x[0].f[6]        */ check(&x2[5], &[0, 6]   , None   , Some((76, 66)));
1325    }
1326
1327    #[rustfmt::skip]
1328    #[test]
1329    fn expand_union() {
1330        // struct x0 {
1331        //   a: logic<2>,
1332        //   b: logic<3>,
1333        // }
1334        // union x1 {
1335        //   e: x0<2>,
1336        //   f: logic<10>,
1337        // }
1338        // struct x2 {
1339        //   g: x1<2>,
1340        //   h: logic<5>,
1341        // }
1342        let x0 = create_struct(&[("a", create_logic(2)), ("b", create_logic(3))], 2);
1343        let x1 = create_union (&[("e", x0.clone()), ("f", create_logic(10))], 2);
1344        let x2 = create_struct(&[("g", x1.clone()), ("h", create_logic(5))], 2);
1345
1346        let path = VarPath::new(resource_table::insert_str("x"));
1347
1348        let x0 = x0.expand_struct_union(&path, &[], None);
1349        let x1 = x1.expand_struct_union(&path, &[], None);
1350        let x2 = x2.expand_struct_union(&path, &[], None);
1351
1352        assert_eq!(x0[0].to_string(), "x.a: [3: logic<2>]");
1353        assert_eq!(x0[1].to_string(), "x.b: [0: logic<3>]");
1354        assert_eq!(x1[0].to_string(), "x.e.a: [0: struct {a: logic<2>, b: logic<3>}<2>][3: logic<2>]");
1355        assert_eq!(x1[1].to_string(), "x.e.b: [0: struct {a: logic<2>, b: logic<3>}<2>][0: logic<3>]");
1356        assert_eq!(x1[2].to_string(), "x.e: [0: struct {a: logic<2>, b: logic<3>}<2>]");
1357        assert_eq!(x1[3].to_string(), "x.f: [0: logic<10>]");
1358        assert_eq!(x2[0].to_string(), "x.g.e.a: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: struct {a: logic<2>, b: logic<3>}<2>][3: logic<2>]");
1359        assert_eq!(x2[1].to_string(), "x.g.e.b: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: struct {a: logic<2>, b: logic<3>}<2>][0: logic<3>]");
1360        assert_eq!(x2[2].to_string(), "x.g.e: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: struct {a: logic<2>, b: logic<3>}<2>]");
1361        assert_eq!(x2[3].to_string(), "x.g.f: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>][0: logic<10>]");
1362        assert_eq!(x2[4].to_string(), "x.g: [5: union {e: struct {a: logic<2>, b: logic<3>}<2>, f: logic<10>}<2>]");
1363        assert_eq!(x2[5].to_string(), "x.h: [0: logic<5>]");
1364
1365        /* x[0].a           */ check(&x0[0], &[0]      , None   , Some((4, 3)));
1366        /* x[0].b           */ check(&x0[1], &[0]      , None   , Some((2, 0)));
1367        /* x[0].e.a         */ check(&x1[0], &[0]      , None   , None);
1368        /* x[0].e[0].a      */ check(&x1[0], &[0, 0]   , None   , Some((4, 3)));
1369        /* x[0].e[1].a      */ check(&x1[0], &[0, 1]   , None   , Some((9, 8)));
1370        /* x[0].e.b         */ check(&x1[1], &[0]      , None   , None);
1371        /* x[0].e[0].b      */ check(&x1[1], &[0, 0]   , None   , Some((2, 0)));
1372        /* x[0].e[1].b      */ check(&x1[1], &[0, 1]   , None   , Some((7, 5)));
1373        /* x[0].e[1].b[2]   */ check(&x1[1], &[0, 1, 2], None   , Some((7, 7)));
1374        /* x[0].e[1].b[1:0] */ check(&x1[1], &[0, 1, 1], Some(0), Some((6, 5)));
1375        /* x[0].e           */ check(&x1[2], &[0]      , None   , Some((9, 0)));
1376        /* x[0].e[0]        */ check(&x1[2], &[0, 0]   , None   , Some((4, 0)));
1377        /* x[0].e[1]        */ check(&x1[2], &[0, 1]   , None   , Some((9, 5)));
1378        /* x[0].f           */ check(&x1[3], &[0]      , None   , Some((9, 0)));
1379        /* x[0].f[5]        */ check(&x1[3], &[0, 5]   , None   , Some((5, 5)));
1380        /* x[0].f[5:4]      */ check(&x1[3], &[0, 5]   , Some(4), Some((5, 4)));
1381        /* x[0].g.e.a       */ check(&x2[0], &[0]      , None   , None);
1382        /* x[0].g[0].e.a    */ check(&x2[0], &[0, 0]   , None   , None);
1383        /* x[0].g[0].e[0].a */ check(&x2[0], &[0, 0, 0], None   , Some((9, 8)));
1384        /* x[0].g[0].e[1].a */ check(&x2[0], &[0, 0, 1], None   , Some((14, 13)));
1385        /* x[0].g[1].e.a    */ check(&x2[0], &[0, 1]   , None   , None);
1386        /* x[0].g[1].e[0].a */ check(&x2[0], &[0, 1, 0], None   , Some((19, 18)));
1387        /* x[0].g[1].e[1].a */ check(&x2[0], &[0, 1, 1], None   , Some((24, 23)));
1388        /* x[0].g.e.b       */ check(&x2[1], &[0]      , None   , None);
1389        /* x[0].g[0].e.b    */ check(&x2[1], &[0, 0]   , None   , None);
1390        /* x[0].g[0].e[0].b */ check(&x2[1], &[0, 0, 0], None   , Some((7, 5)));
1391        /* x[0].g[0].e[1].b */ check(&x2[1], &[0, 0, 1], None   , Some((12, 10)));
1392        /* x[0].g[1].e.b    */ check(&x2[1], &[0, 1]   , None   , None);
1393        /* x[0].g[1].e[0].b */ check(&x2[1], &[0, 1, 0], None   , Some((17, 15)));
1394        /* x[0].g[1].e[1].b */ check(&x2[1], &[0, 1, 1], None   , Some((22, 20)));
1395        /* x[0].g.e         */ check(&x2[2], &[0]      , None   , None);
1396        /* x[0].g[0].e      */ check(&x2[2], &[0, 0]   , None   , Some((14, 5)));
1397        /* x[0].g[0].e[0]   */ check(&x2[2], &[0, 0, 0], None   , Some((9, 5)));
1398        /* x[0].g[0].e[1]   */ check(&x2[2], &[0, 0, 1], None   , Some((14, 10)));
1399        /* x[0].g[0].e[1:0] */ check(&x2[2], &[0, 0, 1], Some(0), Some((14, 5)));
1400        /* x[0].g[1].e      */ check(&x2[2], &[0, 1]   , None   , Some((24, 15)));
1401        /* x[0].g[1].e[0]   */ check(&x2[2], &[0, 1, 0], None   , Some((19, 15)));
1402        /* x[0].g[1].e[1]   */ check(&x2[2], &[0, 1, 1], None   , Some((24, 20)));
1403        /* x[0].g.f         */ check(&x2[3], &[0, ]    , None   , None);
1404        /* x[0].g[0].f      */ check(&x2[3], &[0, 0]   , None   , Some((14, 5)));
1405        /* x[0].g[1].f      */ check(&x2[3], &[0, 1]   , None   , Some((24, 15)));
1406        /* x[0].g           */ check(&x2[4], &[0, ]    , None   , Some((24, 5)));
1407        /* x[0].g[0]        */ check(&x2[4], &[0, 0]   , None   , Some((14, 5)));
1408        /* x[0].g[1]        */ check(&x2[4], &[0, 1]   , None   , Some((24, 15)));
1409        /* x[0].h           */ check(&x2[5], &[0, ]    , None   , Some((4, 0)));
1410        /* x[0].h[3]        */ check(&x2[5], &[0, 3]   , None   , Some((3, 3)));
1411        /* x[0].h[3:2]      */ check(&x2[5], &[0, 3]   , Some(2), Some((3, 2)));
1412    }
1413
1414    #[rustfmt::skip]
1415    #[test]
1416    fn expand_struct_with_multi_dim() {
1417        // struct x0 {
1418        //   a: logic<2, 4>,
1419        //   b: logic<3, 6>,
1420        // }
1421        let x0 = create_struct(&[("a", create_logic_multi_dim(&[Some(2), Some(4)])), ("b", create_logic_multi_dim(&[Some(3), Some(6)]))], 4);
1422
1423        let path = VarPath::new(resource_table::insert_str("x"));
1424
1425        let x0 = x0.expand_struct_union(&path, &[], None);
1426
1427        assert_eq!(x0[0].to_string(), "x.a: [18: logic<2, 4>]");
1428        assert_eq!(x0[1].to_string(), "x.b: [0: logic<3, 6>]");
1429
1430        /* x[0].a           */ check(&x0[0], &[0]      , None   , Some((25, 18)));
1431        /* x[0].a[0]        */ check(&x0[0], &[0, 0]   , None   , Some((21, 18)));
1432        /* x[0].a[1]        */ check(&x0[0], &[0, 1]   , None   , Some((25, 22)));
1433        /* x[0].a[1:0]      */ check(&x0[0], &[0, 1]   , Some(0), Some((25, 18)));
1434        /* x[0].a[0][0]     */ check(&x0[0], &[0, 0, 0], None   , Some((18, 18)));
1435        /* x[0].a[0][1]     */ check(&x0[0], &[0, 0, 1], None   , Some((19, 19)));
1436        /* x[0].a[0][2]     */ check(&x0[0], &[0, 0, 2], None   , Some((20, 20)));
1437        /* x[0].a[0][3]     */ check(&x0[0], &[0, 0, 3], None   , Some((21, 21)));
1438        /* x[0].a[0][2:1]   */ check(&x0[0], &[0, 0, 2], Some(1), Some((20, 19)));
1439        /* x[0].a[1][0]     */ check(&x0[0], &[0, 1, 0], None   , Some((22, 22)));
1440        /* x[0].a[1][1]     */ check(&x0[0], &[0, 1, 1], None   , Some((23, 23)));
1441        /* x[0].a[1][2]     */ check(&x0[0], &[0, 1, 2], None   , Some((24, 24)));
1442        /* x[0].a[1][3]     */ check(&x0[0], &[0, 1, 3], None   , Some((25, 25)));
1443        /* x[0].a[1][2:1]   */ check(&x0[0], &[0, 1, 2], Some(1), Some((24, 23)));
1444    }
1445}