1use itertools::Either;
9
10use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
11use crate::expression_tree::{self, BindingExpression, Expression, Unit};
12use crate::langtype::PropertyLookupResult;
13use crate::langtype::{BuiltinElement, NativeClass, Type};
14use crate::layout::{LayoutConstraints, Orientation};
15use crate::namedreference::NamedReference;
16use crate::parser;
17use crate::parser::{syntax_nodes, SyntaxKind, SyntaxNode};
18use crate::typeloader::ImportedTypes;
19use crate::typeregister::TypeRegister;
20use std::cell::{Cell, RefCell};
21use std::collections::btree_map::Entry;
22use std::collections::{BTreeMap, HashMap};
23use std::rc::{Rc, Weak};
24
25macro_rules! unwrap_or_continue {
26 ($e:expr ; $diag:expr) => {
27 match $e {
28 Some(x) => x,
29 None => {
30 debug_assert!($diag.has_error()); continue;
32 }
33 }
34 };
35}
36
37#[derive(Default, Debug)]
39pub struct Document {
40 pub node: Option<syntax_nodes::Document>,
41 pub inner_components: Vec<Rc<Component>>,
42 pub inner_structs: Vec<Type>,
43 pub root_component: Rc<Component>,
44 pub local_registry: TypeRegister,
45 pub custom_fonts: Vec<String>,
48 exports: Exports,
49}
50
51impl Document {
52 pub fn from_node(
53 node: syntax_nodes::Document,
54 foreign_imports: Vec<ImportedTypes>,
55 diag: &mut BuildDiagnostics,
56 parent_registry: &Rc<RefCell<TypeRegister>>,
57 ) -> Self {
58 debug_assert_eq!(node.kind(), SyntaxKind::Document);
59
60 let mut local_registry = TypeRegister::new(parent_registry);
61 let mut inner_components = vec![];
62 let mut inner_structs = vec![];
63
64 let mut process_component =
65 |n: syntax_nodes::Component,
66 diag: &mut BuildDiagnostics,
67 local_registry: &mut TypeRegister| {
68 let compo = Component::from_node(n, diag, local_registry);
69 local_registry.add(compo.clone());
70 inner_components.push(compo);
71 };
72 let mut process_struct =
73 |n: syntax_nodes::StructDeclaration,
74 diag: &mut BuildDiagnostics,
75 local_registry: &mut TypeRegister| {
76 let mut ty = type_struct_from_node(n.ObjectType(), diag, local_registry);
77 if let Type::Struct { name, .. } = &mut ty {
78 *name = parser::identifier_text(&n.DeclaredIdentifier());
79 } else {
80 assert!(diag.has_error());
81 return;
82 }
83 local_registry.insert_type(ty.clone());
84 inner_structs.push(ty);
85 };
86
87 for n in node.children() {
88 match n.kind() {
89 SyntaxKind::Component => process_component(n.into(), diag, &mut local_registry),
90 SyntaxKind::StructDeclaration => {
91 process_struct(n.into(), diag, &mut local_registry)
92 }
93 SyntaxKind::ExportsList => {
94 for n in n.children() {
95 match n.kind() {
96 SyntaxKind::Component => {
97 process_component(n.into(), diag, &mut local_registry)
98 }
99 SyntaxKind::StructDeclaration => {
100 process_struct(n.into(), diag, &mut local_registry)
101 }
102 _ => {}
103 }
104 }
105 }
106 _ => {}
107 };
108 }
109 let exports = Exports::from_node(&node, &inner_components, &local_registry, diag);
110
111 let root_component = inner_components
112 .last()
113 .cloned()
114 .or_else(|| {
115 node.ImportSpecifier()
116 .last()
117 .and_then(|import| {
118 crate::typeloader::ImportedName::extract_imported_names(&import)
119 .and_then(|it| it.last())
120 })
121 .and_then(|import| match local_registry.lookup(&import.internal_name) {
122 Type::Component(c) => Some(c),
123 _ => None,
124 })
125 })
126 .unwrap_or_default();
127
128 let custom_fonts = foreign_imports
129 .into_iter()
130 .filter_map(|import| {
131 if import.file.ends_with(".ttc")
132 || import.file.ends_with(".ttf")
133 || import.file.ends_with(".otf")
134 {
135 if import.file.starts_with("http://")
138 || import.file.starts_with("https://")
139 || crate::fileaccess::load_file(std::path::Path::new(&import.file))
140 .is_some()
141 {
142 Some(import.file)
143 } else {
144 diag.push_error(
145 format!("File \"{}\" not found", import.file),
146 &import.import_token,
147 );
148 None
149 }
150 } else {
151 diag.push_error(
152 format!("Unsupported foreign import \"{}\"", import.file),
153 &import.import_token,
154 );
155 None
156 }
157 })
158 .collect();
159
160 Document {
161 node: Some(node),
162 root_component,
163 inner_components,
164 inner_structs,
165 local_registry,
166 custom_fonts,
167 exports,
168 }
169 }
170
171 pub fn exports(&self) -> &Vec<(ExportedName, Type)> {
172 &self.exports.0
173 }
174}
175
176#[derive(Debug)]
177pub struct PopupWindow {
178 pub component: Rc<Component>,
179 pub x: NamedReference,
180 pub y: NamedReference,
181 pub parent_element: ElementRc,
182}
183
184type ChildrenInsertionPoint = (ElementRc, syntax_nodes::ChildrenPlaceholder);
185
186#[derive(Debug, Default)]
188pub struct UsedSubTypes {
189 pub globals: Vec<Rc<Component>>,
191 pub structs: Vec<Type>,
193 pub sub_components: Vec<Rc<Component>>,
196}
197
198#[derive(Default, Debug)]
201pub struct Component {
202 pub id: String,
204 pub root_element: ElementRc,
205
206 pub parent_element: Weak<RefCell<Element>>,
208
209 pub optimized_elements: RefCell<Vec<ElementRc>>,
212
213 pub embedded_file_resources:
216 RefCell<HashMap<String, crate::embedded_resources::EmbeddedResources>>,
217
218 pub root_constraints: RefCell<LayoutConstraints>,
220
221 pub child_insertion_point: RefCell<Option<ChildrenInsertionPoint>>,
224
225 pub setup_code: RefCell<Vec<Expression>>,
227
228 pub used_types: RefCell<UsedSubTypes>,
231 pub popup_windows: RefCell<Vec<PopupWindow>>,
232
233 pub exported_global_names: RefCell<Vec<ExportedName>>,
236
237 pub is_root_component: Cell<bool>,
240}
241
242impl Component {
243 pub fn from_node(
244 node: syntax_nodes::Component,
245 diag: &mut BuildDiagnostics,
246 tr: &TypeRegister,
247 ) -> Rc<Self> {
248 let mut child_insertion_point = None;
249 let c = Component {
250 id: parser::identifier_text(&node.DeclaredIdentifier()).unwrap_or_default(),
251 root_element: Element::from_node(
252 node.Element(),
253 "root".into(),
254 Type::Invalid,
255 &mut child_insertion_point,
256 diag,
257 tr,
258 ),
259 child_insertion_point: RefCell::new(child_insertion_point),
260 ..Default::default()
261 };
262 let c = Rc::new(c);
263 let weak = Rc::downgrade(&c);
264 recurse_elem(&c.root_element, &(), &mut |e, _| {
265 e.borrow_mut().enclosing_component = weak.clone()
266 });
267 c
268 }
269
270 pub fn is_global(&self) -> bool {
272 match &self.root_element.borrow().base_type {
273 Type::Void => true,
274 Type::Builtin(c) => c.is_global,
275 _ => false,
276 }
277 }
278
279 pub fn requires_code_generation(&self) -> bool {
282 !matches!(self.root_element.borrow().base_type, Type::Builtin(_))
283 }
284
285 pub fn visible_in_public_api(&self) -> bool {
286 if self.is_global() {
287 !self.exported_global_names.borrow().is_empty()
288 } else {
289 self.parent_element.upgrade().is_none() && self.is_root_component.get()
290 }
291 }
292
293 pub fn global_aliases(&self) -> Vec<String> {
296 self.exported_global_names
297 .borrow()
298 .iter()
299 .filter(|name| name.as_str() != self.root_element.borrow().id)
300 .map(|name| name.original_name())
301 .collect()
302 }
303
304 pub fn is_sub_component(&self) -> bool {
305 !self.is_root_component.get()
306 && self.parent_element.upgrade().is_none()
307 && !self.is_global()
308 }
309
310 pub fn repeater_count(&self) -> u32 {
312 let mut count = 0;
313 recurse_elem(&self.root_element, &(), &mut |element, _| {
314 let element = element.borrow();
315 if let Some(sub_component) = element.sub_component() {
316 count += sub_component.repeater_count();
317 } else if element.repeated.is_some() {
318 count += 1;
319 }
320 });
321 count
322 }
323}
324
325#[derive(Clone, Debug, Default)]
326pub struct PropertyDeclaration {
327 pub property_type: Type,
328 pub node: Option<Either<syntax_nodes::PropertyDeclaration, syntax_nodes::CallbackDeclaration>>,
329 pub expose_in_public_api: bool,
331 pub is_alias: Option<NamedReference>,
333}
334
335impl PropertyDeclaration {
336 pub fn type_node(&self) -> Option<SyntaxNode> {
338 self.node.as_ref().map(|x| -> crate::parser::SyntaxNode {
339 x.as_ref().either(
340 |x| x.Type().map_or_else(|| x.clone().into(), |x| x.into()),
341 |x| x.clone().into(),
342 )
343 })
344 }
345}
346
347impl From<Type> for PropertyDeclaration {
348 fn from(ty: Type) -> Self {
349 PropertyDeclaration { property_type: ty, ..Self::default() }
350 }
351}
352
353#[derive(Debug, Clone)]
354pub struct TransitionPropertyAnimation {
355 pub state_id: i32,
357 pub is_out: bool,
359 pub animation: ElementRc,
361}
362
363impl TransitionPropertyAnimation {
364 pub fn condition(&self, state: Expression) -> Expression {
367 Expression::BinaryExpression {
368 lhs: Box::new(Expression::StructFieldAccess {
369 base: Box::new(state),
370 name: (if self.is_out { "previous-state" } else { "current-state" }).into(),
371 }),
372 rhs: Box::new(Expression::NumberLiteral(self.state_id as _, Unit::None)),
373 op: '=',
374 }
375 }
376}
377
378#[derive(Debug)]
379pub enum PropertyAnimation {
380 Static(ElementRc),
381 Transition { state_ref: Expression, animations: Vec<TransitionPropertyAnimation> },
382}
383
384impl Clone for PropertyAnimation {
385 fn clone(&self) -> Self {
386 fn deep_clone(e: &ElementRc) -> ElementRc {
387 let e = e.borrow();
388 debug_assert!(e.children.is_empty());
389 debug_assert!(e.property_declarations.is_empty());
390 debug_assert!(e.states.is_empty() && e.transitions.is_empty());
391 Rc::new(RefCell::new(Element {
392 id: e.id.clone(),
393 base_type: e.base_type.clone(),
394 bindings: e.bindings.clone(),
395 property_analysis: e.property_analysis.clone(),
396 enclosing_component: e.enclosing_component.clone(),
397 repeated: None,
398 node: e.node.clone(),
399 ..Default::default()
400 }))
401 }
402 match self {
403 PropertyAnimation::Static(e) => PropertyAnimation::Static(deep_clone(e)),
404 PropertyAnimation::Transition { state_ref, animations } => {
405 PropertyAnimation::Transition {
406 state_ref: state_ref.clone(),
407 animations: animations
408 .iter()
409 .map(|t| TransitionPropertyAnimation {
410 state_id: t.state_id,
411 is_out: t.is_out,
412 animation: deep_clone(&t.animation),
413 })
414 .collect(),
415 }
416 }
417 }
418 }
419}
420
421pub type BindingsMap = BTreeMap<String, RefCell<BindingExpression>>;
422
423#[derive(Default)]
425pub struct Element {
426 pub id: String,
432 pub base_type: crate::langtype::Type,
434 pub bindings: BindingsMap,
436 pub property_analysis: RefCell<HashMap<String, PropertyAnalysis>>,
437
438 pub children: Vec<ElementRc>,
439 pub enclosing_component: Weak<Component>,
441
442 pub property_declarations: BTreeMap<String, PropertyDeclaration>,
443
444 pub named_references: crate::namedreference::NamedReferenceContainer,
446
447 pub repeated: Option<RepeatedElementInfo>,
449
450 pub states: Vec<State>,
451 pub transitions: Vec<Transition>,
452
453 pub child_of_layout: bool,
455 pub layout_info_prop: Option<(NamedReference, NamedReference)>,
457
458 pub is_flickable_viewport: bool,
460
461 pub item_index: once_cell::unsync::OnceCell<usize>,
464 pub item_index_of_first_children: once_cell::unsync::OnceCell<usize>,
466
467 pub node: Option<syntax_nodes::Element>,
469}
470
471impl Spanned for Element {
472 fn span(&self) -> crate::diagnostics::Span {
473 self.node.as_ref().map(|n| n.span()).unwrap_or_default()
474 }
475
476 fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> {
477 self.node.as_ref().map(|n| &n.source_file)
478 }
479}
480
481impl core::fmt::Debug for Element {
482 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
483 pretty_print(f, self, 0)
484 }
485}
486
487pub fn pretty_print(
488 f: &mut impl std::fmt::Write,
489 e: &Element,
490 indentation: usize,
491) -> std::fmt::Result {
492 if let Some(repeated) = &e.repeated {
493 write!(f, "for {}[{}] in ", repeated.model_data_id, repeated.index_id)?;
494 expression_tree::pretty_print(f, &repeated.model)?;
495 write!(f, ":")?;
496 }
497 writeln!(f, "{} := {} {{", e.id, e.base_type)?;
498 let mut indentation = indentation + 1;
499 macro_rules! indent {
500 () => {
501 for _ in 0..indentation {
502 write!(f, " ")?
503 }
504 };
505 }
506 for (name, ty) in &e.property_declarations {
507 indent!();
508 if let Some(alias) = &ty.is_alias {
509 writeln!(f, "alias<{}> {} <=> {:?};", ty.property_type, name, alias)?
510 } else {
511 writeln!(f, "property<{}> {};", ty.property_type, name)?
512 }
513 }
514 for (name, expr) in &e.bindings {
515 let expr = expr.borrow();
516 indent!();
517 write!(f, "{}: ", name)?;
518 expression_tree::pretty_print(f, &expr.expression)?;
519 if expr.analysis.as_ref().map_or(false, |a| a.is_const) {
520 write!(f, "/*const*/")?;
521 }
522 writeln!(f, ";")?;
523 if let Some(anim) = &expr.animation {
525 indent!();
526 writeln!(f, "animate {} {:?}", name, anim)?;
527 }
528 for nr in &expr.two_way_bindings {
529 indent!();
530 writeln!(f, "{} <=> {:?};", name, nr)?;
531 }
532 }
533 if !e.states.is_empty() {
534 indent!();
535 writeln!(f, "states {:?}", e.states)?;
536 }
537 if !e.transitions.is_empty() {
538 indent!();
539 writeln!(f, "transitions {:?} ", e.transitions)?;
540 }
541 for c in &e.children {
542 indent!();
543 pretty_print(f, &c.borrow(), indentation)?
544 }
545
546 indentation -= 1;
550 indent!();
551 writeln!(f, "}}")
552}
553
554#[derive(Clone, Default, Debug)]
555pub struct PropertyAnalysis {
556 pub is_set: bool,
558
559 pub is_set_externally: bool,
561
562 pub is_read: bool,
565
566 pub is_read_externally: bool,
568}
569
570impl PropertyAnalysis {
571 pub fn merge_with_base(&mut self, other: &PropertyAnalysis) {
576 self.is_set |= other.is_set;
577 self.is_read |= other.is_read;
578 }
579
580 pub fn merge(&mut self, other: &PropertyAnalysis) {
582 self.is_set |= other.is_set;
583 self.is_read |= other.is_read;
584 self.is_read_externally |= other.is_read_externally;
585 self.is_set_externally |= other.is_set_externally;
586 }
587
588 pub fn is_used(&self) -> bool {
590 self.is_read || self.is_read_externally || self.is_set || self.is_set_externally
591 }
592}
593
594#[derive(Debug, Clone)]
595pub struct ListViewInfo {
596 pub viewport_y: NamedReference,
597 pub viewport_height: NamedReference,
598 pub viewport_width: NamedReference,
599 pub listview_height: NamedReference,
601 pub listview_width: NamedReference,
603}
604
605#[derive(Debug, Clone)]
606pub struct RepeatedElementInfo {
608 pub model: Expression,
609 pub model_data_id: String,
610 pub index_id: String,
611 pub is_conditional_element: bool,
615 pub is_listview: Option<ListViewInfo>,
617}
618
619pub type ElementRc = Rc<RefCell<Element>>;
620
621impl Element {
622 pub fn from_node(
623 node: syntax_nodes::Element,
624 id: String,
625 parent_type: Type,
626 component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
627 diag: &mut BuildDiagnostics,
628 tr: &TypeRegister,
629 ) -> ElementRc {
630 let base_type = if let Some(base_node) = node.QualifiedName() {
631 let base = QualifiedTypeName::from_node(base_node.clone());
632 let base_string = base.to_string();
633 if base_string == "Clip" {
634 diag.push_warning("The 'Clip' element is deprecated, use the 'clip' property on a Rectangle instead".into(), &base_node);
635 }
636 match parent_type.lookup_type_for_child_element(&base_string, tr) {
637 Ok(Type::Component(c)) if c.is_global() => {
638 diag.push_error(
639 "Cannot create an instance of a global component".into(),
640 &base_node,
641 );
642 Type::Invalid
643 }
644 Ok(ty @ Type::Component(_)) | Ok(ty @ Type::Builtin(_)) => ty,
645 Ok(ty) => {
646 diag.push_error(format!("'{}' cannot be used as an element", ty), &base_node);
647 Type::Invalid
648 }
649 Err(err) => {
650 diag.push_error(err, &base_node);
651 Type::Invalid
652 }
653 }
654 } else {
655 if parent_type != Type::Invalid {
656 assert!(diag.has_error());
658 return ElementRc::default();
659 }
660
661 let mut error_on = |node: &dyn Spanned, what: &str| {
663 diag.push_error(format!("A global component cannot have {}", what), node);
664 };
665 node.SubElement().for_each(|n| error_on(&n, "sub elements"));
666 node.RepeatedElement().for_each(|n| error_on(&n, "sub elements"));
667 if let Some(n) = node.ChildrenPlaceholder() {
668 error_on(&n, "sub elements");
669 }
670 node.PropertyAnimation().for_each(|n| error_on(&n, "animations"));
671 node.States().for_each(|n| error_on(&n, "states"));
672 node.Transitions().for_each(|n| error_on(&n, "transitions"));
673 Type::Void
674 };
675 let mut r = Element { id, base_type, node: Some(node.clone()), ..Default::default() };
676
677 for prop_decl in node.PropertyDeclaration() {
678 let prop_type = prop_decl
679 .Type()
680 .map(|type_node| {
681 let prop_type = type_from_node(type_node.clone(), diag, tr);
682
683 if prop_type != Type::Invalid && !prop_type.is_property_type() {
684 diag.push_error(
685 format!("'{}' is not a valid property type", prop_type),
686 &type_node,
687 );
688 }
689 prop_type
690 })
691 .unwrap_or(Type::InferredProperty);
693
694 let unresolved_prop_name =
695 unwrap_or_continue!(parser::identifier_text(&prop_decl.DeclaredIdentifier()); diag);
696 let PropertyLookupResult {
697 resolved_name: prop_name,
698 property_type: maybe_existing_prop_type,
699 } = r.lookup_property(&unresolved_prop_name);
700 if !matches!(maybe_existing_prop_type, Type::Invalid) {
701 diag.push_error(
702 format!("Cannot override property '{}'", prop_name),
703 &prop_decl.DeclaredIdentifier().child_token(SyntaxKind::Identifier).unwrap(),
704 )
705 }
706
707 r.property_declarations.insert(
708 prop_name.to_string(),
709 PropertyDeclaration {
710 property_type: prop_type,
711 node: Some(Either::Left(prop_decl.clone())),
712 ..Default::default()
713 },
714 );
715
716 if let Some(csn) = prop_decl.BindingExpression() {
717 if r.bindings
718 .insert(
719 prop_name.to_string(),
720 BindingExpression::new_uncompiled(csn.into()).into(),
721 )
722 .is_some()
723 {
724 diag.push_error(
725 "Duplicated property binding".into(),
726 &prop_decl.DeclaredIdentifier(),
727 );
728 }
729 }
730 if let Some(csn) = prop_decl.TwoWayBinding() {
731 if r.bindings
732 .insert(prop_name.into(), BindingExpression::new_uncompiled(csn.into()).into())
733 .is_some()
734 {
735 diag.push_error(
736 "Duplicated property binding".into(),
737 &prop_decl.DeclaredIdentifier(),
738 );
739 }
740 }
741 }
742
743 r.parse_bindings(
744 node.Binding().filter_map(|b| {
745 Some((b.child_token(SyntaxKind::Identifier)?, b.BindingExpression().into()))
746 }),
747 diag,
748 );
749 r.parse_bindings(
750 node.TwoWayBinding()
751 .filter_map(|b| Some((b.child_token(SyntaxKind::Identifier)?, b.into()))),
752 diag,
753 );
754
755 if let Type::Builtin(builtin_base) = &r.base_type {
756 for (prop, info) in &builtin_base.properties {
757 if let Some(expr) = &info.default_value {
758 r.bindings
759 .entry(prop.clone())
760 .or_insert_with(|| RefCell::new(expr.clone().into()));
761 }
762 }
763 }
764
765 for sig_decl in node.CallbackDeclaration() {
766 let name =
767 unwrap_or_continue!(parser::identifier_text(&sig_decl.DeclaredIdentifier()); diag);
768
769 if let Some(csn) = sig_decl.TwoWayBinding() {
770 r.bindings
771 .insert(name.clone(), BindingExpression::new_uncompiled(csn.into()).into());
772 r.property_declarations.insert(
773 name,
774 PropertyDeclaration {
775 property_type: Type::InferredCallback,
776 node: Some(Either::Right(sig_decl)),
777 ..Default::default()
778 },
779 );
780 continue;
781 }
782
783 let args = sig_decl.Type().map(|node_ty| type_from_node(node_ty, diag, tr)).collect();
784 let return_type = sig_decl
785 .ReturnType()
786 .map(|ret_ty| Box::new(type_from_node(ret_ty.Type(), diag, tr)));
787 r.property_declarations.insert(
788 name,
789 PropertyDeclaration {
790 property_type: Type::Callback { return_type, args },
791 node: Some(Either::Right(sig_decl)),
792 ..Default::default()
793 },
794 );
795 }
796
797 for con_node in node.CallbackConnection() {
798 let unresolved_name = unwrap_or_continue!(parser::identifier_text(&con_node); diag);
799 let PropertyLookupResult { resolved_name, property_type } =
800 r.lookup_property(&unresolved_name);
801 if let Type::Callback { args, .. } = &property_type {
802 let num_arg = con_node.DeclaredIdentifier().count();
803 if num_arg > args.len() {
804 diag.push_error(
805 format!(
806 "'{}' only has {} arguments, but {} were provided",
807 unresolved_name,
808 args.len(),
809 num_arg
810 ),
811 &con_node.child_token(SyntaxKind::Identifier).unwrap(),
812 );
813 }
814 } else if property_type == Type::InferredCallback {
815 } else {
817 diag.push_error(
818 format!("'{}' is not a callback in {}", unresolved_name, r.base_type),
819 &con_node.child_token(SyntaxKind::Identifier).unwrap(),
820 );
821 continue;
822 }
823 if r.bindings
824 .insert(
825 resolved_name.into_owned(),
826 BindingExpression::new_uncompiled(con_node.clone().into()).into(),
827 )
828 .is_some()
829 {
830 diag.push_error(
831 "Duplicated callback".into(),
832 &con_node.child_token(SyntaxKind::Identifier).unwrap(),
833 );
834 }
835 }
836
837 for anim in node.PropertyAnimation() {
838 if let Some(star) = anim.child_token(SyntaxKind::Star) {
839 diag.push_error(
840 "catch-all property is only allowed within transitions".into(),
841 &star,
842 )
843 };
844 for prop_name_token in anim.QualifiedName() {
845 match QualifiedTypeName::from_node(prop_name_token.clone()).members.as_slice() {
846 [unresolved_prop_name] => {
847 let PropertyLookupResult { resolved_name, property_type } =
848 r.lookup_property(unresolved_prop_name);
849 if let Some(anim_element) = animation_element_from_node(
850 &anim,
851 &prop_name_token,
852 property_type,
853 diag,
854 tr,
855 ) {
856 if unresolved_prop_name != resolved_name.as_ref() {
857 diag.push_property_deprecation_warning(
858 unresolved_prop_name,
859 &resolved_name,
860 &prop_name_token,
861 );
862 }
863
864 let expr_binding =
865 r.bindings.entry(resolved_name.to_string()).or_insert_with(|| {
866 let mut r = BindingExpression::from(Expression::Invalid);
867 r.priority = 1;
868 r.span = Some(prop_name_token.to_source_location());
869 r.into()
870 });
871 if expr_binding
872 .get_mut()
873 .animation
874 .replace(PropertyAnimation::Static(anim_element))
875 .is_some()
876 {
877 diag.push_error("Duplicated animation".into(), &prop_name_token)
878 }
879 }
880 }
881 _ => diag.push_error(
882 "Can only refer to property in the current element".into(),
883 &prop_name_token,
884 ),
885 }
886 }
887 }
888
889 let mut children_placeholder = None;
890 let r = ElementRc::new(RefCell::new(r));
891
892 for se in node.children() {
893 if se.kind() == SyntaxKind::SubElement {
894 let parent_type = r.borrow().base_type.clone();
895 r.borrow_mut().children.push(Element::from_sub_element_node(
896 se.into(),
897 parent_type,
898 component_child_insertion_point,
899 diag,
900 tr,
901 ));
902 } else if se.kind() == SyntaxKind::RepeatedElement {
903 let rep = Element::from_repeated_node(
904 se.into(),
905 &r,
906 component_child_insertion_point,
907 diag,
908 tr,
909 );
910 r.borrow_mut().children.push(rep);
911 } else if se.kind() == SyntaxKind::ConditionalElement {
912 let rep = Element::from_conditional_node(
913 se.into(),
914 r.borrow().base_type.clone(),
915 component_child_insertion_point,
916 diag,
917 tr,
918 );
919 r.borrow_mut().children.push(rep);
920 } else if se.kind() == SyntaxKind::ChildrenPlaceholder {
921 if children_placeholder.is_some() {
922 diag.push_error(
923 "The @children placeholder can only appear once in an element".into(),
924 &se,
925 )
926 } else {
927 children_placeholder = Some(se.clone().into());
928 }
929 }
930 }
931
932 if let Some(children_placeholder) = children_placeholder {
933 if component_child_insertion_point.is_some() {
934 diag.push_error(
935 "The @children placeholder can only appear once in an element hierarchy".into(),
936 &children_placeholder,
937 )
938 } else {
939 *component_child_insertion_point = Some((r.clone(), children_placeholder));
940 }
941 }
942
943 for state in node.States().flat_map(|s| s.State()) {
944 let s = State {
945 id: parser::identifier_text(&state.DeclaredIdentifier()).unwrap_or_default(),
946 condition: state.Expression().map(|e| Expression::Uncompiled(e.into())),
947 property_changes: state
948 .StatePropertyChange()
949 .filter_map(|s| {
950 lookup_property_from_qualified_name(s.QualifiedName(), &r, diag).map(
951 |(ne, _)| (ne, Expression::Uncompiled(s.BindingExpression().into()), s),
952 )
953 })
954 .collect(),
955 };
956 r.borrow_mut().states.push(s);
957 }
958
959 for trs in node.Transitions().flat_map(|s| s.Transition()) {
960 if let Some(star) = trs.child_token(SyntaxKind::Star) {
961 diag.push_error("TODO: catch-all not yet implemented".into(), &star);
962 };
963 let trans = Transition {
964 is_out: parser::identifier_text(&trs).unwrap_or_default() == "out",
965 state_id: parser::identifier_text(&trs.DeclaredIdentifier()).unwrap_or_default(),
966 property_animations: trs
967 .PropertyAnimation()
968 .flat_map(|pa| pa.QualifiedName().map(move |qn| (pa.clone(), qn)))
969 .filter_map(|(pa, qn)| {
970 lookup_property_from_qualified_name(qn.clone(), &r, diag).and_then(
971 |(ne, prop_type)| {
972 animation_element_from_node(&pa, &qn, prop_type, diag, tr)
973 .map(|anim_element| (ne, qn.to_source_location(), anim_element))
974 },
975 )
976 })
977 .collect(),
978 node: trs.DeclaredIdentifier().into(),
979 };
980 r.borrow_mut().transitions.push(trans);
981 }
982
983 r
984 }
985
986 fn from_sub_element_node(
987 node: syntax_nodes::SubElement,
988 parent_type: Type,
989 component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
990 diag: &mut BuildDiagnostics,
991 tr: &TypeRegister,
992 ) -> ElementRc {
993 let id = parser::identifier_text(&node).unwrap_or_default();
994 if matches!(id.as_ref(), "parent" | "self" | "root") {
995 diag.push_error(
996 format!("'{}' is a reserved id", id),
997 &node.child_token(SyntaxKind::Identifier).unwrap(),
998 )
999 }
1000 Element::from_node(
1001 node.Element(),
1002 id,
1003 parent_type,
1004 component_child_insertion_point,
1005 diag,
1006 tr,
1007 )
1008 }
1009
1010 fn from_repeated_node(
1011 node: syntax_nodes::RepeatedElement,
1012 parent: &ElementRc,
1013 component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
1014 diag: &mut BuildDiagnostics,
1015 tr: &TypeRegister,
1016 ) -> ElementRc {
1017 let is_listview = if parent.borrow().base_type.to_string() == "ListView" {
1018 Some(ListViewInfo {
1019 viewport_y: NamedReference::new(parent, "viewport-y"),
1020 viewport_height: NamedReference::new(parent, "viewport-height"),
1021 viewport_width: NamedReference::new(parent, "viewport-width"),
1022 listview_height: NamedReference::new(parent, "visible-height"),
1023 listview_width: NamedReference::new(parent, "visible-width"),
1024 })
1025 } else {
1026 None
1027 };
1028 let rei = RepeatedElementInfo {
1029 model: Expression::Uncompiled(node.Expression().into()),
1030 model_data_id: node
1031 .DeclaredIdentifier()
1032 .and_then(|n| parser::identifier_text(&n))
1033 .unwrap_or_default(),
1034 index_id: node
1035 .RepeatedIndex()
1036 .and_then(|r| parser::identifier_text(&r))
1037 .unwrap_or_default(),
1038 is_conditional_element: false,
1039 is_listview,
1040 };
1041 let e = Element::from_sub_element_node(
1042 node.SubElement(),
1043 parent.borrow().base_type.clone(),
1044 component_child_insertion_point,
1045 diag,
1046 tr,
1047 );
1048 e.borrow_mut().repeated = Some(rei);
1049 e
1050 }
1051
1052 fn from_conditional_node(
1053 node: syntax_nodes::ConditionalElement,
1054 parent_type: Type,
1055 component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
1056 diag: &mut BuildDiagnostics,
1057 tr: &TypeRegister,
1058 ) -> ElementRc {
1059 let rei = RepeatedElementInfo {
1060 model: Expression::Uncompiled(node.Expression().into()),
1061 model_data_id: String::new(),
1062 index_id: String::new(),
1063 is_conditional_element: true,
1064 is_listview: None,
1065 };
1066 let e = Element::from_sub_element_node(
1067 node.SubElement(),
1068 parent_type,
1069 component_child_insertion_point,
1070 diag,
1071 tr,
1072 );
1073 e.borrow_mut().repeated = Some(rei);
1074 e
1075 }
1076
1077 pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {
1081 self.property_declarations.get(name).cloned().map(|decl| decl.property_type).map_or_else(
1082 || self.base_type.lookup_property(name),
1083 |property_type| PropertyLookupResult { resolved_name: name.into(), property_type },
1084 )
1085 }
1086
1087 pub fn span(&self) -> crate::diagnostics::Span {
1089 self.node.as_ref().map(|n| n.span()).unwrap_or_default()
1090 }
1091
1092 fn parse_bindings(
1093 &mut self,
1094 bindings: impl Iterator<Item = (crate::parser::SyntaxToken, SyntaxNode)>,
1095 diag: &mut BuildDiagnostics,
1096 ) {
1097 for (name_token, b) in bindings {
1098 let unresolved_name = crate::parser::normalize_identifier(name_token.text());
1099 let PropertyLookupResult { resolved_name, property_type } =
1100 self.lookup_property(&unresolved_name);
1101 if !property_type.is_property_type() {
1102 diag.push_error(
1103 match property_type {
1104 Type::Invalid => {
1105 if self.base_type != Type::Invalid {
1106 format!(
1107 "Unknown property {} in {}",
1108 unresolved_name, self.base_type
1109 )
1110 } else {
1111 continue;
1112 }
1113 }
1114 Type::Callback { .. } => {
1115 format!("'{}' is a callback. Use `=>` to connect", unresolved_name)
1116 }
1117 _ => format!(
1118 "Cannot assign to {} in {} because it does not have a valid property type",
1119 unresolved_name, self.base_type,
1120 ),
1121 },
1122 &name_token,
1123 );
1124 }
1125
1126 if resolved_name != unresolved_name {
1127 diag.push_property_deprecation_warning(
1128 &unresolved_name,
1129 &resolved_name,
1130 &name_token,
1131 );
1132 }
1133
1134 if self
1135 .bindings
1136 .insert(resolved_name.to_string(), BindingExpression::new_uncompiled(b).into())
1137 .is_some()
1138 {
1139 diag.push_error("Duplicated property binding".into(), &name_token);
1140 }
1141 }
1142 }
1143
1144 pub fn native_class(&self) -> Option<Rc<NativeClass>> {
1145 let mut base_type = self.base_type.clone();
1146 loop {
1147 match &base_type {
1148 Type::Component(component) => {
1149 base_type = component.root_element.clone().borrow().base_type.clone();
1150 }
1151 Type::Builtin(builtin) => break Some(builtin.native_class.clone()),
1152 Type::Native(native) => break Some(native.clone()),
1153 _ => break None,
1154 }
1155 }
1156 }
1157
1158 pub fn builtin_type(&self) -> Option<Rc<BuiltinElement>> {
1159 let mut base_type = self.base_type.clone();
1160 loop {
1161 match &base_type {
1162 Type::Component(component) => {
1163 base_type = component.root_element.clone().borrow().base_type.clone();
1164 }
1165 Type::Builtin(builtin) => break Some(builtin.clone()),
1166 _ => break None,
1167 }
1168 }
1169 }
1170
1171 pub fn layout_info_prop(&self, orientation: Orientation) -> Option<&NamedReference> {
1172 self.layout_info_prop.as_ref().map(|prop| match orientation {
1173 Orientation::Horizontal => &prop.0,
1174 Orientation::Vertical => &prop.1,
1175 })
1176 }
1177
1178 pub fn original_name(&self) -> String {
1180 self.node
1181 .as_ref()
1182 .and_then(|n| n.child_token(parser::SyntaxKind::Identifier))
1183 .map(|n| n.to_string())
1184 .unwrap_or_else(|| self.id.clone())
1185 }
1186
1187 pub fn is_binding_set(self: &Element, property_name: &str, need_explicit: bool) -> bool {
1192 if self.bindings.get(property_name).map_or(false, |b| {
1193 b.borrow().has_binding() && (!need_explicit || b.borrow().priority > 0)
1194 }) {
1195 true
1196 } else if let Type::Component(base) = &self.base_type {
1197 base.root_element.borrow().is_binding_set(property_name, need_explicit)
1198 } else {
1199 false
1200 }
1201 }
1202
1203 pub fn set_binding_if_not_set(
1206 &mut self,
1207 property_name: String,
1208 expression_fn: impl FnOnce() -> Expression,
1209 ) {
1210 if self.is_binding_set(&property_name, false) {
1211 return;
1212 }
1213
1214 match self.bindings.entry(property_name) {
1215 Entry::Vacant(vacant_entry) => {
1216 let mut binding: BindingExpression = expression_fn().into();
1217 binding.priority = i32::MAX;
1218 vacant_entry.insert(binding.into());
1219 }
1220 Entry::Occupied(mut existing_entry) => {
1221 let mut binding: BindingExpression = expression_fn().into();
1222 binding.priority = i32::MAX;
1223 existing_entry.get_mut().get_mut().merge_with(&binding);
1224 }
1225 };
1226 }
1227
1228 pub fn sub_component(&self) -> Option<&Rc<Component>> {
1229 if self.repeated.is_some() {
1230 None
1231 } else if let Type::Component(sub_component) = &self.base_type {
1232 Some(sub_component)
1233 } else {
1234 None
1235 }
1236 }
1237}
1238
1239pub fn type_from_node(
1241 node: syntax_nodes::Type,
1242 diag: &mut BuildDiagnostics,
1243 tr: &TypeRegister,
1244) -> Type {
1245 if let Some(qualified_type_node) = node.QualifiedName() {
1246 let qualified_type = QualifiedTypeName::from_node(qualified_type_node.clone());
1247
1248 let prop_type = tr.lookup_qualified(&qualified_type.members);
1249
1250 if prop_type == Type::Invalid {
1251 diag.push_error(format!("Unknown type '{}'", qualified_type), &qualified_type_node);
1252 }
1253 prop_type
1254 } else if let Some(object_node) = node.ObjectType() {
1255 type_struct_from_node(object_node, diag, tr)
1256 } else if let Some(array_node) = node.ArrayType() {
1257 Type::Array(Box::new(type_from_node(array_node.Type(), diag, tr)))
1258 } else {
1259 assert!(diag.has_error());
1260 Type::Invalid
1261 }
1262}
1263
1264pub fn type_struct_from_node(
1266 object_node: syntax_nodes::ObjectType,
1267 diag: &mut BuildDiagnostics,
1268 tr: &TypeRegister,
1269) -> Type {
1270 let fields = object_node
1271 .ObjectTypeMember()
1272 .map(|member| {
1273 (
1274 parser::identifier_text(&member).unwrap_or_default(),
1275 type_from_node(member.Type(), diag, tr),
1276 )
1277 })
1278 .collect();
1279 Type::Struct { fields, name: None, node: Some(object_node) }
1280}
1281
1282fn animation_element_from_node(
1283 anim: &syntax_nodes::PropertyAnimation,
1284 prop_name: &syntax_nodes::QualifiedName,
1285 prop_type: Type,
1286 diag: &mut BuildDiagnostics,
1287 tr: &TypeRegister,
1288) -> Option<ElementRc> {
1289 let anim_type = tr.property_animation_type_for_property(prop_type);
1290 if !matches!(anim_type, Type::Builtin(..)) {
1291 diag.push_error(
1292 format!(
1293 "'{}' is not a property that can be animated",
1294 prop_name.text().to_string().trim()
1295 ),
1296 prop_name,
1297 );
1298 None
1299 } else {
1300 let mut anim_element =
1301 Element { id: "".into(), base_type: anim_type, node: None, ..Default::default() };
1302 anim_element.parse_bindings(
1303 anim.Binding().filter_map(|b| {
1304 Some((b.child_token(SyntaxKind::Identifier)?, b.BindingExpression().into()))
1305 }),
1306 diag,
1307 );
1308 Some(Rc::new(RefCell::new(anim_element)))
1309 }
1310}
1311
1312#[derive(Default, Debug, Clone)]
1313pub struct QualifiedTypeName {
1314 pub members: Vec<String>,
1315}
1316
1317impl QualifiedTypeName {
1318 pub fn from_node(node: syntax_nodes::QualifiedName) -> Self {
1319 debug_assert_eq!(node.kind(), SyntaxKind::QualifiedName);
1320 let members = node
1321 .children_with_tokens()
1322 .filter(|n| n.kind() == SyntaxKind::Identifier)
1323 .filter_map(|x| x.as_token().map(|x| crate::parser::normalize_identifier(x.text())))
1324 .collect();
1325 Self { members }
1326 }
1327}
1328
1329impl std::fmt::Display for QualifiedTypeName {
1330 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1331 write!(f, "{}", self.members.join("."))
1332 }
1333}
1334
1335fn lookup_property_from_qualified_name(
1337 node: syntax_nodes::QualifiedName,
1338 r: &Rc<RefCell<Element>>,
1339 diag: &mut BuildDiagnostics,
1340) -> Option<(NamedReference, Type)> {
1341 let qualname = QualifiedTypeName::from_node(node.clone());
1342 match qualname.members.as_slice() {
1343 [unresolved_prop_name] => {
1344 let PropertyLookupResult { resolved_name, property_type } =
1345 r.borrow().lookup_property(unresolved_prop_name.as_ref());
1346 if !property_type.is_property_type() {
1347 diag.push_error(format!("'{}' is not a valid property", qualname), &node);
1348 }
1349 Some((NamedReference::new(r, &resolved_name), property_type))
1350 }
1351 [elem_id, unresolved_prop_name] => {
1352 if let Some(element) = find_element_by_id(r, elem_id.as_ref()) {
1353 let PropertyLookupResult { resolved_name, property_type } =
1354 element.borrow().lookup_property(unresolved_prop_name.as_ref());
1355 if !property_type.is_property_type() {
1356 diag.push_error(
1357 format!("'{}' not found in '{}'", unresolved_prop_name, elem_id),
1358 &node,
1359 );
1360 }
1361 Some((NamedReference::new(&element, &resolved_name), property_type))
1362 } else {
1363 diag.push_error(format!("'{}' is not a valid element id", elem_id), &node);
1364 None
1365 }
1366 }
1367 _ => {
1368 diag.push_error(format!("'{}' is not a valid property", qualname), &node);
1369 None
1370 }
1371 }
1372}
1373
1374fn find_element_by_id(e: &ElementRc, name: &str) -> Option<ElementRc> {
1376 if e.borrow().id == name {
1377 return Some(e.clone());
1378 }
1379 for x in &e.borrow().children {
1380 if x.borrow().repeated.is_some() {
1381 continue;
1382 }
1383 if let Some(x) = find_element_by_id(x, name) {
1384 return Some(x);
1385 }
1386 }
1387
1388 None
1389}
1390
1391pub fn find_parent_element(e: &ElementRc) -> Option<ElementRc> {
1394 fn recurse(base: &ElementRc, e: &ElementRc) -> Option<ElementRc> {
1395 for child in &base.borrow().children {
1396 if Rc::ptr_eq(child, e) {
1397 return Some(base.clone());
1398 }
1399 if let Some(x) = recurse(child, e) {
1400 return Some(x);
1401 }
1402 }
1403 None
1404 }
1405
1406 let root = e.borrow().enclosing_component.upgrade().unwrap().root_element.clone();
1407 if Rc::ptr_eq(&root, e) {
1408 return None;
1409 }
1410 recurse(&root, e)
1411}
1412
1413pub fn recurse_elem<State>(
1417 elem: &ElementRc,
1418 state: &State,
1419 vis: &mut impl FnMut(&ElementRc, &State) -> State,
1420) {
1421 let state = vis(elem, state);
1422 for sub in &elem.borrow().children {
1423 recurse_elem(sub, &state, vis);
1424 }
1425}
1426
1427pub fn recurse_elem_including_sub_components<State>(
1429 component: &Component,
1430 state: &State,
1431 vis: &mut impl FnMut(&ElementRc, &State) -> State,
1432) {
1433 recurse_elem(&component.root_element, state, &mut |elem, state| {
1434 debug_assert!(std::ptr::eq(
1435 component as *const Component,
1436 (&*elem.borrow().enclosing_component.upgrade().unwrap()) as *const Component
1437 ));
1438 if elem.borrow().repeated.is_some() {
1439 if let Type::Component(base) = &elem.borrow().base_type {
1440 if base.parent_element.upgrade().is_some() {
1441 recurse_elem_including_sub_components(base, state, vis);
1442 }
1443 }
1444 }
1445 vis(elem, state)
1446 });
1447 component
1448 .popup_windows
1449 .borrow()
1450 .iter()
1451 .for_each(|p| recurse_elem_including_sub_components(&p.component, state, vis))
1452}
1453
1454pub fn recurse_elem_no_borrow<State>(
1456 elem: &ElementRc,
1457 state: &State,
1458 vis: &mut impl FnMut(&ElementRc, &State) -> State,
1459) {
1460 let state = vis(elem, state);
1461 let children = elem.borrow().children.clone();
1462 for sub in &children {
1463 recurse_elem_no_borrow(sub, &state, vis);
1464 }
1465}
1466
1467pub fn recurse_elem_including_sub_components_no_borrow<State>(
1469 component: &Component,
1470 state: &State,
1471 vis: &mut impl FnMut(&ElementRc, &State) -> State,
1472) {
1473 recurse_elem_no_borrow(&component.root_element, state, &mut |elem, state| {
1474 let base = if elem.borrow().repeated.is_some() {
1475 if let Type::Component(base) = &elem.borrow().base_type {
1476 Some(base.clone())
1477 } else {
1478 None
1479 }
1480 } else {
1481 None
1482 };
1483 if let Some(base) = base {
1484 recurse_elem_including_sub_components_no_borrow(&base, state, vis);
1485 }
1486 vis(elem, state)
1487 });
1488 component
1489 .popup_windows
1490 .borrow()
1491 .iter()
1492 .for_each(|p| recurse_elem_including_sub_components_no_borrow(&p.component, state, vis));
1493 component
1494 .used_types
1495 .borrow()
1496 .globals
1497 .iter()
1498 .for_each(|p| recurse_elem_including_sub_components_no_borrow(p, state, vis));
1499}
1500
1501pub fn visit_element_expressions(
1507 elem: &ElementRc,
1508 mut vis: impl FnMut(&mut Expression, Option<&str>, &dyn Fn() -> Type),
1509) {
1510 fn visit_element_expressions_simple(
1511 elem: &ElementRc,
1512 vis: &mut impl FnMut(&mut Expression, Option<&str>, &dyn Fn() -> Type),
1513 ) {
1514 for (name, expr) in &elem.borrow().bindings {
1515 vis(&mut *expr.borrow_mut(), Some(name.as_str()), &|| {
1516 elem.borrow().lookup_property(name).property_type
1517 });
1518
1519 match &mut expr.borrow_mut().animation {
1520 Some(PropertyAnimation::Static(e)) => visit_element_expressions_simple(e, vis),
1521 Some(PropertyAnimation::Transition { animations, state_ref }) => {
1522 vis(state_ref, None, &|| Type::Int32);
1523 for a in animations {
1524 visit_element_expressions_simple(&a.animation, vis)
1525 }
1526 }
1527 None => (),
1528 }
1529 }
1530 }
1531
1532 let repeated = std::mem::take(&mut elem.borrow_mut().repeated);
1533 if let Some(mut r) = repeated {
1534 let is_conditional_element = r.is_conditional_element;
1535 vis(&mut r.model, None, &|| if is_conditional_element { Type::Bool } else { Type::Model });
1536 elem.borrow_mut().repeated = Some(r)
1537 }
1538 visit_element_expressions_simple(elem, &mut vis);
1539 let mut states = std::mem::take(&mut elem.borrow_mut().states);
1540 for s in &mut states {
1541 if let Some(cond) = s.condition.as_mut() {
1542 vis(cond, None, &|| Type::Bool)
1543 }
1544 for (ne, e, _) in &mut s.property_changes {
1545 vis(e, Some(ne.name()), &|| {
1546 ne.element().borrow().lookup_property(ne.name()).property_type
1547 });
1548 }
1549 }
1550 elem.borrow_mut().states = states;
1551
1552 let mut transitions = std::mem::take(&mut elem.borrow_mut().transitions);
1553 for t in &mut transitions {
1554 for (_, _, a) in &mut t.property_animations {
1555 visit_element_expressions_simple(a, &mut vis);
1556 }
1557 }
1558 elem.borrow_mut().transitions = transitions;
1559}
1560
1561pub fn visit_all_named_references_in_element(
1564 elem: &ElementRc,
1565 mut vis: impl FnMut(&mut NamedReference),
1566) {
1567 fn recurse_expression(expr: &mut Expression, vis: &mut impl FnMut(&mut NamedReference)) {
1568 expr.visit_mut(|sub| recurse_expression(sub, vis));
1569 match expr {
1570 Expression::PropertyReference(r) | Expression::CallbackReference(r) => vis(r),
1571 Expression::LayoutCacheAccess { layout_cache_prop, .. } => vis(layout_cache_prop),
1572 Expression::SolveLayout(l, _) => l.visit_named_references(vis),
1573 Expression::ComputeLayoutInfo(l, _) => l.visit_named_references(vis),
1574 Expression::RepeaterModelReference { element }
1577 | Expression::RepeaterIndexReference { element } => {
1578 let mut nc = NamedReference::new(&element.upgrade().unwrap(), "$model");
1580 vis(&mut nc);
1581 debug_assert!(nc.element().borrow().repeated.is_some());
1582 *element = Rc::downgrade(&nc.element());
1583 }
1584 _ => {}
1585 }
1586 }
1587 visit_element_expressions(elem, |expr, _, _| recurse_expression(expr, &mut vis));
1588 let mut states = std::mem::take(&mut elem.borrow_mut().states);
1589 for s in &mut states {
1590 for (r, _, _) in &mut s.property_changes {
1591 vis(r);
1592 }
1593 }
1594 elem.borrow_mut().states = states;
1595 let mut transitions = std::mem::take(&mut elem.borrow_mut().transitions);
1596 for t in &mut transitions {
1597 for (r, _, _) in &mut t.property_animations {
1598 vis(r)
1599 }
1600 }
1601 elem.borrow_mut().transitions = transitions;
1602 let mut repeated = std::mem::take(&mut elem.borrow_mut().repeated);
1603 if let Some(r) = &mut repeated {
1604 if let Some(lv) = &mut r.is_listview {
1605 vis(&mut lv.viewport_y);
1606 vis(&mut lv.viewport_height);
1607 vis(&mut lv.viewport_width);
1608 vis(&mut lv.listview_height);
1609 vis(&mut lv.listview_width);
1610 }
1611 }
1612 elem.borrow_mut().repeated = repeated;
1613 let mut layout_info_prop = std::mem::take(&mut elem.borrow_mut().layout_info_prop);
1614 layout_info_prop.as_mut().map(|(h, b)| (vis(h), vis(b)));
1615 elem.borrow_mut().layout_info_prop = layout_info_prop;
1616
1617 for expr in elem.borrow().bindings.values() {
1619 for nr in &mut expr.borrow_mut().two_way_bindings {
1620 vis(nr);
1621 }
1622 }
1623
1624 let mut property_declarations = std::mem::take(&mut elem.borrow_mut().property_declarations);
1625 for pd in property_declarations.values_mut() {
1626 pd.is_alias.as_mut().map(&mut vis);
1627 }
1628 elem.borrow_mut().property_declarations = property_declarations;
1629}
1630
1631pub fn visit_all_named_references(
1633 component: &Component,
1634 vis: &mut impl FnMut(&mut NamedReference),
1635) {
1636 recurse_elem_including_sub_components_no_borrow(
1637 component,
1638 &Weak::new(),
1639 &mut |elem, parent_compo| {
1640 visit_all_named_references_in_element(elem, |nr| vis(nr));
1641 let compo = elem.borrow().enclosing_component.clone();
1642 if !Weak::ptr_eq(parent_compo, &compo) {
1643 let compo = compo.upgrade().unwrap();
1644 compo.root_constraints.borrow_mut().visit_named_references(vis);
1645 compo.popup_windows.borrow_mut().iter_mut().for_each(|p| {
1646 vis(&mut p.x);
1647 vis(&mut p.y);
1648 });
1649 }
1650 compo
1651 },
1652 );
1653}
1654
1655pub fn visit_all_expressions(
1659 component: &Component,
1660 mut vis: impl FnMut(&mut Expression, &dyn Fn() -> Type),
1661) {
1662 recurse_elem_including_sub_components(component, &(), &mut |elem, _| {
1663 visit_element_expressions(elem, |expr, _, ty| vis(expr, ty));
1664 })
1665}
1666
1667#[derive(Debug, Clone)]
1668pub struct State {
1669 pub id: String,
1670 pub condition: Option<Expression>,
1671 pub property_changes: Vec<(NamedReference, Expression, syntax_nodes::StatePropertyChange)>,
1672}
1673
1674#[derive(Debug, Clone)]
1675pub struct Transition {
1676 pub is_out: bool,
1678 pub state_id: String,
1679 pub property_animations: Vec<(NamedReference, SourceLocation, ElementRc)>,
1680 pub node: SyntaxNode,
1682}
1683
1684#[derive(Clone, Debug, derive_more::Deref)]
1685pub struct ExportedName {
1686 #[deref]
1687 pub name: String, pub name_ident: SyntaxNode,
1689}
1690
1691impl ExportedName {
1692 pub fn original_name(&self) -> String {
1693 self.name_ident
1694 .child_token(parser::SyntaxKind::Identifier)
1695 .map(|n| n.to_string())
1696 .unwrap_or_else(|| self.name.clone())
1697 }
1698}
1699
1700#[derive(Default, Debug, derive_more::Deref)]
1701pub struct Exports(Vec<(ExportedName, Type)>);
1702
1703impl Exports {
1704 pub fn from_node(
1705 doc: &syntax_nodes::Document,
1706 inner_components: &[Rc<Component>],
1707 type_registry: &TypeRegister,
1708 diag: &mut BuildDiagnostics,
1709 ) -> Self {
1710 #[derive(Debug, Clone)]
1711 struct NamedExport {
1712 internal_name_ident: SyntaxNode,
1713 internal_name: String,
1714 external_name_ident: SyntaxNode,
1715 exported_name: String,
1716 }
1717
1718 let exports_it = doc.ExportsList().flat_map(|exports| exports.ExportSpecifier()).map(
1719 |export_specifier| {
1720 let internal_name = parser::identifier_text(&export_specifier.ExportIdentifier())
1721 .unwrap_or_else(|| {
1722 debug_assert!(diag.has_error());
1723 String::new()
1724 });
1725
1726 let (exported_name, name_location): (String, SyntaxNode) = export_specifier
1727 .ExportName()
1728 .and_then(|ident| {
1729 parser::identifier_text(&ident).map(|text| (text, ident.clone().into()))
1730 })
1731 .unwrap_or_else(|| {
1732 (internal_name.clone(), export_specifier.ExportIdentifier().into())
1733 });
1734
1735 NamedExport {
1736 internal_name_ident: export_specifier.ExportIdentifier().into(),
1737 internal_name,
1738 external_name_ident: name_location,
1739 exported_name,
1740 }
1741 },
1742 );
1743
1744 let exports_it = exports_it.chain(
1745 doc.ExportsList().filter_map(|exports| exports.Component()).map(|component| {
1746 let name_location: SyntaxNode = component.DeclaredIdentifier().into();
1747 let name =
1748 parser::identifier_text(&component.DeclaredIdentifier()).unwrap_or_else(|| {
1749 debug_assert!(diag.has_error());
1750 String::new()
1751 });
1752 NamedExport {
1753 internal_name_ident: name_location.clone(),
1754 internal_name: name.clone(),
1755 external_name_ident: name_location,
1756 exported_name: name,
1757 }
1758 }),
1759 );
1760 let exports_it = exports_it.chain(
1761 doc.ExportsList().flat_map(|exports| exports.StructDeclaration()).map(|st| {
1762 let name_location: SyntaxNode = st.DeclaredIdentifier().into();
1763 let name = parser::identifier_text(&st.DeclaredIdentifier()).unwrap_or_else(|| {
1764 debug_assert!(diag.has_error());
1765 String::new()
1766 });
1767 NamedExport {
1768 internal_name_ident: name_location.clone(),
1769 internal_name: name.clone(),
1770 external_name_ident: name_location,
1771 exported_name: name,
1772 }
1773 }),
1774 );
1775
1776 struct SeenExport {
1777 name_location: SyntaxNode,
1778 warned: bool,
1779 }
1780 let mut seen_exports: HashMap<String, SeenExport> = HashMap::new();
1781 let mut export_diagnostics = Vec::new();
1782
1783 let mut exports: Vec<_> = exports_it
1784 .filter(|export| {
1785 if let Some(other_loc) = seen_exports.get_mut(&export.exported_name) {
1786 let message = format!("Duplicated export '{}'", export.exported_name);
1787 if !other_loc.warned {
1788 export_diagnostics.push((message.clone(), other_loc.name_location.clone()));
1789 other_loc.warned = true;
1790 }
1791 export_diagnostics.push((message, export.external_name_ident.clone()));
1792 false
1793 } else {
1794 seen_exports.insert(
1795 export.exported_name.clone(),
1796 SeenExport {
1797 name_location: export.external_name_ident.clone(),
1798 warned: false,
1799 },
1800 );
1801
1802 true
1803 }
1804 })
1805 .collect();
1806
1807 for (message, location) in export_diagnostics {
1808 diag.push_error(message, &location);
1809 }
1810
1811 if exports.is_empty() {
1812 if let Some(internal_name) = inner_components.last().as_ref().map(|x| x.id.clone()) {
1813 exports.push(NamedExport {
1814 internal_name_ident: doc.clone().into(),
1815 internal_name: internal_name.clone(),
1816 external_name_ident: doc.clone().into(),
1817 exported_name: internal_name,
1818 })
1819 }
1820 }
1821
1822 let mut resolve_export_to_inner_component_or_import =
1823 |export: &NamedExport| match type_registry.lookup(export.internal_name.as_str()) {
1824 ty @ Type::Component(_) | ty @ Type::Struct { .. } => Some(ty),
1825 Type::Invalid => {
1826 diag.push_error(
1827 format!("'{}' not found", export.internal_name),
1828 &export.internal_name_ident,
1829 );
1830 None
1831 }
1832 _ => {
1833 diag.push_error(
1834 format!(
1835 "Cannot export '{}' because it is not a component",
1836 export.internal_name,
1837 ),
1838 &export.internal_name_ident,
1839 );
1840 None
1841 }
1842 };
1843
1844 Self(
1845 exports
1846 .iter()
1847 .filter_map(|export| {
1848 Some((
1849 ExportedName {
1850 name: export.exported_name.clone(),
1851 name_ident: export.external_name_ident.clone(),
1852 },
1853 resolve_export_to_inner_component_or_import(export)?,
1854 ))
1855 })
1856 .collect(),
1857 )
1858 }
1859}
1860
1861pub fn inject_element_as_repeated_element(repeated_element: &ElementRc, new_root: ElementRc) {
1865 let component = repeated_element.borrow().base_type.as_component().clone();
1866 debug_assert_eq!(Rc::strong_count(&component), 2);
1870 let old_root = &component.root_element;
1871
1872 {
1883 let mut old_root = old_root.borrow_mut();
1884 for (binding_to_move, _) in crate::typeregister::RESERVED_GEOMETRY_PROPERTIES.iter() {
1885 let binding_to_move = binding_to_move.to_string();
1886 if let Some(binding) = old_root.bindings.remove(&binding_to_move) {
1887 new_root.borrow_mut().bindings.insert(binding_to_move, binding);
1888 }
1889 }
1890 }
1891
1892 let mut elements_with_enclosing_component_reference = Vec::new();
1894 recurse_elem(old_root, &(), &mut |element: &ElementRc, _| {
1895 if let Some(enclosing_component) = element.borrow().enclosing_component.upgrade() {
1896 if Rc::ptr_eq(&enclosing_component, &component) {
1897 elements_with_enclosing_component_reference.push(element.clone());
1898 }
1899 }
1900 });
1901 elements_with_enclosing_component_reference
1902 .extend_from_slice(component.optimized_elements.borrow().as_slice());
1903 elements_with_enclosing_component_reference.push(new_root.clone());
1904
1905 new_root.borrow_mut().child_of_layout =
1906 std::mem::replace(&mut old_root.borrow_mut().child_of_layout, false);
1907 new_root.borrow_mut().layout_info_prop = old_root.borrow().layout_info_prop.clone();
1908 new_root
1909 .borrow_mut()
1910 .bindings
1911 .extend(["x", "y"].iter().filter_map(|x| old_root.borrow_mut().bindings.remove_entry(*x)));
1912
1913 drop(std::mem::take(&mut repeated_element.borrow_mut().base_type));
1916
1917 debug_assert_eq!(Rc::strong_count(&component), 1);
1918
1919 let mut component = Rc::try_unwrap(component).expect("internal compiler error: more than one strong reference left to repeated component when lowering shadow properties");
1920
1921 let old_root = std::mem::replace(&mut component.root_element, new_root.clone());
1922 new_root.borrow_mut().children.push(old_root);
1923
1924 let component = Rc::new(component);
1925 repeated_element.borrow_mut().base_type = Type::Component(component.clone());
1926
1927 for elem in elements_with_enclosing_component_reference {
1928 elem.borrow_mut().enclosing_component = Rc::downgrade(&component);
1929 }
1930}