neo_solidity/ir/statements/
logical.rs1fn lower_require(
2 args: &[Expression],
3 ctx: &mut LoweringContext,
4 instructions: &mut Vec<Instruction>,
5) {
6 if args.is_empty() {
7 ctx.record_error_with_suggestion(
8 "require() expects at least one argument",
9 "usage: require(condition) or require(condition, \"error message\")",
10 );
11 return;
12 }
13
14 let fail_label = ctx.next_label();
15 let ok_label = ctx.next_label();
16
17 if lower_expression(&args[0], ctx, instructions) {
19 instructions.push(Instruction::JumpIf { target: fail_label });
20 instructions.push(Instruction::Jump { target: ok_label });
21 }
22
23 instructions.push(Instruction::Label(fail_label));
24 if args.len() > 1 {
25 if let Expression::FunctionCall(_, callee, error_args) = &args[1] {
35 if let Expression::Variable(error_ident) = callee.as_ref() {
36 for error_arg in error_args {
39 if lower_expression(error_arg, ctx, instructions) {
40 instructions.push(Instruction::Drop(ValueType::Any));
41 }
42 }
43 let msg = if error_args.is_empty() {
44 error_ident.name.clone()
45 } else {
46 format!("{}({} args)", error_ident.name, error_args.len())
47 };
48 instructions.push(Instruction::PushLiteral(LiteralValue::String(
49 msg.as_bytes().to_vec(),
50 )));
51 instructions.push(Instruction::Throw);
52 instructions.push(Instruction::Label(ok_label));
53 return;
54 }
55 }
56
57 if lower_expression(&args[1], ctx, instructions) {
60 instructions.push(Instruction::Throw);
61 instructions.push(Instruction::Label(ok_label));
62 return;
63 }
64 }
65
66 instructions.push(Instruction::PushLiteral(LiteralValue::Null));
68 instructions.push(Instruction::Throw);
69 instructions.push(Instruction::Label(ok_label));
70}
71
72fn lower_assert(args: &[Expression], ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) {
73 if args.len() != 1 {
74 ctx.record_error_with_suggestion(
75 "assert() expects exactly one argument",
76 "usage: assert(condition)",
77 );
78 return;
79 }
80
81 let fail_label = ctx.next_label();
82 let ok_label = ctx.next_label();
83
84 if lower_expression(&args[0], ctx, instructions) {
86 instructions.push(Instruction::JumpIf { target: fail_label });
87 instructions.push(Instruction::Jump { target: ok_label });
88 }
89
90 instructions.push(Instruction::Label(fail_label));
91 instructions.push(Instruction::PushLiteral(LiteralValue::String(
93 b"Panic: 0x01".to_vec(),
94 )));
95 instructions.push(Instruction::Throw);
96
97 instructions.push(Instruction::Label(ok_label));
98}
99
100fn lower_logical_or(
101 left: &Expression,
102 right: &Expression,
103 ctx: &mut LoweringContext,
104 instructions: &mut Vec<Instruction>,
105) -> bool {
106 let false_label = ctx.next_label();
107 let end_label = ctx.next_label();
108
109 if !lower_expression(left, ctx, instructions) {
110 return false;
111 }
112
113 instructions.push(Instruction::JumpIf {
114 target: false_label,
115 });
116 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
117 instructions.push(Instruction::Jump { target: end_label });
118 instructions.push(Instruction::Label(false_label));
119
120 if !lower_expression(right, ctx, instructions) {
121 return false;
122 }
123
124 instructions.push(Instruction::Label(end_label));
125 true
126}
127
128fn lower_logical_and(
129 left: &Expression,
130 right: &Expression,
131 ctx: &mut LoweringContext,
132 instructions: &mut Vec<Instruction>,
133) -> bool {
134 let false_label = ctx.next_label();
135 let end_label = ctx.next_label();
136
137 if !lower_expression(left, ctx, instructions) {
138 return false;
139 }
140
141 instructions.push(Instruction::JumpIf {
142 target: false_label,
143 });
144
145 if !lower_expression(right, ctx, instructions) {
146 return false;
147 }
148
149 instructions.push(Instruction::Jump { target: end_label });
150 instructions.push(Instruction::Label(false_label));
151 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
152 instructions.push(Instruction::Label(end_label));
153 true
154}