1use super::PropertyReference;
5use crate::expression_tree::{BuiltinFunction, OperatorClass};
6use crate::langtype::Type;
7use crate::layout::Orientation;
8use itertools::Either;
9use std::collections::HashMap;
10
11#[derive(Debug, Clone)]
12pub enum Expression {
13 StringLiteral(String),
15 NumberLiteral(f64),
17 BoolLiteral(bool),
19
20 PropertyReference(PropertyReference),
22
23 FunctionParameterReference {
25 index: usize,
26 },
28
29 StoreLocalVariable {
31 name: String,
32 value: Box<Expression>,
33 },
34
35 ReadLocalVariable {
38 name: String,
39 ty: Type,
40 },
41
42 StructFieldAccess {
44 base: Box<Expression>,
46 name: String,
47 },
48
49 ArrayIndex {
51 array: Box<Expression>,
53 index: Box<Expression>,
54 },
55
56 Cast {
58 from: Box<Expression>,
59 to: Type,
60 },
61
62 CodeBlock(Vec<Expression>),
64
65 BuiltinFunctionCall {
67 function: BuiltinFunction,
68 arguments: Vec<Expression>,
69 },
70 CallBackCall {
71 callback: PropertyReference,
72 arguments: Vec<Expression>,
73 },
74
75 ExtraBuiltinFunctionCall {
78 return_ty: Type,
79 function: String,
80 arguments: Vec<Expression>,
81 },
82
83 PropertyAssignment {
85 property: PropertyReference,
86 value: Box<Expression>,
87 },
88 ModelDataAssignment {
90 level: usize,
92 value: Box<Expression>,
93 },
94 ArrayIndexAssignment {
96 array: Box<Expression>,
97 index: Box<Expression>,
98 value: Box<Expression>,
99 },
100
101 BinaryExpression {
102 lhs: Box<Expression>,
103 rhs: Box<Expression>,
104 op: char,
106 },
107
108 UnaryOp {
109 sub: Box<Expression>,
110 op: char,
112 },
113
114 ImageReference {
115 resource_ref: crate::expression_tree::ImageReference,
116 },
117
118 Condition {
119 condition: Box<Expression>,
120 true_expr: Box<Expression>,
121 false_expr: Box<Expression>,
122 },
123
124 Array {
125 element_ty: Type,
126 values: Vec<Expression>,
127 as_model: bool,
129 },
130 Struct {
131 ty: Type,
132 values: HashMap<String, Expression>,
133 },
134
135 EasingCurve(crate::expression_tree::EasingCurve),
136
137 LinearGradient {
138 angle: Box<Expression>,
139 stops: Vec<(Expression, Expression)>,
141 },
142
143 EnumerationValue(crate::langtype::EnumerationValue),
144
145 ReturnStatement(Option<Box<Expression>>),
146
147 LayoutCacheAccess {
148 layout_cache_prop: PropertyReference,
149 index: usize,
150 repeater_index: Option<Box<Expression>>,
153 },
154 BoxLayoutFunction {
157 cells_variable: String,
159 repeater_indices: Option<String>,
161 elements: Vec<Either<Expression, usize>>,
163 orientation: Orientation,
164 sub_expression: Box<Expression>,
165 },
166
167 ComputeDialogLayoutCells {
168 cells_variable: String,
170 roles: Box<Expression>,
171 unsorted_cells: Box<Expression>,
173 },
174}
175
176impl Expression {
177 pub fn default_value_for_type(ty: &Type) -> Option<Self> {
178 Some(match ty {
179 Type::Invalid
180 | Type::Component(_)
181 | Type::Builtin(_)
182 | Type::Native(_)
183 | Type::Callback { .. }
184 | Type::Function { .. }
185 | Type::Void
186 | Type::InferredProperty
187 | Type::InferredCallback
188 | Type::ElementReference
189 | Type::LayoutCache => return None,
190 Type::Float32
191 | Type::Duration
192 | Type::Int32
193 | Type::Angle
194 | Type::PhysicalLength
195 | Type::LogicalLength
196 | Type::UnitProduct(_) => Expression::NumberLiteral(0.),
197 Type::Percent => Expression::NumberLiteral(1.),
198 Type::String => Expression::StringLiteral(String::new()),
199 Type::Color => {
200 Expression::Cast { from: Box::new(Expression::NumberLiteral(0.)), to: ty.clone() }
201 }
202 Type::Image => Expression::ImageReference {
203 resource_ref: crate::expression_tree::ImageReference::None,
204 },
205 Type::Bool => Expression::BoolLiteral(false),
206 Type::Model => return None,
207 Type::PathData => return None,
208 Type::Array(element_ty) => Expression::Array {
209 element_ty: (**element_ty).clone(),
210 values: vec![],
211 as_model: true,
212 },
213 Type::Struct { fields, .. } => Expression::Struct {
214 ty: ty.clone(),
215 values: fields
216 .iter()
217 .map(|(k, v)| Some((k.clone(), Expression::default_value_for_type(v)?)))
218 .collect::<Option<_>>()?,
219 },
220 Type::Easing => Expression::EasingCurve(crate::expression_tree::EasingCurve::default()),
221 Type::Brush => Expression::Cast {
222 from: Box::new(Expression::default_value_for_type(&Type::Color)?),
223 to: Type::Brush,
224 },
225 Type::Enumeration(enumeration) => {
226 Expression::EnumerationValue(enumeration.clone().default_value())
227 }
228 })
229 }
230
231 pub fn ty(&self, ctx: &dyn TypeResolutionContext) -> Type {
232 match self {
233 Self::StringLiteral(_) => Type::String,
234 Self::NumberLiteral(_) => Type::Float32,
235 Self::BoolLiteral(_) => Type::Bool,
236 Self::PropertyReference(prop) => ctx.property_ty(prop).clone(),
237 Self::FunctionParameterReference { index } => ctx.arg_type(*index).clone(),
238 Self::StoreLocalVariable { .. } => Type::Void,
239 Self::ReadLocalVariable { ty, .. } => ty.clone(),
240 Self::StructFieldAccess { base, name } => match base.ty(ctx) {
241 Type::Struct { fields, .. } => fields[name].clone(),
242 _ => unreachable!(),
243 },
244 Self::ArrayIndex { array, .. } => array.ty(ctx),
245 Self::Cast { to, .. } => to.clone(),
246 Self::CodeBlock(sub) => sub.last().map_or(Type::Void, |e| e.ty(ctx)),
247 Self::BuiltinFunctionCall { function, .. } => match function.ty() {
248 Type::Function { return_type, .. } => *return_type,
249 _ => unreachable!(),
250 },
251 Self::CallBackCall { callback, .. } => {
252 if let Type::Callback { return_type, .. } = ctx.property_ty(callback) {
253 return_type.as_ref().map_or(Type::Void, |x| (**x).clone())
254 } else {
255 Type::Invalid
256 }
257 }
258 Self::ExtraBuiltinFunctionCall { return_ty, .. } => return_ty.clone(),
259 Self::PropertyAssignment { .. } => Type::Void,
260 Self::ModelDataAssignment { .. } => Type::Void,
261 Self::ArrayIndexAssignment { .. } => Type::Void,
262 Self::BinaryExpression { lhs, rhs: _, op } => {
263 if crate::expression_tree::operator_class(*op) != OperatorClass::ArithmeticOp {
264 Type::Bool
265 } else {
266 lhs.ty(ctx)
267 }
268 }
269 Self::UnaryOp { sub, .. } => sub.ty(ctx),
270 Self::ImageReference { .. } => Type::Image,
271 Self::Condition { true_expr, .. } => true_expr.ty(ctx),
272 Self::Array { element_ty, .. } => Type::Array(element_ty.clone().into()),
273 Self::Struct { ty, .. } => ty.clone(),
274 Self::EasingCurve(_) => Type::Easing,
275 Self::LinearGradient { .. } => Type::Brush,
276 Self::EnumerationValue(e) => Type::Enumeration(e.enumeration.clone()),
277 Self::ReturnStatement(_) => Type::Invalid,
278 Self::LayoutCacheAccess { .. } => Type::Array(Type::Int32.into()),
279 Self::BoxLayoutFunction { sub_expression, .. } => sub_expression.ty(ctx),
280 Self::ComputeDialogLayoutCells { .. } => {
281 Type::Array(super::lower_expression::grid_layout_cell_data_ty().into())
282 }
283 }
284 }
285
286 fn visit(&self, mut visitor: impl FnMut(&Self)) {
288 match self {
289 Expression::StringLiteral(_) => {}
290 Expression::NumberLiteral(_) => {}
291 Expression::BoolLiteral(_) => {}
292 Expression::PropertyReference(_) => {}
293 Expression::FunctionParameterReference { .. } => {}
294 Expression::StoreLocalVariable { value, .. } => visitor(&value),
295 Expression::ReadLocalVariable { .. } => {}
296 Expression::StructFieldAccess { base, .. } => visitor(&base),
297 Expression::ArrayIndex { array, index } => {
298 (visitor(array), visitor(index));
299 }
300 Expression::Cast { from, .. } => visitor(from),
301 Expression::CodeBlock(b) => b.iter().for_each(visitor),
302 Expression::BuiltinFunctionCall { arguments, .. } => arguments.iter().for_each(visitor),
303 Expression::CallBackCall { arguments, .. } => arguments.iter().for_each(visitor),
304 Expression::ExtraBuiltinFunctionCall { arguments, .. } => {
305 arguments.iter().for_each(visitor)
306 }
307 Expression::PropertyAssignment { value, .. } => visitor(&value),
308 Expression::ModelDataAssignment { value, .. } => visitor(&value),
309 Expression::ArrayIndexAssignment { array, index, value } => {
310 (visitor(array), visitor(index), visitor(value));
311 }
312 Expression::BinaryExpression { lhs, rhs, .. } => {
313 (visitor(lhs), visitor(rhs));
314 }
315 Expression::UnaryOp { sub, .. } => {
316 visitor(sub);
317 }
318 Expression::ImageReference { .. } => {}
319 Expression::Condition { condition, true_expr, false_expr } => {
320 visitor(&condition);
321 visitor(&true_expr);
322 visitor(&false_expr);
323 }
324 Expression::Array { values, .. } => values.iter().for_each(visitor),
325 Expression::Struct { values, .. } => values.values().for_each(visitor),
326 Expression::EasingCurve(_) => {}
327 Expression::LinearGradient { angle, stops } => {
328 visitor(&angle);
329 for (a, b) in stops {
330 visitor(a);
331 visitor(b);
332 }
333 }
334 Expression::EnumerationValue(_) => {}
335 Expression::ReturnStatement(_) => {}
336 Expression::LayoutCacheAccess { repeater_index, .. } => {
337 if let Some(repeater_index) = repeater_index {
338 visitor(&repeater_index);
339 }
340 }
341 Expression::BoxLayoutFunction { elements, sub_expression, .. } => {
342 visitor(&sub_expression);
343 elements.iter().filter_map(|x| x.as_ref().left()).for_each(visitor);
344 }
345 Expression::ComputeDialogLayoutCells { roles, unsorted_cells, .. } => {
346 visitor(&roles);
347 visitor(&unsorted_cells);
348 }
349 }
350 }
351
352 pub fn visit_recursive(&self, visitor: &mut dyn FnMut(&Self)) {
354 visitor(self);
355 self.visit(|e| e.visit_recursive(visitor));
356 }
357}
358
359pub trait TypeResolutionContext {
360 fn property_ty(&self, _: &PropertyReference) -> &Type;
361 fn arg_type(&self, _index: usize) -> &Type {
363 unimplemented!()
364 }
365}
366
367#[derive(Clone, Copy)]
368pub struct ParentCtx<'a, T> {
369 pub ctx: &'a EvaluationContext<'a, T>,
370 pub repeater_index: Option<usize>,
372}
373
374impl<'a, T> ParentCtx<'a, T> {
375 pub fn new(ctx: &'a EvaluationContext<'a, T>, repeater_index: Option<usize>) -> Self {
376 Self { ctx, repeater_index }
377 }
378}
379
380#[derive(Clone)]
381pub struct EvaluationContext<'a, T> {
382 pub public_component: &'a super::PublicComponent,
383 pub current_sub_component: Option<&'a super::SubComponent>,
384 pub current_global: Option<&'a super::GlobalComponent>,
385 pub generator_state: T,
388 pub parent: Option<ParentCtx<'a, T>>,
390
391 pub argument_types: &'a [Type],
393}
394
395impl<'a, T> EvaluationContext<'a, T> {
396 pub fn new_sub_component(
397 public_component: &'a super::PublicComponent,
398 sub_component: &'a super::SubComponent,
399 generator_state: T,
400 parent: Option<ParentCtx<'a, T>>,
401 ) -> Self {
402 Self {
409 public_component,
410 current_sub_component: Some(sub_component),
411 current_global: None,
412 generator_state,
413 parent,
414 argument_types: &[],
415 }
416 }
417}
418
419impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
420 fn property_ty(&self, prop: &PropertyReference) -> &Type {
421 match prop {
422 PropertyReference::Local { sub_component_path, property_index } => {
423 if let Some(mut sub_component) = self.current_sub_component {
424 for i in sub_component_path {
425 sub_component = &sub_component.sub_components[*i].ty;
426 }
427 &sub_component.properties[*property_index].ty
428 } else if let Some(current_global) = self.current_global {
429 ¤t_global.properties[*property_index].ty
430 } else {
431 unreachable!()
432 }
433 }
434 PropertyReference::InNativeItem { sub_component_path, item_index, prop_name } => {
435 if prop_name == "elements" {
436 return &Type::PathData;
438 }
439
440 let mut sub_component = self.current_sub_component.unwrap();
441 for i in sub_component_path {
442 sub_component = &sub_component.sub_components[*i].ty;
443 }
444 sub_component.items[*item_index].ty.lookup_property(prop_name).unwrap()
445 }
446 PropertyReference::InParent { level, parent_reference } => {
447 let mut ctx = self;
448 for _ in 0..level.get() {
449 ctx = ctx.parent.as_ref().unwrap().ctx;
450 }
451 ctx.property_ty(parent_reference)
452 }
453 PropertyReference::Global { global_index, property_index } => {
454 &self.public_component.globals[*global_index].properties[*property_index].ty
455 }
456 }
457 }
458
459 fn arg_type(&self, index: usize) -> &Type {
460 &self.argument_types[index]
461 }
462}