Skip to main content

veryl_analyzer/ir/
expression.rs

1use crate::conv::Context;
2use crate::conv::checker::clock_domain::check_clock_domain;
3use crate::ir::assign_table::{AssignContext, AssignTable};
4use crate::ir::utils::convert_cast;
5use crate::ir::{
6    Comptime, ExpressionContext, FfTable, FunctionCall, Op, Signature, SystemFunctionCall,
7    SystemFunctionKind, Type, TypeKind, ValueVariant, VarId, VarIndex, VarSelect,
8};
9use crate::symbol::{ClockDomain, Symbol, SymbolKind};
10use crate::value::{Value, ValueBigUint};
11use std::fmt;
12use veryl_parser::resource_table::StrId;
13use veryl_parser::token_range::TokenRange;
14
15#[derive(Clone, Debug)]
16pub enum Expression {
17    Term(Box<Factor>),
18    Unary(Op, Box<Expression>, Box<Comptime>),
19    Binary(Box<Expression>, Op, Box<Expression>, Box<Comptime>),
20    Ternary(
21        Box<Expression>,
22        Box<Expression>,
23        Box<Expression>,
24        Box<Comptime>,
25    ),
26    Concatenation(Vec<(Expression, Option<Expression>)>, Box<Comptime>),
27    ArrayLiteral(Vec<ArrayLiteralItem>, Box<Comptime>),
28    StructConstructor(Type, Vec<(StrId, Expression)>, Box<Comptime>),
29}
30
31impl Expression {
32    pub fn create_value(value: Value, token: TokenRange) -> Self {
33        Self::Term(Box::new(Factor::create_value(value, token)))
34    }
35}
36
37impl fmt::Display for Expression {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        let ret = match self {
40            Expression::Term(x) => x.to_string(),
41            Expression::Unary(x, y, _) => {
42                format!("({x} {y})")
43            }
44            Expression::Binary(x, y, z, _) => {
45                format!("({x} {y} {z})")
46            }
47            Expression::Ternary(x, y, z, _) => {
48                format!("({x} ? {y} : {z})")
49            }
50            Expression::Concatenation(x, _) => {
51                let mut ret = String::new();
52                for (x, y) in x {
53                    if let Some(y) = y {
54                        ret = format!("{ret}, {x} repeat {y}")
55                    } else {
56                        ret = format!("{ret}, {x}")
57                    }
58                }
59                format!("{{{}}}", &ret[2..])
60            }
61            Expression::ArrayLiteral(x, _) => {
62                let mut ret = String::new();
63                for x in x {
64                    ret = format!("{ret}, {x}")
65                }
66                format!("'{{{}}}", &ret[2..])
67            }
68            Expression::StructConstructor(_, x, _) => {
69                let mut ret = String::new();
70                for x in x {
71                    ret = format!("{ret}, {}: {}", x.0, x.1)
72                }
73                format!("'{{{}}}", &ret[2..])
74            }
75        };
76
77        ret.fmt(f)
78    }
79}
80
81impl Expression {
82    pub fn is_assignable(&self) -> bool {
83        match self {
84            Expression::Term(x) => x.is_assignable(),
85            Expression::Concatenation(x, _) => {
86                x.iter().all(|x| x.0.is_assignable() && x.1.is_none())
87            }
88            _ => false,
89        }
90    }
91
92    pub fn gather_context(&mut self, context: &mut Context) -> ExpressionContext {
93        match self {
94            Expression::Term(x) => x.gather_context(context),
95            Expression::Unary(op, x, comptime) => {
96                let x = x.gather_context(context);
97
98                comptime.is_const = x.is_const;
99                comptime.is_global = x.is_global;
100
101                op.eval_context_unary(x)
102            }
103            Expression::Binary(x, op, y, comptime) => {
104                let (x, y) = if op.binary_op_self_determined() {
105                    let expr_context = x.gather_context(context).merge(y.gather_context(context));
106                    x.apply_context(context, expr_context);
107                    y.apply_context(context, expr_context);
108                    (expr_context, expr_context)
109                } else {
110                    let x = if op.binary_x_self_determined() {
111                        let expr_context = x.gather_context(context);
112                        x.apply_context(context, expr_context);
113                        x.comptime().expr_context
114                    } else {
115                        x.gather_context(context)
116                    };
117
118                    let y = if op.binary_y_self_determined() {
119                        let expr_context = y.gather_context(context);
120                        y.apply_context(context, expr_context);
121                        y.comptime().expr_context
122                    } else {
123                        y.gather_context(context)
124                    };
125
126                    (x, y)
127                };
128
129                comptime.is_const = x.is_const & y.is_const;
130                comptime.is_global = x.is_global & y.is_global;
131
132                op.eval_context_binary(x, y)
133            }
134            Expression::Ternary(x, y, z, comptime) => {
135                // x is self-determined
136                let expr_context = x.gather_context(context);
137                x.apply_context(context, expr_context);
138                let x = x.comptime();
139
140                let y = y.gather_context(context);
141                let z = z.gather_context(context);
142
143                let is_const = x.is_const & y.is_const & z.is_const;
144                let is_global = x.is_global & y.is_global & z.is_global;
145
146                comptime.is_const = is_const;
147                comptime.is_global = is_global;
148
149                ExpressionContext {
150                    width: y.width.max(z.width),
151                    signed: y.signed & z.signed,
152                    is_const,
153                    is_global,
154                }
155            }
156            Expression::Concatenation(x, comptime) => {
157                let op = Op::Concatenation;
158                op.eval_type_concatenation(context, x, comptime);
159                comptime.evaluated = true;
160
161                ExpressionContext {
162                    width: comptime.r#type.total_width().unwrap_or(0),
163                    signed: comptime.r#type.signed,
164                    is_const: comptime.is_const,
165                    is_global: comptime.is_global,
166                }
167            }
168            Expression::StructConstructor(r#type, exprs, comptime) => {
169                let mut is_const = true;
170                let mut is_global = true;
171                for (_, expr) in exprs {
172                    let expr_context = expr.gather_context(context);
173                    is_const &= expr_context.is_const;
174                    is_global &= expr_context.is_global;
175
176                    let expr = expr.comptime();
177                    check_clock_domain(context, comptime, expr, &comptime.token.beg);
178                    comptime.clock_domain = expr.clock_domain;
179                }
180
181                comptime.r#type = r#type.clone();
182                comptime.is_const = is_const;
183                comptime.is_global = is_global;
184                comptime.evaluated = true;
185
186                ExpressionContext {
187                    width: r#type.total_width().unwrap_or(0),
188                    signed: false,
189                    is_const,
190                    is_global,
191                }
192            }
193            Expression::ArrayLiteral(items, comptime) => {
194                let mut is_const = true;
195                let mut is_global = true;
196                for item in items {
197                    match item {
198                        ArrayLiteralItem::Value(x, y) => {
199                            let x_context = x.gather_context(context);
200                            is_const &= x_context.is_const;
201                            is_global &= x_context.is_global;
202                            if let Some(y) = y {
203                                let y_context = y.gather_context(context);
204                                is_const &= y_context.is_const;
205                                is_global &= y_context.is_global;
206                            }
207                        }
208                        ArrayLiteralItem::Defaul(x) => {
209                            let x_context = x.gather_context(context);
210                            is_const &= x_context.is_const;
211                            is_global &= x_context.is_global;
212                        }
213                    }
214                }
215
216                comptime.is_const = is_const;
217                comptime.is_global = is_global;
218                comptime.evaluated = true;
219
220                // ArrayLiteral doesn't affect context width
221                ExpressionContext {
222                    width: 0,
223                    signed: false,
224                    is_const,
225                    is_global,
226                }
227            }
228        }
229    }
230
231    pub fn apply_context(&mut self, context: &mut Context, expr_context: ExpressionContext) {
232        match self {
233            Expression::Term(x) => x.apply_context(expr_context),
234            Expression::Unary(op, x, comptime) => {
235                x.apply_context(context, expr_context);
236                comptime.expr_context = expr_context;
237                op.eval_type_unary(context, x.comptime(), comptime);
238                comptime.evaluated = true;
239            }
240            Expression::Binary(x, op, y, comptime) => {
241                if !op.binary_op_self_determined() {
242                    if !op.binary_x_self_determined() {
243                        x.apply_context(context, expr_context);
244                    }
245                    if !op.binary_y_self_determined() {
246                        y.apply_context(context, expr_context);
247                    }
248                }
249
250                comptime.expr_context = expr_context;
251                op.eval_type_binary(context, x.comptime(), y.comptime(), comptime);
252                comptime.evaluated = true;
253            }
254            Expression::Ternary(x, y, z, comptime) => {
255                y.apply_context(context, expr_context);
256                z.apply_context(context, expr_context);
257
258                comptime.expr_context = expr_context;
259                let op = Op::Ternary;
260                op.eval_type_ternary(context, x.comptime(), y.comptime(), z.comptime(), comptime);
261                comptime.evaluated = true;
262            }
263            Expression::Concatenation(_, _) => (),
264            Expression::StructConstructor(_, _, _) => (),
265            Expression::ArrayLiteral(_, _) => (),
266        }
267    }
268
269    pub fn eval_value(&self, context: &mut Context) -> Option<Value> {
270        let context_width = self.comptime().expr_context.width;
271        let signed = self.comptime().expr_context.signed;
272
273        match self {
274            Expression::Term(x) => x.eval_value(context),
275            Expression::Unary(op, x, _) => {
276                let ret = x.eval_value(context)?;
277                let x_kind = &x.comptime().r#type.kind;
278                if x_kind.is_float() {
279                    op.eval_float_unary(&ret, x_kind)
280                } else {
281                    let ret =
282                        op.eval_value_unary(&ret, context_width, signed, &mut context.mask_cache);
283                    Some(ret)
284                }
285            }
286            Expression::Binary(x, op, y, comptime) => {
287                if op == &Op::As {
288                    let src_kind = &x.comptime().r#type.kind;
289                    let dst_kind = &comptime.r#type.kind;
290
291                    let val = x.eval_value(context)?;
292                    if src_kind.is_float() || dst_kind.is_float() {
293                        return Some(convert_cast(val, src_kind, dst_kind, context_width));
294                    }
295
296                    let cast_width = comptime.r#type.total_width()?;
297                    let val_width = val.width();
298                    if val_width > cast_width {
299                        let mut val = val.clone();
300                        val.trunc(cast_width);
301                        return Some(convert_cast(val, src_kind, dst_kind, context_width));
302                    } else if val_width < cast_width {
303                        let val = val.expand(cast_width, false).into_owned();
304                        return Some(convert_cast(val, src_kind, dst_kind, context_width));
305                    } else {
306                        return Some(convert_cast(val, src_kind, dst_kind, context_width));
307                    }
308                }
309
310                // Re-derive signed from the operands for Div/Rem: the
311                // outer-propagated expr_context may have dropped signed
312                // via merge() when a sibling branch is unsigned.
313                let signed = if matches!(op, Op::Div | Op::Rem) {
314                    x.comptime().expr_context.signed & y.comptime().expr_context.signed
315                } else {
316                    signed
317                };
318
319                let x_kind = x.comptime().r#type.kind.clone();
320                let y_kind = y.comptime().r#type.kind.clone();
321                let x = x.eval_value(context)?;
322                let y = y.eval_value(context)?;
323                if x_kind.is_float() || y_kind.is_float() {
324                    let float_kind = if x_kind.is_float() { &x_kind } else { &y_kind };
325                    let float_width = if matches!(float_kind, TypeKind::F32) {
326                        32
327                    } else {
328                        64
329                    };
330                    let x = if !x_kind.is_float() {
331                        convert_cast(x, &x_kind, float_kind, float_width)
332                    } else {
333                        x
334                    };
335                    let y = if !y_kind.is_float() {
336                        convert_cast(y, &y_kind, float_kind, float_width)
337                    } else {
338                        y
339                    };
340                    op.eval_float_binary(&x, &y, float_kind)
341                } else {
342                    let ret = op.eval_value_binary(
343                        &x,
344                        &y,
345                        context_width,
346                        signed,
347                        &mut context.mask_cache,
348                    );
349                    Some(ret)
350                }
351            }
352            Expression::Ternary(x, y, z, _) => {
353                let x = x.eval_value(context)?;
354                let y = y.eval_value(context)?;
355                let z = z.eval_value(context)?;
356
357                let width = y.width().max(z.width());
358
359                let ret = if x.to_usize().unwrap_or(0) == 0 { z } else { y };
360                let ret = ret.expand(width, false).into_owned();
361                Some(ret)
362            }
363            Expression::Concatenation(x, _) => {
364                let mut ret = Value::new(0, 0, false);
365                for (exp, rep) in x.iter() {
366                    let exp = exp.eval_value(context)?;
367
368                    let rep = if let Some(rep) = rep {
369                        let token = rep.token_range();
370                        let rep = rep.eval_value(context)?;
371                        let rep = rep.to_usize()?;
372                        context.check_size(rep, token)?
373                    } else {
374                        1
375                    };
376
377                    for _ in 0..rep {
378                        ret = ret.concat(&exp);
379                    }
380                }
381                Some(ret)
382            }
383            Expression::StructConstructor(r#type, exprs, _) => {
384                let mut ret = Value::new(0u32.into(), 0, false);
385                for (name, expr) in exprs {
386                    let sub_type = r#type.get_member_type(*name)?;
387                    let width = sub_type.total_width()?;
388                    let mut value = expr.eval_value(context)?;
389                    value.trunc(width);
390                    ret = ret.concat(&value);
391                }
392                Some(ret)
393            }
394            // ArrayLiteral doesn't require evaluation because it is expanded in conv phase
395            Expression::ArrayLiteral(_, _) => None,
396        }
397    }
398
399    pub fn eval_comptime(
400        &mut self,
401        context: &mut Context,
402        context_width: Option<usize>,
403    ) -> &Comptime {
404        if !self.comptime().evaluated {
405            let mut expr_context = self.gather_context(context);
406            expr_context.width = expr_context.width.max(context_width.unwrap_or(0));
407            self.apply_context(context, expr_context);
408
409            let value = self.eval_value(context);
410            let comptime = self.comptime_mut();
411            if comptime.value.is_unknown()
412                && let Some(x) = &value
413            {
414                comptime.value = ValueVariant::Numeric(x.clone());
415            }
416
417            // const optimization
418            if !context.disalbe_const_opt
419                && comptime.is_const
420                && let Some(value) = value
421                && !value.is_xz()
422            {
423                let is_global = comptime.is_global;
424                let r#type = comptime.r#type.clone();
425                let mut expr = Expression::create_value(value.clone(), self.token_range());
426
427                let expr_comptime = expr.comptime_mut();
428                expr_comptime.is_global = is_global;
429                expr_comptime.r#type = r#type;
430                expr_comptime.evaluated = true;
431
432                *self = expr;
433            }
434        }
435
436        self.comptime()
437    }
438
439    pub fn eval_assign(
440        &self,
441        context: &mut Context,
442        assign_table: &mut AssignTable,
443        assign_context: AssignContext,
444    ) {
445        match self {
446            Expression::Term(x) => x.eval_assign(context, assign_table, assign_context),
447            Expression::Unary(_, x, _) => x.eval_assign(context, assign_table, assign_context),
448            Expression::Binary(x, _, y, _) => {
449                x.eval_assign(context, assign_table, assign_context);
450                y.eval_assign(context, assign_table, assign_context);
451            }
452            Expression::Ternary(x, y, z, _) => {
453                x.eval_assign(context, assign_table, assign_context);
454                y.eval_assign(context, assign_table, assign_context);
455                z.eval_assign(context, assign_table, assign_context);
456            }
457            Expression::Concatenation(x, _) => {
458                for (x, y) in x {
459                    x.eval_assign(context, assign_table, assign_context);
460                    if let Some(y) = y {
461                        y.eval_assign(context, assign_table, assign_context);
462                    }
463                }
464            }
465            Expression::StructConstructor(_, exprs, _) => {
466                for (_, expr) in exprs {
467                    expr.eval_assign(context, assign_table, assign_context);
468                }
469            }
470            // ArrayLiteral doesn't require evaluation because it is expanded in conv phase
471            Expression::ArrayLiteral(_, _) => (),
472        }
473    }
474
475    pub fn gather_ff(
476        &self,
477        context: &mut Context,
478        table: &mut FfTable,
479        decl: usize,
480        assign_target: Option<(VarId, Option<usize>)>,
481        from_ff: bool,
482    ) {
483        match self {
484            Expression::Term(x) => x.gather_ff(context, table, decl, assign_target, from_ff),
485            Expression::Unary(_, x, _) => x.gather_ff(context, table, decl, assign_target, from_ff),
486            Expression::Binary(x, _, y, _) => {
487                x.gather_ff(context, table, decl, assign_target, from_ff);
488                y.gather_ff(context, table, decl, assign_target, from_ff);
489            }
490            Expression::Ternary(x, y, z, _) => {
491                x.gather_ff(context, table, decl, assign_target, from_ff);
492                y.gather_ff(context, table, decl, assign_target, from_ff);
493                z.gather_ff(context, table, decl, assign_target, from_ff);
494            }
495            Expression::Concatenation(x, _) => {
496                for (x, y) in x {
497                    x.gather_ff(context, table, decl, assign_target, from_ff);
498                    if let Some(y) = y {
499                        y.gather_ff(context, table, decl, assign_target, from_ff);
500                    }
501                }
502            }
503            Expression::StructConstructor(_, exprs, _) => {
504                for (_, expr) in exprs {
505                    expr.gather_ff(context, table, decl, assign_target, from_ff);
506                }
507            }
508            // ArrayLiteral doesn't require evaluation because it is expanded in conv phase
509            Expression::ArrayLiteral(_, _) => (),
510        }
511    }
512
513    pub fn set_index(&mut self, index: &VarIndex) {
514        match self {
515            Expression::Term(x) => x.set_index(index),
516            Expression::Unary(_, x, _) => x.set_index(index),
517            Expression::Binary(x, _, y, _) => {
518                x.set_index(index);
519                y.set_index(index);
520            }
521            Expression::Ternary(x, y, z, _) => {
522                x.set_index(index);
523                y.set_index(index);
524                z.set_index(index);
525            }
526            Expression::Concatenation(x, _) => {
527                for (x, y) in x {
528                    x.set_index(index);
529                    if let Some(y) = y {
530                        y.set_index(index);
531                    }
532                }
533            }
534            Expression::StructConstructor(_, exprs, _) => {
535                for (_, expr) in exprs {
536                    expr.set_index(index);
537                }
538            }
539            // ArrayLiteral doesn't require evaluation because it is expanded in conv phase
540            Expression::ArrayLiteral(_, _) => (),
541        }
542    }
543
544    pub fn comptime(&self) -> &Comptime {
545        match self {
546            Expression::Term(x) => x.comptime(),
547            Expression::Unary(_, _, x) => x,
548            Expression::Binary(_, _, _, x) => x,
549            Expression::Ternary(_, _, _, x) => x,
550            Expression::Concatenation(_, x) => x,
551            Expression::ArrayLiteral(_, x) => x,
552            Expression::StructConstructor(_, _, x) => x,
553        }
554    }
555
556    pub fn comptime_mut(&mut self) -> &mut Comptime {
557        match self {
558            Expression::Term(x) => x.comptime_mut(),
559            Expression::Unary(_, _, x) => x,
560            Expression::Binary(_, _, _, x) => x,
561            Expression::Ternary(_, _, _, x) => x,
562            Expression::Concatenation(_, x) => x,
563            Expression::ArrayLiteral(_, x) => x,
564            Expression::StructConstructor(_, _, x) => x,
565        }
566    }
567
568    pub fn token_range(&self) -> TokenRange {
569        match self {
570            Expression::Term(x) => x.token_range(),
571            Expression::Unary(_, _, x) => x.token,
572            Expression::Binary(_, _, _, x) => x.token,
573            Expression::Ternary(_, _, _, x) => x.token,
574            Expression::Concatenation(_, x) => x.token,
575            Expression::ArrayLiteral(_, x) => x.token,
576            Expression::StructConstructor(_, _, x) => x.token,
577        }
578    }
579}
580
581#[derive(Clone, Debug)]
582pub enum Factor {
583    Variable(VarId, VarIndex, VarSelect, Comptime),
584    Value(Comptime),
585    SystemFunctionCall(SystemFunctionCall),
586    FunctionCall(FunctionCall),
587    Anonymous(Comptime),
588    Unknown(Comptime),
589}
590
591impl Factor {
592    pub fn create_value(value: Value, token: TokenRange) -> Self {
593        let comptime = Comptime::create_value(value, token);
594        Factor::Value(comptime)
595    }
596
597    pub fn from_component_symbol(symbol: &Symbol, token: TokenRange) -> Self {
598        let sig = Signature::new(symbol.id);
599        let kind = match &symbol.kind {
600            SymbolKind::Module(_)
601            | SymbolKind::ProtoModule(_)
602            | SymbolKind::AliasModule(_)
603            | SymbolKind::ProtoAliasModule(_) => TypeKind::Module(sig),
604            SymbolKind::Interface(_)
605            | SymbolKind::ProtoInterface(_)
606            | SymbolKind::AliasInterface(_)
607            | SymbolKind::ProtoAliasInterface(_) => TypeKind::Interface(sig),
608            SymbolKind::Package(_)
609            | SymbolKind::ProtoPackage(_)
610            | SymbolKind::AliasPackage(_)
611            | SymbolKind::ProtoAliasPackage(_) => TypeKind::Package(sig),
612            _ => unreachable!(),
613        };
614        let r#type = Type::new(kind);
615
616        let mut comptime = Comptime::from_type(r#type, ClockDomain::None, token);
617        comptime.is_const = true;
618        comptime.is_global = true;
619
620        Factor::Value(comptime)
621    }
622
623    pub fn is_assignable(&self) -> bool {
624        match self {
625            // SystemVerilog member is interpreted as Factor::Value, but it may be assignable.
626            Factor::Value(x) => x.r#type.is_systemverilog(),
627            Factor::FunctionCall(_) | Factor::SystemFunctionCall(_) => false,
628            _ => true,
629        }
630    }
631
632    pub fn gather_context(&mut self, context: &mut Context) -> ExpressionContext {
633        match self {
634            Factor::Variable(_, _index, select, comptime) => {
635                // Array dimensions are already drained at Factor construction time
636                // (in VarPathSelect::to_expression and eval_factor).
637
638                if !comptime.evaluated {
639                    // Struct/Union/Enum should be treated as flatten bit/logic when it is bit-selected
640                    if !select.is_empty() {
641                        comptime.r#type.flatten_struct_union_enum();
642                    }
643
644                    // Skip on empty select to preserve parametric `width_expr`.
645                    if !select.is_empty()
646                        && let Some(width) = select.eval_comptime(context, &comptime.r#type, false)
647                    {
648                        comptime.r#type.set_concrete_width(width);
649                    }
650                }
651
652                ExpressionContext {
653                    width: comptime.r#type.total_width().unwrap_or(0),
654                    signed: comptime.r#type.signed,
655                    is_const: comptime.is_const,
656                    is_global: comptime.is_global,
657                }
658            }
659            Factor::Value(x) => ExpressionContext {
660                width: x.r#type.total_width().unwrap_or(0),
661                signed: x.r#type.signed,
662                is_const: x.is_const,
663                is_global: x.is_global,
664            },
665            Factor::FunctionCall(x) => {
666                x.eval_type(context);
667                ExpressionContext {
668                    width: x.comptime.r#type.total_width().unwrap_or(0),
669                    signed: x.comptime.r#type.signed,
670                    is_const: x.comptime.is_const,
671                    is_global: x.comptime.is_global,
672                }
673            }
674            Factor::SystemFunctionCall(x) => ExpressionContext {
675                width: x.comptime.r#type.total_width().unwrap_or(0),
676                signed: x.comptime.expr_context.signed,
677                is_const: x.comptime.is_const,
678                is_global: x.comptime.is_global,
679            },
680            Factor::Anonymous(_) | Factor::Unknown(_) => ExpressionContext::default(),
681        }
682    }
683
684    pub fn apply_context(&mut self, expr_context: ExpressionContext) {
685        match self {
686            Factor::Variable(_, _, _, x) => {
687                x.expr_context = expr_context;
688                x.evaluated = true;
689            }
690            Factor::Value(x) => {
691                x.expr_context = expr_context;
692                x.evaluated = true;
693            }
694            Factor::SystemFunctionCall(x) => {
695                // Preserve the signed flag set by $signed / $unsigned:
696                // the outer-propagated expr_context must not clobber the
697                // explicit cast intent.
698                let preserve_signed = matches!(
699                    x.kind,
700                    SystemFunctionKind::Signed(_) | SystemFunctionKind::Unsigned(_)
701                );
702                let kept = x.comptime.expr_context.signed;
703                x.comptime.expr_context = expr_context;
704                if preserve_signed {
705                    x.comptime.expr_context.signed = kept;
706                }
707                x.comptime.evaluated = true;
708            }
709            Factor::FunctionCall(x) => {
710                x.comptime.expr_context = expr_context;
711                x.comptime.evaluated = true;
712            }
713            Factor::Anonymous(x) => {
714                x.expr_context = expr_context;
715                x.evaluated = true
716            }
717            Factor::Unknown(x) => {
718                x.expr_context = expr_context;
719                x.evaluated = true;
720            }
721        }
722    }
723
724    pub fn eval_value(&self, context: &mut Context) -> Option<Value> {
725        match self {
726            Factor::Variable(id, index, select, comptime) => {
727                let index = index.eval_value(context)?;
728                let value = context.variables.get(id)?.get_value(&index)?.clone();
729
730                if !select.is_empty() {
731                    let (beg, end) = select.eval_value(context, &comptime.r#type, false)?;
732                    Some(value.select(beg, end))
733                } else {
734                    Some(value)
735                }
736            }
737            Factor::Value(x) => x.get_value().ok().cloned(),
738            Factor::SystemFunctionCall(x) => x.eval_value(context),
739            Factor::FunctionCall(x) => x.eval_value(context),
740            Factor::Anonymous(_) => None,
741            Factor::Unknown(_) => None,
742        }
743    }
744
745    pub fn eval_assign(
746        &self,
747        context: &mut Context,
748        assign_table: &mut AssignTable,
749        assign_context: AssignContext,
750    ) {
751        match self {
752            Factor::Variable(id, index, select, _) => {
753                // `insert_reference` bails out on arrays over `array_limit`;
754                // short-circuit to avoid cloning the full Variable (value
755                // vec scales with array size).
756                let total_array = context
757                    .variables
758                    .get(id)
759                    .map(|v| v.r#type.total_array().unwrap_or(0))
760                    .unwrap_or(0);
761                if total_array > assign_table.array_limit {
762                    return;
763                }
764                if let Some(index) = index.eval_value(context)
765                    && let Some(variable) = context.variables.get(id).cloned()
766                    && let Some((beg, end)) = select.eval_value(context, &variable.r#type, false)
767                {
768                    let mask = ValueBigUint::gen_mask_range(beg, end);
769                    assign_table.insert_reference(&variable, index, mask);
770                }
771            }
772            Factor::FunctionCall(x) => {
773                x.eval_assign(context, assign_table, assign_context);
774            }
775            Factor::SystemFunctionCall(x) => {
776                x.eval_assign(context, assign_table, assign_context);
777            }
778            _ => (),
779        }
780    }
781
782    pub fn gather_ff(
783        &self,
784        context: &mut Context,
785        table: &mut FfTable,
786        decl: usize,
787        assign_target: Option<(VarId, Option<usize>)>,
788        from_ff: bool,
789    ) {
790        match self {
791            Factor::Variable(id, index, _, _) => {
792                if let Some(variable) = context.get_variable_info(*id) {
793                    if let Some(index) = index.eval_value(context) {
794                        if let Some(index) = variable.r#type.array.calc_index(&index) {
795                            table.insert_refered(*id, index, decl, assign_target, from_ff);
796                        }
797                    } else if let Some(total_array) = variable.r#type.total_array() {
798                        for i in 0..total_array {
799                            table.insert_refered(*id, i, decl, assign_target, from_ff);
800                        }
801                    }
802                }
803            }
804            Factor::FunctionCall(x) => {
805                x.gather_ff(context, table, decl, assign_target, from_ff);
806            }
807            _ => (),
808        }
809    }
810
811    pub fn set_index(&mut self, index: &VarIndex) {
812        match self {
813            Factor::Variable(_, i, _, _) => {
814                *i = index.clone();
815            }
816            Factor::FunctionCall(x) => {
817                x.set_index(index);
818            }
819            _ => (),
820        }
821    }
822
823    pub fn comptime(&self) -> &Comptime {
824        match self {
825            Factor::Variable(_, _, _, x) => x,
826            Factor::Value(x) => x,
827            Factor::SystemFunctionCall(x) => &x.comptime,
828            Factor::FunctionCall(x) => &x.comptime,
829            Factor::Anonymous(x) => x,
830            Factor::Unknown(x) => x,
831        }
832    }
833
834    pub fn comptime_mut(&mut self) -> &mut Comptime {
835        match self {
836            Factor::Variable(_, _, _, x) => x,
837            Factor::Value(x) => x,
838            Factor::SystemFunctionCall(x) => &mut x.comptime,
839            Factor::FunctionCall(x) => &mut x.comptime,
840            Factor::Anonymous(x) => x,
841            Factor::Unknown(x) => x,
842        }
843    }
844
845    pub fn token_range(&self) -> TokenRange {
846        match self {
847            Factor::Variable(_, _, _, x) => x.token,
848            Factor::Value(x) => x.token,
849            Factor::SystemFunctionCall(x) => x.comptime.token,
850            Factor::FunctionCall(x) => x.comptime.token,
851            Factor::Anonymous(x) => x.token,
852            Factor::Unknown(x) => x.token,
853        }
854    }
855}
856
857impl fmt::Display for Factor {
858    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
859        let ret = match self {
860            Factor::Variable(id, index, select, _) => {
861                format!("{id}{index}{select}")
862            }
863            Factor::Value(x) => {
864                if let Ok(x) = x.get_value() {
865                    format!("{:x}", x)
866                } else {
867                    String::from("unknown")
868                }
869            }
870            Factor::SystemFunctionCall(x) => x.to_string(),
871            Factor::FunctionCall(x) => x.to_string(),
872            Factor::Anonymous(_) => String::from("_"),
873            Factor::Unknown(_) => String::from("unknown"),
874        };
875
876        ret.fmt(f)
877    }
878}
879
880#[derive(Clone, Debug)]
881pub enum ArrayLiteralItem {
882    Value(Box<Expression>, Option<Box<Expression>>),
883    Defaul(Box<Expression>),
884}
885
886impl ArrayLiteralItem {
887    pub fn token_range(&self) -> TokenRange {
888        match self {
889            ArrayLiteralItem::Value(x, y) => {
890                let beg = x.token_range();
891                let mut end = if let Some(y) = y {
892                    y.token_range()
893                } else {
894                    beg
895                };
896                end.set_beg(beg);
897                end
898            }
899            ArrayLiteralItem::Defaul(x) => x.token_range(),
900        }
901    }
902
903    pub fn is_const(&self) -> bool {
904        match self {
905            ArrayLiteralItem::Value(x, y) => {
906                let mut ret = x.comptime().is_const;
907                if let Some(y) = y {
908                    ret &= y.comptime().is_const;
909                }
910                ret
911            }
912            ArrayLiteralItem::Defaul(x) => x.comptime().is_const,
913        }
914    }
915
916    pub fn is_global(&self) -> bool {
917        match self {
918            ArrayLiteralItem::Value(x, y) => {
919                let mut ret = x.comptime().is_global;
920                if let Some(y) = y {
921                    ret &= y.comptime().is_global;
922                }
923                ret
924            }
925            ArrayLiteralItem::Defaul(x) => x.comptime().is_global,
926        }
927    }
928}
929
930impl fmt::Display for ArrayLiteralItem {
931    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
932        let ret = match self {
933            ArrayLiteralItem::Value(x, y) => {
934                if let Some(y) = y {
935                    format!("{} repeat {}", x, y)
936                } else {
937                    format!("{}", x)
938                }
939            }
940            ArrayLiteralItem::Defaul(x) => {
941                format!("default: {}", x)
942            }
943        };
944
945        ret.fmt(f)
946    }
947}
948
949#[cfg(test)]
950mod tests {
951    use super::*;
952    use crate::conv::utils::parse_expression;
953    use crate::conv::{Context, Conv};
954    use crate::ir::{Shape, TypeKind};
955
956    fn calc_expression(s: &str, context_width: Option<usize>) -> Value {
957        let mut context = Context::default();
958        let x = parse_expression(s);
959        let mut x: Expression = Conv::conv(&mut context, &x).unwrap();
960        x.eval_comptime(&mut context, context_width)
961            .get_value()
962            .unwrap()
963            .clone()
964    }
965
966    #[test]
967    fn arithmetic() {
968        let x00 = calc_expression("1 + 2", None);
969        let x01 = calc_expression("5 - 1", None);
970        let x02 = calc_expression("2 * 7", None);
971        let x03 = calc_expression("8 / 3", None);
972        let x04 = calc_expression("9 % 4", None);
973        let x05 = calc_expression("2 ** 3", None);
974        let x06 = calc_expression("+5", None);
975        let x07 = calc_expression("-1", None);
976        let x08 = calc_expression("1 << 2", None);
977        let x09 = calc_expression("1 <<< 2", None);
978        let x10 = calc_expression("-8 >> 2", None);
979        let x11 = calc_expression("-8 >>> 2", None);
980
981        assert_eq!(format!("{:x}", x00), "32'sh00000003");
982        assert_eq!(format!("{:x}", x01), "32'sh00000004");
983        assert_eq!(format!("{:x}", x02), "32'sh0000000e");
984        assert_eq!(format!("{:x}", x03), "32'sh00000002");
985        assert_eq!(format!("{:x}", x04), "32'sh00000001");
986        assert_eq!(format!("{:x}", x05), "32'sh00000008");
987        assert_eq!(format!("{:x}", x06), "32'sh00000005");
988        assert_eq!(format!("{:x}", x07), "32'shffffffff");
989        assert_eq!(format!("{:x}", x08), "32'h00000004");
990        assert_eq!(format!("{:x}", x09), "32'sh00000004");
991        assert_eq!(format!("{:x}", x10), "32'h3ffffffe");
992        assert_eq!(format!("{:x}", x11), "32'shfffffffe");
993    }
994
995    #[test]
996    fn relational() {
997        let x0 = calc_expression("1 <: 2", None);
998        let x1 = calc_expression("1 >: 2", None);
999        let x2 = calc_expression("1 <= 2", None);
1000        let x3 = calc_expression("1 >= 2", None);
1001        let x4 = calc_expression("2 <: 2", None);
1002        let x5 = calc_expression("2 >: 2", None);
1003        let x6 = calc_expression("2 <= 2", None);
1004        let x7 = calc_expression("2 >= 2", None);
1005
1006        assert_eq!(format!("{:x}", x0), "1'h1");
1007        assert_eq!(format!("{:x}", x1), "1'h0");
1008        assert_eq!(format!("{:x}", x2), "1'h1");
1009        assert_eq!(format!("{:x}", x3), "1'h0");
1010        assert_eq!(format!("{:x}", x4), "1'h0");
1011        assert_eq!(format!("{:x}", x5), "1'h0");
1012        assert_eq!(format!("{:x}", x6), "1'h1");
1013        assert_eq!(format!("{:x}", x7), "1'h1");
1014    }
1015
1016    #[test]
1017    fn equality() {
1018        let x0 = calc_expression("1 == 2", None);
1019        let x1 = calc_expression("1 != 2", None);
1020        let x2 = calc_expression("2 == 2", None);
1021        let x3 = calc_expression("2 != 2", None);
1022
1023        assert_eq!(format!("{:x}", x0), "1'h0");
1024        assert_eq!(format!("{:x}", x1), "1'h1");
1025        assert_eq!(format!("{:x}", x2), "1'h1");
1026        assert_eq!(format!("{:x}", x3), "1'h0");
1027    }
1028
1029    #[test]
1030    fn wildcard_equality() {
1031        let x0 = calc_expression("4'b0000 ==? 4'b00xx", None);
1032        let x1 = calc_expression("4'b0011 ==? 4'b00xx", None);
1033        let x2 = calc_expression("4'b0100 ==? 4'b00xx", None);
1034        let x3 = calc_expression("4'b0111 ==? 4'b00xx", None);
1035        let x4 = calc_expression("4'b0000 !=? 4'b00xx", None);
1036        let x5 = calc_expression("4'b0011 !=? 4'b00xx", None);
1037        let x6 = calc_expression("4'b0100 !=? 4'b00xx", None);
1038        let x7 = calc_expression("4'b0111 !=? 4'b00xx", None);
1039
1040        assert_eq!(format!("{:x}", x0), "1'h1");
1041        assert_eq!(format!("{:x}", x1), "1'h1");
1042        assert_eq!(format!("{:x}", x2), "1'h0");
1043        assert_eq!(format!("{:x}", x3), "1'h0");
1044        assert_eq!(format!("{:x}", x4), "1'h0");
1045        assert_eq!(format!("{:x}", x5), "1'h0");
1046        assert_eq!(format!("{:x}", x6), "1'h1");
1047        assert_eq!(format!("{:x}", x7), "1'h1");
1048    }
1049
1050    #[test]
1051    fn logical() {
1052        let x0 = calc_expression("10 && 0", None);
1053        let x1 = calc_expression("10 || 0", None);
1054        let x2 = calc_expression("!0", None);
1055        let x3 = calc_expression("!10", None);
1056
1057        assert_eq!(format!("{:x}", x0), "1'h0");
1058        assert_eq!(format!("{:x}", x1), "1'h1");
1059        assert_eq!(format!("{:x}", x2), "1'h1");
1060        assert_eq!(format!("{:x}", x3), "1'h0");
1061    }
1062
1063    #[test]
1064    fn bitwise() {
1065        let x0 = calc_expression("4'b0001  & 4'b0101", None);
1066        let x1 = calc_expression("4'b0001  | 4'b0101", None);
1067        let x2 = calc_expression("4'b0001  ^ 4'b0101", None);
1068        let x3 = calc_expression("4'b0001 ~^ 4'b0101", None);
1069        let x4 = calc_expression("~4'b0101", None);
1070
1071        assert_eq!(format!("{:x}", x0), "4'h1");
1072        assert_eq!(format!("{:x}", x1), "4'h5");
1073        assert_eq!(format!("{:x}", x2), "4'h4");
1074        assert_eq!(format!("{:x}", x3), "4'hb");
1075        assert_eq!(format!("{:x}", x4), "4'ha");
1076    }
1077
1078    #[test]
1079    fn reduction() {
1080        let x00 = calc_expression(" &4'b0000", None);
1081        let x01 = calc_expression(" |4'b0000", None);
1082        let x02 = calc_expression(" ^4'b0000", None);
1083        let x03 = calc_expression("~&4'b0000", None);
1084        let x04 = calc_expression("~|4'b0000", None);
1085        let x05 = calc_expression("~^4'b0000", None);
1086
1087        let x06 = calc_expression(" &4'b1111", None);
1088        let x07 = calc_expression(" |4'b1111", None);
1089        let x08 = calc_expression(" ^4'b1111", None);
1090        let x09 = calc_expression("~&4'b1111", None);
1091        let x10 = calc_expression("~|4'b1111", None);
1092        let x11 = calc_expression("~^4'b1111", None);
1093
1094        let x12 = calc_expression(" &4'b0110", None);
1095        let x13 = calc_expression(" |4'b0110", None);
1096        let x14 = calc_expression(" ^4'b0110", None);
1097        let x15 = calc_expression("~&4'b0110", None);
1098        let x16 = calc_expression("~|4'b0110", None);
1099        let x17 = calc_expression("~^4'b0110", None);
1100
1101        let x18 = calc_expression(" &4'b1000", None);
1102        let x19 = calc_expression(" |4'b1000", None);
1103        let x20 = calc_expression(" ^4'b1000", None);
1104        let x21 = calc_expression("~&4'b1000", None);
1105        let x22 = calc_expression("~|4'b1000", None);
1106        let x23 = calc_expression("~^4'b1000", None);
1107
1108        assert_eq!(format!("{:x}", x00), "1'h0");
1109        assert_eq!(format!("{:x}", x01), "1'h0");
1110        assert_eq!(format!("{:x}", x02), "1'h0");
1111        assert_eq!(format!("{:x}", x03), "1'h1");
1112        assert_eq!(format!("{:x}", x04), "1'h1");
1113        assert_eq!(format!("{:x}", x05), "1'h1");
1114
1115        assert_eq!(format!("{:x}", x06), "1'h1");
1116        assert_eq!(format!("{:x}", x07), "1'h1");
1117        assert_eq!(format!("{:x}", x08), "1'h0");
1118        assert_eq!(format!("{:x}", x09), "1'h0");
1119        assert_eq!(format!("{:x}", x10), "1'h0");
1120        assert_eq!(format!("{:x}", x11), "1'h1");
1121
1122        assert_eq!(format!("{:x}", x12), "1'h0");
1123        assert_eq!(format!("{:x}", x13), "1'h1");
1124        assert_eq!(format!("{:x}", x14), "1'h0");
1125        assert_eq!(format!("{:x}", x15), "1'h1");
1126        assert_eq!(format!("{:x}", x16), "1'h0");
1127        assert_eq!(format!("{:x}", x17), "1'h1");
1128
1129        assert_eq!(format!("{:x}", x18), "1'h0");
1130        assert_eq!(format!("{:x}", x19), "1'h1");
1131        assert_eq!(format!("{:x}", x20), "1'h1");
1132        assert_eq!(format!("{:x}", x21), "1'h1");
1133        assert_eq!(format!("{:x}", x22), "1'h0");
1134        assert_eq!(format!("{:x}", x23), "1'h0");
1135    }
1136
1137    #[test]
1138    fn conditional() {
1139        let x0 = calc_expression("if 0 ? 1 : 2", None);
1140        let x1 = calc_expression("if 1 ? 1 : 2", None);
1141
1142        assert_eq!(format!("{:x}", x0), "32'sh00000002");
1143        assert_eq!(format!("{:x}", x1), "32'sh00000001");
1144    }
1145
1146    #[test]
1147    fn concatenation() {
1148        let x0 = calc_expression("{4'h1, 4'h3}", None);
1149        let x1 = calc_expression("{4'h1 repeat 3, 4'h3}", None);
1150
1151        assert_eq!(format!("{:x}", x0), "8'h13");
1152        assert_eq!(format!("{:x}", x1), "16'h1113");
1153    }
1154
1155    #[test]
1156    fn inside_outside() {
1157        let x0 = calc_expression("inside 1 {1, 2}", None);
1158        let x1 = calc_expression("inside 0 {1, 2}", None);
1159        let x2 = calc_expression("inside 5 {3, 2..=10}", None);
1160        let x3 = calc_expression("inside 1 {3, 2..=10}", None);
1161        let x4 = calc_expression("outside 1 {1, 2}", None);
1162        let x5 = calc_expression("outside 0 {1, 2}", None);
1163        let x6 = calc_expression("outside 5 {3, 2..=10}", None);
1164        let x7 = calc_expression("outside 1 {3, 2..=10}", None);
1165
1166        assert_eq!(format!("{:x}", x0), "1'h1");
1167        assert_eq!(format!("{:x}", x1), "1'h0");
1168        assert_eq!(format!("{:x}", x2), "1'h1");
1169        assert_eq!(format!("{:x}", x3), "1'h0");
1170        assert_eq!(format!("{:x}", x4), "1'h0");
1171        assert_eq!(format!("{:x}", x5), "1'h1");
1172        assert_eq!(format!("{:x}", x6), "1'h0");
1173        assert_eq!(format!("{:x}", x7), "1'h1");
1174    }
1175
1176    #[test]
1177    fn mixed_int_float_pow() {
1178        let x0 = calc_expression("2 ** (41 as f64)", None);
1179        let x1 = calc_expression("2 ** ((48 - 7) as f64)", None);
1180
1181        let expected = 2.0_f64.powf(41.0).to_bits();
1182        assert_eq!(x0.to_u64(), Some(expected), "2 ** (41 as f64)");
1183        assert_eq!(x1.to_u64(), Some(expected), "2 ** ((48-7) as f64)");
1184    }
1185
1186    #[test]
1187    fn context_width() {
1188        let x0 = calc_expression("(2'd0 - 2'd1) == 3'd7", None);
1189
1190        assert_eq!(format!("{:x}", x0), "1'h1");
1191    }
1192
1193    fn bit(width: usize) -> Box<Expression> {
1194        let mut t = Type::new(TypeKind::Bit);
1195        t.set_concrete_width(Shape::new(vec![Some(width)]));
1196        let ret = Comptime {
1197            value: ValueVariant::Unknown,
1198            r#type: t,
1199            ..Default::default()
1200        };
1201        Box::new(Expression::Term(Box::new(Factor::Value(ret))))
1202    }
1203
1204    fn logic(width: usize) -> Box<Expression> {
1205        let mut t = Type::new(TypeKind::Logic);
1206        t.set_concrete_width(Shape::new(vec![Some(width)]));
1207        let ret = Comptime {
1208            value: ValueVariant::Unknown,
1209            r#type: t,
1210            ..Default::default()
1211        };
1212        Box::new(Expression::Term(Box::new(Factor::Value(ret))))
1213    }
1214
1215    fn signed_bit(width: usize) -> Box<Expression> {
1216        let mut t = Type::new(TypeKind::Bit);
1217        t.set_concrete_width(Shape::new(vec![Some(width)]));
1218        t.signed = true;
1219        let ret = Comptime {
1220            value: ValueVariant::Unknown,
1221            r#type: t,
1222            ..Default::default()
1223        };
1224        Box::new(Expression::Term(Box::new(Factor::Value(ret))))
1225    }
1226
1227    fn signed_logic(width: usize) -> Box<Expression> {
1228        let mut t = Type::new(TypeKind::Logic);
1229        t.set_concrete_width(Shape::new(vec![Some(width)]));
1230        t.signed = true;
1231        let ret = Comptime {
1232            value: ValueVariant::Unknown,
1233            r#type: t,
1234            ..Default::default()
1235        };
1236        Box::new(Expression::Term(Box::new(Factor::Value(ret))))
1237    }
1238
1239    fn value(value: usize) -> Box<Expression> {
1240        let mut t = Type::new(TypeKind::Logic);
1241        t.set_concrete_width(Shape::new(vec![Some(32)]));
1242        let ret = Comptime {
1243            value: ValueVariant::Numeric(Value::new(value as u64, 32, false)),
1244            r#type: t,
1245            is_const: true,
1246            is_global: true,
1247            ..Default::default()
1248        };
1249        Box::new(Expression::Term(Box::new(Factor::Value(ret))))
1250    }
1251
1252    fn eval_comptime_unary(context: &mut Context, op: Op, x: Box<Expression>) -> Comptime {
1253        let comptime = Box::new(Comptime::create_unknown(TokenRange::default()));
1254        let mut ret = Expression::Unary(op, x, comptime);
1255        ret.eval_comptime(context, None).clone()
1256    }
1257
1258    fn eval_comptime_binary(
1259        context: &mut Context,
1260        x: Box<Expression>,
1261        op: Op,
1262        y: Box<Expression>,
1263    ) -> Comptime {
1264        let comptime = Box::new(Comptime::create_unknown(TokenRange::default()));
1265        let mut ret = Expression::Binary(x, op, y, comptime);
1266        ret.eval_comptime(context, None).clone()
1267    }
1268
1269    fn eval_comptime_ternary(
1270        context: &mut Context,
1271        x: Box<Expression>,
1272        y: Box<Expression>,
1273        z: Box<Expression>,
1274    ) -> Comptime {
1275        let comptime = Box::new(Comptime::create_unknown(TokenRange::default()));
1276        let mut ret = Expression::Ternary(x, y, z, comptime);
1277        ret.eval_comptime(context, None).clone()
1278    }
1279
1280    fn eval_comptime_concat(
1281        context: &mut Context,
1282        x: Vec<(Expression, Option<Expression>)>,
1283    ) -> Comptime {
1284        let comptime = Box::new(Comptime::create_unknown(TokenRange::default()));
1285        let mut ret = Expression::Concatenation(x, comptime);
1286        ret.eval_comptime(context, None).clone()
1287    }
1288
1289    #[test]
1290    fn unary_type() {
1291        let mut context = Context::default();
1292
1293        let x0 = eval_comptime_unary(&mut context, Op::BitAnd, bit(3));
1294        let x1 = eval_comptime_unary(&mut context, Op::BitAnd, logic(4));
1295        let x2 = eval_comptime_unary(&mut context, Op::BitNot, bit(3));
1296        let x3 = eval_comptime_unary(&mut context, Op::BitNot, logic(4));
1297        let x4 = eval_comptime_unary(&mut context, Op::LogicNot, bit(1));
1298        let x5 = eval_comptime_unary(&mut context, Op::LogicNot, logic(1));
1299        let x6 = eval_comptime_unary(&mut context, Op::Add, bit(3));
1300        let x7 = eval_comptime_unary(&mut context, Op::Add, logic(4));
1301
1302        let errors = context.drain_errors();
1303        assert!(errors.is_empty());
1304
1305        assert_eq!(format!("{}", x0.r#type), "bit<1>");
1306        assert_eq!(format!("{}", x1.r#type), "logic<1>");
1307        assert_eq!(format!("{}", x2.r#type), "bit<3>");
1308        assert_eq!(format!("{}", x3.r#type), "logic<4>");
1309        assert_eq!(format!("{}", x4.r#type), "bit<1>");
1310        assert_eq!(format!("{}", x5.r#type), "logic<1>");
1311        assert_eq!(format!("{}", x6.r#type), "bit<3>");
1312        assert_eq!(format!("{}", x7.r#type), "logic<4>");
1313    }
1314
1315    #[test]
1316    fn binary_type() {
1317        let mut context = Context::default();
1318
1319        let x00 = eval_comptime_binary(&mut context, bit(4), Op::Add, bit(3));
1320        let x01 = eval_comptime_binary(&mut context, bit(4), Op::Add, logic(3));
1321        let x02 = eval_comptime_binary(&mut context, logic(4), Op::Add, logic(3));
1322        let x03 = eval_comptime_binary(&mut context, bit(4), Op::Eq, bit(3));
1323        let x04 = eval_comptime_binary(&mut context, bit(4), Op::Eq, logic(3));
1324        let x05 = eval_comptime_binary(&mut context, logic(4), Op::Eq, logic(3));
1325        let x06 = eval_comptime_binary(&mut context, bit(1), Op::LogicAnd, bit(1));
1326        let x07 = eval_comptime_binary(&mut context, bit(1), Op::LogicAnd, logic(1));
1327        let x08 = eval_comptime_binary(&mut context, logic(1), Op::LogicAnd, logic(1));
1328        let x09 = eval_comptime_binary(&mut context, signed_bit(4), Op::ArithShiftL, bit(3));
1329        let x10 = eval_comptime_binary(&mut context, signed_bit(4), Op::ArithShiftL, logic(3));
1330        let x11 = eval_comptime_binary(&mut context, signed_logic(4), Op::ArithShiftL, logic(3));
1331
1332        let errors = context.drain_errors();
1333        assert!(errors.is_empty());
1334
1335        assert_eq!(format!("{}", x00.r#type), "bit<4>");
1336        assert_eq!(format!("{}", x01.r#type), "logic<4>");
1337        assert_eq!(format!("{}", x02.r#type), "logic<4>");
1338        assert_eq!(format!("{}", x03.r#type), "bit<1>");
1339        assert_eq!(format!("{}", x04.r#type), "logic<1>");
1340        assert_eq!(format!("{}", x05.r#type), "logic<1>");
1341        assert_eq!(format!("{}", x06.r#type), "bit<1>");
1342        assert_eq!(format!("{}", x07.r#type), "logic<1>");
1343        assert_eq!(format!("{}", x08.r#type), "logic<1>");
1344        assert_eq!(format!("{}", x09.r#type), "signed bit<4>");
1345        assert_eq!(format!("{}", x10.r#type), "signed bit<4>");
1346        assert_eq!(format!("{}", x11.r#type), "signed logic<4>");
1347    }
1348
1349    #[test]
1350    fn ternary_type() {
1351        let mut context = Context::default();
1352
1353        let x0 = eval_comptime_ternary(&mut context, bit(1), bit(4), bit(3));
1354        let x1 = eval_comptime_ternary(&mut context, bit(1), bit(4), logic(3));
1355        let x2 = eval_comptime_ternary(&mut context, bit(1), logic(4), bit(3));
1356        let x3 = eval_comptime_ternary(&mut context, bit(1), logic(4), logic(3));
1357        let x4 = eval_comptime_ternary(&mut context, logic(1), bit(4), bit(3));
1358        let x5 = eval_comptime_ternary(&mut context, logic(1), bit(4), logic(3));
1359        let x6 = eval_comptime_ternary(&mut context, logic(1), logic(4), bit(3));
1360        let x7 = eval_comptime_ternary(&mut context, logic(1), logic(4), logic(3));
1361
1362        let errors = context.drain_errors();
1363        assert!(errors.is_empty());
1364
1365        assert_eq!(format!("{}", x0.r#type), "bit<4>");
1366        assert_eq!(format!("{}", x1.r#type), "logic<4>");
1367        assert_eq!(format!("{}", x2.r#type), "logic<4>");
1368        assert_eq!(format!("{}", x3.r#type), "logic<4>");
1369        assert_eq!(format!("{}", x4.r#type), "bit<4>");
1370        assert_eq!(format!("{}", x5.r#type), "logic<4>");
1371        assert_eq!(format!("{}", x6.r#type), "logic<4>");
1372        assert_eq!(format!("{}", x7.r#type), "logic<4>");
1373    }
1374
1375    #[test]
1376    fn concat_type() {
1377        let mut context = Context::default();
1378
1379        let x0 = eval_comptime_concat(
1380            &mut context,
1381            vec![(*bit(1), None), (*bit(4), None), (*bit(3), None)],
1382        );
1383        let x1 = eval_comptime_concat(
1384            &mut context,
1385            vec![(*bit(1), None), (*logic(4), None), (*bit(3), None)],
1386        );
1387        let x2 = eval_comptime_concat(
1388            &mut context,
1389            vec![(*logic(1), None), (*logic(4), None), (*logic(3), None)],
1390        );
1391        let x3 = eval_comptime_concat(
1392            &mut context,
1393            vec![(*bit(1), Some(*value(2))), (*bit(4), None), (*bit(3), None)],
1394        );
1395        let x4 = eval_comptime_concat(
1396            &mut context,
1397            vec![
1398                (*bit(1), None),
1399                (*logic(4), Some(*value(2))),
1400                (*bit(3), None),
1401            ],
1402        );
1403        let x5 = eval_comptime_concat(
1404            &mut context,
1405            vec![
1406                (*logic(1), None),
1407                (*logic(4), None),
1408                (*logic(3), Some(*value(3))),
1409            ],
1410        );
1411
1412        let errors = context.drain_errors();
1413        assert!(errors.is_empty());
1414
1415        assert_eq!(format!("{}", x0.r#type), "bit<8>");
1416        assert_eq!(format!("{}", x1.r#type), "logic<8>");
1417        assert_eq!(format!("{}", x2.r#type), "logic<8>");
1418        assert_eq!(format!("{}", x3.r#type), "bit<9>");
1419        assert_eq!(format!("{}", x4.r#type), "logic<12>");
1420        assert_eq!(format!("{}", x5.r#type), "logic<14>");
1421    }
1422}