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_primitive!(eg, "+" = |a: i64, b: i64| -?> i64 { a.checked_add(b) });
30        add_primitive!(eg, "-" = |a: i64, b: i64| -?> i64 { a.checked_sub(b) });
31        add_primitive!(eg, "*" = |a: i64, b: i64| -?> i64 { a.checked_mul(b) });
32        add_primitive!(eg, "/" = |a: i64, b: i64| -?> i64 { a.checked_div(b) });
33        add_primitive!(eg, "%" = |a: i64, b: i64| -?> i64 { a.checked_rem(b) });
34
35        add_primitive!(eg, "&" = |a: i64, b: i64| -> i64 { a & b });
36        add_primitive!(eg, "|" = |a: i64, b: i64| -> i64 { a | b });
37        add_primitive!(eg, "^" = |a: i64, b: i64| -> i64 { a ^ b });
38        add_primitive!(eg, "<<" = |a: i64, b: i64| -?> i64 { b.try_into().ok().and_then(|b| a.checked_shl(b)) });
39        add_primitive!(eg, ">>" = |a: i64, b: i64| -?> i64 { b.try_into().ok().and_then(|b| a.checked_shr(b)) });
40        add_primitive!(eg, "not-i64" = |a: i64| -> i64 { !a });
41
42        add_primitive!(eg, "log2" = |a: i64| -> i64 { a.ilog2() as i64 });
43
44        add_primitive!(eg, "<" = |a: i64, b: i64| -?> () { (a < b).then_some(()) });
45        add_primitive!(eg, ">" = |a: i64, b: i64| -?> () { (a > b).then_some(()) });
46        add_primitive!(eg, "<=" = |a: i64, b: i64| -?> () { (a <= b).then_some(()) });
47        add_primitive!(eg, ">=" = |a: i64, b: i64| -?> () { (a >= b).then_some(()) });
48
49        add_primitive!(eg, "bool-=" = |a: i64, b: i64| -> bool { a == b });
50        add_primitive!(eg, "bool-<" = |a: i64, b: i64| -> bool { a < b });
51        add_primitive!(eg, "bool->" = |a: i64, b: i64| -> bool { a > b });
52        add_primitive!(eg, "bool-<=" = |a: i64, b: i64| -> bool { a <= b });
53        add_primitive!(eg, "bool->=" = |a: i64, b: i64| -> bool { a >= b });
54
55        add_primitive!(eg, "min" = |a: i64, b: i64| -> i64 { a.min(b) });
56        add_primitive!(eg, "max" = |a: i64, b: i64| -> i64 { a.max(b) });
57
58        add_primitive!(eg, "to-string" = |a: i64| -> S { S::new(a.to_string()) });
59
60        // Must be in the i64 sort register function because
61        // the string sort is registered before the i64 sort.
62        add_primitive!(eg, "count-matches" = |a: S, b: S| -> i64 {
63            a.as_str().matches(b.as_str()).count() as i64
64        });
65    }
66
67    fn reconstruct_termdag(
68        &self,
69        base_values: &BaseValues,
70        value: Value,
71        termdag: &mut TermDag,
72    ) -> Term {
73        let i = base_values.unwrap::<i64>(value);
74
75        termdag.lit(Literal::Int(i))
76    }
77}