1use by_address::ByAddress;
5
6use crate::expression_tree::Expression as tree_Expression;
7use crate::langtype::Type;
8use crate::llr::item_tree::*;
9use crate::namedreference::NamedReference;
10use crate::object_tree::{Component, ElementRc};
11use std::collections::HashMap;
12use std::rc::Rc;
13
14use super::lower_expression::ExpressionContext;
15
16pub fn lower_to_item_tree(component: &Rc<Component>) -> PublicComponent {
17 let mut state = LoweringState::default();
18
19 let mut globals = Vec::new();
20 for g in &component.used_types.borrow().globals {
21 let count = globals.len();
22 globals.push(lower_global(g, count, &mut state));
23 }
24 for c in &component.used_types.borrow().sub_components {
25 let sc = lower_sub_component(c, &state, None);
26 state.sub_components.insert(ByAddress(c.clone()), sc);
27 }
28
29 let sc = lower_sub_component(component, &state, None);
30 let public_properties = public_properties(component, &sc.mapping, &state);
31 let item_tree = ItemTree {
32 tree: make_tree(&state, &component.root_element, &sc, &[]),
33 root: Rc::try_unwrap(sc.sub_component).unwrap(),
34 parent_context: None,
35 };
36 PublicComponent {
37 item_tree,
38 globals,
39 sub_components: component
40 .used_types
41 .borrow()
42 .sub_components
43 .iter()
44 .map(|tree_sub_compo| {
45 state.sub_components[&ByAddress(tree_sub_compo.clone())].sub_component.clone()
46 })
47 .collect(),
48 public_properties,
49 }
50}
51
52#[derive(Default)]
53pub struct LoweringState {
54 global_properties: HashMap<NamedReference, PropertyReference>,
55 sub_components: HashMap<ByAddress<Rc<Component>>, LoweredSubComponent>,
56}
57
58#[derive(Debug, Clone)]
59pub enum LoweredElement {
60 SubComponent { sub_component_index: usize },
61 NativeItem { item_index: usize },
62 Repeated { repeated_index: usize },
63}
64
65#[derive(Default, Debug, Clone)]
66pub struct LoweredSubComponentMapping {
67 pub element_mapping: HashMap<ByAddress<ElementRc>, LoweredElement>,
68 pub property_mapping: HashMap<NamedReference, PropertyReference>,
69}
70
71impl LoweredSubComponentMapping {
72 pub fn map_property_reference(
73 &self,
74 from: &NamedReference,
75 state: &LoweringState,
76 ) -> PropertyReference {
77 if let Some(x) = self.property_mapping.get(&from) {
78 return x.clone();
79 }
80 if let Some(x) = state.global_properties.get(&from) {
81 return x.clone();
82 }
83 let element = from.element();
84 if let Some(alias) = element
85 .borrow()
86 .property_declarations
87 .get(from.name())
88 .and_then(|x| x.is_alias.as_ref())
89 {
90 return self.map_property_reference(alias, state);
91 }
92 match self.element_mapping.get(&element.clone().into()).unwrap() {
93 LoweredElement::SubComponent { sub_component_index } => {
94 if let Type::Component(base) = &element.borrow().base_type {
95 return property_reference_within_sub_component(
96 state.map_property_reference(&NamedReference::new(
97 &base.root_element,
98 from.name(),
99 )),
100 *sub_component_index,
101 );
102 }
103 unreachable!()
104 }
105 LoweredElement::NativeItem { item_index } => {
106 return PropertyReference::InNativeItem {
107 sub_component_path: vec![],
108 item_index: *item_index,
109 prop_name: from.name().into(),
110 };
111 }
112 LoweredElement::Repeated { .. } => unreachable!(),
113 }
114 }
115}
116
117pub struct LoweredSubComponent {
118 sub_component: Rc<SubComponent>,
119 mapping: LoweredSubComponentMapping,
120}
121
122impl LoweringState {
123 pub fn map_property_reference(&self, from: &NamedReference) -> PropertyReference {
124 if let Some(x) = self.global_properties.get(&from) {
125 return x.clone();
126 }
127
128 let element = from.element();
129 let enclosing = self
130 .sub_components
131 .get(&element.borrow().enclosing_component.upgrade().unwrap().into())
132 .unwrap();
133
134 enclosing.mapping.map_property_reference(from, self)
135 }
136}
137
138fn property_reference_within_sub_component(
140 mut prop_ref: PropertyReference,
141 sub_component: usize,
142) -> PropertyReference {
143 match &mut prop_ref {
144 PropertyReference::Local { sub_component_path, .. }
145 | PropertyReference::InNativeItem { sub_component_path, .. } => {
146 sub_component_path.insert(0, sub_component);
147 }
148 PropertyReference::InParent { .. } => panic!("the sub-component had no parents"),
149 PropertyReference::Global { .. } => (),
150 }
151 prop_ref
152}
153
154impl LoweringState {
155 fn sub_component(&self, component: &Rc<Component>) -> &LoweredSubComponent {
156 &self.sub_components[&ByAddress(component.clone())]
157 }
158}
159
160fn component_id(component: &Rc<Component>) -> String {
161 if component.is_global() {
162 component.root_element.borrow().id.clone()
163 } else if component.id.is_empty() {
164 format!("Component_{}", component.root_element.borrow().id)
165 } else if component.is_sub_component() {
166 format!("{}_{}", component.id, component.root_element.borrow().id)
167 } else {
168 component.id.clone()
169 }
170}
171
172fn lower_sub_component(
173 component: &Rc<Component>,
174 state: &LoweringState,
175 parent_context: Option<&ExpressionContext>,
176) -> LoweredSubComponent {
177 let mut sub_component = SubComponent {
178 name: component_id(component),
179 properties: Default::default(),
180 items: Default::default(),
181 repeated: Default::default(),
182 popup_windows: Default::default(),
183 sub_components: Default::default(),
184 property_init: Default::default(),
185 animations: Default::default(),
186 two_way_bindings: Default::default(),
187 const_properties: Default::default(),
188 init_code: Default::default(),
189 layout_info_h: super::Expression::BoolLiteral(false),
191 layout_info_v: super::Expression::BoolLiteral(false),
192 };
193 let mut mapping = LoweredSubComponentMapping::default();
194 let mut repeated = vec![];
195
196 if let Some(parent) = component.parent_element.upgrade() {
197 if parent.borrow().repeated.as_ref().map_or(false, |x| !x.is_conditional_element) {
199 sub_component.properties.push(Property {
200 name: "model_data".into(),
201 ty: crate::expression_tree::Expression::RepeaterModelReference {
202 element: component.parent_element.clone(),
203 }
204 .ty(),
205 });
206 sub_component.properties.push(Property { name: "model_index".into(), ty: Type::Int32 });
207 }
208 };
209
210 let s: Option<ElementRc> = None;
211 let mut repeater_offset = 0;
212 crate::object_tree::recurse_elem(&component.root_element, &s, &mut |element, parent| {
213 let elem = element.borrow();
214 for (p, x) in &elem.property_declarations {
215 if x.is_alias.is_some() {
216 continue;
217 }
218 let property_index = sub_component.properties.len();
219 mapping.property_mapping.insert(
220 NamedReference::new(element, &p),
221 PropertyReference::Local { sub_component_path: vec![], property_index },
222 );
223 sub_component
224 .properties
225 .push(Property { name: format!("{}_{}", elem.id, p), ty: x.property_type.clone() });
226 }
227 if elem.repeated.is_some() {
228 mapping.element_mapping.insert(
229 element.clone().into(),
230 LoweredElement::Repeated { repeated_index: repeated.len() },
231 );
232 repeated.push(element.clone());
233 return None;
234 }
235 match &elem.base_type {
236 Type::Component(comp) => {
237 let lc = state.sub_component(comp);
238 let ty = lc.sub_component.clone();
239 let sub_component_index = sub_component.sub_components.len();
240 mapping.element_mapping.insert(
241 element.clone().into(),
242 LoweredElement::SubComponent { sub_component_index },
243 );
244 sub_component.sub_components.push(SubComponentInstance {
245 ty: ty.clone(),
246 name: elem.id.clone(),
247 index_in_tree: *elem.item_index.get().unwrap(),
248 index_of_first_child_in_tree: *elem.item_index_of_first_children.get().unwrap(),
249 repeater_offset,
250 });
251 repeater_offset += ty.repeater_count();
252 }
253
254 Type::Native(n) => {
255 let item_index = sub_component.items.len();
256 mapping
257 .element_mapping
258 .insert(element.clone().into(), LoweredElement::NativeItem { item_index });
259 let is_flickable_viewport = elem.is_flickable_viewport;
260 sub_component.items.push(Item {
261 ty: n.clone(),
262 name: if is_flickable_viewport {
263 parent.as_ref().unwrap().borrow().id.clone()
264 } else {
265 elem.id.clone()
266 },
267 index_in_tree: *elem.item_index.get().unwrap(),
268 is_flickable_viewport,
269 })
270 }
271 _ => unreachable!(),
272 };
273 Some(element.clone())
274 });
275 let ctx = ExpressionContext { mapping: &mapping, state, parent: parent_context, component };
276 crate::generator::handle_property_bindings_init(component, |e, p, binding| {
277 let prop = ctx.map_property_reference(&NamedReference::new(e, p));
278 for tw in &binding.two_way_bindings {
279 sub_component.two_way_bindings.push((prop.clone(), ctx.map_property_reference(tw)))
280 }
281 if !matches!(binding.expression, tree_Expression::Invalid) {
282 let expression = super::lower_expression::lower_expression(&binding.expression, &ctx);
283
284 let is_constant = binding.analysis.as_ref().map_or(false, |a| a.is_const);
285 let animation = binding
286 .animation
287 .as_ref()
288 .filter(|_| !is_constant)
289 .map(|a| super::lower_expression::lower_animation(a, &ctx));
290 sub_component
291 .property_init
292 .push((prop.clone(), BindingExpression { expression, animation, is_constant }));
293 }
294
295 if e.borrow()
296 .property_analysis
297 .borrow()
298 .get(p)
299 .map_or(true, |a| a.is_set || a.is_set_externally)
300 {
301 if let Some(anim) = binding.animation.as_ref() {
302 match super::lower_expression::lower_animation(anim, &ctx) {
303 Animation::Static(anim) => {
304 sub_component.animations.insert(prop, anim);
305 }
306 Animation::Transition(_) => {
307 }
309 }
310 }
311 }
312 });
313 sub_component.repeated =
314 repeated.into_iter().map(|elem| lower_repeated_component(&elem, &ctx)).collect();
315 for s in &mut sub_component.sub_components {
316 s.repeater_offset += sub_component.repeated.len();
317 }
318 sub_component.popup_windows = component
319 .popup_windows
320 .borrow()
321 .iter()
322 .map(|popup| lower_popup_component(&popup.component, &ctx))
323 .collect();
324
325 crate::generator::for_each_const_properties(component, |elem, n| {
326 let x = ctx.map_property_reference(&NamedReference::new(elem, n));
327 sub_component.const_properties.push(x);
328 });
329
330 sub_component.init_code = component
331 .setup_code
332 .borrow()
333 .iter()
334 .map(|e| super::lower_expression::lower_expression(e, &ctx))
335 .collect();
336
337 sub_component.layout_info_h = super::lower_expression::get_layout_info(
338 &component.root_element,
339 &ctx,
340 &component.root_constraints.borrow(),
341 crate::layout::Orientation::Horizontal,
342 );
343 sub_component.layout_info_v = super::lower_expression::get_layout_info(
344 &component.root_element,
345 &ctx,
346 &component.root_constraints.borrow(),
347 crate::layout::Orientation::Vertical,
348 );
349
350 LoweredSubComponent { sub_component: Rc::new(sub_component), mapping }
351}
352
353fn lower_repeated_component(elem: &ElementRc, ctx: &ExpressionContext) -> RepeatedElement {
354 let e = elem.borrow();
355 let component = e.base_type.as_component().clone();
356 let repeated = e.repeated.as_ref().unwrap();
357
358 let sc = lower_sub_component(&component, &ctx.state, Some(ctx));
359
360 let map_inner_prop = |p| {
361 sc.mapping
362 .map_property_reference(&NamedReference::new(&component.root_element, p), &ctx.state)
363 };
364
365 let listview = repeated.is_listview.as_ref().map(|lv| ListViewInfo {
366 viewport_y: ctx.map_property_reference(&lv.viewport_y),
367 viewport_height: ctx.map_property_reference(&lv.viewport_height),
368 viewport_width: ctx.map_property_reference(&lv.viewport_width),
369 listview_height: ctx.map_property_reference(&lv.listview_height),
370 listview_width: ctx.map_property_reference(&lv.listview_width),
371
372 prop_y: map_inner_prop("y"),
373 prop_width: map_inner_prop("width"),
374 prop_height: map_inner_prop("height"),
375 });
376
377 RepeatedElement {
378 model: super::lower_expression::lower_expression(&repeated.model, ctx),
379 sub_tree: ItemTree {
380 tree: make_tree(ctx.state, &component.root_element, &sc, &[]),
381 root: Rc::try_unwrap(sc.sub_component).unwrap(),
382 parent_context: Some(e.enclosing_component.upgrade().unwrap().id.clone()),
383 },
384 index_prop: (!repeated.is_conditional_element).then(|| 1),
385 data_prop: (!repeated.is_conditional_element).then(|| 0),
386 index_in_tree: *e.item_index.get().unwrap(),
387 listview,
388 }
389}
390
391fn lower_popup_component(component: &Rc<Component>, ctx: &ExpressionContext) -> ItemTree {
392 let sc = lower_sub_component(component, &ctx.state, Some(ctx));
393 ItemTree {
394 tree: make_tree(ctx.state, &component.root_element, &sc, &[]),
395 root: Rc::try_unwrap(sc.sub_component).unwrap(),
396 parent_context: Some(
397 component
398 .parent_element
399 .upgrade()
400 .unwrap()
401 .borrow()
402 .enclosing_component
403 .upgrade()
404 .unwrap()
405 .id
406 .clone(),
407 ),
408 }
409}
410
411fn lower_global(
412 global: &Rc<Component>,
413 global_index: usize,
414 state: &mut LoweringState,
415) -> GlobalComponent {
416 let mut mapping = LoweredSubComponentMapping::default();
417 let mut properties = vec![];
418 let mut const_properties = vec![];
419
420 for (p, x) in &global.root_element.borrow().property_declarations {
421 let property_index = properties.len();
422 let nr = NamedReference::new(&global.root_element, &p);
423 mapping.property_mapping.insert(
424 nr.clone(),
425 PropertyReference::Local { sub_component_path: vec![], property_index },
426 );
427
428 properties.push(Property { name: p.clone(), ty: x.property_type.clone() });
429 if !matches!(x.property_type, Type::Callback { .. }) {
430 const_properties.push(nr.is_constant());
431 }
432 state
433 .global_properties
434 .insert(nr.clone(), PropertyReference::Global { global_index, property_index });
435 }
436
437 let mut init_values = vec![None; properties.len()];
438
439 let ctx = ExpressionContext { mapping: &mapping, state, parent: None, component: global };
440 for (prop, binding) in &global.root_element.borrow().bindings {
441 assert!(binding.borrow().two_way_bindings.is_empty());
442 assert!(binding.borrow().animation.is_none());
443 let expression =
444 super::lower_expression::lower_expression(&binding.borrow().expression, &ctx);
445
446 let nr = NamedReference::new(&global.root_element, prop);
447 let property_index = match mapping.property_mapping[&nr] {
448 PropertyReference::Local { property_index, .. } => property_index,
449 _ => unreachable!(),
450 };
451 let is_constant = binding.borrow().analysis.as_ref().map_or(false, |a| a.is_const);
452 init_values[property_index] =
453 Some(BindingExpression { expression, animation: None, is_constant });
454 }
455
456 let is_builtin = if let Some(builtin) = global.root_element.borrow().native_class() {
457 for (p, x) in &builtin.properties {
459 let property_index = properties.len();
460 properties.push(Property { name: p.clone(), ty: x.ty.clone() });
461 let nr = NamedReference::new(&global.root_element, &p);
462 state
463 .global_properties
464 .insert(nr, PropertyReference::Global { global_index, property_index });
465 }
466 true
467 } else {
468 false
469 };
470
471 let public_properties = public_properties(global, &mapping, &state);
472 GlobalComponent {
473 name: global.root_element.borrow().id.clone(),
474 properties,
475 init_values,
476 const_properties,
477 public_properties,
478 exported: !global.exported_global_names.borrow().is_empty(),
479 aliases: global.global_aliases(),
480 is_builtin,
481 }
482}
483
484fn make_tree(
485 state: &LoweringState,
486 element: &ElementRc,
487 component: &LoweredSubComponent,
488 sub_component_path: &[usize],
489) -> TreeNode {
490 let e = element.borrow();
491 let children = e.children.iter().map(|c| make_tree(state, c, component, sub_component_path));
492 match component.mapping.element_mapping.get(&ByAddress(element.clone())).unwrap() {
493 LoweredElement::SubComponent { sub_component_index } => {
494 let sub_component = e.sub_component().unwrap();
495 let new_sub_component_path = sub_component_path
496 .iter()
497 .copied()
498 .chain(std::iter::once(*sub_component_index))
499 .collect::<Vec<_>>();
500 let mut tree_node = make_tree(
501 state,
502 &sub_component.root_element,
503 state.sub_component(sub_component),
504 &new_sub_component_path,
505 );
506 tree_node.children.extend(children);
507 tree_node
508 }
509 LoweredElement::NativeItem { item_index } => TreeNode {
510 sub_component_path: sub_component_path.into(),
511 item_index: *item_index,
512 children: children.collect(),
513 repeated: false,
514 },
515 LoweredElement::Repeated { repeated_index } => TreeNode {
516 sub_component_path: sub_component_path.into(),
517 item_index: *repeated_index,
518 children: vec![],
519 repeated: true,
520 },
521 }
522}
523
524fn public_properties(
525 component: &Component,
526 mapping: &LoweredSubComponentMapping,
527 state: &LoweringState,
528) -> PublicProperties {
529 component
530 .root_element
531 .borrow()
532 .property_declarations
533 .iter()
534 .filter(|(_, c)| c.expose_in_public_api)
535 .map(|(p, c)| {
536 let property_reference = mapping
537 .map_property_reference(&NamedReference::new(&component.root_element, p), &state);
538 (p.clone(), (c.property_type.clone(), property_reference))
539 })
540 .collect()
541}