neo_solidity/ir/expressions/dispatch/
binary.rs1fn fixed_len_bytes_be_from_hex_number(expr: &Expression, fixed_len: u16) -> Option<Vec<u8>> {
2 let Expression::HexNumberLiteral(_, value, unit) = expr else {
3 return None;
4 };
5
6 if unit.is_some() {
7 return None;
8 }
9
10 let raw = value.trim().trim_start_matches("0x");
11 let mut hex: String = raw
12 .chars()
13 .filter(|c| !c.is_whitespace() && *c != '_')
14 .collect();
15 if hex.is_empty() {
16 return None;
17 }
18
19 if hex.len() % 2 == 1 {
20 hex.insert(0, '0');
21 }
22
23 let bytes = hex_decode(&hex).ok()?;
24 let fixed_len = fixed_len as usize;
25 if bytes.len() > fixed_len {
26 return None;
27 }
28
29 let mut out = vec![0u8; fixed_len - bytes.len()];
30 out.extend_from_slice(&bytes);
31 Some(out)
32}
33
34fn lower_bytes_eq_hex_number_literal(
35 left: &Expression,
36 right: &Expression,
37 ctx: &mut LoweringContext,
38 instructions: &mut Vec<Instruction>,
39 operator: BinaryOperator,
40) -> Option<bool> {
41 if !matches!(operator, BinaryOperator::Eq | BinaryOperator::Ne) {
42 return None;
43 }
44
45 if let Some(ValueType::ByteArray {
48 fixed_len: Some(fixed_len),
49 }) = infer_type_from_expression(left, ctx)
50 {
51 let literal_expr = match right {
52 Expression::Parenthesis(_, inner) => inner.as_ref(),
53 other => other,
54 };
55
56 if let Some(bytes) = fixed_len_bytes_be_from_hex_number(literal_expr, fixed_len) {
57 if lower_expression(left, ctx, instructions) {
58 instructions.push(Instruction::PushLiteral(LiteralValue::ByteArray(bytes)));
59 instructions.push(Instruction::BinaryOp(operator));
60 return Some(true);
61 }
62 return Some(false);
63 }
64 }
65
66 if let Some(ValueType::ByteArray {
67 fixed_len: Some(fixed_len),
68 }) = infer_type_from_expression(right, ctx)
69 {
70 let literal_expr = match left {
71 Expression::Parenthesis(_, inner) => inner.as_ref(),
72 other => other,
73 };
74
75 if let Some(bytes) = fixed_len_bytes_be_from_hex_number(literal_expr, fixed_len) {
76 instructions.push(Instruction::PushLiteral(LiteralValue::ByteArray(bytes)));
77 if lower_expression(right, ctx, instructions) {
78 instructions.push(Instruction::BinaryOp(operator));
79 return Some(true);
80 }
81 return Some(false);
82 }
83 }
84
85 None
86}
87
88fn lower_binary_expr(
89 left: &Expression,
90 right: &Expression,
91 ctx: &mut LoweringContext,
92 instructions: &mut Vec<Instruction>,
93 operator: BinaryOperator,
94) -> bool {
95 if let Some(result) =
96 lower_bytes_eq_hex_number_literal(left, right, ctx, instructions, operator)
97 {
98 return result;
99 }
100
101 if !lower_expression(left, ctx, instructions) || !lower_expression(right, ctx, instructions) {
102 return false;
103 }
104
105 if matches!(operator, BinaryOperator::Div | BinaryOperator::Mod) {
107 let tmp_id = ctx.next_label();
108 let rhs_local = ctx.allocate_local(format!("__div_rhs_{tmp_id}"), None);
109
110 instructions.push(Instruction::StoreLocal(rhs_local)); let ok_label = ctx.next_label();
115 instructions.push(Instruction::LoadLocal(rhs_local));
116 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
117 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
118 instructions.push(Instruction::JumpIf { target: ok_label });
119 instructions.push(Instruction::PushLiteral(LiteralValue::String(
120 b"Panic: 0x12".to_vec(),
121 )));
122 instructions.push(Instruction::Throw);
123 instructions.push(Instruction::Label(ok_label));
124
125 instructions.push(Instruction::LoadLocal(rhs_local));
127 }
128
129 instructions.push(Instruction::BinaryOp(operator));
130 true
131}