Skip to main content

cl_typeck/
consteval.rs

1use std::ops;
2
3use cl_ast::{Annotation, At, Expr, Op, types::Literal};
4
5pub trait ConstEval {
6    fn const_eval(&self) -> Option<i128> {
7        None
8    }
9}
10
11impl<T: ConstEval + Annotation> ConstEval for At<T> {
12    fn const_eval(&self) -> Option<i128> {
13        self.0.const_eval()
14    }
15}
16
17fn const_eval_bin<T: ConstEval>(op: Op, exprs: &[T]) -> Option<i128> {
18    let [lhs, rhs] = exprs else { return None };
19    let (lhs, rhs) = (lhs.const_eval()?, rhs.const_eval()?);
20    match op {
21        Op::Mul => Some(lhs * rhs),
22        Op::Div => Some(lhs / rhs),
23        Op::Rem => Some(lhs % rhs),
24        Op::Add => Some(lhs + rhs),
25        Op::Sub => Some(lhs - rhs),
26        Op::Shl => Some(lhs << rhs as u32),
27        Op::Shr => Some(lhs >> rhs as u32),
28        Op::And => Some(lhs & rhs),
29        Op::Xor => Some(lhs ^ rhs),
30        Op::Or => Some(lhs | rhs),
31        Op::Lt => None,
32        Op::Leq => None,
33        Op::Eq => None,
34        Op::Neq => None,
35        Op::Geq => None,
36        Op::Gt => None,
37        _ => unreachable!("eval_bin called with enby op {op} ({lhs}, {rhs})"),
38    }
39}
40
41impl ConstEval for Expr {
42    fn const_eval(&self) -> Option<i128> {
43        match self {
44            Self::Omitted => None,
45            Self::Id(_) => todo!("Consteval paths"),
46            Self::MetId(_) => None,
47            Self::Lit(lit) => lit.const_eval(),
48            Self::Use(_) => None,
49            Self::Bind(_) => None,
50            Self::Make(_) => None,
51            Self::Match(_) => None,
52            Self::Op(op, ats) => match op {
53                Op::Do => ats.last().and_then(At::const_eval),
54                Op::As => ats.first().and_then(At::const_eval),
55                Op::Block => ats.first().and_then(At::const_eval),
56                Op::Array => todo!("Consteval {op}"),
57                Op::ArRep => todo!("Consteval {op}"),
58                Op::Group => ats.first().and_then(At::const_eval),
59                Op::Tuple => todo!("Consteval {op}"),
60                Op::MetaInner => ats.last().and_then(At::const_eval),
61                Op::MetaOuter => ats.last().and_then(At::const_eval),
62                Op::Try => ats.first().and_then(At::const_eval),
63                Op::Index => todo!("Consteval {op}"),
64                Op::Call => todo!("Consteval {op}"),
65                Op::Pub => ats.first().and_then(At::const_eval),
66                Op::Const => ats.first().and_then(At::const_eval),
67                Op::Static => ats.first().and_then(At::const_eval),
68                Op::Macro => todo!("Consteval {op}"),
69                Op::Loop => todo!("Consteval {op}"),
70                Op::If => todo!("Consteval {op}"),
71                Op::While => todo!("Consteval {op}"),
72                Op::Break => todo!("Consteval {op}"),
73                Op::Return => todo!("Consteval {op}"),
74                Op::Continue => todo!("Consteval {op}"),
75                Op::Dot => todo!("Consteval {op}"),
76                Op::RangeEx => todo!("Consteval {op}"),
77                Op::RangeIn => todo!("Consteval {op}"),
78                Op::Neg => ats.first().and_then(At::const_eval).map(ops::Neg::neg),
79                Op::Not => ats.first().and_then(At::const_eval).map(ops::Not::not),
80                Op::Identity => ats.first().and_then(At::const_eval),
81                Op::Refer => todo!("Consteval {op}"),
82                Op::Deref => todo!("Consteval {op}"),
83                Op::Mul => const_eval_bin(*op, ats),
84                Op::Div => const_eval_bin(*op, ats),
85                Op::Rem => const_eval_bin(*op, ats),
86                Op::Add => const_eval_bin(*op, ats),
87                Op::Sub => const_eval_bin(*op, ats),
88                Op::Shl => const_eval_bin(*op, ats),
89                Op::Shr => const_eval_bin(*op, ats),
90                Op::And => const_eval_bin(*op, ats),
91                Op::Xor => const_eval_bin(*op, ats),
92                Op::Or => const_eval_bin(*op, ats),
93                Op::Lt => const_eval_bin(*op, ats),
94                Op::Leq => const_eval_bin(*op, ats),
95                Op::Eq => const_eval_bin(*op, ats),
96                Op::Neq => const_eval_bin(*op, ats),
97                Op::Geq => const_eval_bin(*op, ats),
98                Op::Gt => const_eval_bin(*op, ats),
99                Op::LogAnd => todo!("Consteval {op}"),
100                Op::LogXor => todo!("Consteval {op}"),
101                Op::LogOr => todo!("Consteval {op}"),
102                Op::Set => todo!("Consteval {op}"),
103                Op::MulSet => todo!("Consteval {op}"),
104                Op::DivSet => todo!("Consteval {op}"),
105                Op::RemSet => todo!("Consteval {op}"),
106                Op::AddSet => todo!("Consteval {op}"),
107                Op::SubSet => todo!("Consteval {op}"),
108                Op::ShlSet => todo!("Consteval {op}"),
109                Op::ShrSet => todo!("Consteval {op}"),
110                Op::AndSet => todo!("Consteval {op}"),
111                Op::XorSet => todo!("Consteval {op}"),
112                Op::OrSet => todo!("Consteval {op}"),
113            },
114        }
115    }
116}
117
118impl ConstEval for Literal {
119    fn const_eval(&self) -> Option<i128> {
120        match *self {
121            Self::Bool(_) => None,
122            Self::Char(_) => None,
123            Self::Int(v, _) => Some(v as _),
124            Self::Str(_) => None,
125        }
126    }
127}