Skip to main content

veryl_analyzer/conv/
statement.rs

1use crate::analyzer_error::MismatchTypeKind;
2use crate::conv::utils::{
3    TypePosition, argument_list, build_for_range, build_for_statement, case_condition,
4    eval_assign_statement, eval_expr, eval_variable, expand_connect, expand_connect_const,
5    function_call, get_return_str, switch_condition, tb_method_call, try_infer_decl_type,
6    try_infer_var_assign,
7};
8use crate::conv::{Context, Conv};
9use crate::ir::{
10    self, Comptime, IrResult, Shape, TypeKind, VarIndex, VarKind, VarPath, VarPathSelect, VarSelect,
11};
12use crate::namespace::DefineContext;
13use crate::symbol::{Affiliation, SymbolKind};
14use crate::symbol_table;
15use crate::{AnalyzerError, ir_error};
16use veryl_parser::token_range::TokenRange;
17use veryl_parser::veryl_grammar_trait::*;
18
19impl Conv<&StatementBlock> for ir::StatementBlock {
20    fn conv(context: &mut Context, value: &StatementBlock) -> IrResult<Self> {
21        let statements: Vec<_> = value.into();
22        let mut ret = vec![];
23        for s in statements {
24            let x: IrResult<ir::StatementBlock> = Conv::conv(context, s);
25            match x {
26                Ok(x) => {
27                    ret.append(&mut x.0.into_iter().filter(|x| !x.is_null()).collect());
28                }
29                Err(e) => {
30                    if !context.in_generic {
31                        ret.push(ir::Statement::Unsupported(e.token));
32                    }
33                }
34            }
35        }
36        Ok(ir::StatementBlock(ret))
37    }
38}
39
40impl Conv<&StatementBlockItem> for ir::StatementBlock {
41    fn conv(context: &mut Context, value: &StatementBlockItem) -> IrResult<Self> {
42        match value {
43            StatementBlockItem::VarDeclaration(x) => {
44                let _: ir::Declaration = Conv::conv(context, x.var_declaration.as_ref())?;
45                Ok(ir::StatementBlock::default())
46            }
47            StatementBlockItem::LetStatement(x) => Conv::conv(context, x.let_statement.as_ref()),
48            StatementBlockItem::ConstDeclaration(x) => {
49                let _: ir::Declaration = Conv::conv(context, x.const_declaration.as_ref())?;
50                Ok(ir::StatementBlock::default())
51            }
52            StatementBlockItem::GenDeclaration(x) => {
53                let _: ir::Declaration = Conv::conv(context, x.gen_declaration.as_ref())?;
54                Ok(ir::StatementBlock::default())
55            }
56            StatementBlockItem::Statement(x) => Conv::conv(context, x.statement.as_ref()),
57            StatementBlockItem::ConcatenationAssignment(x) => {
58                Conv::conv(context, x.concatenation_assignment.as_ref())
59            }
60        }
61    }
62}
63
64impl Conv<&LetStatement> for ir::StatementBlock {
65    fn conv(context: &mut Context, value: &LetStatement) -> IrResult<Self> {
66        let define_context: DefineContext = (&value.r#let.let_token).into();
67        if !define_context.is_default() {
68            return Ok(ir::StatementBlock::default());
69        }
70
71        let token: TokenRange = value.into();
72
73        if let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref())
74            && let SymbolKind::Variable(x) = &symbol.found.kind
75        {
76            let path = VarPath::new(symbol.found.token.text);
77            let kind = VarKind::Let;
78            let variable_token: TokenRange = (&value.identifier.identifier_token).into();
79
80            let inferred = try_infer_decl_type(
81                context,
82                &x.r#type,
83                &value.expression,
84                value.identifier.identifier_token.token.id,
85                token,
86            )?;
87            let r#type = if let Some((ref comptime, _)) = inferred {
88                comptime.r#type.clone()
89            } else {
90                x.r#type.to_ir_type(context, TypePosition::Variable)?
91            };
92            let clock_domain = x.clock_domain;
93
94            eval_variable(context, &path, kind, &r#type, clock_domain, variable_token);
95
96            let (id, comptime) = context.find_path(&path).ok_or_else(|| ir_error!(token))?;
97
98            let mut dst = ir::AssignDestination {
99                id,
100                path,
101                index: VarIndex::default(),
102                select: VarSelect::default(),
103                comptime,
104                token: variable_token,
105            };
106
107            let mut expr = if let Some(inferred) = inferred {
108                inferred
109            } else {
110                eval_expr(context, Some(r#type.clone()), &value.expression, false)?
111            };
112
113            let statements = eval_assign_statement(context, &mut dst, &mut expr, token)?;
114            Ok(ir::StatementBlock(statements))
115        } else {
116            Err(ir_error!(token))
117        }
118    }
119}
120
121impl Conv<&ConcatenationAssignment> for ir::StatementBlock {
122    fn conv(context: &mut Context, value: &ConcatenationAssignment) -> IrResult<Self> {
123        let token: TokenRange = value.into();
124
125        let items: Vec<_> = value.assign_concatenation_list.as_ref().into();
126
127        let mut dst = vec![];
128        for item in items {
129            let ident = item.hierarchical_identifier.as_ref();
130            let x: VarPathSelect = Conv::conv(context, ident)?;
131            if let Some(x) = x.to_assign_destination(context, false) {
132                dst.push(x);
133            } else {
134                if let Ok(symbol) = symbol_table::resolve(item.hierarchical_identifier.as_ref())
135                    && let SymbolKind::Variable(x) = &symbol.found.kind
136                    && x.affiliation == Affiliation::Module
137                {
138                    let ident_token = ident.identifier.identifier_token.token;
139                    context.insert_error(AnalyzerError::referring_before_definition(
140                        &ident_token.text.to_string(),
141                        &ident_token.into(),
142                    ));
143                }
144                return Err(ir_error!(token));
145            }
146        }
147
148        let mut width = Some(0);
149        for x in &dst {
150            if let Some(x) = x.total_width(context)
151                && let Some(width) = &mut width
152            {
153                *width += x;
154            } else {
155                width = None;
156            }
157        }
158        if let Some(x) = width {
159            width = context.check_size(x, token);
160        }
161
162        let r#type = {
163            let mut t = ir::Type::new(TypeKind::Logic);
164            t.set_concrete_width(Shape::new(vec![width]));
165            t
166        };
167
168        let (_, expr) = eval_expr(context, Some(r#type), &value.expression, false)?;
169        let statement = ir::Statement::Assign(ir::AssignStatement {
170            dst,
171            width,
172            expr,
173            token,
174        });
175
176        Ok(ir::StatementBlock(vec![statement]))
177    }
178}
179
180impl Conv<&Statement> for ir::StatementBlock {
181    fn conv(context: &mut Context, value: &Statement) -> IrResult<Self> {
182        match value {
183            Statement::IdentifierStatement(x) => {
184                Conv::conv(context, x.identifier_statement.as_ref())
185            }
186            Statement::IfStatement(x) => Conv::conv(context, x.if_statement.as_ref()),
187            Statement::IfResetStatement(x) => Conv::conv(context, x.if_reset_statement.as_ref()),
188            Statement::ReturnStatement(x) => Ok(ir::StatementBlock(vec![Conv::conv(
189                context,
190                x.return_statement.as_ref(),
191            )?])),
192            Statement::BreakStatement(_) => Ok(ir::StatementBlock(vec![ir::Statement::Break])),
193            Statement::ForStatement(x) => Conv::conv(context, x.for_statement.as_ref()),
194            Statement::CaseStatement(x) => Conv::conv(context, x.case_statement.as_ref()),
195            Statement::SwitchStatement(x) => Conv::conv(context, x.switch_statement.as_ref()),
196        }
197    }
198}
199
200impl Conv<&IdentifierStatement> for ir::StatementBlock {
201    fn conv(context: &mut Context, value: &IdentifierStatement) -> IrResult<Self> {
202        let define_context: DefineContext = (&value.semicolon.semicolon_token).into();
203        if !define_context.is_default() {
204            return Ok(ir::StatementBlock::default());
205        }
206
207        let token: TokenRange = value.into();
208        let expr = value.expression_identifier.as_ref();
209
210        match value.identifier_statement_group.as_ref() {
211            IdentifierStatementGroup::Assignment(x) => {
212                match x.assignment.assignment_group.as_ref() {
213                    AssignmentGroup::Equ(_) => {
214                        let inferred = if let Ok(symbol) = symbol_table::resolve(expr) {
215                            try_infer_var_assign(
216                                context,
217                                &symbol.found,
218                                &x.assignment.expression,
219                                token,
220                            )?
221                        } else {
222                            None
223                        };
224
225                        let dst: VarPathSelect = Conv::conv(context, expr)?;
226
227                        if let Some(mut dst) = dst.to_assign_destination(context, false) {
228                            let mut expr = if let Some(inferred) = inferred {
229                                inferred
230                            } else {
231                                eval_expr(
232                                    context,
233                                    Some(dst.comptime.r#type.clone()),
234                                    &x.assignment.expression,
235                                    false,
236                                )?
237                            };
238
239                            let statements =
240                                eval_assign_statement(context, &mut dst, &mut expr, token)?;
241                            Ok(ir::StatementBlock(statements))
242                        } else {
243                            // check expression even if dst can't be determined
244                            let _ = eval_expr(context, None, &x.assignment.expression, false)?;
245
246                            Err(ir_error!(token))
247                        }
248                    }
249                    AssignmentGroup::AssignmentOperator(op) => {
250                        let op: ir::Op = Conv::conv(context, op.assignment_operator.as_ref())?;
251
252                        let dst: VarPathSelect = Conv::conv(context, expr)?;
253                        let src: VarPathSelect = Conv::conv(context, expr)?;
254
255                        if let Some(dst) = dst.to_assign_destination(context, false)
256                            && let Some(src) = src.to_expression(context)
257                        {
258                            let (_, expr) = eval_expr(
259                                context,
260                                Some(dst.comptime.r#type.clone()),
261                                &x.assignment.expression,
262                                false,
263                            )?;
264
265                            let width = dst.total_width(context);
266                            let comptime = Box::new(Comptime::create_unknown(token));
267                            let mut expr =
268                                ir::Expression::Binary(Box::new(src), op, Box::new(expr), comptime);
269                            let _ = expr.eval_comptime(context, width);
270
271                            let statement = ir::AssignStatement {
272                                dst: vec![dst],
273                                width,
274                                expr,
275                                token,
276                            };
277                            let statement = ir::Statement::Assign(statement);
278                            Ok(ir::StatementBlock(vec![statement]))
279                        } else {
280                            // check expression even if dst can't be determined
281                            let _ = eval_expr(context, None, &x.assignment.expression, false)?;
282
283                            Err(ir_error!(token))
284                        }
285                    }
286                    AssignmentGroup::DiamondOperator(_) => {
287                        let lhs: VarPathSelect = Conv::conv(context, expr)?;
288                        let rhs: Vec<VarPathSelect> =
289                            Conv::conv(context, x.assignment.expression.as_ref())?;
290
291                        let (comptime, _) =
292                            eval_expr(context, None, x.assignment.expression.as_ref(), false)?;
293
294                        let statements = if comptime.is_const {
295                            expand_connect_const(context, lhs, comptime, token)?
296                        } else {
297                            if rhs.len() != 1 {
298                                context.insert_error(AnalyzerError::mismatch_type(
299                                    MismatchTypeKind::ConnectMultipleExpression,
300                                    &token,
301                                ));
302                                return Err(ir_error!(token));
303                            }
304
305                            let rhs = rhs[0].clone();
306
307                            expand_connect(context, lhs, rhs, token)?
308                        };
309
310                        Ok(ir::StatementBlock(statements))
311                    }
312                }
313            }
314            IdentifierStatementGroup::FunctionCall(x) => {
315                // Intercept $tb component method calls before argument evaluation
316                if let Some(tb_stmt) = tb_method_call(
317                    context,
318                    value.expression_identifier.as_ref(),
319                    &x.function_call,
320                    token,
321                )? {
322                    return Ok(ir::StatementBlock(vec![tb_stmt]));
323                }
324
325                let args = if let Some(x) = &x.function_call.function_call_opt {
326                    argument_list(context, x.argument_list.as_ref())?
327                } else {
328                    ir::Arguments::Null
329                };
330
331                let resolved_path =
332                    context.resolve_path(value.expression_identifier.as_ref().into());
333                let symbol = symbol_table::resolve(&resolved_path).map_err(|_| ir_error!(token))?;
334
335                match &symbol.found.kind {
336                    SymbolKind::SystemFunction(_) => {
337                        let name = symbol.found.token.text;
338                        let args = args.to_system_function_args(context, &symbol.found);
339                        let ret = ir::SystemFunctionCall::new(context, name, args, token)?;
340                        Ok(ir::StatementBlock(vec![ir::Statement::SystemFunctionCall(
341                            Box::new(ret),
342                        )]))
343                    }
344                    SymbolKind::Function(x) => {
345                        let ret = function_call(
346                            context,
347                            value.expression_identifier.as_ref(),
348                            args,
349                            token,
350                        )?;
351
352                        if x.ret.is_some() {
353                            context.insert_error(AnalyzerError::unused_return(
354                                &symbol.found.token.text.to_string(),
355                                &token,
356                            ));
357                        }
358
359                        Ok(ir::StatementBlock(vec![ir::Statement::FunctionCall(
360                            Box::new(ret),
361                        )]))
362                    }
363                    SymbolKind::ModportFunctionMember(x) => {
364                        let symbol = symbol_table::get(x.function).unwrap();
365                        if let SymbolKind::Function(x) = &symbol.kind {
366                            let ret = function_call(
367                                context,
368                                value.expression_identifier.as_ref(),
369                                args,
370                                token,
371                            )?;
372
373                            if x.ret.is_some() {
374                                context.insert_error(AnalyzerError::unused_return(
375                                    &symbol.token.text.to_string(),
376                                    &token,
377                                ));
378                            }
379
380                            Ok(ir::StatementBlock(vec![ir::Statement::FunctionCall(
381                                Box::new(ret),
382                            )]))
383                        } else {
384                            unreachable!();
385                        }
386                    }
387                    SymbolKind::ProtoFunction(_) | SymbolKind::SystemVerilog => {
388                        Err(ir_error!(token))
389                    }
390                    _ => {
391                        let name = symbol.found.token.text.to_string();
392                        let kind = symbol.found.kind.to_kind_name();
393                        context
394                            .insert_error(AnalyzerError::call_non_function(&name, &kind, &token));
395                        Err(ir_error!(token))
396                    }
397                }
398            }
399        }
400    }
401}
402
403fn check_true_false(comptime: &Comptime) -> (bool, bool) {
404    if comptime.is_const
405        && let Ok(value) = comptime.get_value()
406    {
407        if value.to_usize().unwrap_or(0) != 0 {
408            (true, false)
409        } else {
410            (false, true)
411        }
412    } else {
413        (false, false)
414    }
415}
416
417impl Conv<&IfStatement> for ir::StatementBlock {
418    fn conv(context: &mut Context, value: &IfStatement) -> IrResult<Self> {
419        let define_context: DefineContext = (&value.r#if.if_token).into();
420        if !define_context.is_default() {
421            return Ok(ir::StatementBlock::default());
422        }
423
424        let (comptime, cond) = eval_expr(context, None, &value.expression, false)?;
425
426        if !comptime.r#type.is_binary() {
427            let token: TokenRange = value.expression.as_ref().into();
428            context.insert_error(AnalyzerError::invalid_logical_operand(false, &token));
429        }
430
431        let (true_side_only, false_side_only) = check_true_false(&comptime);
432
433        let true_side = if false_side_only {
434            vec![]
435        } else {
436            let true_side: ir::StatementBlock =
437                Conv::conv(context, value.statement_block.as_ref())?;
438            true_side.0
439        };
440
441        if true_side_only {
442            return Ok(ir::StatementBlock(true_side));
443        }
444
445        let mut false_side = vec![];
446        let mut else_if_break = false;
447
448        for x in &value.if_statement_list {
449            let (comptime, cond) = eval_expr(context, None, &x.expression, false)?;
450
451            if !comptime.r#type.is_binary() {
452                let token: TokenRange = x.expression.as_ref().into();
453                context.insert_error(AnalyzerError::invalid_logical_operand(false, &token));
454            }
455
456            let (true_side_only, false_side_only) = check_true_false(&comptime);
457
458            // If this `else if` is false_side_only, this iteration should be skipped.
459            if false_side_only {
460                continue;
461            }
462
463            let true_side: ir::StatementBlock = Conv::conv(context, x.statement_block.as_ref())?;
464            let true_side = true_side.0;
465
466            let statement = ir::Statement::If(ir::IfStatement {
467                cond,
468                true_side,
469                false_side: vec![],
470                token: x.into(),
471            });
472
473            if let Some(x) = false_side.last_mut() {
474                if let ir::Statement::If(x) = x {
475                    x.insert_leaf_false(vec![statement]);
476                }
477            } else {
478                false_side.push(statement);
479            }
480
481            // If this `else if` is true_side_only, the remaining else should be skipped.
482            if true_side_only {
483                else_if_break = true;
484                break;
485            }
486        }
487        if let Some(x) = &value.if_statement_opt
488            && !else_if_break
489        {
490            let block: ir::StatementBlock = Conv::conv(context, x.statement_block.as_ref())?;
491            let mut block = block.0;
492
493            if let Some(x) = false_side.last_mut() {
494                if let ir::Statement::If(x) = x {
495                    x.insert_leaf_false(block);
496                }
497            } else {
498                false_side.append(&mut block);
499            }
500        }
501
502        if false_side_only {
503            Ok(ir::StatementBlock(false_side))
504        } else {
505            let statement = ir::Statement::If(ir::IfStatement {
506                cond,
507                true_side,
508                false_side,
509                token: value.into(),
510            });
511            Ok(ir::StatementBlock(vec![statement]))
512        }
513    }
514}
515
516impl Conv<&IfResetStatement> for ir::StatementBlock {
517    fn conv(context: &mut Context, value: &IfResetStatement) -> IrResult<Self> {
518        let define_context: DefineContext = (&value.if_reset.if_reset_token).into();
519        if !define_context.is_default() {
520            return Ok(ir::StatementBlock::default());
521        }
522
523        context.in_if_reset = true;
524
525        let true_side: ir::IrResult<ir::StatementBlock> =
526            context.block(|c| Conv::conv(c, value.statement_block.as_ref()));
527
528        context.in_if_reset = false;
529
530        let true_side = true_side?.0;
531
532        let mut false_side = vec![];
533        let mut else_if_break = false;
534
535        for x in &value.if_reset_statement_list {
536            let (comptime, cond) = eval_expr(context, None, &x.expression, false)?;
537
538            if !comptime.r#type.is_binary() {
539                let token: TokenRange = x.expression.as_ref().into();
540                context.insert_error(AnalyzerError::invalid_logical_operand(false, &token));
541            }
542
543            let (true_side_only, false_side_only) = check_true_false(&comptime);
544
545            // If this `else if` is false_side_only, this iteration should be skipped.
546            if false_side_only {
547                continue;
548            }
549
550            let true_side: ir::StatementBlock = Conv::conv(context, x.statement_block.as_ref())?;
551            let true_side = true_side.0;
552
553            let statement = ir::Statement::If(ir::IfStatement {
554                cond,
555                true_side,
556                false_side: vec![],
557                token: x.into(),
558            });
559
560            if let Some(x) = false_side.last_mut() {
561                if let ir::Statement::If(x) = x {
562                    x.insert_leaf_false(vec![statement]);
563                }
564            } else {
565                false_side.push(statement);
566            }
567
568            // If this `else if` is true_side_only, the remaining else should be skipped.
569            if true_side_only {
570                else_if_break = true;
571                break;
572            }
573        }
574        if let Some(x) = &value.if_reset_statement_opt
575            && !else_if_break
576        {
577            let block: ir::StatementBlock = Conv::conv(context, x.statement_block.as_ref())?;
578            let mut block = block.0;
579
580            if let Some(x) = false_side.last_mut() {
581                if let ir::Statement::If(x) = x {
582                    x.insert_leaf_false(block);
583                }
584            } else {
585                false_side.append(&mut block);
586            }
587        }
588
589        let statement = ir::Statement::IfReset(ir::IfResetStatement {
590            true_side,
591            false_side,
592            token: value.into(),
593        });
594        Ok(ir::StatementBlock(vec![statement]))
595    }
596}
597
598impl Conv<&ReturnStatement> for ir::Statement {
599    fn conv(context: &mut Context, value: &ReturnStatement) -> IrResult<Self> {
600        let define_context: DefineContext = (&value.semicolon.semicolon_token).into();
601        if !define_context.is_default() {
602            return Ok(ir::Statement::Null);
603        }
604
605        let token: TokenRange = value.into();
606
607        let dst = VarPath::new(get_return_str());
608        let dst = VarPathSelect(dst, ir::VarSelect::default(), token);
609
610        if let Some(dst) = dst.to_assign_destination(context, false) {
611            let width = dst.total_width(context);
612            let (_, expr) = eval_expr(
613                context,
614                Some(dst.comptime.r#type.clone()),
615                &value.expression,
616                false,
617            )?;
618            Ok(ir::Statement::Assign(ir::AssignStatement {
619                dst: vec![dst],
620                width,
621                expr,
622                token,
623            }))
624        } else {
625            Err(ir_error!(token))
626        }
627    }
628}
629
630impl Conv<&ForStatement> for ir::StatementBlock {
631    fn conv(context: &mut Context, value: &ForStatement) -> IrResult<Self> {
632        let define_context: DefineContext = (&value.r#for.for_token).into();
633        if !define_context.is_default() {
634            return Ok(ir::StatementBlock::default());
635        }
636
637        let token: TokenRange = (&value.identifier.identifier_token).into();
638
639        let Ok(symbol) = symbol_table::resolve(value.identifier.as_ref()) else {
640            return Err(ir_error!(token));
641        };
642
643        let SymbolKind::Variable(ref x) = symbol.found.kind else {
644            unreachable!();
645        };
646        let r#type = x.r#type.to_ir_type(context, TypePosition::Variable)?;
647        let clock_domain = x.clock_domain;
648
649        let rev = value.for_statement_opt.is_some();
650
651        let step = value
652            .for_statement_opt0
653            .as_ref()
654            .map(|x| (x.assignment_operator.as_ref(), x.expression.as_ref()));
655
656        let for_range = build_for_range(context, &value.range, rev, step)?;
657
658        // Testbench for-loops may iterate many times at runtime; do not unroll.
659        if !context.in_test_module
660            && let Some(range) = for_range.eval_iter(context)
661        {
662            return unroll_for(context, value, &r#type, clock_domain, &range, token);
663        }
664
665        build_for_statement(context, value, &r#type, clock_domain, for_range, token)
666    }
667}
668
669fn unroll_for(
670    context: &mut Context,
671    value: &ForStatement,
672    r#type: &ir::Type,
673    clock_domain: crate::symbol::ClockDomain,
674    range: &[usize],
675    token: TokenRange,
676) -> ir::IrResult<ir::StatementBlock> {
677    use veryl_parser::resource_table;
678
679    let mut ret = ir::StatementBlock::default();
680    'outer: for &i in range {
681        let label = format!("[{}]", i);
682        let label = resource_table::insert_str(&label);
683
684        context.push_hierarchy(label);
685
686        let block = context.block(|c| {
687            let index = value.identifier.text();
688            let path = ir::VarPath::new(index);
689            let kind = ir::VarKind::Const;
690            let mut comptime = ir::Comptime::from_type(r#type.clone(), clock_domain, token);
691            comptime.is_const = true;
692            if let Some(total_width) = r#type.total_width() {
693                comptime.value = ir::ValueVariant::Numeric(crate::value::Value::new(
694                    i as u64,
695                    total_width,
696                    r#type.signed,
697                ));
698            }
699
700            let id = c.insert_var_path(path.clone(), comptime.clone());
701            let array_limit = c.config.evaluate_array_limit;
702            let variable = ir::Variable::new(
703                id,
704                path,
705                kind,
706                comptime.r#type.clone(),
707                vec![comptime.get_value().unwrap().clone()],
708                c.get_affiliation(),
709                &token,
710                array_limit,
711            );
712            c.insert_variable(id, variable);
713
714            let block: ir::IrResult<ir::StatementBlock> =
715                Conv::conv(c, value.statement_block.as_ref());
716            block
717        });
718
719        context.pop_hierarchy();
720
721        if let Ok(mut block) = block {
722            for stmt in block.0.drain(..) {
723                if matches!(stmt, ir::Statement::Break) {
724                    break 'outer;
725                }
726                ret.0.push(stmt);
727            }
728        }
729    }
730    Ok(ret)
731}
732
733impl Conv<&CaseStatement> for ir::StatementBlock {
734    fn conv(context: &mut Context, value: &CaseStatement) -> IrResult<Self> {
735        let define_context: DefineContext = (&value.case.case_token).into();
736        if !define_context.is_default() {
737            return Ok(ir::StatementBlock::default());
738        }
739
740        let mut tgt: ir::Expression = Conv::conv(context, value.expression.as_ref())?;
741        tgt.eval_comptime(context, None);
742        let mut ret = ir::StatementBlock::default();
743
744        for item in &value.case_statement_list {
745            let cond = match item.case_item.case_item_group.as_ref() {
746                CaseItemGroup::CaseCondition(x) => {
747                    Some(case_condition(context, &tgt, x.case_condition.as_ref())?)
748                }
749                CaseItemGroup::Defaul(_) => None,
750            };
751            let true_side: ir::StatementBlock = match item.case_item.case_item_group0.as_ref() {
752                CaseItemGroup0::Statement(x) => Conv::conv(context, x.statement.as_ref())?,
753                CaseItemGroup0::StatementBlock(x) => {
754                    Conv::conv(context, x.statement_block.as_ref())?
755                }
756            };
757
758            let statements = if let Some(cond) = cond {
759                ir::StatementBlock(vec![ir::Statement::If(ir::IfStatement {
760                    cond,
761                    true_side: true_side.0,
762                    false_side: vec![],
763                    token: item.case_item.as_ref().into(),
764                })])
765            } else {
766                true_side
767            };
768
769            if ret.0.is_empty() {
770                ret = statements;
771            } else if let ir::Statement::If(x) = &mut ret.0[0] {
772                x.insert_leaf_false(statements.0);
773            }
774        }
775
776        Ok(ret)
777    }
778}
779
780impl Conv<&SwitchStatement> for ir::StatementBlock {
781    fn conv(context: &mut Context, value: &SwitchStatement) -> IrResult<Self> {
782        let define_context: DefineContext = (&value.switch.switch_token).into();
783        if !define_context.is_default() {
784            return Ok(ir::StatementBlock::default());
785        }
786
787        let mut ret = ir::StatementBlock::default();
788
789        for item in &value.switch_statement_list {
790            let cond = match item.switch_item.switch_item_group.as_ref() {
791                SwitchItemGroup::SwitchCondition(x) => {
792                    Some(switch_condition(context, x.switch_condition.as_ref())?)
793                }
794                SwitchItemGroup::Defaul(_) => None,
795            };
796            let true_side: ir::StatementBlock = match item.switch_item.switch_item_group0.as_ref() {
797                SwitchItemGroup0::Statement(x) => Conv::conv(context, x.statement.as_ref())?,
798                SwitchItemGroup0::StatementBlock(x) => {
799                    Conv::conv(context, x.statement_block.as_ref())?
800                }
801            };
802
803            let statements = if let Some(cond) = cond {
804                ir::StatementBlock(vec![ir::Statement::If(ir::IfStatement {
805                    cond,
806                    true_side: true_side.0,
807                    false_side: vec![],
808                    token: item.switch_item.as_ref().into(),
809                })])
810            } else {
811                true_side
812            };
813
814            if ret.0.is_empty() {
815                ret = statements;
816            } else if let ir::Statement::If(x) = &mut ret.0[0] {
817                x.insert_leaf_false(statements.0);
818            }
819        }
820
821        Ok(ret)
822    }
823}