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