1use serde::de::{Deserializer, Error as DeError};
2use serde_derive::{Deserialize, Serialize};
3
4pub trait ConstantExpression {
5 fn is_constant(&self) -> bool;
6}
7
8impl ConstantExpression for ExprKind {
9 fn is_constant(&self) -> bool {
10 match self {
11 ExprKind::Literal(_) => true,
12 ExprKind::FieldRef(_) => false, ExprKind::Sizeof(_) => true, ExprKind::Alignof(_) => true, ExprKind::Add(expr) => expr.left.is_constant() && expr.right.is_constant(),
18 ExprKind::Sub(expr) => expr.left.is_constant() && expr.right.is_constant(),
19 ExprKind::Mul(expr) => expr.left.is_constant() && expr.right.is_constant(),
20 ExprKind::Div(expr) => expr.left.is_constant() && expr.right.is_constant(),
21 ExprKind::Mod(expr) => expr.left.is_constant() && expr.right.is_constant(),
22 ExprKind::Pow(expr) => expr.left.is_constant() && expr.right.is_constant(),
23
24 ExprKind::BitAnd(expr) => expr.left.is_constant() && expr.right.is_constant(),
25 ExprKind::BitOr(expr) => expr.left.is_constant() && expr.right.is_constant(),
26 ExprKind::BitXor(expr) => expr.left.is_constant() && expr.right.is_constant(),
27 ExprKind::LeftShift(expr) => expr.left.is_constant() && expr.right.is_constant(),
28 ExprKind::RightShift(expr) => expr.left.is_constant() && expr.right.is_constant(),
29
30 ExprKind::Eq(expr) => expr.left.is_constant() && expr.right.is_constant(),
31 ExprKind::Ne(expr) => expr.left.is_constant() && expr.right.is_constant(),
32 ExprKind::Lt(expr) => expr.left.is_constant() && expr.right.is_constant(),
33 ExprKind::Gt(expr) => expr.left.is_constant() && expr.right.is_constant(),
34 ExprKind::Le(expr) => expr.left.is_constant() && expr.right.is_constant(),
35 ExprKind::Ge(expr) => expr.left.is_constant() && expr.right.is_constant(),
36
37 ExprKind::And(expr) => expr.left.is_constant() && expr.right.is_constant(),
38 ExprKind::Or(expr) => expr.left.is_constant() && expr.right.is_constant(),
39 ExprKind::Xor(expr) => expr.left.is_constant() && expr.right.is_constant(),
40
41 ExprKind::BitNot(expr) => expr.operand.is_constant(),
43 ExprKind::Neg(expr) => expr.operand.is_constant(),
44 ExprKind::Not(expr) => expr.operand.is_constant(),
45 ExprKind::Popcount(expr) => expr.operand.is_constant(),
46 }
47 }
48}
49
50#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
51#[serde(rename_all = "kebab-case")]
52pub enum ExprKind {
53 Literal(LiteralExpr),
54 FieldRef(FieldRefExpr),
55 Sizeof(SizeofExpr),
56 Alignof(AlignofExpr),
57
58 Add(AddExpr),
60 Sub(SubExpr),
61 Mul(MulExpr),
62 Div(DivExpr),
63 Mod(ModExpr),
64 Pow(PowExpr),
65
66 BitAnd(BitAndExpr),
68 BitOr(BitOrExpr),
69 BitXor(BitXorExpr),
70 LeftShift(LeftShiftExpr),
71 RightShift(RightShiftExpr),
72
73 BitNot(BitNotExpr),
75 Neg(NegExpr),
76 Not(NotExpr),
77 Popcount(PopcountExpr),
78
79 Eq(EqExpr),
81 Ne(NeExpr),
82 Lt(LtExpr),
83 Gt(GtExpr),
84 Le(LeExpr),
85 Ge(GeExpr),
86
87 And(AndExpr),
89 Or(OrExpr),
90 Xor(XorExpr),
91}
92
93#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
94#[serde(rename_all = "kebab-case")]
95pub enum LiteralExpr {
96 U64(u64),
97 U32(u32),
98 U16(u16),
99 U8(u8),
100 I64(i64),
101 I32(i32),
102 I16(i16),
103 I8(i8),
104}
105
106#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
107#[serde(rename_all = "kebab-case")]
108pub struct FieldRefExpr {
109 #[serde(deserialize_with = "deserialize_field_path")]
110 pub path: Vec<String>, }
112
113impl FieldRefExpr {
114 pub fn to_c_field_access(&self) -> String {
117 let tag_path: Vec<String> = self
118 .path
119 .iter()
120 .flat_map(|s| s.split('/'))
121 .map(|s| s.trim_start_matches(".."))
122 .filter(|s| !s.is_empty())
123 .fold(Vec::new(), |mut acc, seg| {
124 if seg.chars().all(|c| c.is_ascii_digit()) {
125 let formatted = format!("[{}]", seg);
126 if let Some(last) = acc.last_mut() {
127 last.push_str(&formatted);
128 } else {
129 acc.push(formatted);
130 }
131 } else {
132 acc.push(seg.to_string());
133 }
134 acc
135 });
136
137 if tag_path.is_empty() {
138 "tag".to_string()
139 } else {
140 tag_path.join(".")
141 }
142 }
143}
144
145#[derive(Deserialize)]
146#[serde(untagged)]
147enum FieldPathSegmentValue {
148 Str(String),
149 Unsigned(u64),
150 Signed(i64),
151}
152
153fn deserialize_field_path<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
154where
155 D: Deserializer<'de>,
156{
157 let segments: Vec<FieldPathSegmentValue> = serde::Deserialize::deserialize(deserializer)?;
158 let mut out = Vec::with_capacity(segments.len());
159 for seg in segments {
160 let value = match seg {
161 FieldPathSegmentValue::Str(s) => s,
162 FieldPathSegmentValue::Unsigned(u) => u.to_string(),
163 FieldPathSegmentValue::Signed(i) => i.to_string(),
164 };
165 if value.is_empty() {
166 return Err(DeError::custom("field-ref path segments cannot be empty"));
167 }
168 out.push(value);
169 }
170 Ok(out)
171}
172
173#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
174#[serde(rename_all = "kebab-case")]
175pub struct SizeofExpr {
176 pub type_name: String, }
178
179#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
180#[serde(rename_all = "kebab-case")]
181pub struct AlignofExpr {
182 pub type_name: String, }
184
185#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
187#[serde(rename_all = "kebab-case")]
188pub struct AddExpr {
189 pub left: Box<ExprKind>,
190 pub right: Box<ExprKind>,
191}
192
193#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
194#[serde(rename_all = "kebab-case")]
195pub struct SubExpr {
196 pub left: Box<ExprKind>,
197 pub right: Box<ExprKind>,
198}
199
200#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
201#[serde(rename_all = "kebab-case")]
202pub struct MulExpr {
203 pub left: Box<ExprKind>,
204 pub right: Box<ExprKind>,
205}
206
207#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
208#[serde(rename_all = "kebab-case")]
209pub struct DivExpr {
210 pub left: Box<ExprKind>,
211 pub right: Box<ExprKind>,
212}
213
214#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
215#[serde(rename_all = "kebab-case")]
216pub struct ModExpr {
217 pub left: Box<ExprKind>,
218 pub right: Box<ExprKind>,
219}
220
221#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
222#[serde(rename_all = "kebab-case")]
223pub struct PowExpr {
224 pub left: Box<ExprKind>,
225 pub right: Box<ExprKind>,
226}
227
228#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
230#[serde(rename_all = "kebab-case")]
231pub struct BitAndExpr {
232 pub left: Box<ExprKind>,
233 pub right: Box<ExprKind>,
234}
235
236#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
237#[serde(rename_all = "kebab-case")]
238pub struct BitOrExpr {
239 pub left: Box<ExprKind>,
240 pub right: Box<ExprKind>,
241}
242
243#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
244#[serde(rename_all = "kebab-case")]
245pub struct BitXorExpr {
246 pub left: Box<ExprKind>,
247 pub right: Box<ExprKind>,
248}
249
250#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
251#[serde(rename_all = "kebab-case")]
252pub struct LeftShiftExpr {
253 pub left: Box<ExprKind>,
254 pub right: Box<ExprKind>,
255}
256
257#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
258#[serde(rename_all = "kebab-case")]
259pub struct RightShiftExpr {
260 pub left: Box<ExprKind>,
261 pub right: Box<ExprKind>,
262}
263
264#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
266#[serde(rename_all = "kebab-case")]
267pub struct EqExpr {
268 pub left: Box<ExprKind>,
269 pub right: Box<ExprKind>,
270}
271
272#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
273#[serde(rename_all = "kebab-case")]
274pub struct NeExpr {
275 pub left: Box<ExprKind>,
276 pub right: Box<ExprKind>,
277}
278
279#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
280#[serde(rename_all = "kebab-case")]
281pub struct LtExpr {
282 pub left: Box<ExprKind>,
283 pub right: Box<ExprKind>,
284}
285
286#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
287#[serde(rename_all = "kebab-case")]
288pub struct GtExpr {
289 pub left: Box<ExprKind>,
290 pub right: Box<ExprKind>,
291}
292
293#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
294#[serde(rename_all = "kebab-case")]
295pub struct LeExpr {
296 pub left: Box<ExprKind>,
297 pub right: Box<ExprKind>,
298}
299
300#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
301#[serde(rename_all = "kebab-case")]
302pub struct GeExpr {
303 pub left: Box<ExprKind>,
304 pub right: Box<ExprKind>,
305}
306
307#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
309#[serde(rename_all = "kebab-case")]
310pub struct AndExpr {
311 pub left: Box<ExprKind>,
312 pub right: Box<ExprKind>,
313}
314
315#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
316#[serde(rename_all = "kebab-case")]
317pub struct OrExpr {
318 pub left: Box<ExprKind>,
319 pub right: Box<ExprKind>,
320}
321
322#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
323#[serde(rename_all = "kebab-case")]
324pub struct XorExpr {
325 pub left: Box<ExprKind>,
326 pub right: Box<ExprKind>,
327}
328
329#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
331#[serde(rename_all = "kebab-case")]
332pub struct BitNotExpr {
333 pub operand: Box<ExprKind>,
334}
335
336#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
337#[serde(rename_all = "kebab-case")]
338pub struct NegExpr {
339 pub operand: Box<ExprKind>,
340}
341
342#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
343#[serde(rename_all = "kebab-case")]
344pub struct NotExpr {
345 pub operand: Box<ExprKind>,
346}
347
348#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
349#[serde(rename_all = "kebab-case")]
350pub struct PopcountExpr {
351 pub operand: Box<ExprKind>,
352}
353
354impl ExprKind {
356 pub fn try_evaluate_constant(&self) -> Option<u64> {
359 match self {
360 ExprKind::Literal(literal) => {
361 match literal {
362 LiteralExpr::U64(val) => Some(*val),
363 LiteralExpr::U32(val) => Some(*val as u64),
364 LiteralExpr::U16(val) => Some(*val as u64),
365 LiteralExpr::U8(val) => Some(*val as u64),
366 LiteralExpr::I64(val) if *val >= 0 => Some(*val as u64),
367 LiteralExpr::I32(val) if *val >= 0 => Some(*val as u64),
368 LiteralExpr::I16(val) if *val >= 0 => Some(*val as u64),
369 LiteralExpr::I8(val) if *val >= 0 => Some(*val as u64),
370 _ => None, }
372 }
373
374 ExprKind::Add(add_expr) => {
375 let left = add_expr.left.try_evaluate_constant()?;
376 let right = add_expr.right.try_evaluate_constant()?;
377 left.checked_add(right)
378 }
379
380 ExprKind::Sub(sub_expr) => {
381 let left = sub_expr.left.try_evaluate_constant()?;
382 let right = sub_expr.right.try_evaluate_constant()?;
383 left.checked_sub(right)
384 }
385
386 ExprKind::Mul(mul_expr) => {
387 let left = mul_expr.left.try_evaluate_constant()?;
388 let right = mul_expr.right.try_evaluate_constant()?;
389 left.checked_mul(right)
390 }
391
392 ExprKind::Div(div_expr) => {
393 let left = div_expr.left.try_evaluate_constant()?;
394 let right = div_expr.right.try_evaluate_constant()?;
395 if right == 0 {
396 None } else {
398 left.checked_div(right)
399 }
400 }
401
402 ExprKind::Mod(mod_expr) => {
403 let left = mod_expr.left.try_evaluate_constant()?;
404 let right = mod_expr.right.try_evaluate_constant()?;
405 if right == 0 {
406 None } else {
408 Some(left % right)
409 }
410 }
411
412 ExprKind::Pow(pow_expr) => {
413 let left = pow_expr.left.try_evaluate_constant()?;
414 let right = pow_expr.right.try_evaluate_constant()?;
415 if right <= u32::MAX as u64 {
416 left.checked_pow(right as u32)
417 } else {
418 None }
420 }
421
422 ExprKind::BitAnd(expr) => {
423 let left = expr.left.try_evaluate_constant()?;
424 let right = expr.right.try_evaluate_constant()?;
425 Some(left & right)
426 }
427
428 ExprKind::BitOr(expr) => {
429 let left = expr.left.try_evaluate_constant()?;
430 let right = expr.right.try_evaluate_constant()?;
431 Some(left | right)
432 }
433
434 ExprKind::BitXor(expr) => {
435 let left = expr.left.try_evaluate_constant()?;
436 let right = expr.right.try_evaluate_constant()?;
437 Some(left ^ right)
438 }
439
440 ExprKind::LeftShift(expr) => {
441 let left = expr.left.try_evaluate_constant()?;
442 let right = expr.right.try_evaluate_constant()?;
443 if right < 64 {
444 left.checked_shl(right as u32)
445 } else {
446 None }
448 }
449
450 ExprKind::RightShift(expr) => {
451 let left = expr.left.try_evaluate_constant()?;
452 let right = expr.right.try_evaluate_constant()?;
453 if right < 64 {
454 Some(left >> right)
455 } else {
456 None }
458 }
459
460 ExprKind::BitNot(expr) => {
461 let operand = expr.operand.try_evaluate_constant()?;
462 Some(!operand)
463 }
464
465 ExprKind::Neg(expr) => {
466 let operand = expr.operand.try_evaluate_constant()?;
468 if operand <= i64::MAX as u64 {
469 let signed = operand as i64;
470 let negated = -signed;
471 if negated >= 0 {
472 Some(negated as u64)
473 } else {
474 None }
476 } else {
477 None }
479 }
480
481 ExprKind::Popcount(expr) => {
482 let operand = expr.operand.try_evaluate_constant()?;
483 Some(operand.count_ones() as u64)
484 }
485
486 ExprKind::FieldRef(_) => None, ExprKind::Sizeof(_) => None, ExprKind::Alignof(_) => None, ExprKind::Eq(_)
491 | ExprKind::Ne(_)
492 | ExprKind::Lt(_)
493 | ExprKind::Gt(_)
494 | ExprKind::Le(_)
495 | ExprKind::Ge(_) => None, ExprKind::And(_) | ExprKind::Or(_) | ExprKind::Xor(_) | ExprKind::Not(_) => None, }
498 }
499
500 pub fn to_c_string(&self) -> String {
503 match self {
504 ExprKind::Literal(lit) => match lit {
505 LiteralExpr::U64(val) => val.to_string(),
506 LiteralExpr::U32(val) => val.to_string(),
507 LiteralExpr::U16(val) => val.to_string(),
508 LiteralExpr::U8(val) => val.to_string(),
509 LiteralExpr::I64(val) => val.to_string(),
510 LiteralExpr::I32(val) => val.to_string(),
511 LiteralExpr::I16(val) => val.to_string(),
512 LiteralExpr::I8(val) => val.to_string(),
513 },
514 ExprKind::FieldRef(field_ref) => field_ref.path.join("."),
515 ExprKind::Sizeof(sizeof_expr) => format!("sizeof({})", sizeof_expr.type_name),
516 ExprKind::Alignof(alignof_expr) => format!("alignof({})", alignof_expr.type_name),
517
518 ExprKind::Add(e) => format!("({}+{})", e.left.to_c_string(), e.right.to_c_string()),
520 ExprKind::Sub(e) => format!("({}-{})", e.left.to_c_string(), e.right.to_c_string()),
521 ExprKind::Mul(e) => format!("({}*{})", e.left.to_c_string(), e.right.to_c_string()),
522 ExprKind::Div(e) => format!("({}/{})", e.left.to_c_string(), e.right.to_c_string()),
523 ExprKind::Mod(e) => format!("({}%{})", e.left.to_c_string(), e.right.to_c_string()),
524 ExprKind::Pow(e) => format!("pow({},{})", e.left.to_c_string(), e.right.to_c_string()),
525
526 ExprKind::BitAnd(e) => format!("({}&{})", e.left.to_c_string(), e.right.to_c_string()),
528 ExprKind::BitOr(e) => format!("({}|{})", e.left.to_c_string(), e.right.to_c_string()),
529 ExprKind::BitXor(e) => format!("({}^{})", e.left.to_c_string(), e.right.to_c_string()),
530 ExprKind::LeftShift(e) => {
531 format!("({}<<{})", e.left.to_c_string(), e.right.to_c_string())
532 }
533 ExprKind::RightShift(e) => {
534 format!("({}>>{})", e.left.to_c_string(), e.right.to_c_string())
535 }
536
537 ExprKind::BitNot(e) => format!("~({})", e.operand.to_c_string()),
539 ExprKind::Neg(e) => format!("-({})", e.operand.to_c_string()),
540 ExprKind::Not(e) => format!("!({})", e.operand.to_c_string()),
541 ExprKind::Popcount(e) => format!("__builtin_popcount({})", e.operand.to_c_string()),
542
543 ExprKind::Eq(e) => format!("({}=={})", e.left.to_c_string(), e.right.to_c_string()),
545 ExprKind::Ne(e) => format!("({}!={})", e.left.to_c_string(), e.right.to_c_string()),
546 ExprKind::Lt(e) => format!("({}<{})", e.left.to_c_string(), e.right.to_c_string()),
547 ExprKind::Gt(e) => format!("({}>{})", e.left.to_c_string(), e.right.to_c_string()),
548 ExprKind::Le(e) => format!("({}<={})", e.left.to_c_string(), e.right.to_c_string()),
549 ExprKind::Ge(e) => format!("({}>={})", e.left.to_c_string(), e.right.to_c_string()),
550
551 ExprKind::And(e) => format!("({}&&{})", e.left.to_c_string(), e.right.to_c_string()),
553 ExprKind::Or(e) => format!("({}||{})", e.left.to_c_string(), e.right.to_c_string()),
554 ExprKind::Xor(e) => format!("({}^^{})", e.left.to_c_string(), e.right.to_c_string()), }
556 }
557
558 pub fn to_debug_string(&self) -> String {
560 match self {
561 ExprKind::Literal(literal) => match literal {
562 LiteralExpr::U64(val) => format!("Literal(U64: {})", val),
563 LiteralExpr::U32(val) => format!("Literal(U32: {})", val),
564 LiteralExpr::U16(val) => format!("Literal(U16: {})", val),
565 LiteralExpr::U8(val) => format!("Literal(U8: {})", val),
566 LiteralExpr::I64(val) => format!("Literal(I64: {})", val),
567 LiteralExpr::I32(val) => format!("Literal(I32: {})", val),
568 LiteralExpr::I16(val) => format!("Literal(I16: {})", val),
569 LiteralExpr::I8(val) => format!("Literal(I8: {})", val),
570 },
571 ExprKind::FieldRef(field_ref) => {
572 format!("FieldRef(path: [{}])", field_ref.path.join(", "))
573 }
574 ExprKind::Sizeof(sizeof_expr) => {
575 format!("Sizeof(type: {})", sizeof_expr.type_name)
576 }
577 ExprKind::Alignof(alignof_expr) => {
578 format!("Alignof(type: {})", alignof_expr.type_name)
579 }
580 ExprKind::Add(expr) => {
581 format!(
582 "Add({} + {})",
583 expr.left.to_debug_string(),
584 expr.right.to_debug_string()
585 )
586 }
587 ExprKind::Sub(expr) => {
588 format!(
589 "Sub({} - {})",
590 expr.left.to_debug_string(),
591 expr.right.to_debug_string()
592 )
593 }
594 ExprKind::Mul(expr) => {
595 format!(
596 "Mul({} * {})",
597 expr.left.to_debug_string(),
598 expr.right.to_debug_string()
599 )
600 }
601 ExprKind::Div(expr) => {
602 format!(
603 "Div({} / {})",
604 expr.left.to_debug_string(),
605 expr.right.to_debug_string()
606 )
607 }
608 ExprKind::Mod(expr) => {
609 format!(
610 "Mod({} % {})",
611 expr.left.to_debug_string(),
612 expr.right.to_debug_string()
613 )
614 }
615 ExprKind::Pow(expr) => {
616 format!(
617 "Pow({} ** {})",
618 expr.left.to_debug_string(),
619 expr.right.to_debug_string()
620 )
621 }
622 ExprKind::BitAnd(expr) => {
623 format!(
624 "BitAnd({} & {})",
625 expr.left.to_debug_string(),
626 expr.right.to_debug_string()
627 )
628 }
629 ExprKind::BitOr(expr) => {
630 format!(
631 "BitOr({} | {})",
632 expr.left.to_debug_string(),
633 expr.right.to_debug_string()
634 )
635 }
636 ExprKind::BitXor(expr) => {
637 format!(
638 "BitXor({} ^ {})",
639 expr.left.to_debug_string(),
640 expr.right.to_debug_string()
641 )
642 }
643 ExprKind::LeftShift(expr) => {
644 format!(
645 "LeftShift({} << {})",
646 expr.left.to_debug_string(),
647 expr.right.to_debug_string()
648 )
649 }
650 ExprKind::RightShift(expr) => {
651 format!(
652 "RightShift({} >> {})",
653 expr.left.to_debug_string(),
654 expr.right.to_debug_string()
655 )
656 }
657 ExprKind::BitNot(expr) => {
658 format!("BitNot(~{})", expr.operand.to_debug_string())
659 }
660 ExprKind::Neg(expr) => {
661 format!("Neg(-{})", expr.operand.to_debug_string())
662 }
663 ExprKind::Not(expr) => {
664 format!("Not(!{})", expr.operand.to_debug_string())
665 }
666 ExprKind::Popcount(expr) => {
667 format!("Popcount(popcount({}))", expr.operand.to_debug_string())
668 }
669 ExprKind::Eq(expr) => {
670 format!(
671 "Eq({} == {})",
672 expr.left.to_debug_string(),
673 expr.right.to_debug_string()
674 )
675 }
676 ExprKind::Ne(expr) => {
677 format!(
678 "Ne({} != {})",
679 expr.left.to_debug_string(),
680 expr.right.to_debug_string()
681 )
682 }
683 ExprKind::Lt(expr) => {
684 format!(
685 "Lt({} < {})",
686 expr.left.to_debug_string(),
687 expr.right.to_debug_string()
688 )
689 }
690 ExprKind::Gt(expr) => {
691 format!(
692 "Gt({} > {})",
693 expr.left.to_debug_string(),
694 expr.right.to_debug_string()
695 )
696 }
697 ExprKind::Le(expr) => {
698 format!(
699 "Le({} <= {})",
700 expr.left.to_debug_string(),
701 expr.right.to_debug_string()
702 )
703 }
704 ExprKind::Ge(expr) => {
705 format!(
706 "Ge({} >= {})",
707 expr.left.to_debug_string(),
708 expr.right.to_debug_string()
709 )
710 }
711 ExprKind::And(expr) => {
712 format!(
713 "And({} && {})",
714 expr.left.to_debug_string(),
715 expr.right.to_debug_string()
716 )
717 }
718 ExprKind::Or(expr) => {
719 format!(
720 "Or({} || {})",
721 expr.left.to_debug_string(),
722 expr.right.to_debug_string()
723 )
724 }
725 ExprKind::Xor(expr) => {
726 format!(
727 "Xor({} ^^ {})",
728 expr.left.to_debug_string(),
729 expr.right.to_debug_string()
730 )
731 }
732 }
733 }
734}