1use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
5use crate::langtype::{BuiltinElement, EnumerationValue, Type};
6use crate::layout::Orientation;
7use crate::object_tree::*;
8use crate::parser::{NodeOrToken, SyntaxNode};
9use core::cell::RefCell;
10use std::cell::Cell;
11use std::collections::HashMap;
12use std::rc::{Rc, Weak};
13
14pub use crate::namedreference::NamedReference;
16
17#[derive(Debug, Clone, Copy)]
18pub enum BuiltinFunction {
20 GetWindowScaleFactor,
21 Debug,
22 Mod,
23 Round,
24 Ceil,
25 Floor,
26 Abs,
27 Sqrt,
28 Cos,
29 Sin,
30 Tan,
31 ACos,
32 ASin,
33 ATan,
34 Log,
35 Pow,
36 SetFocusItem,
37 ShowPopupWindow,
38 StringToFloat,
40 StringIsFloat,
42 ColorBrighter,
43 ColorDarker,
44 ImageSize,
45 ArrayLength,
46 Rgb,
47 ImplicitLayoutInfo(Orientation),
48 RegisterCustomFontByPath,
49 RegisterCustomFontByMemory,
50}
51
52#[derive(Debug, Clone)]
53pub enum BuiltinMacroFunction {
55 Min,
56 Max,
57 CubicBezier,
58 Rgb,
59 Debug,
60}
61
62impl BuiltinFunction {
63 pub fn ty(&self) -> Type {
64 match self {
65 BuiltinFunction::GetWindowScaleFactor => Type::Function {
66 return_type: Box::new(Type::UnitProduct(vec![(Unit::Phx, 1), (Unit::Px, -1)])),
67 args: vec![],
68 },
69 BuiltinFunction::Debug => {
70 Type::Function { return_type: Box::new(Type::Void), args: vec![Type::String] }
71 }
72 BuiltinFunction::Mod => Type::Function {
73 return_type: Box::new(Type::Int32),
74 args: vec![Type::Int32, Type::Int32],
75 },
76 BuiltinFunction::Round | BuiltinFunction::Ceil | BuiltinFunction::Floor => {
77 Type::Function { return_type: Box::new(Type::Int32), args: vec![Type::Float32] }
78 }
79 BuiltinFunction::Sqrt | BuiltinFunction::Abs => {
80 Type::Function { return_type: Box::new(Type::Float32), args: vec![Type::Float32] }
81 }
82 BuiltinFunction::Cos | BuiltinFunction::Sin | BuiltinFunction::Tan => {
83 Type::Function { return_type: Box::new(Type::Float32), args: vec![Type::Angle] }
84 }
85 BuiltinFunction::ACos | BuiltinFunction::ASin | BuiltinFunction::ATan => {
86 Type::Function { return_type: Box::new(Type::Angle), args: vec![Type::Float32] }
87 }
88 BuiltinFunction::Log | BuiltinFunction::Pow => Type::Function {
89 return_type: Box::new(Type::Float32),
90 args: vec![Type::Float32, Type::Float32],
91 },
92 BuiltinFunction::SetFocusItem => Type::Function {
93 return_type: Box::new(Type::Void),
94 args: vec![Type::ElementReference],
95 },
96 BuiltinFunction::ShowPopupWindow => Type::Function {
97 return_type: Box::new(Type::Void),
98 args: vec![Type::ElementReference],
99 },
100 BuiltinFunction::StringToFloat => {
101 Type::Function { return_type: Box::new(Type::Float32), args: vec![Type::String] }
102 }
103 BuiltinFunction::StringIsFloat => {
104 Type::Function { return_type: Box::new(Type::Bool), args: vec![Type::String] }
105 }
106 BuiltinFunction::ImplicitLayoutInfo(_) => Type::Function {
107 return_type: Box::new(crate::layout::layout_info_type()),
108 args: vec![Type::ElementReference],
109 },
110 BuiltinFunction::ColorBrighter => Type::Function {
111 return_type: Box::new(Type::Color),
112 args: vec![Type::Color, Type::Float32],
113 },
114 BuiltinFunction::ColorDarker => Type::Function {
115 return_type: Box::new(Type::Color),
116 args: vec![Type::Color, Type::Float32],
117 },
118 BuiltinFunction::ImageSize => Type::Function {
119 return_type: Box::new(Type::Struct {
120 fields: IntoIterator::into_iter([
121 ("width".to_string(), Type::Int32),
122 ("height".to_string(), Type::Int32),
123 ])
124 .collect(),
125 name: Some("Size".to_string()),
126 node: None,
127 }),
128 args: vec![Type::Image],
129 },
130 BuiltinFunction::ArrayLength => {
131 Type::Function { return_type: Box::new(Type::Int32), args: vec![Type::Model] }
132 }
133 BuiltinFunction::Rgb => Type::Function {
134 return_type: Box::new(Type::Color),
135 args: vec![Type::Int32, Type::Int32, Type::Int32, Type::Float32],
136 },
137 BuiltinFunction::RegisterCustomFontByPath => {
138 Type::Function { return_type: Box::new(Type::Void), args: vec![Type::String] }
139 }
140 BuiltinFunction::RegisterCustomFontByMemory => {
141 Type::Function { return_type: Box::new(Type::Void), args: vec![Type::Int32] }
142 }
143 }
144 }
145
146 fn is_pure(&self) -> bool {
148 match self {
149 BuiltinFunction::GetWindowScaleFactor => false,
150 BuiltinFunction::Debug => true,
152 BuiltinFunction::Mod
153 | BuiltinFunction::Round
154 | BuiltinFunction::Ceil
155 | BuiltinFunction::Floor
156 | BuiltinFunction::Abs
157 | BuiltinFunction::Sqrt
158 | BuiltinFunction::Cos
159 | BuiltinFunction::Sin
160 | BuiltinFunction::Tan
161 | BuiltinFunction::ACos
162 | BuiltinFunction::ASin
163 | BuiltinFunction::Log
164 | BuiltinFunction::Pow
165 | BuiltinFunction::ATan => true,
166 BuiltinFunction::SetFocusItem => false,
167 BuiltinFunction::ShowPopupWindow => false,
168 BuiltinFunction::StringToFloat | BuiltinFunction::StringIsFloat => true,
169 BuiltinFunction::ColorBrighter | BuiltinFunction::ColorDarker => true,
170 #[cfg(not(target_arch = "wasm32"))]
175 BuiltinFunction::ImageSize => true,
176 #[cfg(target_arch = "wasm32")]
177 BuiltinFunction::ImageSize => false,
178 BuiltinFunction::ArrayLength => true,
179 BuiltinFunction::Rgb => true,
180 BuiltinFunction::ImplicitLayoutInfo(_) => false,
181 BuiltinFunction::RegisterCustomFontByPath
182 | BuiltinFunction::RegisterCustomFontByMemory => false,
183 }
184 }
185}
186
187#[derive(Debug, Clone, Eq, PartialEq)]
188pub enum OperatorClass {
189 ComparisonOp,
190 LogicalOp,
191 ArithmeticOp,
192}
193
194pub fn operator_class(op: char) -> OperatorClass {
196 match op {
197 '=' | '!' | '<' | '>' | '≤' | '≥' => OperatorClass::ComparisonOp,
198 '&' | '|' => OperatorClass::LogicalOp,
199 '+' | '-' | '/' | '*' => OperatorClass::ArithmeticOp,
200 _ => panic!("Invalid operator {:?}", op),
201 }
202}
203
204macro_rules! declare_units {
205 ($( $(#[$m:meta])* $ident:ident = $string:literal -> $ty:ident $(* $factor:expr)? ,)*) => {
206 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
208 pub enum Unit {
209 $($(#[$m])* $ident,)*
210 }
211
212 impl std::fmt::Display for Unit {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214 match self {
215 $(Self::$ident => write!(f, $string), )*
216 }
217 }
218 }
219
220 impl std::str::FromStr for Unit {
221 type Err = ();
222 fn from_str(s: &str) -> Result<Self, Self::Err> {
223 match s {
224 $($string => Ok(Self::$ident), )*
225 _ => Err(())
226 }
227 }
228 }
229
230 impl Unit {
231 pub fn ty(self) -> Type {
232 match self {
233 $(Self::$ident => Type::$ty, )*
234 }
235 }
236
237 pub fn normalize(self, x: f64) -> f64 {
238 match self {
239 $(Self::$ident => x $(* $factor as f64)?, )*
240 }
241 }
242
243 }
244 };
245}
246
247declare_units! {
248 None = "" -> Float32,
250 Percent = "%" -> Percent,
252
253 Phx = "phx" -> PhysicalLength,
257 Px = "px" -> LogicalLength,
259 Cm = "cm" -> LogicalLength * 37.8,
261 Mm = "mm" -> LogicalLength * 3.78,
263 In = "in" -> LogicalLength * 96,
265 Pt = "pt" -> LogicalLength * 96./72.,
267
268 S = "s" -> Duration * 1000,
272 Ms = "ms" -> Duration,
274
275 Deg = "deg" -> Angle,
279 Grad = "grad" -> Angle * 360./180.,
281 Turn = "turn" -> Angle * 360.,
283 Rad = "rad" -> Angle * 360./std::f32::consts::TAU,
285}
286
287impl Default for Unit {
288 fn default() -> Self {
289 Self::None
290 }
291}
292
293#[derive(Debug, Clone)]
295pub enum Expression {
296 Invalid,
298 Uncompiled(SyntaxNode),
300
301 StringLiteral(String),
303 NumberLiteral(f64, Unit),
305 BoolLiteral(bool),
307
308 CallbackReference(NamedReference),
312
313 PropertyReference(NamedReference),
315
316 BuiltinFunctionReference(BuiltinFunction, Option<SourceLocation>),
318
319 MemberFunction {
322 base: Box<Expression>,
323 base_node: Option<NodeOrToken>,
324 member: Box<Expression>,
325 },
326
327 BuiltinMacroReference(BuiltinMacroFunction, Option<NodeOrToken>),
330
331 ElementReference(Weak<RefCell<Element>>),
334
335 RepeaterIndexReference {
340 element: Weak<RefCell<Element>>,
341 },
342
343 RepeaterModelReference {
348 element: Weak<RefCell<Element>>,
349 },
350
351 FunctionParameterReference {
353 index: usize,
354 ty: Type,
355 },
356
357 StoreLocalVariable {
359 name: String,
360 value: Box<Expression>,
361 },
362
363 ReadLocalVariable {
366 name: String,
367 ty: Type,
368 },
369
370 StructFieldAccess {
372 base: Box<Expression>,
374 name: String,
375 },
376
377 ArrayIndex {
379 array: Box<Expression>,
381 index: Box<Expression>,
382 },
383
384 Cast {
386 from: Box<Expression>,
387 to: Type,
388 },
389
390 CodeBlock(Vec<Expression>),
392
393 FunctionCall {
395 function: Box<Expression>,
396 arguments: Vec<Expression>,
397 source_location: Option<SourceLocation>,
398 },
399
400 SelfAssignment {
402 lhs: Box<Expression>,
403 rhs: Box<Expression>,
404 op: char,
406 },
407
408 BinaryExpression {
409 lhs: Box<Expression>,
410 rhs: Box<Expression>,
411 op: char,
413 },
414
415 UnaryOp {
416 sub: Box<Expression>,
417 op: char,
419 },
420
421 ImageReference {
422 resource_ref: ImageReference,
423 source_location: Option<SourceLocation>,
424 },
425
426 Condition {
427 condition: Box<Expression>,
428 true_expr: Box<Expression>,
429 false_expr: Box<Expression>,
430 },
431
432 Array {
433 element_ty: Type,
434 values: Vec<Expression>,
435 },
436 Struct {
437 ty: Type,
438 values: HashMap<String, Expression>,
439 },
440
441 PathData(Path),
442
443 EasingCurve(EasingCurve),
444
445 LinearGradient {
446 angle: Box<Expression>,
447 stops: Vec<(Expression, Expression)>,
449 },
450
451 EnumerationValue(EnumerationValue),
452
453 ReturnStatement(Option<Box<Expression>>),
454
455 LayoutCacheAccess {
456 layout_cache_prop: NamedReference,
457 index: usize,
458 repeater_index: Option<Box<Expression>>,
461 },
462 ComputeLayoutInfo(crate::layout::Layout, crate::layout::Orientation),
465 SolveLayout(crate::layout::Layout, crate::layout::Orientation),
466}
467
468impl Default for Expression {
469 fn default() -> Self {
470 Expression::Invalid
471 }
472}
473
474impl Expression {
475 pub fn ty(&self) -> Type {
477 match self {
478 Expression::Invalid => Type::Invalid,
479 Expression::Uncompiled(_) => Type::Invalid,
480 Expression::StringLiteral(_) => Type::String,
481 Expression::NumberLiteral(_, unit) => unit.ty(),
482 Expression::BoolLiteral(_) => Type::Bool,
483 Expression::CallbackReference(nr) => nr.ty(),
484 Expression::PropertyReference(nr) => nr.ty(),
485 Expression::BuiltinFunctionReference(funcref, _) => funcref.ty(),
486 Expression::MemberFunction { member, .. } => member.ty(),
487 Expression::BuiltinMacroReference { .. } => Type::Invalid, Expression::ElementReference(_) => Type::ElementReference,
489 Expression::RepeaterIndexReference { .. } => Type::Int32,
490 Expression::RepeaterModelReference { element } => {
491 if let Expression::Cast { from, .. } = element
492 .upgrade()
493 .unwrap()
494 .borrow()
495 .repeated
496 .as_ref()
497 .map_or(&Expression::Invalid, |e| &e.model)
498 {
499 match from.ty() {
500 Type::Float32 | Type::Int32 => Type::Int32,
501 Type::Array(elem) => *elem,
502 _ => Type::Invalid,
503 }
504 } else {
505 Type::Invalid
506 }
507 }
508 Expression::FunctionParameterReference { ty, .. } => ty.clone(),
509 Expression::StructFieldAccess { base, name } => match base.ty() {
510 Type::Struct { fields, .. } => {
511 fields.get(name.as_str()).unwrap_or(&Type::Invalid).clone()
512 }
513 Type::Component(c) => c.root_element.borrow().lookup_property(name).property_type,
514 _ => Type::Invalid,
515 },
516 Expression::ArrayIndex { array, .. } => match array.ty() {
517 Type::Array(ty) => (*ty).clone(),
518 _ => Type::Invalid,
519 },
520 Expression::Cast { to, .. } => to.clone(),
521 Expression::CodeBlock(sub) => sub.last().map_or(Type::Void, |e| e.ty()),
522 Expression::FunctionCall { function, .. } => match function.ty() {
523 Type::Function { return_type, .. } => *return_type,
524 Type::Callback { return_type, .. } => return_type.map_or(Type::Void, |x| *x),
525 _ => Type::Invalid,
526 },
527 Expression::SelfAssignment { .. } => Type::Void,
528 Expression::ImageReference { .. } => Type::Image,
529 Expression::Condition { condition: _, true_expr, false_expr } => {
530 let true_type = true_expr.ty();
531 let false_type = false_expr.ty();
532 if true_type == false_type {
533 true_type
534 } else if true_type == Type::Invalid {
535 false_type
536 } else if false_type == Type::Invalid {
537 true_type
538 } else {
539 Type::Void
540 }
541 }
542 Expression::BinaryExpression { op, lhs, rhs } => {
543 if operator_class(*op) != OperatorClass::ArithmeticOp {
544 Type::Bool
545 } else if *op == '+' || *op == '-' {
546 let (rhs_ty, lhs_ty) = (rhs.ty(), lhs.ty());
547 if rhs_ty == lhs_ty {
548 rhs_ty
549 } else {
550 Type::Invalid
551 }
552 } else {
553 debug_assert!(*op == '*' || *op == '/');
554 let unit_vec = |ty| {
555 if let Type::UnitProduct(v) = ty {
556 v
557 } else if let Some(u) = ty.default_unit() {
558 vec![(u, 1)]
559 } else {
560 vec![]
561 }
562 };
563 let mut l_units = unit_vec(lhs.ty());
564 let mut r_units = unit_vec(rhs.ty());
565 if *op == '/' {
566 for (_, power) in &mut r_units {
567 *power = -*power;
568 }
569 }
570 for (unit, power) in r_units {
571 if let Some((_, p)) = l_units.iter_mut().find(|(u, _)| *u == unit) {
572 *p += power;
573 } else {
574 l_units.push((unit, power));
575 }
576 }
577
578 l_units.retain(|(_, p)| *p != 0);
580 l_units.sort_unstable_by(|(u1, p1), (u2, p2)| match p2.cmp(p1) {
581 std::cmp::Ordering::Equal => u1.cmp(u2),
582 x => x,
583 });
584
585 if l_units.is_empty() {
586 Type::Float32
587 } else if l_units.len() == 1 && l_units[0].1 == 1 {
588 l_units[0].0.ty()
589 } else {
590 Type::UnitProduct(l_units)
591 }
592 }
593 }
594 Expression::UnaryOp { sub, .. } => sub.ty(),
595 Expression::Array { element_ty, .. } => Type::Array(Box::new(element_ty.clone())),
596 Expression::Struct { ty, .. } => ty.clone(),
597 Expression::PathData { .. } => Type::PathData,
598 Expression::StoreLocalVariable { .. } => Type::Void,
599 Expression::ReadLocalVariable { ty, .. } => ty.clone(),
600 Expression::EasingCurve(_) => Type::Easing,
601 Expression::LinearGradient { .. } => Type::Brush,
602 Expression::EnumerationValue(value) => Type::Enumeration(value.enumeration.clone()),
603 Expression::ReturnStatement(_) => Type::Invalid,
605 Expression::LayoutCacheAccess { .. } => Type::LogicalLength,
606 Expression::ComputeLayoutInfo(..) => crate::layout::layout_info_type(),
607 Expression::SolveLayout(..) => Type::LayoutCache,
608 }
609 }
610
611 pub fn visit(&self, mut visitor: impl FnMut(&Self)) {
613 match self {
614 Expression::Invalid => {}
615 Expression::Uncompiled(_) => {}
616 Expression::StringLiteral(_) => {}
617 Expression::NumberLiteral(_, _) => {}
618 Expression::BoolLiteral(_) => {}
619 Expression::CallbackReference { .. } => {}
620 Expression::PropertyReference { .. } => {}
621 Expression::FunctionParameterReference { .. } => {}
622 Expression::BuiltinFunctionReference { .. } => {}
623 Expression::MemberFunction { base, member, .. } => {
624 visitor(&**base);
625 visitor(&**member);
626 }
627 Expression::BuiltinMacroReference { .. } => {}
628 Expression::ElementReference(_) => {}
629 Expression::StructFieldAccess { base, .. } => visitor(&**base),
630 Expression::ArrayIndex { array, index } => {
631 visitor(&**array);
632 visitor(&**index);
633 }
634 Expression::RepeaterIndexReference { .. } => {}
635 Expression::RepeaterModelReference { .. } => {}
636 Expression::Cast { from, .. } => visitor(&**from),
637 Expression::CodeBlock(sub) => {
638 sub.iter().for_each(visitor);
639 }
640 Expression::FunctionCall { function, arguments, source_location: _ } => {
641 visitor(&**function);
642 arguments.iter().for_each(visitor);
643 }
644 Expression::SelfAssignment { lhs, rhs, .. } => {
645 visitor(&**lhs);
646 visitor(&**rhs);
647 }
648 Expression::ImageReference { .. } => {}
649 Expression::Condition { condition, true_expr, false_expr } => {
650 visitor(&**condition);
651 visitor(&**true_expr);
652 visitor(&**false_expr);
653 }
654 Expression::BinaryExpression { lhs, rhs, .. } => {
655 visitor(&**lhs);
656 visitor(&**rhs);
657 }
658 Expression::UnaryOp { sub, .. } => visitor(&**sub),
659 Expression::Array { values, .. } => {
660 for x in values {
661 visitor(x);
662 }
663 }
664 Expression::Struct { values, .. } => {
665 for x in values.values() {
666 visitor(x);
667 }
668 }
669 Expression::PathData(data) => match data {
670 Path::Elements(elements) => {
671 for element in elements {
672 element.bindings.values().for_each(|binding| visitor(&binding.borrow()))
673 }
674 }
675 Path::Events(events, coordinates) => {
676 events.iter().chain(coordinates.iter()).for_each(visitor);
677 }
678 },
679 Expression::StoreLocalVariable { value, .. } => visitor(&**value),
680 Expression::ReadLocalVariable { .. } => {}
681 Expression::EasingCurve(_) => {}
682 Expression::LinearGradient { angle, stops } => {
683 visitor(angle);
684 for (c, s) in stops {
685 visitor(c);
686 visitor(s);
687 }
688 }
689 Expression::EnumerationValue(_) => {}
690 Expression::ReturnStatement(expr) => {
691 expr.as_deref().map(visitor);
692 }
693 Expression::LayoutCacheAccess { repeater_index, .. } => {
694 repeater_index.as_deref().map(visitor);
695 }
696 Expression::ComputeLayoutInfo(..) => {}
697 Expression::SolveLayout(..) => {}
698 }
699 }
700
701 pub fn visit_mut(&mut self, mut visitor: impl FnMut(&mut Self)) {
702 match self {
703 Expression::Invalid => {}
704 Expression::Uncompiled(_) => {}
705 Expression::StringLiteral(_) => {}
706 Expression::NumberLiteral(_, _) => {}
707 Expression::BoolLiteral(_) => {}
708 Expression::CallbackReference { .. } => {}
709 Expression::PropertyReference { .. } => {}
710 Expression::FunctionParameterReference { .. } => {}
711 Expression::BuiltinFunctionReference { .. } => {}
712 Expression::MemberFunction { base, member, .. } => {
713 visitor(&mut **base);
714 visitor(&mut **member);
715 }
716 Expression::BuiltinMacroReference { .. } => {}
717 Expression::ElementReference(_) => {}
718 Expression::StructFieldAccess { base, .. } => visitor(&mut **base),
719 Expression::ArrayIndex { array, index } => {
720 visitor(&mut **array);
721 visitor(&mut **index);
722 }
723 Expression::RepeaterIndexReference { .. } => {}
724 Expression::RepeaterModelReference { .. } => {}
725 Expression::Cast { from, .. } => visitor(&mut **from),
726 Expression::CodeBlock(sub) => {
727 sub.iter_mut().for_each(visitor);
728 }
729 Expression::FunctionCall { function, arguments, source_location: _ } => {
730 visitor(&mut **function);
731 arguments.iter_mut().for_each(visitor);
732 }
733 Expression::SelfAssignment { lhs, rhs, .. } => {
734 visitor(&mut **lhs);
735 visitor(&mut **rhs);
736 }
737 Expression::ImageReference { .. } => {}
738 Expression::Condition { condition, true_expr, false_expr } => {
739 visitor(&mut **condition);
740 visitor(&mut **true_expr);
741 visitor(&mut **false_expr);
742 }
743 Expression::BinaryExpression { lhs, rhs, .. } => {
744 visitor(&mut **lhs);
745 visitor(&mut **rhs);
746 }
747 Expression::UnaryOp { sub, .. } => visitor(&mut **sub),
748 Expression::Array { values, .. } => {
749 for x in values {
750 visitor(x);
751 }
752 }
753 Expression::Struct { values, .. } => {
754 for x in values.values_mut() {
755 visitor(x);
756 }
757 }
758 Expression::PathData(data) => match data {
759 Path::Elements(elements) => {
760 for element in elements {
761 element
762 .bindings
763 .values_mut()
764 .for_each(|binding| visitor(&mut binding.borrow_mut()))
765 }
766 }
767 Path::Events(events, coordinates) => {
768 events.iter_mut().chain(coordinates.iter_mut()).for_each(visitor);
769 }
770 },
771 Expression::StoreLocalVariable { value, .. } => visitor(&mut **value),
772 Expression::ReadLocalVariable { .. } => {}
773 Expression::EasingCurve(_) => {}
774 Expression::LinearGradient { angle, stops } => {
775 visitor(&mut *angle);
776 for (c, s) in stops {
777 visitor(c);
778 visitor(s);
779 }
780 }
781 Expression::EnumerationValue(_) => {}
782 Expression::ReturnStatement(expr) => {
783 expr.as_deref_mut().map(visitor);
784 }
785 Expression::LayoutCacheAccess { repeater_index, .. } => {
786 repeater_index.as_deref_mut().map(visitor);
787 }
788 Expression::ComputeLayoutInfo(..) => {}
789 Expression::SolveLayout(..) => {}
790 }
791 }
792
793 pub fn visit_recursive(&self, visitor: &mut dyn FnMut(&Self)) {
795 visitor(self);
796 self.visit(|e| e.visit_recursive(visitor));
797 }
798
799 pub fn visit_recursive_mut(&mut self, visitor: &mut dyn FnMut(&mut Self)) {
801 visitor(self);
802 self.visit_mut(|e| e.visit_recursive_mut(visitor));
803 }
804
805 pub fn is_constant(&self) -> bool {
806 match self {
807 Expression::Invalid => true,
808 Expression::Uncompiled(_) => false,
809 Expression::StringLiteral(_) => true,
810 Expression::NumberLiteral(_, _) => true,
811 Expression::BoolLiteral(_) => true,
812 Expression::CallbackReference { .. } => false,
813 Expression::PropertyReference(nr) => nr.is_constant(),
814 Expression::BuiltinFunctionReference(func, _) => func.is_pure(),
815 Expression::MemberFunction { .. } => false,
816 Expression::ElementReference(_) => false,
817 Expression::RepeaterIndexReference { .. } => false,
818 Expression::RepeaterModelReference { .. } => false,
819 Expression::FunctionParameterReference { .. } => false,
820 Expression::BuiltinMacroReference { .. } => true,
821 Expression::StructFieldAccess { base, .. } => base.is_constant(),
822 Expression::ArrayIndex { array, index } => array.is_constant() && index.is_constant(),
823 Expression::Cast { from, .. } => from.is_constant(),
824 Expression::CodeBlock(sub) => sub.len() == 1 && sub.first().unwrap().is_constant(),
825 Expression::FunctionCall { function, arguments, .. } => {
826 function.is_constant() && arguments.iter().all(|a| a.is_constant())
828 }
829 Expression::SelfAssignment { .. } => false,
830 Expression::ImageReference { .. } => true,
831 Expression::Condition { condition, false_expr, true_expr } => {
832 condition.is_constant() && false_expr.is_constant() && true_expr.is_constant()
833 }
834 Expression::BinaryExpression { lhs, rhs, .. } => lhs.is_constant() && rhs.is_constant(),
835 Expression::UnaryOp { sub, .. } => sub.is_constant(),
836 Expression::Array { values, .. } => values.iter().all(Expression::is_constant),
837 Expression::Struct { values, .. } => values.iter().all(|(_, v)| v.is_constant()),
838 Expression::PathData(data) => {
839 if let Path::Elements(elements) = data {
840 elements
841 .iter()
842 .all(|element| element.bindings.values().all(|v| v.borrow().is_constant()))
843 } else {
844 true
845 }
846 }
847 Expression::StoreLocalVariable { .. } => false,
848 Expression::ReadLocalVariable { .. } => false,
850 Expression::EasingCurve(_) => true,
851 Expression::LinearGradient { angle, stops } => {
852 angle.is_constant() && stops.iter().all(|(c, s)| c.is_constant() && s.is_constant())
853 }
854 Expression::EnumerationValue(_) => true,
855 Expression::ReturnStatement(expr) => {
856 expr.as_ref().map_or(true, |expr| expr.is_constant())
857 }
858 Expression::LayoutCacheAccess { .. } => false,
860 Expression::ComputeLayoutInfo(..) => false,
861 Expression::SolveLayout(..) => false,
862 }
863 }
864
865 #[must_use]
867 pub fn maybe_convert_to(
868 self,
869 target_type: Type,
870 node: &impl Spanned,
871 diag: &mut BuildDiagnostics,
872 ) -> Expression {
873 let ty = self.ty();
874 if ty == target_type
875 || target_type == Type::Void
876 || target_type == Type::Invalid
877 || ty == Type::Invalid
878 {
879 self
880 } else if ty.can_convert(&target_type) {
881 let from = match (ty, &target_type) {
882 (Type::Percent, Type::Float32) => Expression::BinaryExpression {
883 lhs: Box::new(self),
884 rhs: Box::new(Expression::NumberLiteral(0.01, Unit::None)),
885 op: '*',
886 },
887 (
888 Type::Struct { fields: ref left, .. },
889 Type::Struct { fields: right, name, node: n },
890 ) if left != right => {
891 if let Expression::Struct { mut values, .. } = self {
892 let mut new_values = HashMap::new();
893 for (key, ty) in right {
894 let (key, expression) = values.remove_entry(key).map_or_else(
895 || (key.clone(), Expression::default_value_for_type(ty)),
896 |(k, e)| (k, e.maybe_convert_to(ty.clone(), node, diag)),
897 );
898 new_values.insert(key, expression);
899 }
900 return Expression::Struct { values: new_values, ty: target_type };
901 }
902 let var_name = "tmpobj";
903 let mut new_values = HashMap::new();
904 for (key, ty) in right {
905 let expression = if left.contains_key(key) {
906 Expression::StructFieldAccess {
907 base: Box::new(Expression::ReadLocalVariable {
908 name: var_name.into(),
909 ty: Type::Struct {
910 fields: left.clone(),
911 name: name.clone(),
912 node: n.clone(),
913 },
914 }),
915 name: key.clone(),
916 }
917 .maybe_convert_to(ty.clone(), node, diag)
918 } else {
919 Expression::default_value_for_type(ty)
920 };
921 new_values.insert(key.clone(), expression);
922 }
923 return Expression::CodeBlock(vec![
924 Expression::StoreLocalVariable {
925 name: var_name.into(),
926 value: Box::new(self),
927 },
928 Expression::Struct { values: new_values, ty: target_type },
929 ]);
930 }
931 (Type::Struct { .. }, Type::Component(component)) => {
932 let struct_type_for_component = Type::Struct {
933 fields: component
934 .root_element
935 .borrow()
936 .property_declarations
937 .iter()
938 .map(|(name, prop_decl)| {
939 (name.clone(), prop_decl.property_type.clone())
940 })
941 .collect(),
942 name: None,
943 node: None,
944 };
945 self.maybe_convert_to(struct_type_for_component, node, diag)
946 }
947 (left, right) => match (left.as_unit_product(), right.as_unit_product()) {
948 (Some(left), Some(right)) => {
949 if let Some(power) =
950 crate::langtype::unit_product_length_conversion(&left, &right)
951 {
952 let op = if power < 0 { '*' } else { '/' };
953 let mut result = self;
954 for _ in 0..power.abs() {
955 result = Expression::BinaryExpression {
956 lhs: Box::new(result),
957 rhs: Box::new(Expression::FunctionCall {
958 function: Box::new(Expression::BuiltinFunctionReference(
959 BuiltinFunction::GetWindowScaleFactor,
960 Some(node.to_source_location()),
961 )),
962 arguments: vec![],
963 source_location: Some(node.to_source_location()),
964 }),
965 op,
966 }
967 }
968 result
969 } else {
970 self
971 }
972 }
973 _ => self,
974 },
975 };
976 Expression::Cast { from: Box::new(from), to: target_type }
977 } else if matches!((&ty, &target_type, &self), (Type::Array(left), Type::Array(right), Expression::Array{..})
978 if left.can_convert(right) || **left == Type::Invalid)
979 {
980 match (self, target_type) {
982 (Expression::Array { values, .. }, Type::Array(target_type)) => Expression::Array {
983 values: values
984 .into_iter()
985 .map(|e| e.maybe_convert_to((*target_type).clone(), node, diag))
986 .collect(),
987 element_ty: *target_type,
988 },
989 _ => unreachable!(),
990 }
991 } else {
992 let mut message = format!("Cannot convert {} to {}", ty, target_type);
993 if let Some(from_unit) = ty.default_unit() {
995 if matches!(&target_type, Type::Int32 | Type::Float32 | Type::String) {
996 message = format!(
997 "{}. Divide by 1{} to convert to a plain number",
998 message, from_unit
999 );
1000 }
1001 } else if let Some(to_unit) = target_type.default_unit() {
1002 if matches!(ty, Type::Int32 | Type::Float32) {
1003 if let Expression::NumberLiteral(value, Unit::None) = self {
1004 if value == 0. {
1005 return Expression::NumberLiteral(0., to_unit);
1007 }
1008 }
1009 message = format!(
1010 "{}. Use an unit, or multiply by 1{} to convert explicitly",
1011 message, to_unit
1012 );
1013 }
1014 }
1015 diag.push_error(message, node);
1016 self
1017 }
1018 }
1019
1020 pub fn default_value_for_type(ty: &Type) -> Expression {
1022 match ty {
1023 Type::Invalid
1024 | Type::Component(_)
1025 | Type::Builtin(_)
1026 | Type::Native(_)
1027 | Type::Callback { .. }
1028 | Type::Function { .. }
1029 | Type::Void
1030 | Type::InferredProperty
1031 | Type::InferredCallback
1032 | Type::ElementReference
1033 | Type::LayoutCache => Expression::Invalid,
1034 Type::Float32 => Expression::NumberLiteral(0., Unit::None),
1035 Type::String => Expression::StringLiteral(String::new()),
1036 Type::Int32 | Type::Color | Type::UnitProduct(_) => Expression::Cast {
1037 from: Box::new(Expression::NumberLiteral(0., Unit::None)),
1038 to: ty.clone(),
1039 },
1040 Type::Duration => Expression::NumberLiteral(0., Unit::Ms),
1041 Type::Angle => Expression::NumberLiteral(0., Unit::Deg),
1042 Type::PhysicalLength => Expression::NumberLiteral(0., Unit::Phx),
1043 Type::LogicalLength => Expression::NumberLiteral(0., Unit::Px),
1044 Type::Percent => Expression::NumberLiteral(100., Unit::Percent),
1045 Type::Image => Expression::ImageReference {
1046 resource_ref: ImageReference::None,
1047 source_location: None,
1048 },
1049 Type::Bool => Expression::BoolLiteral(false),
1050 Type::Model => Expression::Invalid,
1051 Type::PathData => Expression::PathData(Path::Elements(vec![])),
1052 Type::Array(element_ty) => {
1053 Expression::Array { element_ty: (**element_ty).clone(), values: vec![] }
1054 }
1055 Type::Struct { fields, .. } => Expression::Struct {
1056 ty: ty.clone(),
1057 values: fields
1058 .iter()
1059 .map(|(k, v)| (k.clone(), Expression::default_value_for_type(v)))
1060 .collect(),
1061 },
1062 Type::Easing => Expression::EasingCurve(EasingCurve::default()),
1063 Type::Brush => Expression::Cast {
1064 from: Box::new(Expression::default_value_for_type(&Type::Color)),
1065 to: Type::Brush,
1066 },
1067 Type::Enumeration(enumeration) => {
1068 Expression::EnumerationValue(enumeration.clone().default_value())
1069 }
1070 }
1071 }
1072
1073 pub fn try_set_rw(&mut self) -> bool {
1077 match self {
1078 Expression::PropertyReference(nr) => {
1079 nr.mark_as_set();
1080 true
1081 }
1082 Expression::StructFieldAccess { base, .. } => base.try_set_rw(),
1083 Expression::RepeaterModelReference { .. } => true,
1084 Expression::ArrayIndex { .. } => true,
1085 _ => false,
1086 }
1087 }
1088}
1089
1090#[derive(Debug, Clone, derive_more::Deref, derive_more::DerefMut)]
1092pub struct BindingExpression {
1093 #[deref]
1094 #[deref_mut]
1095 pub expression: Expression,
1096 pub span: Option<SourceLocation>,
1098 pub priority: i32,
1103
1104 pub animation: Option<PropertyAnimation>,
1105
1106 pub analysis: Option<BindingAnalysis>,
1108
1109 pub two_way_bindings: Vec<NamedReference>,
1111}
1112
1113impl std::convert::From<Expression> for BindingExpression {
1114 fn from(expression: Expression) -> Self {
1115 Self {
1116 expression,
1117 span: None,
1118 priority: 0,
1119 animation: Default::default(),
1120 analysis: Default::default(),
1121 two_way_bindings: Default::default(),
1122 }
1123 }
1124}
1125
1126impl BindingExpression {
1127 pub fn new_uncompiled(node: SyntaxNode) -> Self {
1128 Self {
1129 expression: Expression::Uncompiled(node.clone()),
1130 span: Some(node.to_source_location()),
1131 priority: 1,
1132 animation: Default::default(),
1133 analysis: Default::default(),
1134 two_way_bindings: Default::default(),
1135 }
1136 }
1137 pub fn new_with_span(expression: Expression, span: SourceLocation) -> Self {
1138 Self {
1139 expression,
1140 span: Some(span),
1141 priority: 0,
1142 animation: Default::default(),
1143 analysis: Default::default(),
1144 two_way_bindings: Default::default(),
1145 }
1146 }
1147
1148 pub fn new_two_way(other: NamedReference) -> Self {
1150 Self {
1151 expression: Expression::Invalid,
1152 span: None,
1153 priority: 0,
1154 animation: Default::default(),
1155 analysis: Default::default(),
1156 two_way_bindings: vec![other],
1157 }
1158 }
1159
1160 pub fn merge_with(&mut self, other: &Self) -> bool {
1168 if self.animation.is_none() {
1169 self.animation = other.animation.clone();
1170 }
1171 self.two_way_bindings.extend_from_slice(&other.two_way_bindings);
1172 if matches!(self.expression, Expression::Invalid) {
1173 self.priority = other.priority;
1174 self.expression = other.expression.clone();
1175 true
1176 } else {
1177 false
1178 }
1179 }
1180
1181 pub fn has_binding(&self) -> bool {
1183 !matches!(self.expression, Expression::Invalid) || !self.two_way_bindings.is_empty()
1184 }
1185}
1186
1187impl Spanned for BindingExpression {
1188 fn span(&self) -> crate::diagnostics::Span {
1189 self.span.as_ref().map(|x| x.span()).unwrap_or_default()
1190 }
1191 fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> {
1192 self.span.as_ref().and_then(|x| x.source_file())
1193 }
1194}
1195
1196#[derive(Default, Debug, Clone)]
1197pub struct BindingAnalysis {
1198 pub is_in_binding_loop: Cell<bool>,
1200
1201 pub is_const: bool,
1203
1204 pub no_external_dependencies: bool,
1207}
1208
1209#[derive(Debug, Clone)]
1210pub enum Path {
1211 Elements(Vec<PathElement>),
1212 Events(Vec<Expression>, Vec<Expression>),
1213}
1214
1215#[derive(Debug, Clone)]
1216pub struct PathElement {
1217 pub element_type: Rc<BuiltinElement>,
1218 pub bindings: BindingsMap,
1219}
1220
1221#[derive(Clone, Debug)]
1222pub enum EasingCurve {
1223 Linear,
1224 CubicBezier(f32, f32, f32, f32),
1225 }
1228
1229impl Default for EasingCurve {
1230 fn default() -> Self {
1231 Self::Linear
1232 }
1233}
1234
1235#[derive(Clone, Debug)]
1238pub enum ImageReference {
1239 None,
1240 AbsolutePath(String),
1241 EmbeddedData { resource_id: usize, extension: String },
1242 EmbeddedTexture { resource_id: usize },
1243}
1244
1245pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std::fmt::Result {
1247 match expression {
1248 Expression::Invalid => write!(f, "<invalid>"),
1249 Expression::Uncompiled(u) => write!(f, "{:?}", u),
1250 Expression::StringLiteral(s) => write!(f, "{:?}", s),
1251 Expression::NumberLiteral(vl, unit) => write!(f, "{}{}", vl, unit),
1252 Expression::BoolLiteral(b) => write!(f, "{:?}", b),
1253 Expression::CallbackReference(a) => write!(f, "{:?}", a),
1254 Expression::PropertyReference(a) => write!(f, "{:?}", a),
1255 Expression::BuiltinFunctionReference(a, _) => write!(f, "{:?}", a),
1256 Expression::MemberFunction { base, base_node: _, member } => {
1257 pretty_print(f, base)?;
1258 write!(f, ".")?;
1259 pretty_print(f, member)
1260 }
1261 Expression::BuiltinMacroReference(a, _) => write!(f, "{:?}", a),
1262 Expression::ElementReference(a) => write!(f, "{:?}", a),
1263 Expression::RepeaterIndexReference { element } => {
1264 crate::namedreference::pretty_print_element_ref(f, element)
1265 }
1266 Expression::RepeaterModelReference { element } => {
1267 crate::namedreference::pretty_print_element_ref(f, element)?;
1268 write!(f, ".@model")
1269 }
1270 Expression::FunctionParameterReference { index, ty: _ } => write!(f, "_arg_{}", index),
1271 Expression::StoreLocalVariable { name, value } => {
1272 write!(f, "{} = ", name)?;
1273 pretty_print(f, value)
1274 }
1275 Expression::ReadLocalVariable { name, ty: _ } => write!(f, "{}", name),
1276 Expression::StructFieldAccess { base, name } => {
1277 pretty_print(f, base)?;
1278 write!(f, ".{}", name)
1279 }
1280 Expression::ArrayIndex { array, index } => {
1281 pretty_print(f, array)?;
1282 write!(f, "[")?;
1283 pretty_print(f, index)?;
1284 write!(f, "]")
1285 }
1286 Expression::Cast { from, to } => {
1287 write!(f, "(")?;
1288 pretty_print(f, from)?;
1289 write!(f, "/* as {} */)", to)
1290 }
1291 Expression::CodeBlock(c) => {
1292 write!(f, "{{ ")?;
1293 for e in c {
1294 pretty_print(f, e)?;
1295 write!(f, "; ")?;
1296 }
1297 write!(f, "}}")
1298 }
1299 Expression::FunctionCall { function, arguments, source_location: _ } => {
1300 pretty_print(f, function)?;
1301 write!(f, "(")?;
1302 for e in arguments {
1303 pretty_print(f, e)?;
1304 write!(f, ", ")?;
1305 }
1306 write!(f, ")")
1307 }
1308 Expression::SelfAssignment { lhs, rhs, op } => {
1309 pretty_print(f, lhs)?;
1310 write!(f, " {}= ", if *op == '=' { ' ' } else { *op })?;
1311 pretty_print(f, rhs)
1312 }
1313 Expression::BinaryExpression { lhs, rhs, op } => {
1314 write!(f, "(")?;
1315 pretty_print(f, lhs)?;
1316 match *op {
1317 '=' | '!' => write!(f, " {}= ", op)?,
1318 _ => write!(f, " {} ", op)?,
1319 };
1320 pretty_print(f, rhs)?;
1321 write!(f, ")")
1322 }
1323 Expression::UnaryOp { sub, op } => {
1324 write!(f, "{}", op)?;
1325 pretty_print(f, sub)
1326 }
1327 Expression::ImageReference { resource_ref, .. } => write!(f, "{:?}", resource_ref),
1328 Expression::Condition { condition, true_expr, false_expr } => {
1329 write!(f, "if (")?;
1330 pretty_print(f, condition)?;
1331 write!(f, ") {{ ")?;
1332 pretty_print(f, true_expr)?;
1333 write!(f, " }} else {{ ")?;
1334 pretty_print(f, false_expr)?;
1335 write!(f, " }}")
1336 }
1337 Expression::Array { element_ty: _, values } => {
1338 write!(f, "[")?;
1339 for e in values {
1340 pretty_print(f, e)?;
1341 write!(f, ", ")?;
1342 }
1343 write!(f, "]")
1344 }
1345 Expression::Struct { ty: _, values } => {
1346 write!(f, "{{ ")?;
1347 for (name, e) in values {
1348 write!(f, "{}: ", name)?;
1349 pretty_print(f, e)?;
1350 write!(f, ", ")?;
1351 }
1352 write!(f, " }}")
1353 }
1354 Expression::PathData(data) => write!(f, "{:?}", data),
1355 Expression::EasingCurve(e) => write!(f, "{:?}", e),
1356 Expression::LinearGradient { angle, stops } => {
1357 write!(f, "@linear-gradient(")?;
1358 pretty_print(f, angle)?;
1359 for (c, s) in stops {
1360 write!(f, ", ")?;
1361 pretty_print(f, c)?;
1362 write!(f, " ")?;
1363 pretty_print(f, s)?;
1364 }
1365 write!(f, ")")
1366 }
1367 Expression::EnumerationValue(e) => match e.enumeration.values.get(e.value as usize) {
1368 Some(val) => write!(f, "{}.{}", e.enumeration.name, val),
1369 None => write!(f, "{}.{}", e.enumeration.name, e.value),
1370 },
1371 Expression::ReturnStatement(e) => {
1372 write!(f, "return ")?;
1373 e.as_ref().map(|e| pretty_print(f, e)).unwrap_or(Ok(()))
1374 }
1375 Expression::LayoutCacheAccess { layout_cache_prop, index, repeater_index } => {
1376 write!(
1377 f,
1378 "{:?}[{}{}]",
1379 layout_cache_prop,
1380 index,
1381 if repeater_index.is_some() { " + $index" } else { "" }
1382 )
1383 }
1384 Expression::ComputeLayoutInfo(..) => write!(f, "layout_info(..)"),
1385 Expression::SolveLayout(..) => write!(f, "solve_layout(..)"),
1386 }
1387}