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