1use enum_dispatch::enum_dispatch;
2
3use crate::{debg2, galloc::AllocForAny, parser::problem::FunSig, value::{ConstValue, Value}};
4
5
6pub mod context;
8
9pub mod cfg;
11
12pub mod ops;
14
15use derive_more::DebugCustom;
16
17use self::{context::Context, ops::{Op1, Op1Enum, Op2, Op2Enum, Op3, Op3Enum}};
18#[derive(DebugCustom, PartialEq, Eq, Clone, Hash)]
19pub enum Expr {
30 #[debug(fmt = "{:?}", _0)]
31 Const(ConstValue),
32 #[debug(fmt = "<{:?}>", _0)]
33 Var(i64),
34 #[debug(fmt = "({} {:?})", _0, _1)]
35 Op1(&'static Op1Enum, &'static Expr),
36 #[debug(fmt = "({} {:?} {:?})", _0, _1, _2)]
37 Op2(&'static Op2Enum, &'static Expr, &'static Expr),
38 #[debug(fmt = "({} {:?} {:?} {:?})", _0, _1, _2, _3)]
39 Op3(&'static Op3Enum, &'static Expr, &'static Expr, &'static Expr),
40}
41
42impl Expr {
43 pub fn eval(&self, ctx: &Context) -> Value {
45
46 match self {
47 Expr::Const(c) => c.value(ctx.len()),
48 Expr::Var(index) => ctx[*index],
49 Expr::Op1(op1, a1) => op1.eval(a1.eval(ctx)),
50 Expr::Op2(op2, a1, a2) => op2.eval(a1.eval(ctx), a2.eval(ctx)),
51 Expr::Op3(op3, a1, a2, a3) => op3.eval(a1.eval(ctx), a2.eval(ctx), a3.eval(ctx)),
52 }
53 }
54 pub fn cost(&self) -> usize {
56 match self {
57 Expr::Const(c) => 1,
58 Expr::Var(index) => 1,
59 Expr::Op1(op1, a1) => op1.cost() + a1.cost(),
60 Expr::Op2(op2, a1, a2) => op2.cost() + a1.cost() + a2.cost(),
61 Expr::Op3(op3, a1, a2, a3) => op3.cost() + a1.cost() + a2.cost() + a3.cost(),
62 }
63 }
64 pub fn contains(&self, other: &Expr) -> bool {
66 if self == other { true }
67 else {
68 match self {
69 Expr::Const(_) => false,
70 Expr::Var(_) => false,
71 Expr::Op1(_, e1) => e1.contains(other),
72 Expr::Op2(_, e1, e2) => e1.contains(other) || e2.contains(other),
73 Expr::Op3(_, e1, e2, e3) => e1.contains(other) || e2.contains(other) || e3.contains(other),
74 }
75 }
76 }
77 pub fn format(&self, sig: &FunSig) -> String {
79 match self {
80 Expr::Const(c) => format!("{:?}", c),
81 Expr::Var(index) => sig.args[*index as usize].0.clone(),
82 Expr::Op1(op1, a1) => format!("({} {})", op1, a1.format(sig)),
83 Expr::Op2(op2, a1, a2) => format!("({} {} {})", op2, a1.format(sig), a2.format(sig)),
84 Expr::Op3(op3, a1, a2, a3) => format!("({} {} {} {})", op3, a1.format(sig), a2.format(sig), a3.format(sig)),
85 }
86 }
87 pub fn ite(&'static self, t: &'static Expr, f: &'static Expr) -> &'static Expr {
89 crate::expr!(Ite {self} {t} {f}).galloc()
90 }
91 pub fn to_expression(&self) -> Expression {
93 match self {
94 Expr::Const(c) => Expression::Const(*c),
95 Expr::Var(v) => Expression::Var(*v),
96 Expr::Op1(op, a1) => Expression::Op1((*op).clone(), a1.to_expression().into()),
97 Expr::Op2(op, a1, a2) => Expression::Op2((*op).clone(), a1.to_expression().into(), a2.to_expression().into()),
98 Expr::Op3(op, a1, a2, a3) => Expression::Op3((*op).clone(), a1.to_expression().into(), a2.to_expression().into(), a3.to_expression().into()),
99 }
100 }
101}
102
103#[derive(DebugCustom, PartialEq, Eq, Clone, Hash)]
104pub enum Expression {
106 #[debug(fmt = "{:?}", _0)]
107 Const(ConstValue),
108 #[debug(fmt = "<{:?}>", _0)]
109 Var(i64),
110 #[debug(fmt = "({} {:?})", _0, _1)]
111 Op1(Op1Enum, Box<Expression>),
112 #[debug(fmt = "({} {:?} {:?})", _0, _1, _2)]
113 Op2(Op2Enum, Box<Expression>, Box<Expression>),
114 #[debug(fmt = "({} {:?} {:?} {:?})", _0, _1, _2, _3)]
115 Op3(Op3Enum, Box<Expression>, Box<Expression>, Box<Expression>),
116}
117
118impl Expression {
119 pub fn alloc_local(self) -> &'static Expr {
121 match self {
122 Expression::Const(a) => Expr::Const(a).galloc(),
123 Expression::Var(v) => Expr::Var(v).galloc(),
124 Expression::Op1(op1, a1) => Expr::Op1(op1.galloc(), a1.alloc_local()).galloc(),
125 Expression::Op2(op1, a1, a2) => Expr::Op2(op1.galloc(), a1.alloc_local(), a2.alloc_local()).galloc(),
126 Expression::Op3(op1, a1, a2, a3) => Expr::Op3(op1.galloc(), a1.alloc_local(), a2.alloc_local(), a3.alloc_local()).galloc(),
127 }
128 }
129}
130
131#[macro_export]
132macro_rules! expr_no_use {
133 ($l:literal) => { $crate::expr::Expr::Const($crate::const_value!($l))};
134 ([$l:literal]) => { $crate::expr::Expr::Var($l)};
135 ({$l:expr}) => { $l };
136 ($op:ident $a1:tt) => {
137 crate::expr::Expr::Op1(Op1Enum::$op($op::default()).galloc(), crate::expr![$a1].galloc())
138 };
139 ($op:ident $a1:tt $a2:tt) => {
140 crate::expr::Expr::Op2(Op2Enum::$op($op::default()).galloc(), crate::expr![$a1].galloc(), crate::expr![$a2].galloc())
141 };
142 ($op:ident $a1:tt $a2:tt $a3:tt) => {
143 crate::expr::Expr::Op3(Op3Enum::$op($op::default()).galloc(), crate::expr![$a1].galloc(), crate::expr![$a2].galloc(), crate::expr![$a3].galloc())
144 };
145 ( ($( $inner:tt )*) ) => { $crate::expr_no_use!($($inner)*) };
146}
147
148#[macro_export]
149macro_rules! expr {
151 ( $( $inner:tt )*) => { {
152 use $crate::galloc::AllocForAny;
153 use $crate::expr::ops::str::*;
154 use $crate::expr::ops::*;
155 use $crate::expr::ops::float::*;
156 $crate::expr_no_use!($($inner)*)
157 }};
158}
159
160#[cfg(test)]
161mod tests {
162 use crate::{value::Value, galloc, expr::{ops::str::{Replace, Concat}, context::Context}, const_value};
163 use crate::galloc::AllocForAny;
164
165 #[test]
166 fn test1() {
167 let input = const_value!("938-242-504").value(1);
168 let output = const_value!("938.242.504").value(1);
169 let ctx = Context::new(1, vec![input], vec![], output);
170 let e = expr!{ (Replace (Replace [0] "-" ".") "-" ".") };
171 assert_eq!(e.eval(&ctx), output);
172 }
173}
174
175