1use super::{
5 GlobalIdx, GridLayoutRepeatedElement, LayoutRepeatedElement, LocalMemberIndex,
6 LocalMemberReference, MemberReference, RepeatedElementIdx, SubComponentIdx,
7 SubComponentInstanceIdx,
8};
9use crate::expression_tree::{BuiltinFunction, MinMaxOp, OperatorClass};
10use crate::langtype::{Keys, Type};
11use crate::layout::Orientation;
12use itertools::Either;
13use smol_str::SmolStr;
14use std::collections::BTreeMap;
15use std::rc::Rc;
16
17#[derive(Debug, Clone)]
18pub enum ArrayOutput {
19 Slice,
20 Model,
21 Vector,
22}
23
24#[derive(Debug, Clone)]
25pub enum Expression {
26 StringLiteral(SmolStr),
28 NumberLiteral(f64),
30 BoolLiteral(bool),
32
33 KeysLiteral(Keys),
35
36 PropertyReference(MemberReference),
38
39 FunctionParameterReference {
41 index: usize,
42 },
44
45 StoreLocalVariable {
47 name: SmolStr,
48 value: Box<Expression>,
49 },
50
51 ReadLocalVariable {
54 name: SmolStr,
55 ty: Type,
56 },
57
58 StructFieldAccess {
60 base: Box<Expression>,
62 name: SmolStr,
63 },
64
65 ArrayIndex {
67 array: Box<Expression>,
69 index: Box<Expression>,
70 },
71
72 Cast {
74 from: Box<Expression>,
75 to: Type,
76 },
77
78 CodeBlock(Vec<Expression>),
80
81 BuiltinFunctionCall {
83 function: BuiltinFunction,
84 arguments: Vec<Expression>,
85 },
86 CallBackCall {
87 callback: MemberReference,
88 arguments: Vec<Expression>,
89 },
90 FunctionCall {
91 function: MemberReference,
92 arguments: Vec<Expression>,
93 },
94 ItemMemberFunctionCall {
95 function: MemberReference,
96 },
97
98 ExtraBuiltinFunctionCall {
101 return_ty: Type,
102 function: String,
103 arguments: Vec<Expression>,
104 },
105
106 PropertyAssignment {
108 property: MemberReference,
109 value: Box<Expression>,
110 },
111 ModelDataAssignment {
113 level: usize,
115 value: Box<Expression>,
116 },
117 ArrayIndexAssignment {
119 array: Box<Expression>,
120 index: Box<Expression>,
121 value: Box<Expression>,
122 },
123 SliceIndexAssignment {
126 slice_name: SmolStr,
128 index: usize,
129 value: Box<Expression>,
130 },
131
132 BinaryExpression {
133 lhs: Box<Expression>,
134 rhs: Box<Expression>,
135 op: char,
137 },
138
139 UnaryOp {
140 sub: Box<Expression>,
141 op: char,
143 },
144
145 ImageReference {
146 resource_ref: crate::expression_tree::ImageReference,
147 nine_slice: Option<[u16; 4]>,
148 },
149
150 Condition {
151 condition: Box<Expression>,
152 true_expr: Box<Expression>,
153 false_expr: Box<Expression>,
154 },
155
156 Array {
157 element_ty: Type,
158 values: Vec<Expression>,
159 output: ArrayOutput,
161 },
162 Struct {
163 ty: Rc<crate::langtype::Struct>,
164 values: BTreeMap<SmolStr, Expression>,
165 },
166
167 EasingCurve(crate::expression_tree::EasingCurve),
168
169 LinearGradient {
170 angle: Box<Expression>,
171 stops: Vec<(Expression, Expression)>,
173 },
174
175 RadialGradient {
176 center: Option<(Box<Expression>, Box<Expression>)>,
179 radius: Option<Box<Expression>>,
182 stops: Vec<(Expression, Expression)>,
184 },
185
186 ConicGradient {
187 from_angle: Box<Expression>,
189 center: Option<(Box<Expression>, Box<Expression>)>,
192 stops: Vec<(Expression, Expression)>,
194 },
195
196 EnumerationValue(crate::langtype::EnumerationValue),
197
198 LayoutCacheAccess {
201 layout_cache_prop: MemberReference,
202 index: usize,
203 repeater_index: Option<Box<Expression>>,
204 entries_per_item: usize,
205 },
206 GridRepeaterCacheAccess {
209 layout_cache_prop: MemberReference,
210 index: usize,
211 repeater_index: Box<Expression>,
212 stride: Box<Expression>,
213 child_offset: usize,
214 inner_repeater_index: Option<Box<Expression>>,
215 entries_per_item: usize,
216 },
217 WithLayoutItemInfo {
220 cells_variable: String,
222 repeater_indices_var_name: Option<SmolStr>,
224 repeater_steps_var_name: Option<SmolStr>,
226 elements: Vec<Either<Expression, LayoutRepeatedElement>>,
228 orientation: Orientation,
229 sub_expression: Box<Expression>,
230 },
231 WithFlexboxLayoutItemInfo {
234 cells_h_variable: String,
236 cells_v_variable: String,
238 repeater_indices_var_name: Option<SmolStr>,
240 elements: Vec<Either<(Expression, Expression), LayoutRepeatedElement>>,
242 sub_expression: Box<Expression>,
243 },
244 SolveFlexboxLayoutWithMeasure {
258 data: Box<Expression>,
261 repeater_indices: Box<Expression>,
262 measure_cells: Vec<Either<(Expression, Expression), LayoutRepeatedElement>>,
263 default_cells: Vec<Either<(Expression, Expression), LayoutRepeatedElement>>,
264 },
265 WithGridInputData {
268 cells_variable: String,
270 repeater_indices_var_name: SmolStr,
272 repeater_steps_var_name: SmolStr,
274 elements: Vec<Either<Expression, GridLayoutRepeatedElement>>,
276 sub_expression: Box<Expression>,
277 },
278
279 MinMax {
280 ty: Type,
281 op: MinMaxOp,
282 lhs: Box<Expression>,
283 rhs: Box<Expression>,
284 },
285
286 EmptyComponentFactory,
287
288 EmptyDataTransfer,
289
290 TranslationReference {
292 format_args: Box<Expression>,
294 string_index: usize,
295 plural: Option<Box<Expression>>,
297 },
298}
299
300impl Expression {
301 pub fn default_value_for_type(ty: &Type) -> Option<Self> {
302 Some(match ty {
303 Type::Invalid
304 | Type::Callback { .. }
305 | Type::Function { .. }
306 | Type::Void
307 | Type::InferredProperty
308 | Type::InferredCallback
309 | Type::ElementReference
310 | Type::LayoutCache
311 | Type::ArrayOfU16 => return None,
312 Type::Float32
313 | Type::Duration
314 | Type::Int32
315 | Type::Angle
316 | Type::PhysicalLength
317 | Type::LogicalLength
318 | Type::Rem
319 | Type::UnitProduct(_) => Expression::NumberLiteral(0.),
320 Type::Percent => Expression::NumberLiteral(1.),
321 Type::String => Expression::StringLiteral(SmolStr::default()),
322 Type::Color => {
323 Expression::Cast { from: Box::new(Expression::NumberLiteral(0.)), to: ty.clone() }
324 }
325 Type::Image => Expression::ImageReference {
326 resource_ref: crate::expression_tree::ImageReference::None,
327 nine_slice: None,
328 },
329 Type::Bool => Expression::BoolLiteral(false),
330 Type::Model => return None,
331 Type::PathData => return None,
332 Type::Array(element_ty) => Expression::Array {
333 element_ty: (**element_ty).clone(),
334 values: Vec::new(),
335 output: ArrayOutput::Model,
336 },
337 Type::Struct(s) => Expression::Struct {
338 ty: s.clone(),
339 values: s
340 .fields
341 .iter()
342 .map(|(k, v)| Some((k.clone(), Expression::default_value_for_type(v)?)))
343 .collect::<Option<_>>()?,
344 },
345 Type::Easing => Expression::EasingCurve(crate::expression_tree::EasingCurve::default()),
346 Type::Brush => Expression::Cast {
347 from: Box::new(Expression::default_value_for_type(&Type::Color)?),
348 to: Type::Brush,
349 },
350 Type::Enumeration(enumeration) => {
351 Expression::EnumerationValue(enumeration.clone().default_value())
352 }
353 Type::Keys => Expression::KeysLiteral(Keys::default()),
354 Type::DataTransfer => Expression::EmptyDataTransfer,
355 Type::ComponentFactory => Expression::EmptyComponentFactory,
356 Type::StyledText => Expression::BuiltinFunctionCall {
357 function: BuiltinFunction::StringToStyledText,
358 arguments: vec![Expression::StringLiteral(SmolStr::default())],
359 },
360 })
361 }
362
363 pub fn ty(&self, ctx: &dyn TypeResolutionContext) -> Type {
364 match self {
365 Self::StringLiteral(_) => Type::String,
366 Self::NumberLiteral(_) => Type::Float32,
367 Self::BoolLiteral(_) => Type::Bool,
368 Self::PropertyReference(prop) => ctx.property_ty(prop).clone(),
369 Self::FunctionParameterReference { index } => ctx.arg_type(*index).clone(),
370 Self::StoreLocalVariable { .. } => Type::Void,
371 Self::ReadLocalVariable { ty, .. } => ty.clone(),
372 Self::StructFieldAccess { base, name } => match base.ty(ctx) {
373 Type::Struct(s) => s.fields[name].clone(),
374 _ => unreachable!(),
375 },
376 Self::ArrayIndex { array, .. } => match array.ty(ctx) {
377 Type::Array(ty) => (*ty).clone(),
378 _ => unreachable!(),
379 },
380 Self::Cast { to, .. } => to.clone(),
381 Self::CodeBlock(sub) => sub.last().map_or(Type::Void, |e| e.ty(ctx)),
382 Self::BuiltinFunctionCall { function, .. } => function.ty().return_type.clone(),
383 Self::CallBackCall { callback, .. } => match ctx.property_ty(callback) {
384 Type::Callback(callback) => callback.return_type.clone(),
385 _ => Type::Invalid,
386 },
387 Self::FunctionCall { function, .. } => ctx.property_ty(function).clone(),
388 Self::ItemMemberFunctionCall { function } => match ctx.property_ty(function) {
389 Type::Function(function) => function.return_type.clone(),
390 _ => Type::Invalid,
391 },
392 Self::ExtraBuiltinFunctionCall { return_ty, .. } => return_ty.clone(),
393 Self::PropertyAssignment { .. } => Type::Void,
394 Self::ModelDataAssignment { .. } => Type::Void,
395 Self::ArrayIndexAssignment { .. } => Type::Void,
396 Self::SliceIndexAssignment { .. } => Type::Void,
397 Self::BinaryExpression { lhs, rhs: _, op } => {
398 if crate::expression_tree::operator_class(*op) != OperatorClass::ArithmeticOp {
399 Type::Bool
400 } else {
401 lhs.ty(ctx)
402 }
403 }
404 Self::UnaryOp { sub, .. } => sub.ty(ctx),
405 Self::ImageReference { .. } => Type::Image,
406 Self::Condition { false_expr, .. } => false_expr.ty(ctx),
407 Self::Array { element_ty, .. } => Type::Array(element_ty.clone().into()),
408 Self::Struct { ty, .. } => ty.clone().into(),
409 Self::EasingCurve(_) => Type::Easing,
410 Self::LinearGradient { .. } => Type::Brush,
411 Self::RadialGradient { .. } => Type::Brush,
412 Self::ConicGradient { .. } => Type::Brush,
413 Self::EnumerationValue(e) => Type::Enumeration(e.enumeration.clone()),
414 Self::KeysLiteral(_) => Type::Keys,
415 Self::LayoutCacheAccess { .. } => Type::LogicalLength,
416 Self::GridRepeaterCacheAccess { .. } => Type::LogicalLength,
417 Self::WithLayoutItemInfo { sub_expression, .. } => sub_expression.ty(ctx),
418 Self::WithFlexboxLayoutItemInfo { sub_expression, .. } => sub_expression.ty(ctx),
419 Self::SolveFlexboxLayoutWithMeasure { .. } => Type::LayoutCache,
420 Self::WithGridInputData { sub_expression, .. } => sub_expression.ty(ctx),
421 Self::MinMax { ty, .. } => ty.clone(),
422 Self::EmptyComponentFactory => Type::ComponentFactory,
423 Self::EmptyDataTransfer => Type::DataTransfer,
424 Self::TranslationReference { .. } => Type::String,
425 }
426 }
427}
428
429macro_rules! visit_impl {
430 ($self:ident, $visitor:ident, $as_ref:ident, $iter:ident, $values:ident) => {
431 match $self {
432 Expression::StringLiteral(_) => {}
433 Expression::NumberLiteral(_) => {}
434 Expression::BoolLiteral(_) => {}
435 Expression::PropertyReference(_) => {}
436 Expression::FunctionParameterReference { .. } => {}
437 Expression::StoreLocalVariable { value, .. } => $visitor(value),
438 Expression::ReadLocalVariable { .. } => {}
439 Expression::StructFieldAccess { base, .. } => $visitor(base),
440 Expression::ArrayIndex { array, index } => {
441 $visitor(array);
442 $visitor(index);
443 }
444 Expression::Cast { from, .. } => $visitor(from),
445 Expression::CodeBlock(b) => b.$iter().for_each($visitor),
446 Expression::BuiltinFunctionCall { arguments, .. }
447 | Expression::CallBackCall { arguments, .. }
448 | Expression::FunctionCall { arguments, .. } => arguments.$iter().for_each($visitor),
449 Expression::ItemMemberFunctionCall { function: _ } => {}
450 Expression::ExtraBuiltinFunctionCall { arguments, .. } => {
451 arguments.$iter().for_each($visitor)
452 }
453 Expression::PropertyAssignment { value, .. } => $visitor(value),
454 Expression::ModelDataAssignment { value, .. } => $visitor(value),
455 Expression::ArrayIndexAssignment { array, index, value } => {
456 $visitor(array);
457 $visitor(index);
458 $visitor(value);
459 }
460 Expression::SliceIndexAssignment { value, .. } => {
461 $visitor(value);
462 }
463 Expression::BinaryExpression { lhs, rhs, .. } => {
464 $visitor(lhs);
465 $visitor(rhs);
466 }
467 Expression::UnaryOp { sub, .. } => {
468 $visitor(sub);
469 }
470 Expression::ImageReference { .. } => {}
471 Expression::Condition { condition, true_expr, false_expr } => {
472 $visitor(condition);
473 $visitor(true_expr);
474 $visitor(false_expr);
475 }
476 Expression::Array { values, .. } => values.$iter().for_each($visitor),
477 Expression::Struct { values, .. } => values.$values().for_each($visitor),
478 Expression::EasingCurve(_) => {}
479 Expression::LinearGradient { angle, stops } => {
480 $visitor(angle);
481 for (a, b) in stops {
482 $visitor(a);
483 $visitor(b);
484 }
485 }
486 Expression::RadialGradient { center, radius, stops } => {
487 if let Some((cx, cy)) = center {
488 $visitor(cx);
489 $visitor(cy);
490 }
491 if let Some(r) = radius {
492 $visitor(r);
493 }
494 for (a, b) in stops {
495 $visitor(a);
496 $visitor(b);
497 }
498 }
499 Expression::ConicGradient { from_angle, center, stops } => {
500 $visitor(from_angle);
501 if let Some((cx, cy)) = center {
502 $visitor(cx);
503 $visitor(cy);
504 }
505 for (a, b) in stops {
506 $visitor(a);
507 $visitor(b);
508 }
509 }
510 Expression::EnumerationValue(_) => {}
511 Expression::KeysLiteral(_) => {}
512 Expression::LayoutCacheAccess { repeater_index, .. } => {
513 if let Some(repeater_index) = repeater_index {
514 $visitor(repeater_index);
515 }
516 }
517 Expression::GridRepeaterCacheAccess {
518 repeater_index,
519 stride,
520 inner_repeater_index,
521 ..
522 } => {
523 $visitor(repeater_index);
524 $visitor(stride);
525 if let Some(inner_repeater_index) = inner_repeater_index {
526 $visitor(inner_repeater_index);
527 }
528 }
529 Expression::WithLayoutItemInfo { elements, sub_expression, .. } => {
530 $visitor(sub_expression);
531 elements.$iter().filter_map(|x| x.$as_ref().left()).for_each($visitor);
532 }
533 Expression::WithFlexboxLayoutItemInfo { elements, sub_expression, .. } => {
534 $visitor(sub_expression);
535 elements.$iter().filter_map(|x| x.$as_ref().left()).for_each(|(h, v)| {
536 $visitor(h);
537 $visitor(v);
538 });
539 }
540 Expression::SolveFlexboxLayoutWithMeasure {
541 data,
542 repeater_indices,
543 measure_cells,
544 default_cells,
545 } => {
546 $visitor(data);
547 $visitor(repeater_indices);
548 measure_cells.$iter().filter_map(|x| x.$as_ref().left()).for_each(|(h, v)| {
549 $visitor(h);
550 $visitor(v);
551 });
552 default_cells.$iter().filter_map(|x| x.$as_ref().left()).for_each(|(h, v)| {
553 $visitor(h);
554 $visitor(v);
555 });
556 }
557 Expression::WithGridInputData { elements, sub_expression, .. } => {
558 $visitor(sub_expression);
559 elements.$iter().filter_map(|x| x.$as_ref().left()).for_each($visitor);
560 }
561 Expression::MinMax { ty: _, op: _, lhs, rhs } => {
562 $visitor(lhs);
563 $visitor(rhs);
564 }
565 Expression::EmptyComponentFactory => {}
566 Expression::EmptyDataTransfer => {}
567 Expression::TranslationReference { format_args, plural, string_index: _ } => {
568 $visitor(format_args);
569 if let Some(plural) = plural {
570 $visitor(plural);
571 }
572 }
573 }
574 };
575}
576
577impl Expression {
578 pub fn visit(&self, mut visitor: impl FnMut(&Self)) {
580 visit_impl!(self, visitor, as_ref, iter, values)
581 }
582
583 pub fn visit_mut(&mut self, mut visitor: impl FnMut(&mut Self)) {
585 visit_impl!(self, visitor, as_mut, iter_mut, values_mut)
586 }
587
588 pub fn visit_recursive(&self, visitor: &mut dyn FnMut(&Self)) {
590 visitor(self);
591 self.visit(|e| e.visit_recursive(visitor));
592 }
593
594 pub fn visit_recursive_mut(&mut self, visitor: &mut dyn FnMut(&mut Self)) {
596 visitor(self);
597 self.visit_mut(|e| e.visit_recursive_mut(visitor));
598 }
599
600 pub fn visit_property_references(
601 &self,
602 ctx: &EvaluationContext,
603 visitor: &mut dyn FnMut(&MemberReference, &EvaluationContext),
604 ) {
605 self.visit_recursive(&mut |expr| {
606 let p = match expr {
607 Expression::PropertyReference(p) => p,
608 Expression::CallBackCall { callback, .. } => callback,
609 Expression::PropertyAssignment { property, .. } => {
610 if let Some((a, map)) = &ctx.property_info(property).animation {
611 let ctx2 = map.map_context(ctx);
612 a.visit_property_references(&ctx2, visitor);
613 }
614 property
615 }
616 Expression::ModelDataAssignment { .. } => return,
618 Expression::LayoutCacheAccess { layout_cache_prop, .. } => layout_cache_prop,
619 Expression::GridRepeaterCacheAccess { layout_cache_prop, .. } => layout_cache_prop,
620 _ => return,
621 };
622 visitor(p, ctx)
623 });
624 }
625}
626
627pub trait TypeResolutionContext {
628 fn property_ty(&self, _: &MemberReference) -> &Type;
632
633 fn arg_type(&self, _index: usize) -> &Type {
635 unimplemented!()
636 }
637}
638
639#[derive(Clone, Copy)]
641pub struct ParentScope<'a> {
642 pub sub_component: SubComponentIdx,
644 pub repeater_index: Option<RepeatedElementIdx>,
646 pub parent: Option<&'a ParentScope<'a>>,
648}
649
650impl<'a> ParentScope<'a> {
651 pub fn new<T>(
652 ctx: &'a EvaluationContext<'a, T>,
653 repeater_index: Option<RepeatedElementIdx>,
654 ) -> Self {
655 let EvaluationScope::SubComponent(sub_component, parent) = ctx.current_scope else {
656 unreachable!()
657 };
658 Self { sub_component, repeater_index, parent }
659 }
660}
661
662#[derive(Clone, Copy)]
663pub enum EvaluationScope<'a> {
664 SubComponent(SubComponentIdx, Option<&'a ParentScope<'a>>),
666 Global(GlobalIdx),
668}
669
670#[derive(Clone)]
671pub struct EvaluationContext<'a, T = ()> {
672 pub compilation_unit: &'a super::CompilationUnit,
673 pub current_scope: EvaluationScope<'a>,
674 pub generator_state: T,
675
676 pub argument_types: &'a [Type],
678}
679
680impl<'a, T> EvaluationContext<'a, T> {
681 pub fn new_sub_component(
682 compilation_unit: &'a super::CompilationUnit,
683 sub_component: SubComponentIdx,
684 generator_state: T,
685 parent: Option<&'a ParentScope<'a>>,
686 ) -> Self {
687 Self {
688 compilation_unit,
689 current_scope: EvaluationScope::SubComponent(sub_component, parent),
690 generator_state,
691 argument_types: &[],
692 }
693 }
694
695 pub fn new_global(
696 compilation_unit: &'a super::CompilationUnit,
697 global: GlobalIdx,
698 generator_state: T,
699 ) -> Self {
700 Self {
701 compilation_unit,
702 current_scope: EvaluationScope::Global(global),
703 generator_state,
704 argument_types: &[],
705 }
706 }
707
708 pub(crate) fn property_info<'b>(&'b self, prop: &MemberReference) -> PropertyInfoResult<'b> {
709 fn match_in_sub_component<'b>(
710 cu: &'b super::CompilationUnit,
711 sc: &'b super::SubComponent,
712 prop: &LocalMemberReference,
713 map: ContextMap,
714 ) -> PropertyInfoResult<'b> {
715 let use_count_and_ty = || {
716 let mut sc = sc;
717 for i in &prop.sub_component_path {
718 sc = &cu.sub_components[sc.sub_components[*i].ty];
719 }
720 match &prop.reference {
721 LocalMemberIndex::Property(property_index) => {
722 sc.properties.get(*property_index).map(|x| (&x.use_count, &x.ty))
723 }
724 LocalMemberIndex::Callback(callback_index) => {
725 sc.callbacks.get(*callback_index).map(|x| (&x.use_count, &x.ty))
726 }
727 _ => None,
728 }
729 };
730
731 let animation = sc.animations.get(prop).map(|a| (a, map.clone()));
732 let analysis = sc.prop_analysis.get(&prop.clone().into());
733 if let Some(a) = &analysis
734 && let Some(init) = a.property_init
735 {
736 let u = use_count_and_ty();
737 return PropertyInfoResult {
738 analysis: Some(&a.analysis),
739 binding: Some((&sc.property_init[init].1, map)),
740 animation,
741 ty: u.map_or(Type::Invalid, |x| x.1.clone()),
742 use_count: u.map(|x| x.0),
743 };
744 }
745 let mut r = if let &[idx, ref rest @ ..] = prop.sub_component_path.as_slice() {
746 let prop2 = LocalMemberReference {
747 sub_component_path: rest.to_vec(),
748 reference: prop.reference.clone(),
749 };
750 match_in_sub_component(
751 cu,
752 &cu.sub_components[sc.sub_components[idx].ty],
753 &prop2,
754 map.deeper_in_sub_component(idx),
755 )
756 } else {
757 let u = use_count_and_ty();
758 PropertyInfoResult {
759 ty: u.map_or(Type::Invalid, |x| x.1.clone()),
760 use_count: u.map(|x| x.0),
761 ..Default::default()
762 }
763 };
764
765 if animation.is_some() {
766 r.animation = animation
767 };
768 if let Some(a) = analysis {
769 r.analysis = Some(&a.analysis);
770 }
771 r
772 }
773
774 fn in_global<'a>(
775 g: &'a super::GlobalComponent,
776 r: &'_ LocalMemberIndex,
777 map: ContextMap,
778 ) -> PropertyInfoResult<'a> {
779 let binding = g.init_values.get(r).map(|b| (b, map));
780 match r {
781 LocalMemberIndex::Property(index) => {
782 let property_decl = &g.properties[*index];
783 PropertyInfoResult {
784 analysis: Some(&g.prop_analysis[*index]),
785 binding,
786 animation: None,
787 ty: property_decl.ty.clone(),
788 use_count: Some(&property_decl.use_count),
789 }
790 }
791 LocalMemberIndex::Callback(index) => {
792 let callback_decl = &g.callbacks[*index];
793 PropertyInfoResult {
794 analysis: None,
795 binding,
796 animation: None,
797 ty: callback_decl.ty.clone(),
798 use_count: Some(&callback_decl.use_count),
799 }
800 }
801 _ => PropertyInfoResult::default(),
802 }
803 }
804
805 match prop {
806 MemberReference::Relative { parent_level, local_reference } => {
807 match self.current_scope {
808 EvaluationScope::Global(g) => {
809 let g = &self.compilation_unit.globals[g];
810 in_global(g, &local_reference.reference, ContextMap::Identity)
811 }
812 EvaluationScope::SubComponent(mut sc, mut parent) => {
813 for _ in 0..*parent_level {
814 let p = parent.unwrap();
815 sc = p.sub_component;
816 parent = p.parent;
817 }
818 match_in_sub_component(
819 self.compilation_unit,
820 &self.compilation_unit.sub_components[sc],
821 local_reference,
822 ContextMap::from_parent_level(*parent_level),
823 )
824 }
825 }
826 }
827 MemberReference::Global { global_index, member } => {
828 let g = &self.compilation_unit.globals[*global_index];
829 in_global(g, member, ContextMap::InGlobal(*global_index))
830 }
831 }
832 }
833
834 pub fn current_sub_component(&self) -> Option<&super::SubComponent> {
835 let EvaluationScope::SubComponent(i, _) = self.current_scope else { return None };
836 self.compilation_unit.sub_components.get(i)
837 }
838
839 pub fn current_global(&self) -> Option<&super::GlobalComponent> {
840 let EvaluationScope::Global(i) = self.current_scope else { return None };
841 self.compilation_unit.globals.get(i)
842 }
843
844 pub fn parent_sub_component_idx(&self, parent: usize) -> Option<SubComponentIdx> {
845 let EvaluationScope::SubComponent(mut sc, mut par) = self.current_scope else {
846 return None;
847 };
848 for _ in 0..parent {
849 let p = par?;
850 sc = p.sub_component;
851 par = p.parent;
852 }
853 Some(sc)
854 }
855
856 pub fn relative_property_ty(
857 &self,
858 local_reference: &LocalMemberReference,
859 parent_level: usize,
860 ) -> &Type {
861 if let Some(g) = self.current_global() {
862 return match &local_reference.reference {
863 LocalMemberIndex::Property(property_idx) => &g.properties[*property_idx].ty,
864 LocalMemberIndex::Function(function_idx) => &g.functions[*function_idx].ret_ty,
865 LocalMemberIndex::Callback(callback_idx) => &g.callbacks[*callback_idx].ty,
866 LocalMemberIndex::Native { .. } => unreachable!(),
867 };
868 }
869
870 let mut sc = &self.compilation_unit.sub_components
871 [self.parent_sub_component_idx(parent_level).unwrap()];
872 for i in &local_reference.sub_component_path {
873 sc = &self.compilation_unit.sub_components[sc.sub_components[*i].ty];
874 }
875 match &local_reference.reference {
876 LocalMemberIndex::Property(property_index) => &sc.properties[*property_index].ty,
877 LocalMemberIndex::Function(function_index) => &sc.functions[*function_index].ret_ty,
878 LocalMemberIndex::Callback(callback_index) => &sc.callbacks[*callback_index].ty,
879 LocalMemberIndex::Native { item_index, prop_name } => {
880 if prop_name == "elements" {
881 return &Type::PathData;
883 }
884 let item = &sc.items[*item_index];
885 item.ty.lookup_property(prop_name).unwrap_or_else(|| {
886 panic!("Failed to lookup property {prop_name} for {}", item.name)
887 })
888 }
889 }
890 }
891}
892
893impl<T> TypeResolutionContext for EvaluationContext<'_, T> {
894 fn property_ty(&self, prop: &MemberReference) -> &Type {
895 match prop {
896 MemberReference::Relative { parent_level, local_reference } => {
897 self.relative_property_ty(local_reference, *parent_level)
898 }
899 MemberReference::Global { global_index, member } => {
900 let g = &self.compilation_unit.globals[*global_index];
901 match member {
902 LocalMemberIndex::Property(property_idx) => &g.properties[*property_idx].ty,
903 LocalMemberIndex::Function(function_idx) => &g.functions[*function_idx].ret_ty,
904 LocalMemberIndex::Callback(callback_idx) => &g.callbacks[*callback_idx].ty,
905 LocalMemberIndex::Native { .. } => unreachable!(),
906 }
907 }
908 }
909 }
910
911 fn arg_type(&self, index: usize) -> &Type {
912 &self.argument_types[index]
913 }
914}
915
916#[derive(Default, Debug)]
917pub(crate) struct PropertyInfoResult<'a> {
918 pub analysis: Option<&'a crate::object_tree::PropertyAnalysis>,
919 pub binding: Option<(&'a super::BindingExpression, ContextMap)>,
920 pub animation: Option<(&'a Expression, ContextMap)>,
921 pub ty: Type,
922 pub use_count: Option<&'a std::cell::Cell<usize>>,
923}
924
925#[derive(Debug, Clone)]
929pub(crate) enum ContextMap {
930 Identity,
931 InSubElement { path: Vec<SubComponentInstanceIdx>, parent: usize },
932 InGlobal(GlobalIdx),
933}
934
935impl ContextMap {
936 fn from_parent_level(parent_level: usize) -> Self {
937 if parent_level == 0 {
938 ContextMap::Identity
939 } else {
940 ContextMap::InSubElement { parent: parent_level, path: Vec::new() }
941 }
942 }
943
944 fn deeper_in_sub_component(self, sub: SubComponentInstanceIdx) -> Self {
945 match self {
946 ContextMap::Identity => ContextMap::InSubElement { parent: 0, path: vec![sub] },
947 ContextMap::InSubElement { mut path, parent } => {
948 path.push(sub);
949 ContextMap::InSubElement { path, parent }
950 }
951 ContextMap::InGlobal(_) => panic!(),
952 }
953 }
954
955 pub fn map_property_reference(&self, p: &MemberReference) -> MemberReference {
956 match self {
957 ContextMap::Identity => p.clone(),
958 ContextMap::InSubElement { path, parent } => match p {
959 MemberReference::Relative { parent_level, local_reference } => {
960 MemberReference::Relative {
961 parent_level: *parent_level + *parent,
962 local_reference: LocalMemberReference {
963 sub_component_path: path
964 .iter()
965 .chain(local_reference.sub_component_path.iter())
966 .copied()
967 .collect(),
968 reference: local_reference.reference.clone(),
969 },
970 }
971 }
972 MemberReference::Global { .. } => p.clone(),
973 },
974 ContextMap::InGlobal(global_index) => match p {
975 MemberReference::Relative { parent_level, local_reference } => {
976 assert!(local_reference.sub_component_path.is_empty());
977 assert_eq!(*parent_level, 0);
978 MemberReference::Global {
979 global_index: *global_index,
980 member: local_reference.reference.clone(),
981 }
982 }
983 g @ MemberReference::Global { .. } => g.clone(),
984 },
985 }
986 }
987
988 pub fn map_expression(&self, e: &mut Expression) {
989 match e {
990 Expression::PropertyReference(p)
991 | Expression::CallBackCall { callback: p, .. }
992 | Expression::PropertyAssignment { property: p, .. }
993 | Expression::LayoutCacheAccess { layout_cache_prop: p, .. }
994 | Expression::GridRepeaterCacheAccess { layout_cache_prop: p, .. } => {
995 *p = self.map_property_reference(p);
996 }
997 _ => (),
998 }
999 e.visit_mut(|e| self.map_expression(e))
1000 }
1001
1002 pub fn map_context<'a>(&self, ctx: &EvaluationContext<'a>) -> EvaluationContext<'a> {
1003 match self {
1004 ContextMap::Identity => ctx.clone(),
1005 ContextMap::InSubElement { path, parent } => {
1006 let mut sc = ctx.parent_sub_component_idx(*parent).unwrap();
1007 for i in path {
1008 sc = ctx.compilation_unit.sub_components[sc].sub_components[*i].ty;
1009 }
1010 EvaluationContext::new_sub_component(ctx.compilation_unit, sc, (), None)
1011 }
1012 ContextMap::InGlobal(g) => EvaluationContext::new_global(ctx.compilation_unit, *g, ()),
1013 }
1014 }
1015}