1use{
2 std::cell::Cell,
3 crate::{
4 makepad_live_compiler::{
5 LiveError,
6 LiveErrorOrigin,
7 live_error_origin,
8 TokenSpan
9 },
10 shader_ast::*,
11 analyse::ShaderAnalyseOptions
12 }
13};
14
15pub struct ConstEvaluator {
16 pub options: ShaderAnalyseOptions
17}
18
19impl ConstEvaluator {
20 pub fn const_eval_expr(&self, expr: &Expr) -> Result<Val, LiveError> {
21 self.try_const_eval_expr(expr).ok_or_else(|| LiveError {
22 origin:live_error_origin!(),
23 span: expr.span.into(),
24 message: String::from("expression is not const"),
25 })
26 }
27
28 pub fn try_const_eval_expr(&self, expr: &Expr) -> Option<Val> {
29 let const_val = match expr.kind {
30 ExprKind::Cond {
31 span,
32 ref expr,
33 ref expr_if_true,
34 ref expr_if_false,
35 } => self.try_const_eval_cond_expr(span, expr, expr_if_true, expr_if_false),
36 ExprKind::Bin {
37 span,
38 op,
39 ref left_expr,
40 ref right_expr,
41 } => self.try_const_eval_bin_expr(span, op, left_expr, right_expr),
42 ExprKind::Un { span, op, ref expr } => self.try_const_eval_un_expr(span, op, expr),
43 ExprKind::Field {
44 span,
45 ref expr,
46 field_ident,
47 } => self.try_const_eval_field_expr(span, expr, field_ident),
48 ExprKind::Index {
49 span,
50 ref expr,
51 ref index_expr,
52 } => self.try_const_eval_index_expr(span, expr, index_expr),
53 ExprKind::MethodCall {
54 ref arg_exprs,
55 ..
56 } => self.try_const_eval_all_call_expr(arg_exprs),
57 ExprKind::PlainCall {
58 ref arg_exprs,
59 ..
60 } => self.try_const_eval_all_call_expr(arg_exprs),
61 ExprKind::BuiltinCall {
62 ref arg_exprs,
63 ..
64 } => self.try_const_eval_all_call_expr(arg_exprs),
65 ExprKind::ClosureDef(_) => None,
70 ExprKind::ConsCall {
71 ref arg_exprs,
72 ..
73 } => self.try_const_eval_all_call_expr(arg_exprs),
74 ExprKind::Var {
75 span,
76 ref kind,
77 ..
78 } => self.try_const_eval_var_expr(span, kind),
79 ExprKind::StructCons{
80 struct_ptr,
81 span,
82 ref args
83 } => self.try_const_eval_struct_cons(struct_ptr, span, args),
84 ExprKind::Lit { span, lit } => self.try_const_eval_lit_expr(span, lit),
85 };
86 *expr.const_val.borrow_mut() = Some(const_val.clone());
87 expr.const_index.set(None);
88 const_val
89 }
90
91 fn try_const_eval_cond_expr(
92 &self,
93 _span: TokenSpan,
94 expr: &Expr,
95 expr_if_true: &Expr,
96 expr_if_false: &Expr,
97 ) -> Option<Val> {
98 let val = self.try_const_eval_expr(expr)?;
99 let val_if_true = self.try_const_eval_expr(expr_if_true)?;
100 let val_if_false = self.try_const_eval_expr(expr_if_false)?;
101 Some(if val.to_bool().unwrap() {
102 val_if_true
103 } else {
104 val_if_false
105 })
106 }
107
108 #[allow(clippy::float_cmp)]
109 fn try_const_eval_bin_expr(
110 &self,
111 _span: TokenSpan,
112 op: BinOp,
113 left_expr: &Expr,
114 right_expr: &Expr,
115 ) -> Option<Val> {
116 let left_val = self.try_const_eval_expr(left_expr);
117 let right_val = self.try_const_eval_expr(right_expr);
118 let left_val = left_val?;
119 let right_val = right_val?;
120 if self.options.no_const_collapse{
121 return None
122 }
123 match op {
124 BinOp::Or => match (&left_val, &right_val) {
125 (Val::Bool(x), Val::Bool(y)) => Some(Val::Bool(*x || *y)),
126 _ => None,
127 },
128 BinOp::And => match (&left_val, &right_val) {
129 (Val::Bool(x), Val::Bool(y)) => Some(Val::Bool(*x && *y)),
130 _ => None,
131 },
132 BinOp::Eq => match (&left_val, &right_val) {
133 (Val::Bool(x), Val::Bool(y)) => Some(Val::Bool(x == y)),
134 (Val::Int(x), Val::Int(y)) => Some(Val::Bool(x == y)),
135 (Val::Float(x), Val::Float(y)) => Some(Val::Bool(x == y)),
136 _ => None,
137 },
138 BinOp::Ne => match (&left_val, &right_val) {
139 (Val::Bool(x), Val::Bool(y)) => Some(Val::Bool(x != y)),
140 (Val::Int(x), Val::Int(y)) => Some(Val::Bool(x != y)),
141 (Val::Float(x), Val::Float(y)) => Some(Val::Bool(x != y)),
142 _ => None,
143 },
144 BinOp::Lt => match (&left_val, &right_val) {
145 (Val::Int(x), Val::Int(y)) => Some(Val::Bool(x < y)),
146 (Val::Float(x), Val::Float(y)) => Some(Val::Bool(x < y)),
147 _ => None,
148 },
149 BinOp::Le => match (&left_val, &right_val) {
150 (Val::Int(x), Val::Int(y)) => Some(Val::Bool(x <= y)),
151 (Val::Float(x), Val::Float(y)) => Some(Val::Bool(x <= y)),
152 _ => None,
153 },
154 BinOp::Gt => match (&left_val, &right_val) {
155 (Val::Int(x), Val::Int(y)) => Some(Val::Bool(x > y)),
156 (Val::Float(x), Val::Float(y)) => Some(Val::Bool(x > y)),
157 _ => None,
158 },
159 BinOp::Ge => match (&left_val, &right_val) {
160 (Val::Int(x), Val::Int(y)) => Some(Val::Bool(x >= y)),
161 (Val::Float(x), Val::Float(y)) => Some(Val::Bool(x >= y)),
162 _ => None,
163 },
164 BinOp::Add => match (&left_val, &right_val) {
165 (Val::Int(x), Val::Int(y)) => Some(Val::Int(x + y)),
166 (Val::Float(x), Val::Float(y)) => Some(Val::Float(x + y)),
167 _ => None,
168 },
169 BinOp::Sub => match (&left_val, &right_val) {
170 (Val::Int(x), Val::Int(y)) => Some(Val::Int(x - y)),
171 (Val::Float(x), Val::Float(y)) => Some(Val::Float(x - y)),
172 _ => None,
173 },
174 BinOp::Mul => match (&left_val, &right_val) {
175 (Val::Int(x), Val::Int(y)) => Some(Val::Int(x * y)),
176 (Val::Float(x), Val::Float(y)) => Some(Val::Float(x * y)),
177 _ => None,
178 },
179 BinOp::Div => match (&left_val, &right_val) {
180 (Val::Int(x), Val::Int(y)) => Some(Val::Int(x / y)),
181 (Val::Float(x), Val::Float(y)) => Some(Val::Float(x / y)),
182 _ => None,
183 },
184 _ => None,
185 }
186 }
187
188 fn try_const_eval_un_expr(&self, _span: TokenSpan, op: UnOp, expr: &Expr) -> Option<Val> {
189 let val = self.try_const_eval_expr(expr);
190 let val = val?;
191 if self.options.no_const_collapse{
192 return None
193 }
194 match op {
195 UnOp::Not => match val {
196 Val::Bool(x) => Some(Val::Bool(!x)),
197 _ => None,
198 },
199 UnOp::Neg => match val {
200 Val::Int(x) => Some(Val::Int(-x)),
201 Val::Float(x) => Some(Val::Float(-x)),
202 _ => None,
203 },
204 }
205 }
206
207 fn try_const_eval_field_expr(
208 &self,
209 _span: TokenSpan,
210 expr: &Expr,
211 _field_ident: Ident,
212 ) -> Option<Val> {
213 self.try_const_eval_expr(expr);
214 None
215 }
216
217 fn try_const_eval_index_expr(
218 &self,
219 _span: TokenSpan,
220 expr: &Expr,
221 _index_expr: &Expr,
222 ) -> Option<Val> {
223 self.try_const_eval_expr(expr);
224 None
225 }
226
227 fn try_const_eval_all_call_expr(
228 &self,
229 arg_exprs: &[Expr],
232 ) -> Option<Val> {
233 for arg_expr in arg_exprs {
234 self.try_const_eval_expr(arg_expr);
235 }
236 None
237 }
238
239 fn try_const_eval_var_expr(
240 &self,
241 _span: TokenSpan,
242 _kind: &Cell<Option<VarKind>>,
243 ) -> Option<Val> {
245 None
246 }
247
248 fn try_const_eval_struct_cons(
249 &self,
250 _struct_ptr: StructPtr,
251 _span: TokenSpan,
252 args: &Vec<(Ident,Expr)>,
253 ) -> Option<Val> {
254 for arg in args{
255 self.try_const_eval_expr(&arg.1);
256 }
257 None
258 }
259
260 fn try_const_eval_lit_expr(&self, _span: TokenSpan, lit: Lit) -> Option<Val> {
261 Some(lit.to_val())
262 }
263}