egglog/sort/
i64.rs

1use super::*;
2
3/// Signed 64-bit integers supporting these primitives:
4/// - Arithmetic: `+`, `-`, `*`, `/`, `%`
5/// - Bitwise: `&`, `|`, `^`, `<<`, `>>`, `not-i64`
6/// - Fallible comparisons: `<`, `>`, `<=`, `>=`
7/// - Boolean comparisons: `bool-=`, `bool-<`, `bool->`, `bool-<=`, `bool->=`
8/// - Other: `min`, `max`, `to-f64`, `to-string`, `log2`
9///
10/// Note: fallible comparisons are used at the top-level of a query.
11/// For example, this rule will only match if `a` is less than `b`.
12/// ```text
13/// (rule (... (< a b)) (...))
14/// ```
15/// On the other hand, boolean comparisons will always match, and so
16/// make sense to use inside expressions.
17#[derive(Debug)]
18pub struct I64Sort;
19
20impl BaseSort for I64Sort {
21    type Base = i64;
22
23    fn name(&self) -> &str {
24        "i64"
25    }
26
27    #[rustfmt::skip]
28    fn register_primitives(&self, eg: &mut EGraph) {
29        add_literal_prim!(eg, "+" = |a: i64, b: i64| -?> i64 { a.checked_add(b) });
30        add_literal_prim!(eg, "-" = |a: i64, b: i64| -?> i64 { a.checked_sub(b) });
31        add_literal_prim!(eg, "*" = |a: i64, b: i64| -?> i64 { a.checked_mul(b) });
32        add_literal_prim!(eg, "/" = |a: i64, b: i64| -?> i64 { a.checked_div(b) });
33        add_literal_prim!(eg, "%" = |a: i64, b: i64| -?> i64 { a.checked_rem(b) });
34
35        add_literal_prim!(eg, "&" = |a: i64, b: i64| -> i64 { a & b });
36        add_literal_prim!(eg, "|" = |a: i64, b: i64| -> i64 { a | b });
37        add_literal_prim!(eg, "^" = |a: i64, b: i64| -> i64 { a ^ b });
38        add_literal_prim!(eg, "<<" = |a: i64, b: i64| -?> i64 { b.try_into().ok().and_then(|b| a.checked_shl(b)) });
39        add_literal_prim!(eg, ">>" = |a: i64, b: i64| -?> i64 { b.try_into().ok().and_then(|b| a.checked_shr(b)) });
40        add_literal_prim!(eg, "not-i64" = |a: i64| -> i64 { !a });
41
42        add_literal_prim!(eg, "log2" = |a: i64| -> i64 { a.ilog2() as i64 });
43
44        add_literal_prim!(eg, "abs" = |a: i64| -?> i64 { a.checked_abs() });
45
46        add_literal_prim!(eg, "<" = |a: i64, b: i64| -?> () { (a < b).then_some(()) });
47        add_literal_prim!(eg, ">" = |a: i64, b: i64| -?> () { (a > b).then_some(()) });
48        add_literal_prim!(eg, "<=" = |a: i64, b: i64| -?> () { (a <= b).then_some(()) });
49        add_literal_prim!(eg, ">=" = |a: i64, b: i64| -?> () { (a >= b).then_some(()) });
50
51        add_literal_prim!(eg, "bool-=" = |a: i64, b: i64| -> bool { a == b });
52        add_literal_prim!(eg, "bool-<" = |a: i64, b: i64| -> bool { a < b });
53        add_literal_prim!(eg, "bool->" = |a: i64, b: i64| -> bool { a > b });
54        add_literal_prim!(eg, "bool-<=" = |a: i64, b: i64| -> bool { a <= b });
55        add_literal_prim!(eg, "bool->=" = |a: i64, b: i64| -> bool { a >= b });
56
57        add_literal_prim!(eg, "min" = |a: i64, b: i64| -> i64 { a.min(b) });
58        add_literal_prim!(eg, "max" = |a: i64, b: i64| -> i64 { a.max(b) });
59
60        add_literal_prim!(eg, "to-string" = |a: i64| -> S { S::new(a.to_string()) });
61
62        // Must be in the i64 sort register function because
63        // the string sort is registered before the i64 sort.
64        add_literal_prim!(eg, "count-matches" = |a: S, b: S| -> i64 {
65            a.as_str().matches(b.as_str()).count() as i64
66        });
67    }
68
69    fn reconstruct_termdag(
70        &self,
71        base_values: &BaseValues,
72        value: Value,
73        termdag: &mut TermDag,
74    ) -> TermId {
75        let i = base_values.unwrap::<i64>(value);
76
77        termdag.lit(Literal::Int(i))
78    }
79}