1use std::collections::{BTreeSet, HashSet, VecDeque};
11use std::rc::{Rc, Weak};
12
13use crate::expression_tree::{BindingExpression, Expression};
14use crate::langtype::Type;
15use crate::namedreference::NamedReference;
16use crate::object_tree::{Component, Document, ElementRc};
17
18#[cfg(feature = "cpp")]
19mod cpp;
20
21#[cfg(feature = "rust")]
22pub mod rust;
23
24#[derive(Copy, Clone, Debug, PartialEq)]
25pub enum OutputFormat {
26 #[cfg(feature = "cpp")]
27 Cpp,
28 #[cfg(feature = "rust")]
29 Rust,
30 Interpreter,
31 Llr,
32}
33
34impl OutputFormat {
35 pub fn guess_from_extension(path: &std::path::Path) -> Option<Self> {
36 match path.extension().and_then(|ext| ext.to_str()) {
37 #[cfg(feature = "cpp")]
38 Some("cpp") | Some("cxx") | Some("h") | Some("hpp") => Some(Self::Cpp),
39 #[cfg(feature = "rust")]
40 Some("rs") => Some(Self::Rust),
41 _ => None,
42 }
43 }
44}
45
46impl std::str::FromStr for OutputFormat {
47 type Err = String;
48 fn from_str(s: &str) -> Result<Self, Self::Err> {
49 match s {
50 #[cfg(feature = "cpp")]
51 "cpp" => Ok(Self::Cpp),
52 #[cfg(feature = "rust")]
53 "rust" => Ok(Self::Rust),
54 "llr" => Ok(Self::Llr),
55 _ => Err(format!("Unknown outpout format {}", s)),
56 }
57 }
58}
59
60pub fn generate(
61 format: OutputFormat,
62 destination: &mut impl std::io::Write,
63 doc: &Document,
64) -> std::io::Result<()> {
65 #![allow(unused_variables)]
66 #![allow(unreachable_code)]
67
68 if matches!(doc.root_component.root_element.borrow().base_type, Type::Invalid | Type::Void) {
69 return Ok(());
71 }
72
73 match format {
74 #[cfg(feature = "cpp")]
75 OutputFormat::Cpp => {
76 let output = cpp::generate(doc);
77 write!(destination, "{}", output)?;
78 }
79 #[cfg(feature = "rust")]
80 OutputFormat::Rust => {
81 let output = rust::generate(doc);
82 write!(destination, "{}", output)?;
83 }
84 OutputFormat::Interpreter => {
85 return Err(std::io::Error::new(
86 std::io::ErrorKind::Other,
87 "Unsupported output format: The interpreter is not a valid output format yet.",
88 )); }
90 OutputFormat::Llr => {
91 writeln!(
92 destination,
93 "{:#?}",
94 crate::llr::lower_to_item_tree::lower_to_item_tree(&doc.root_component)
95 )?;
96 }
97 }
98 Ok(())
99}
100
101pub trait ItemTreeBuilder {
104 type SubComponentState: Clone;
106
107 fn push_repeated_item(
108 &mut self,
109 item: &crate::object_tree::ElementRc,
110 repeater_count: u32,
111 parent_index: u32,
112 component_state: &Self::SubComponentState,
113 );
114 fn push_native_item(
115 &mut self,
116 item: &ElementRc,
117 children_offset: u32,
118 parent_index: u32,
119 component_state: &Self::SubComponentState,
120 );
121 fn enter_component(
124 &mut self,
125 item: &ElementRc,
126 sub_component: &Rc<Component>,
127 children_offset: u32,
128 component_state: &Self::SubComponentState,
129 ) -> Self::SubComponentState;
130 fn enter_component_children(
132 &mut self,
133 item: &ElementRc,
134 repeater_count: u32,
135 component_state: &Self::SubComponentState,
136 sub_component_state: &Self::SubComponentState,
137 );
138}
139
140pub fn build_item_tree<T: ItemTreeBuilder>(
142 root_component: &Rc<Component>,
143 initial_state: &T::SubComponentState,
144 builder: &mut T,
145) {
146 if let Some(sub_component) = root_component.root_element.borrow().sub_component() {
147 assert!(root_component.root_element.borrow().children.is_empty());
148 let sub_compo_state =
149 builder.enter_component(&root_component.root_element, sub_component, 1, initial_state);
150 builder.enter_component_children(
151 &root_component.root_element,
152 0,
153 initial_state,
154 &sub_compo_state,
155 );
156 build_item_tree::<T>(sub_component, &sub_compo_state, builder);
157 } else {
158 let mut repeater_count = 0;
159 visit_item(initial_state, &root_component.root_element, 1, &mut repeater_count, 0, builder);
160
161 visit_children(
162 initial_state,
163 &root_component.root_element.borrow().children,
164 root_component,
165 &root_component.root_element,
166 0,
167 0,
168 1,
169 1,
170 &mut repeater_count,
171 builder,
172 );
173 }
174
175 fn item_sub_tree_size(e: &ElementRc) -> usize {
179 let mut count = e.borrow().children.len();
180 if let Some(sub_component) = e.borrow().sub_component() {
181 count += item_sub_tree_size(&sub_component.root_element);
182 }
183 for i in &e.borrow().children {
184 count += item_sub_tree_size(i);
185 }
186 count
187 }
188
189 fn visit_children<T: ItemTreeBuilder>(
190 state: &T::SubComponentState,
191 children: &Vec<ElementRc>,
192 component: &Rc<Component>,
193 parent_item: &ElementRc,
194 parent_index: u32,
195 relative_parent_index: u32,
196 children_offset: u32,
197 relative_children_offset: u32,
198 repeater_count: &mut u32,
199 builder: &mut T,
200 ) {
201 debug_assert_eq!(
202 relative_parent_index,
203 parent_item.borrow().item_index.get().map(|x| *x as u32).unwrap_or(parent_index)
204 );
205
206 if children.is_empty() {
220 if let Some(nested_subcomponent) = parent_item.borrow().sub_component() {
221 let sub_component_state = builder.enter_component(
222 parent_item,
223 nested_subcomponent,
224 children_offset,
225 state,
226 );
227 visit_children(
228 &sub_component_state,
229 &nested_subcomponent.root_element.borrow().children,
230 nested_subcomponent,
231 &nested_subcomponent.root_element,
232 parent_index,
233 relative_parent_index,
234 children_offset,
235 relative_children_offset,
236 repeater_count,
237 builder,
238 );
239 return;
240 }
241 }
242
243 let mut offset = children_offset + children.len() as u32;
244
245 let mut sub_component_states = VecDeque::new();
246
247 for child in children.iter() {
248 if let Some(sub_component) = child.borrow().sub_component() {
249 let sub_component_state =
250 builder.enter_component(child, sub_component, offset, state);
251 visit_item(
252 &sub_component_state,
253 &sub_component.root_element,
254 offset,
255 repeater_count,
256 parent_index,
257 builder,
258 );
259 sub_component_states.push_back(sub_component_state);
260 } else {
261 visit_item(state, child, offset, repeater_count, parent_index, builder);
262 }
263 offset += item_sub_tree_size(child) as u32;
264 }
265
266 let mut offset = children_offset + children.len() as u32;
267 let mut relative_offset = relative_children_offset + children.len() as u32;
268 let mut index = children_offset;
269 let mut relative_index = relative_children_offset;
270
271 for e in children.iter() {
272 if let Some(sub_component) = e.borrow().sub_component() {
273 let sub_tree_state = sub_component_states.pop_front().unwrap();
274 builder.enter_component_children(e, *repeater_count, state, &sub_tree_state);
275 visit_children(
276 &sub_tree_state,
277 &sub_component.root_element.borrow().children,
278 sub_component,
279 &sub_component.root_element,
280 index,
281 0,
282 offset,
283 1,
284 repeater_count,
285 builder,
286 );
287 } else {
288 visit_children(
289 state,
290 &e.borrow().children,
291 component,
292 e,
293 index,
294 relative_index,
295 offset,
296 relative_offset,
297 repeater_count,
298 builder,
299 );
300 }
301
302 index += 1;
303 relative_index += 1;
304 let size = item_sub_tree_size(e) as u32;
305 offset += size;
306 relative_offset += size;
307 }
308 }
309
310 fn visit_item<T: ItemTreeBuilder>(
311 component_state: &T::SubComponentState,
312 item: &ElementRc,
313 children_offset: u32,
314 repeater_count: &mut u32,
315 parent_index: u32,
316 builder: &mut T,
317 ) {
318 if item.borrow().repeated.is_some() {
319 builder.push_repeated_item(item, *repeater_count, parent_index, component_state);
320 *repeater_count += 1;
321 } else {
322 let mut item = item.clone();
323 let mut component_state = component_state.clone();
324 while let Some((base, state)) = {
325 let base = item.borrow().sub_component().map(|c| {
326 (
327 c.root_element.clone(),
328 builder.enter_component(&item, c, children_offset, &component_state),
329 )
330 });
331 base
332 } {
333 item = base;
334 component_state = state;
335 }
336 builder.push_native_item(&item, children_offset, parent_index, &component_state)
337 }
338 }
339}
340
341pub fn handle_property_bindings_init(
345 component: &Rc<Component>,
346 mut handle_property: impl FnMut(&ElementRc, &str, &BindingExpression),
347) {
348 fn handle_property_inner(
349 component: &Weak<Component>,
350 elem: &ElementRc,
351 prop_name: &str,
352 binding_expression: &BindingExpression,
353 handle_property: &mut impl FnMut(&ElementRc, &str, &BindingExpression),
354 processed: &mut HashSet<NamedReference>,
355 ) {
356 let nr = NamedReference::new(elem, prop_name);
357 if processed.contains(&nr) {
358 return;
359 }
360 processed.insert(nr);
361 if binding_expression.analysis.as_ref().map_or(false, |a| a.is_const) {
362 binding_expression.expression.visit_recursive(&mut |e| {
365 if let Expression::PropertyReference(nr) = e {
366 let elem = nr.element();
367 if Weak::ptr_eq(&elem.borrow().enclosing_component, component) {
368 if let Some(be) = elem.borrow().bindings.get(nr.name()) {
369 handle_property_inner(
370 component,
371 &elem,
372 nr.name(),
373 &be.borrow(),
374 handle_property,
375 processed,
376 );
377 }
378 }
379 }
380 })
381 }
382 handle_property(elem, prop_name, binding_expression);
383 }
384
385 let mut processed = HashSet::new();
386 crate::object_tree::recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, ()| {
387 for (prop_name, binding_expression) in &elem.borrow().bindings {
388 handle_property_inner(
389 &Rc::downgrade(component),
390 elem,
391 prop_name,
392 &binding_expression.borrow(),
393 &mut handle_property,
394 &mut processed,
395 );
396 }
397 });
398}
399
400pub fn for_each_const_properties(component: &Rc<Component>, mut f: impl FnMut(&ElementRc, &str)) {
403 crate::object_tree::recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, ()| {
404 if elem.borrow().repeated.is_some() {
405 return;
406 }
407 let mut e = elem.clone();
408 let mut all_prop = BTreeSet::new();
409 loop {
410 all_prop.extend(
411 e.borrow()
412 .property_declarations
413 .iter()
414 .filter(|(_, x)| x.property_type.is_property_type())
415 .map(|(k, _)| k.clone()),
416 );
417 match &e.clone().borrow().base_type {
418 Type::Component(c) => {
419 e = c.root_element.clone();
420 }
421 Type::Native(n) => {
422 all_prop.extend(
423 n.properties
424 .iter()
425 .filter(|(k, x)| {
426 x.ty.is_property_type()
427 && !k.starts_with("viewport-")
428 && k.as_str() != "commands"
429 })
430 .map(|(k, _)| k.clone()),
431 );
432 break;
433 }
434 _ => break,
435 }
436 }
437 for c in all_prop {
438 if NamedReference::new(elem, &c).is_constant() {
439 f(elem, &c);
440 }
441 }
442 });
443}