1use super::{
5 GlobalIdx, PropertyReference, RepeatedElementIdx, SubComponentIdx, SubComponentInstanceIdx,
6};
7use crate::expression_tree::{BuiltinFunction, MinMaxOp, OperatorClass};
8use crate::langtype::Type;
9use crate::layout::Orientation;
10use core::num::NonZeroUsize;
11use itertools::Either;
12use smol_str::SmolStr;
13use std::collections::BTreeMap;
14use std::rc::Rc;
15
16#[derive(Debug, Clone)]
17pub enum Expression {
18 StringLiteral(SmolStr),
20 NumberLiteral(f64),
22 BoolLiteral(bool),
24
25 PropertyReference(PropertyReference),
27
28 FunctionParameterReference {
30 index: usize,
31 },
33
34 StoreLocalVariable {
36 name: SmolStr,
37 value: Box<Expression>,
38 },
39
40 ReadLocalVariable {
43 name: SmolStr,
44 ty: Type,
45 },
46
47 StructFieldAccess {
49 base: Box<Expression>,
51 name: SmolStr,
52 },
53
54 ArrayIndex {
56 array: Box<Expression>,
58 index: Box<Expression>,
59 },
60
61 Cast {
63 from: Box<Expression>,
64 to: Type,
65 },
66
67 CodeBlock(Vec<Expression>),
69
70 BuiltinFunctionCall {
72 function: BuiltinFunction,
73 arguments: Vec<Expression>,
74 },
75 CallBackCall {
76 callback: PropertyReference,
77 arguments: Vec<Expression>,
78 },
79 FunctionCall {
80 function: PropertyReference,
81 arguments: Vec<Expression>,
82 },
83 ItemMemberFunctionCall {
84 function: PropertyReference,
85 },
86
87 ExtraBuiltinFunctionCall {
90 return_ty: Type,
91 function: String,
92 arguments: Vec<Expression>,
93 },
94
95 PropertyAssignment {
97 property: PropertyReference,
98 value: Box<Expression>,
99 },
100 ModelDataAssignment {
102 level: usize,
104 value: Box<Expression>,
105 },
106 ArrayIndexAssignment {
108 array: Box<Expression>,
109 index: Box<Expression>,
110 value: Box<Expression>,
111 },
112
113 BinaryExpression {
114 lhs: Box<Expression>,
115 rhs: Box<Expression>,
116 op: char,
118 },
119
120 UnaryOp {
121 sub: Box<Expression>,
122 op: char,
124 },
125
126 ImageReference {
127 resource_ref: crate::expression_tree::ImageReference,
128 nine_slice: Option<[u16; 4]>,
129 },
130
131 Condition {
132 condition: Box<Expression>,
133 true_expr: Box<Expression>,
134 false_expr: Box<Expression>,
135 },
136
137 Array {
138 element_ty: Type,
139 values: Vec<Expression>,
140 as_model: bool,
142 },
143 Struct {
144 ty: Rc<crate::langtype::Struct>,
145 values: BTreeMap<SmolStr, Expression>,
146 },
147
148 EasingCurve(crate::expression_tree::EasingCurve),
149
150 LinearGradient {
151 angle: Box<Expression>,
152 stops: Vec<(Expression, Expression)>,
154 },
155
156 RadialGradient {
157 stops: Vec<(Expression, Expression)>,
159 },
160
161 ConicGradient {
162 stops: Vec<(Expression, Expression)>,
164 },
165
166 EnumerationValue(crate::langtype::EnumerationValue),
167
168 LayoutCacheAccess {
169 layout_cache_prop: PropertyReference,
170 index: usize,
171 repeater_index: Option<Box<Expression>>,
174 },
175 BoxLayoutFunction {
178 cells_variable: String,
180 repeater_indices: Option<SmolStr>,
182 elements: Vec<Either<Expression, RepeatedElementIdx>>,
184 orientation: Orientation,
185 sub_expression: Box<Expression>,
186 },
187
188 ComputeDialogLayoutCells {
189 cells_variable: String,
191 roles: Box<Expression>,
192 unsorted_cells: Box<Expression>,
194 },
195
196 MinMax {
197 ty: Type,
198 op: MinMaxOp,
199 lhs: Box<Expression>,
200 rhs: Box<Expression>,
201 },
202
203 EmptyComponentFactory,
204
205 TranslationReference {
207 format_args: Box<Expression>,
209 string_index: usize,
210 plural: Option<Box<Expression>>,
212 },
213}
214
215impl Expression {
216 pub fn default_value_for_type(ty: &Type) -> Option<Self> {
217 Some(match ty {
218 Type::Invalid
219 | Type::Callback { .. }
220 | Type::Function { .. }
221 | Type::Void
222 | Type::InferredProperty
223 | Type::InferredCallback
224 | Type::ElementReference
225 | Type::LayoutCache => return None,
226 Type::Float32
227 | Type::Duration
228 | Type::Int32
229 | Type::Angle
230 | Type::PhysicalLength
231 | Type::LogicalLength
232 | Type::Rem
233 | Type::UnitProduct(_) => Expression::NumberLiteral(0.),
234 Type::Percent => Expression::NumberLiteral(1.),
235 Type::String => Expression::StringLiteral(SmolStr::default()),
236 Type::Color => {
237 Expression::Cast { from: Box::new(Expression::NumberLiteral(0.)), to: ty.clone() }
238 }
239 Type::Image => Expression::ImageReference {
240 resource_ref: crate::expression_tree::ImageReference::None,
241 nine_slice: None,
242 },
243 Type::Bool => Expression::BoolLiteral(false),
244 Type::Model => return None,
245 Type::PathData => return None,
246 Type::Array(element_ty) => Expression::Array {
247 element_ty: (**element_ty).clone(),
248 values: vec![],
249 as_model: true,
250 },
251 Type::Struct(s) => Expression::Struct {
252 ty: s.clone(),
253 values: s
254 .fields
255 .iter()
256 .map(|(k, v)| Some((k.clone(), Expression::default_value_for_type(v)?)))
257 .collect::<Option<_>>()?,
258 },
259 Type::Easing => Expression::EasingCurve(crate::expression_tree::EasingCurve::default()),
260 Type::Brush => Expression::Cast {
261 from: Box::new(Expression::default_value_for_type(&Type::Color)?),
262 to: Type::Brush,
263 },
264 Type::Enumeration(enumeration) => {
265 Expression::EnumerationValue(enumeration.clone().default_value())
266 }
267 Type::ComponentFactory => Expression::EmptyComponentFactory,
268 })
269 }
270
271 pub fn ty(&self, ctx: &dyn TypeResolutionContext) -> Type {
272 match self {
273 Self::StringLiteral(_) => Type::String,
274 Self::NumberLiteral(_) => Type::Float32,
275 Self::BoolLiteral(_) => Type::Bool,
276 Self::PropertyReference(prop) => ctx.property_ty(prop).clone(),
277 Self::FunctionParameterReference { index } => ctx.arg_type(*index).clone(),
278 Self::StoreLocalVariable { .. } => Type::Void,
279 Self::ReadLocalVariable { ty, .. } => ty.clone(),
280 Self::StructFieldAccess { base, name } => match base.ty(ctx) {
281 Type::Struct(s) => s.fields[name].clone(),
282 _ => unreachable!(),
283 },
284 Self::ArrayIndex { array, .. } => match array.ty(ctx) {
285 Type::Array(ty) => (*ty).clone(),
286 _ => unreachable!(),
287 },
288 Self::Cast { to, .. } => to.clone(),
289 Self::CodeBlock(sub) => sub.last().map_or(Type::Void, |e| e.ty(ctx)),
290 Self::BuiltinFunctionCall { function, .. } => function.ty().return_type.clone(),
291 Self::CallBackCall { callback, .. } => match ctx.property_ty(callback) {
292 Type::Callback(callback) => callback.return_type.clone(),
293 _ => Type::Invalid,
294 },
295 Self::FunctionCall { function, .. } => ctx.property_ty(function).clone(),
296 Self::ItemMemberFunctionCall { function } => match ctx.property_ty(function) {
297 Type::Function(function) => function.return_type.clone(),
298 _ => Type::Invalid,
299 },
300 Self::ExtraBuiltinFunctionCall { return_ty, .. } => return_ty.clone(),
301 Self::PropertyAssignment { .. } => Type::Void,
302 Self::ModelDataAssignment { .. } => Type::Void,
303 Self::ArrayIndexAssignment { .. } => Type::Void,
304 Self::BinaryExpression { lhs, rhs: _, op } => {
305 if crate::expression_tree::operator_class(*op) != OperatorClass::ArithmeticOp {
306 Type::Bool
307 } else {
308 lhs.ty(ctx)
309 }
310 }
311 Self::UnaryOp { sub, .. } => sub.ty(ctx),
312 Self::ImageReference { .. } => Type::Image,
313 Self::Condition { false_expr, .. } => false_expr.ty(ctx),
314 Self::Array { element_ty, .. } => Type::Array(element_ty.clone().into()),
315 Self::Struct { ty, .. } => ty.clone().into(),
316 Self::EasingCurve(_) => Type::Easing,
317 Self::LinearGradient { .. } => Type::Brush,
318 Self::RadialGradient { .. } => Type::Brush,
319 Self::ConicGradient { .. } => Type::Brush,
320 Self::EnumerationValue(e) => Type::Enumeration(e.enumeration.clone()),
321 Self::LayoutCacheAccess { .. } => Type::LogicalLength,
322 Self::BoxLayoutFunction { sub_expression, .. } => sub_expression.ty(ctx),
323 Self::ComputeDialogLayoutCells { .. } => {
324 Type::Array(super::lower_expression::grid_layout_cell_data_ty().into())
325 }
326 Self::MinMax { ty, .. } => ty.clone(),
327 Self::EmptyComponentFactory => Type::ComponentFactory,
328 Self::TranslationReference { .. } => Type::String,
329 }
330 }
331}
332
333macro_rules! visit_impl {
334 ($self:ident, $visitor:ident, $as_ref:ident, $iter:ident, $values:ident) => {
335 match $self {
336 Expression::StringLiteral(_) => {}
337 Expression::NumberLiteral(_) => {}
338 Expression::BoolLiteral(_) => {}
339 Expression::PropertyReference(_) => {}
340 Expression::FunctionParameterReference { .. } => {}
341 Expression::StoreLocalVariable { value, .. } => $visitor(value),
342 Expression::ReadLocalVariable { .. } => {}
343 Expression::StructFieldAccess { base, .. } => $visitor(base),
344 Expression::ArrayIndex { array, index } => {
345 $visitor(array);
346 $visitor(index);
347 }
348 Expression::Cast { from, .. } => $visitor(from),
349 Expression::CodeBlock(b) => b.$iter().for_each($visitor),
350 Expression::BuiltinFunctionCall { arguments, .. }
351 | Expression::CallBackCall { arguments, .. }
352 | Expression::FunctionCall { arguments, .. } => arguments.$iter().for_each($visitor),
353 Expression::ItemMemberFunctionCall { function: _ } => {}
354 Expression::ExtraBuiltinFunctionCall { arguments, .. } => {
355 arguments.$iter().for_each($visitor)
356 }
357 Expression::PropertyAssignment { value, .. } => $visitor(value),
358 Expression::ModelDataAssignment { value, .. } => $visitor(value),
359 Expression::ArrayIndexAssignment { array, index, value } => {
360 $visitor(array);
361 $visitor(index);
362 $visitor(value);
363 }
364 Expression::BinaryExpression { lhs, rhs, .. } => {
365 $visitor(lhs);
366 $visitor(rhs);
367 }
368 Expression::UnaryOp { sub, .. } => {
369 $visitor(sub);
370 }
371 Expression::ImageReference { .. } => {}
372 Expression::Condition { condition, true_expr, false_expr } => {
373 $visitor(condition);
374 $visitor(true_expr);
375 $visitor(false_expr);
376 }
377 Expression::Array { values, .. } => values.$iter().for_each($visitor),
378 Expression::Struct { values, .. } => values.$values().for_each($visitor),
379 Expression::EasingCurve(_) => {}
380 Expression::LinearGradient { angle, stops } => {
381 $visitor(angle);
382 for (a, b) in stops {
383 $visitor(a);
384 $visitor(b);
385 }
386 }
387 Expression::RadialGradient { stops } => {
388 for (a, b) in stops {
389 $visitor(a);
390 $visitor(b);
391 }
392 }
393 Expression::ConicGradient { stops } => {
394 for (a, b) in stops {
395 $visitor(a);
396 $visitor(b);
397 }
398 }
399 Expression::EnumerationValue(_) => {}
400 Expression::LayoutCacheAccess { repeater_index, .. } => {
401 if let Some(repeater_index) = repeater_index {
402 $visitor(repeater_index);
403 }
404 }
405 Expression::BoxLayoutFunction { elements, sub_expression, .. } => {
406 $visitor(sub_expression);
407 elements.$iter().filter_map(|x| x.$as_ref().left()).for_each($visitor);
408 }
409 Expression::ComputeDialogLayoutCells { roles, unsorted_cells, .. } => {
410 $visitor(roles);
411 $visitor(unsorted_cells);
412 }
413 Expression::MinMax { ty: _, op: _, lhs, rhs } => {
414 $visitor(lhs);
415 $visitor(rhs);
416 }
417 Expression::EmptyComponentFactory => {}
418 Expression::TranslationReference { format_args, plural, string_index: _ } => {
419 $visitor(format_args);
420 if let Some(plural) = plural {
421 $visitor(plural);
422 }
423 }
424 }
425 };
426}
427
428impl Expression {
429 pub fn visit(&self, mut visitor: impl FnMut(&Self)) {
431 visit_impl!(self, visitor, as_ref, iter, values)
432 }
433
434 pub fn visit_mut(&mut self, mut visitor: impl FnMut(&mut Self)) {
436 visit_impl!(self, visitor, as_mut, iter_mut, values_mut)
437 }
438
439 pub fn visit_recursive(&self, visitor: &mut dyn FnMut(&Self)) {
441 visitor(self);
442 self.visit(|e| e.visit_recursive(visitor));
443 }
444
445 pub fn visit_property_references(
446 &self,
447 ctx: &EvaluationContext,
448 visitor: &mut dyn FnMut(&PropertyReference, &EvaluationContext),
449 ) {
450 self.visit_recursive(&mut |expr| {
451 let p = match expr {
452 Expression::PropertyReference(p) => p,
453 Expression::CallBackCall { callback, .. } => callback,
454 Expression::PropertyAssignment { property, .. } => {
455 if let Some((a, map)) = &ctx.property_info(property).animation {
456 let ctx2 = map.map_context(ctx);
457 a.visit_property_references(&ctx2, visitor);
458 }
459 property
460 }
461 Expression::ModelDataAssignment { .. } => return,
463 Expression::LayoutCacheAccess { layout_cache_prop, .. } => layout_cache_prop,
464 _ => return,
465 };
466 visitor(p, ctx)
467 });
468 }
469}
470
471pub trait TypeResolutionContext {
472 fn property_ty(&self, _: &PropertyReference) -> &Type;
476 fn arg_type(&self, _index: usize) -> &Type {
478 unimplemented!()
479 }
480}
481
482pub struct ParentCtx<'a, T = ()> {
483 pub ctx: &'a EvaluationContext<'a, T>,
484 pub repeater_index: Option<RepeatedElementIdx>,
486}
487
488impl<T> Clone for ParentCtx<'_, T> {
489 fn clone(&self) -> Self {
490 *self
491 }
492}
493impl<T> Copy for ParentCtx<'_, T> {}
494
495impl<'a, T> ParentCtx<'a, T> {
496 pub fn new(
497 ctx: &'a EvaluationContext<'a, T>,
498 repeater_index: Option<RepeatedElementIdx>,
499 ) -> Self {
500 Self { ctx, repeater_index }
501 }
502}
503
504#[derive(Clone)]
505pub struct EvaluationContext<'a, T = ()> {
506 pub compilation_unit: &'a super::CompilationUnit,
507 pub current_sub_component: Option<SubComponentIdx>,
508 pub current_global: Option<GlobalIdx>,
509 pub generator_state: T,
510 pub parent: Option<ParentCtx<'a, T>>,
512
513 pub argument_types: &'a [Type],
515}
516
517impl<'a, T> EvaluationContext<'a, T> {
518 pub fn new_sub_component(
519 compilation_unit: &'a super::CompilationUnit,
520 sub_component: SubComponentIdx,
521 generator_state: T,
522 parent: Option<ParentCtx<'a, T>>,
523 ) -> Self {
524 Self {
525 compilation_unit,
526 current_sub_component: Some(sub_component),
527 current_global: None,
528 generator_state,
529 parent,
530 argument_types: &[],
531 }
532 }
533
534 pub fn new_global(
535 compilation_unit: &'a super::CompilationUnit,
536 global: GlobalIdx,
537 generator_state: T,
538 ) -> Self {
539 Self {
540 compilation_unit,
541 current_sub_component: None,
542 current_global: Some(global),
543 generator_state,
544 parent: None,
545 argument_types: &[],
546 }
547 }
548
549 pub(crate) fn property_info<'b>(&'b self, prop: &PropertyReference) -> PropertyInfoResult<'b> {
550 fn match_in_sub_component<'b>(
551 cu: &'b super::CompilationUnit,
552 sc: &'b super::SubComponent,
553 prop: &PropertyReference,
554 map: ContextMap,
555 ) -> PropertyInfoResult<'b> {
556 let property_decl = || {
557 if let PropertyReference::Local { property_index, sub_component_path } = &prop {
558 let mut sc = sc;
559 for i in sub_component_path {
560 sc = &cu.sub_components[sc.sub_components[*i].ty];
561 }
562 Some(&sc.properties[*property_index])
563 } else {
564 None
565 }
566 };
567 let animation = sc.animations.get(prop).map(|a| (a, map.clone()));
568 let analysis = sc.prop_analysis.get(prop);
569 if let Some(a) = &analysis {
570 if let Some(init) = a.property_init {
571 return PropertyInfoResult {
572 analysis: Some(&a.analysis),
573 binding: Some((&sc.property_init[init].1, map)),
574 animation,
575 property_decl: property_decl(),
576 };
577 }
578 }
579 let apply_analysis = |mut r: PropertyInfoResult<'b>| -> PropertyInfoResult<'b> {
580 if animation.is_some() {
581 r.animation = animation
582 };
583 if let Some(a) = analysis {
584 r.analysis = Some(&a.analysis);
585 }
586 r
587 };
588 match prop {
589 PropertyReference::Local { sub_component_path, property_index } => {
590 if !sub_component_path.is_empty() {
591 let prop2 = PropertyReference::Local {
592 sub_component_path: sub_component_path[1..].to_vec(),
593 property_index: *property_index,
594 };
595 let idx = sub_component_path[0];
596 return apply_analysis(match_in_sub_component(
597 cu,
598 &cu.sub_components[sc.sub_components[idx].ty],
599 &prop2,
600 map.deeper_in_sub_component(idx),
601 ));
602 }
603 }
604 PropertyReference::InNativeItem { item_index, sub_component_path, prop_name } => {
605 if !sub_component_path.is_empty() {
606 let prop2 = PropertyReference::InNativeItem {
607 sub_component_path: sub_component_path[1..].to_vec(),
608 prop_name: prop_name.clone(),
609 item_index: *item_index,
610 };
611 let idx = sub_component_path[0];
612 return apply_analysis(match_in_sub_component(
613 cu,
614 &cu.sub_components[sc.sub_components[idx].ty],
615 &prop2,
616 map.deeper_in_sub_component(idx),
617 ));
618 }
619 }
620 _ => unreachable!(),
621 }
622 apply_analysis(PropertyInfoResult {
623 property_decl: property_decl(),
624 ..Default::default()
625 })
626 }
627
628 match prop {
629 PropertyReference::Local { property_index, .. } => {
630 if let Some(g) = self.current_global() {
631 PropertyInfoResult {
632 analysis: Some(&g.prop_analysis[*property_index]),
633 binding: g.init_values[*property_index]
634 .as_ref()
635 .map(|b| (b, ContextMap::Identity)),
636 animation: None,
637 property_decl: Some(&g.properties[*property_index]),
638 }
639 } else if let Some(sc) = self.current_sub_component() {
640 match_in_sub_component(self.compilation_unit, sc, prop, ContextMap::Identity)
641 } else {
642 unreachable!()
643 }
644 }
645 PropertyReference::InNativeItem { .. } => match_in_sub_component(
646 self.compilation_unit,
647 self.current_sub_component().unwrap(),
648 prop,
649 ContextMap::Identity,
650 ),
651 PropertyReference::Global { global_index, property_index } => {
652 let g = &self.compilation_unit.globals[*global_index];
653 PropertyInfoResult {
654 analysis: Some(&g.prop_analysis[*property_index]),
655 animation: None,
656 binding: g
657 .init_values
658 .get(*property_index)
659 .and_then(Option::as_ref)
660 .map(|b| (b, ContextMap::InGlobal(*global_index))),
661 property_decl: Some(&g.properties[*property_index]),
662 }
663 }
664 PropertyReference::InParent { level, parent_reference } => {
665 let mut ctx = self;
666 for _ in 0..level.get() {
667 ctx = ctx.parent.as_ref().unwrap().ctx;
668 }
669 let mut ret = ctx.property_info(parent_reference);
670 let map_mapping = |m: &mut ContextMap| match m {
671 ContextMap::Identity => {
672 *m = ContextMap::InSubElement {
673 path: Default::default(),
674 parent: level.get(),
675 }
676 }
677 ContextMap::InSubElement { parent, .. } => {
678 *parent += level.get();
679 }
680 _ => (),
681 };
682 if let Some(b) = &mut ret.binding {
683 map_mapping(&mut b.1);
684 }
685 if let Some(a) = &mut ret.animation {
686 map_mapping(&mut a.1);
687 }
688 ret
689 }
690 PropertyReference::Function { .. } | PropertyReference::GlobalFunction { .. } => {
691 unreachable!()
692 }
693 }
694 }
695
696 pub fn current_sub_component(&self) -> Option<&super::SubComponent> {
697 self.current_sub_component.and_then(|i| self.compilation_unit.sub_components.get(i))
698 }
699
700 pub fn current_global(&self) -> Option<&super::GlobalComponent> {
701 self.current_global.and_then(|i| self.compilation_unit.globals.get(i))
702 }
703}
704
705impl<T> TypeResolutionContext for EvaluationContext<'_, T> {
706 fn property_ty(&self, prop: &PropertyReference) -> &Type {
707 match prop {
708 PropertyReference::Local { sub_component_path, property_index } => {
709 if let Some(mut sub_component) = self.current_sub_component() {
710 for i in sub_component_path {
711 sub_component = &self.compilation_unit.sub_components
712 [sub_component.sub_components[*i].ty];
713 }
714 &sub_component.properties[*property_index].ty
715 } else if let Some(current_global) = self.current_global() {
716 ¤t_global.properties[*property_index].ty
717 } else {
718 unreachable!()
719 }
720 }
721 PropertyReference::InNativeItem { sub_component_path, item_index, prop_name } => {
722 if prop_name == "elements" {
723 return &Type::PathData;
725 }
726
727 let mut sub_component = self.current_sub_component().unwrap();
728 for i in sub_component_path {
729 sub_component =
730 &self.compilation_unit.sub_components[sub_component.sub_components[*i].ty];
731 }
732
733 sub_component.items[*item_index].ty.lookup_property(prop_name).unwrap()
734 }
735 PropertyReference::InParent { level, parent_reference } => {
736 let mut ctx = self;
737 for _ in 0..level.get() {
738 ctx = ctx.parent.as_ref().unwrap().ctx;
739 }
740 ctx.property_ty(parent_reference)
741 }
742 PropertyReference::Global { global_index, property_index } => {
743 &self.compilation_unit.globals[*global_index].properties[*property_index].ty
744 }
745 PropertyReference::Function { sub_component_path, function_index } => {
746 if let Some(mut sub_component) = self.current_sub_component() {
747 for i in sub_component_path {
748 sub_component = &self.compilation_unit.sub_components
749 [sub_component.sub_components[*i].ty];
750 }
751 &sub_component.functions[*function_index].ret_ty
752 } else if let Some(current_global) = self.current_global() {
753 ¤t_global.functions[*function_index].ret_ty
754 } else {
755 unreachable!()
756 }
757 }
758 PropertyReference::GlobalFunction { global_index, function_index } => {
759 &self.compilation_unit.globals[*global_index].functions[*function_index].ret_ty
760 }
761 }
762 }
763
764 fn arg_type(&self, index: usize) -> &Type {
765 &self.argument_types[index]
766 }
767}
768
769#[derive(Default, Debug)]
770pub(crate) struct PropertyInfoResult<'a> {
771 pub analysis: Option<&'a crate::object_tree::PropertyAnalysis>,
772 pub binding: Option<(&'a super::BindingExpression, ContextMap)>,
773 pub animation: Option<(&'a Expression, ContextMap)>,
774 pub property_decl: Option<&'a super::Property>,
775}
776
777#[derive(Debug, Clone)]
781pub(crate) enum ContextMap {
782 Identity,
783 InSubElement { path: Vec<SubComponentInstanceIdx>, parent: usize },
784 InGlobal(GlobalIdx),
785}
786
787impl ContextMap {
788 fn deeper_in_sub_component(self, sub: SubComponentInstanceIdx) -> Self {
789 match self {
790 ContextMap::Identity => ContextMap::InSubElement { parent: 0, path: vec![sub] },
791 ContextMap::InSubElement { mut path, parent } => {
792 path.push(sub);
793 ContextMap::InSubElement { path, parent }
794 }
795 ContextMap::InGlobal(_) => panic!(),
796 }
797 }
798
799 pub fn map_property_reference(&self, p: &PropertyReference) -> PropertyReference {
800 match self {
801 ContextMap::Identity => p.clone(),
802 ContextMap::InSubElement { path, parent } => {
803 let map_sub_path = |sub_component_path: &[SubComponentInstanceIdx]| -> Vec<SubComponentInstanceIdx> {
804 path.iter().chain(sub_component_path.iter()).copied().collect()
805 };
806
807 let p2 = match p {
808 PropertyReference::Local { sub_component_path, property_index } => {
809 PropertyReference::Local {
810 sub_component_path: map_sub_path(sub_component_path),
811 property_index: *property_index,
812 }
813 }
814 PropertyReference::Function { sub_component_path, function_index } => {
815 PropertyReference::Function {
816 sub_component_path: map_sub_path(sub_component_path),
817 function_index: *function_index,
818 }
819 }
820 PropertyReference::InNativeItem {
821 sub_component_path,
822 item_index,
823 prop_name,
824 } => PropertyReference::InNativeItem {
825 item_index: *item_index,
826 prop_name: prop_name.clone(),
827 sub_component_path: map_sub_path(sub_component_path),
828 },
829 PropertyReference::InParent { level, parent_reference } => {
830 return PropertyReference::InParent {
831 level: (parent + level.get()).try_into().unwrap(),
832 parent_reference: parent_reference.clone(),
833 }
834 }
835 PropertyReference::Global { .. } | PropertyReference::GlobalFunction { .. } => {
836 return p.clone()
837 }
838 };
839 if let Some(level) = NonZeroUsize::new(*parent) {
840 PropertyReference::InParent { level, parent_reference: p2.into() }
841 } else {
842 p2
843 }
844 }
845 ContextMap::InGlobal(global_index) => match p {
846 PropertyReference::Local { sub_component_path, property_index } => {
847 assert!(sub_component_path.is_empty());
848 PropertyReference::Global {
849 global_index: *global_index,
850 property_index: *property_index,
851 }
852 }
853 g @ PropertyReference::Global { .. } => g.clone(),
854 _ => unreachable!(),
855 },
856 }
857 }
858
859 pub fn map_expression(&self, e: &mut Expression) {
860 match e {
861 Expression::PropertyReference(p)
862 | Expression::CallBackCall { callback: p, .. }
863 | Expression::PropertyAssignment { property: p, .. }
864 | Expression::LayoutCacheAccess { layout_cache_prop: p, .. } => {
865 *p = self.map_property_reference(p);
866 }
867 _ => (),
868 }
869 e.visit_mut(|e| self.map_expression(e))
870 }
871
872 pub fn map_context<'a>(&self, ctx: &EvaluationContext<'a>) -> EvaluationContext<'a> {
873 match self {
874 ContextMap::Identity => ctx.clone(),
875 ContextMap::InSubElement { path, parent } => {
876 let mut ctx = ctx;
877 for _ in 0..*parent {
878 ctx = ctx.parent.unwrap().ctx;
879 }
880 if path.is_empty() {
881 ctx.clone()
882 } else {
883 let mut e = ctx.current_sub_component.unwrap();
884 for i in path {
885 e = ctx.compilation_unit.sub_components[e].sub_components[*i].ty;
886 }
887 EvaluationContext::new_sub_component(ctx.compilation_unit, e, (), None)
888 }
889 }
890 ContextMap::InGlobal(g) => EvaluationContext::new_global(ctx.compilation_unit, *g, ()),
891 }
892 }
893}