neo_solidity/ir/statements/dispatch/
control_flow.rs

1fn lower_block_statement(
2    statements: &[Statement],
3    ctx: &mut LoweringContext,
4    instructions: &mut Vec<Instruction>,
5) -> bool {
6    ctx.enter_scope();
7    let mut returned = false;
8    for stmt in statements {
9        if lower_statement(stmt, ctx, instructions) {
10            returned = true;
11            break;
12        }
13    }
14    ctx.exit_scope();
15    returned
16}
17
18fn lower_if_statement(
19    condition: &Expression,
20    then_stmt: &Statement,
21    else_stmt: Option<&Statement>,
22    ctx: &mut LoweringContext,
23    instructions: &mut Vec<Instruction>,
24) -> bool {
25    let else_label = ctx.next_label();
26    let end_label = if else_stmt.is_some() {
27        ctx.next_label()
28    } else {
29        else_label
30    };
31
32    lower_expression(condition, ctx, instructions);
33    instructions.push(Instruction::JumpIf { target: else_label });
34
35    let then_returns = lower_statement(then_stmt, ctx, instructions);
36
37    if let Some(else_stmt) = else_stmt {
38        instructions.push(Instruction::Jump { target: end_label });
39        instructions.push(Instruction::Label(else_label));
40        let else_returns = lower_statement(else_stmt, ctx, instructions);
41        instructions.push(Instruction::Label(end_label));
42        then_returns && else_returns
43    } else {
44        instructions.push(Instruction::Label(else_label));
45        false
46    }
47}
48
49fn lower_while_statement(
50    condition: &Expression,
51    body: &Statement,
52    ctx: &mut LoweringContext,
53    instructions: &mut Vec<Instruction>,
54) -> bool {
55    let start_label = ctx.next_label();
56    let end_label = ctx.next_label();
57
58    instructions.push(Instruction::Label(start_label));
59    lower_expression(condition, ctx, instructions);
60    instructions.push(Instruction::JumpIf { target: end_label });
61    ctx.push_loop(start_label, end_label);
62    lower_statement(body, ctx, instructions);
63    ctx.pop_loop();
64    instructions.push(Instruction::Jump {
65        target: start_label,
66    });
67    instructions.push(Instruction::Label(end_label));
68    false
69}
70
71fn lower_do_while_statement(
72    body: &Statement,
73    condition: &Expression,
74    ctx: &mut LoweringContext,
75    instructions: &mut Vec<Instruction>,
76) -> bool {
77    let start_label = ctx.next_label();
78    let condition_label = ctx.next_label();
79    let end_label = ctx.next_label();
80
81    instructions.push(Instruction::Label(start_label));
82    ctx.push_loop(condition_label, end_label);
83    lower_statement(body, ctx, instructions);
84    ctx.pop_loop();
85    instructions.push(Instruction::Label(condition_label));
86    lower_expression(condition, ctx, instructions);
87    instructions.push(Instruction::JumpIf { target: end_label });
88    instructions.push(Instruction::Jump {
89        target: start_label,
90    });
91    instructions.push(Instruction::Label(end_label));
92    false
93}
94
95fn lower_for_statement(
96    init: Option<&Statement>,
97    condition: Option<&Expression>,
98    post: Option<&Expression>,
99    body: Option<&Statement>,
100    ctx: &mut LoweringContext,
101    instructions: &mut Vec<Instruction>,
102) -> bool {
103    ctx.enter_scope();
104    if let Some(init_stmt) = init {
105        lower_statement(init_stmt, ctx, instructions);
106    }
107
108    let condition_label = ctx.next_label();
109    let post_label = ctx.next_label();
110    let end_label = ctx.next_label();
111
112    instructions.push(Instruction::Label(condition_label));
113
114    if let Some(cond_expr) = condition {
115        lower_expression(cond_expr, ctx, instructions);
116        instructions.push(Instruction::JumpIf { target: end_label });
117    }
118
119    if let Some(body_stmt) = body {
120        ctx.push_loop(post_label, end_label);
121        lower_statement(body_stmt, ctx, instructions);
122        ctx.pop_loop();
123    }
124
125    instructions.push(Instruction::Label(post_label));
126    if let Some(post_expr) = post {
127        if lower_expression(post_expr, ctx, instructions) {
128            instructions.push(Instruction::Drop(ValueType::Any));
129        }
130    }
131
132    instructions.push(Instruction::Jump {
133        target: condition_label,
134    });
135    instructions.push(Instruction::Label(end_label));
136    ctx.exit_scope();
137    false
138}
139
140fn lower_break_statement(ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) -> bool {
141    if let Some(label) = ctx.break_target() {
142        instructions.push(Instruction::Jump { target: label });
143    }
144    false
145}
146
147fn lower_continue_statement(ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) -> bool {
148    if let Some(label) = ctx.continue_target() {
149        instructions.push(Instruction::Jump { target: label });
150    }
151    false
152}