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}