1use smol_str::SmolStr;
13use std::collections::{BTreeSet, HashSet, VecDeque};
14use std::rc::{Rc, Weak};
15
16use crate::CompilerConfiguration;
17use crate::expression_tree::{BindingExpression, Expression};
18use crate::langtype::{BuiltinPrivateStruct, ElementType, StructName};
19use crate::namedreference::NamedReference;
20use crate::object_tree::{Component, Document, ElementRc};
21
22#[cfg(feature = "cpp")]
23pub mod cpp;
24#[cfg(feature = "cpp")]
25pub mod cpp_live_preview;
26#[cfg(feature = "rust")]
27pub mod rust;
28#[cfg(feature = "rust")]
29pub mod rust_live_preview;
30
31#[cfg(feature = "python")]
32pub mod python;
33
34#[derive(Clone, Debug, PartialEq)]
35pub enum OutputFormat {
36 #[cfg(feature = "cpp")]
37 Cpp(cpp::Config),
38 #[cfg(feature = "rust")]
39 Rust,
40 Interpreter,
41 Llr,
42 #[cfg(feature = "python")]
43 Python,
44}
45
46impl OutputFormat {
47 pub fn guess_from_extension(path: &std::path::Path) -> Option<Self> {
48 match path.extension().and_then(|ext| ext.to_str()) {
49 #[cfg(feature = "cpp")]
50 Some("cpp") | Some("cxx") | Some("h") | Some("hpp") => {
51 Some(Self::Cpp(cpp::Config::default()))
52 }
53 #[cfg(feature = "rust")]
54 Some("rs") => Some(Self::Rust),
55 #[cfg(feature = "python")]
56 Some("py") => Some(Self::Python),
57 _ => None,
58 }
59 }
60}
61
62impl std::str::FromStr for OutputFormat {
63 type Err = String;
64 fn from_str(s: &str) -> Result<Self, Self::Err> {
65 match s {
66 #[cfg(feature = "cpp")]
67 "cpp" => Ok(Self::Cpp(cpp::Config::default())),
68 #[cfg(feature = "rust")]
69 "rust" => Ok(Self::Rust),
70 "llr" => Ok(Self::Llr),
71 #[cfg(feature = "python")]
72 "python" => Ok(Self::Python),
73 _ => Err(format!("Unknown output format {s}")),
74 }
75 }
76}
77
78pub fn generate(
79 format: OutputFormat,
80 destination: &mut impl std::io::Write,
81 destination_path: Option<&std::path::Path>,
82 doc: &Document,
83 compiler_config: &CompilerConfiguration,
84) -> std::io::Result<()> {
85 #![allow(unused_variables)]
86 #![allow(unreachable_code)]
87
88 match format {
89 #[cfg(feature = "cpp")]
90 OutputFormat::Cpp(config) => {
91 let output = cpp::generate(doc, config, compiler_config)?;
92 write!(destination, "{output}")?;
93 }
94 #[cfg(feature = "rust")]
95 OutputFormat::Rust => {
96 let output = rust::generate(doc, compiler_config)?;
97 write!(destination, "{output}")?;
98 }
99 OutputFormat::Interpreter => {
100 return Err(std::io::Error::other(
101 "Unsupported output format: The interpreter is not a valid output format yet.",
102 )); }
104 OutputFormat::Llr => {
105 let root = crate::llr::lower_to_item_tree::lower_to_item_tree(doc, compiler_config);
106 let mut output = String::new();
107 crate::llr::pretty_print::pretty_print(&root, &mut output).unwrap();
108 write!(destination, "{output}")?;
109 }
110 #[cfg(feature = "python")]
111 OutputFormat::Python => {
112 let output = python::generate(doc, compiler_config, destination_path)?;
113 write!(destination, "{output}")?;
114 }
115 }
116 Ok(())
117}
118
119pub trait ItemTreeBuilder {
122 type SubComponentState: Clone;
124
125 fn push_repeated_item(
126 &mut self,
127 item: &crate::object_tree::ElementRc,
128 repeater_count: u32,
129 parent_index: u32,
130 component_state: &Self::SubComponentState,
131 );
132 fn push_native_item(
133 &mut self,
134 item: &ElementRc,
135 children_offset: u32,
136 parent_index: u32,
137 component_state: &Self::SubComponentState,
138 );
139 fn enter_component(
142 &mut self,
143 item: &ElementRc,
144 sub_component: &Rc<Component>,
145 children_offset: u32,
146 component_state: &Self::SubComponentState,
147 ) -> Self::SubComponentState;
148 fn enter_component_children(
150 &mut self,
151 item: &ElementRc,
152 repeater_count: u32,
153 component_state: &Self::SubComponentState,
154 sub_component_state: &Self::SubComponentState,
155 );
156}
157
158pub fn build_item_tree<T: ItemTreeBuilder>(
160 root_component: &Rc<Component>,
161 initial_state: &T::SubComponentState,
162 builder: &mut T,
163) {
164 if let Some(sub_component) = root_component.root_element.borrow().sub_component() {
165 assert!(root_component.root_element.borrow().children.is_empty());
166 let sub_compo_state =
167 builder.enter_component(&root_component.root_element, sub_component, 1, initial_state);
168 builder.enter_component_children(
169 &root_component.root_element,
170 0,
171 initial_state,
172 &sub_compo_state,
173 );
174 build_item_tree::<T>(sub_component, &sub_compo_state, builder);
175 } else {
176 let mut repeater_count = 0;
177 visit_item(initial_state, &root_component.root_element, 1, &mut repeater_count, 0, builder);
178
179 visit_children(
180 initial_state,
181 &root_component.root_element.borrow().children,
182 root_component,
183 &root_component.root_element,
184 0,
185 0,
186 1,
187 1,
188 &mut repeater_count,
189 builder,
190 );
191 }
192
193 fn item_sub_tree_size(e: &ElementRc) -> usize {
197 let mut count = e.borrow().children.len();
198 if let Some(sub_component) = e.borrow().sub_component() {
199 count += item_sub_tree_size(&sub_component.root_element);
200 }
201 for i in &e.borrow().children {
202 count += item_sub_tree_size(i);
203 }
204 count
205 }
206
207 fn visit_children<T: ItemTreeBuilder>(
208 state: &T::SubComponentState,
209 children: &[ElementRc],
210 _component: &Rc<Component>,
211 parent_item: &ElementRc,
212 parent_index: u32,
213 relative_parent_index: u32,
214 children_offset: u32,
215 relative_children_offset: u32,
216 repeater_count: &mut u32,
217 builder: &mut T,
218 ) {
219 debug_assert_eq!(
220 relative_parent_index,
221 *parent_item.borrow().item_index.get().unwrap_or(&parent_index)
222 );
223
224 if children.is_empty()
238 && let Some(nested_subcomponent) = parent_item.borrow().sub_component()
239 {
240 let sub_component_state =
241 builder.enter_component(parent_item, nested_subcomponent, children_offset, state);
242 visit_children(
243 &sub_component_state,
244 &nested_subcomponent.root_element.borrow().children,
245 nested_subcomponent,
246 &nested_subcomponent.root_element,
247 parent_index,
248 relative_parent_index,
249 children_offset,
250 relative_children_offset,
251 repeater_count,
252 builder,
253 );
254 return;
255 }
256
257 let mut offset = children_offset + children.len() as u32;
258
259 let mut sub_component_states = VecDeque::new();
260
261 for child in children.iter() {
262 if let Some(sub_component) = child.borrow().sub_component() {
263 let sub_component_state =
264 builder.enter_component(child, sub_component, offset, state);
265 visit_item(
266 &sub_component_state,
267 &sub_component.root_element,
268 offset,
269 repeater_count,
270 parent_index,
271 builder,
272 );
273 sub_component_states.push_back(sub_component_state);
274 } else {
275 visit_item(state, child, offset, repeater_count, parent_index, builder);
276 }
277 offset += item_sub_tree_size(child) as u32;
278 }
279
280 let mut offset = children_offset + children.len() as u32;
281 let mut relative_offset = relative_children_offset + children.len() as u32;
282
283 for (i, e) in children.iter().enumerate() {
284 let index = children_offset + i as u32;
285 let relative_index = relative_children_offset + i as u32;
286 if let Some(sub_component) = e.borrow().sub_component() {
287 let sub_tree_state = sub_component_states.pop_front().unwrap();
288 builder.enter_component_children(e, *repeater_count, state, &sub_tree_state);
289 visit_children(
290 &sub_tree_state,
291 &sub_component.root_element.borrow().children,
292 sub_component,
293 &sub_component.root_element,
294 index,
295 0,
296 offset,
297 1,
298 repeater_count,
299 builder,
300 );
301 } else {
302 visit_children(
303 state,
304 &e.borrow().children,
305 _component,
306 e,
307 index,
308 relative_index,
309 offset,
310 relative_offset,
311 repeater_count,
312 builder,
313 );
314 }
315
316 let size = item_sub_tree_size(e) as u32;
317 offset += size;
318 relative_offset += size;
319 }
320 }
321
322 fn visit_item<T: ItemTreeBuilder>(
323 component_state: &T::SubComponentState,
324 item: &ElementRc,
325 children_offset: u32,
326 repeater_count: &mut u32,
327 parent_index: u32,
328 builder: &mut T,
329 ) {
330 if item.borrow().repeated.is_some() {
331 builder.push_repeated_item(item, *repeater_count, parent_index, component_state);
332 *repeater_count += 1;
333 } else {
334 let mut item = item.clone();
335 let mut component_state = component_state.clone();
336 while let Some((base, state)) = {
337 item.borrow().sub_component().map(|c| {
338 (
339 c.root_element.clone(),
340 builder.enter_component(&item, c, children_offset, &component_state),
341 )
342 })
343 } {
344 item = base;
345 component_state = state;
346 }
347 builder.push_native_item(&item, children_offset, parent_index, &component_state)
348 }
349 }
350}
351
352pub fn handle_property_bindings_init(
356 component: &Rc<Component>,
357 mut handle_property: impl FnMut(&ElementRc, &SmolStr, &BindingExpression),
358) {
359 fn handle_property_inner(
360 component: &Weak<Component>,
361 elem: &ElementRc,
362 prop_name: &SmolStr,
363 binding_expression: &BindingExpression,
364 handle_property: &mut impl FnMut(&ElementRc, &SmolStr, &BindingExpression),
365 processed: &mut HashSet<NamedReference>,
366 ) {
367 if elem.borrow().is_component_placeholder {
368 return; }
370 let nr = NamedReference::new(elem, prop_name.clone());
371 if processed.contains(&nr) {
372 return;
373 }
374 processed.insert(nr);
375 if binding_expression.analysis.as_ref().is_some_and(|a| a.is_const) {
376 binding_expression.expression.visit_recursive(&mut |e| {
379 if let Expression::PropertyReference(nr) = e {
380 let elem = nr.element();
381 if Weak::ptr_eq(&elem.borrow().enclosing_component, component)
382 && let Some(be) = elem.borrow().bindings.get(nr.name())
383 {
384 handle_property_inner(
385 component,
386 &elem,
387 nr.name(),
388 &be.borrow(),
389 handle_property,
390 processed,
391 );
392 }
393 }
394 })
395 }
396 handle_property(elem, prop_name, binding_expression);
397 }
398
399 let mut processed = HashSet::new();
400 crate::object_tree::recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, ()| {
401 for (prop_name, binding_expression) in &elem.borrow().bindings {
402 handle_property_inner(
403 &Rc::downgrade(component),
404 elem,
405 prop_name,
406 &binding_expression.borrow(),
407 &mut handle_property,
408 &mut processed,
409 );
410 }
411 });
412}
413
414pub fn for_each_const_properties(
417 component: &Rc<Component>,
418 mut f: impl FnMut(&ElementRc, &SmolStr),
419) {
420 crate::object_tree::recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, ()| {
421 if elem.borrow().repeated.is_some() {
422 return;
423 }
424 let mut e = elem.clone();
425 let mut all_prop = BTreeSet::new();
426 loop {
427 all_prop.extend(
428 e.borrow()
429 .property_declarations
430 .iter()
431 .filter(|(_, x)| {
432 x.property_type.is_property_type() &&
433 !matches!( &x.property_type, crate::langtype::Type::Struct(s) if matches!(s.name, StructName::BuiltinPrivate(BuiltinPrivateStruct::StateInfo)))
434 })
435 .map(|(k, _)| k.clone()),
436 );
437 match &e.clone().borrow().base_type {
438 ElementType::Component(c) => {
439 e = c.root_element.clone();
440 }
441 ElementType::Native(n) => {
442 let mut n = n;
443 loop {
444 all_prop.extend(
445 n.properties
446 .iter()
447 .filter(|(k, x)| {
448 x.ty.is_property_type()
449 && !k.starts_with("viewport-")
450 && k.as_str() != "commands"
451 })
452 .map(|(k, _)| k.clone()),
453 );
454 match n.parent.as_ref() {
455 Some(p) => n = p,
456 None => break,
457 }
458 }
459 break;
460 }
461 ElementType::Builtin(_) => {
462 unreachable!("builtin element should have been resolved")
463 }
464 ElementType::Global | ElementType::Interface | ElementType::Error => break,
465 }
466 }
467 for c in all_prop {
468 if NamedReference::new(elem, c.clone()).is_constant() {
469 f(elem, &c);
470 }
471 }
472 });
473}
474
475pub fn to_pascal_case(str: &str) -> String {
477 let mut result = Vec::with_capacity(str.len());
478 let mut next_upper = true;
479 for x in str.as_bytes() {
480 if *x == b'-' {
481 next_upper = true;
482 } else if next_upper {
483 result.push(x.to_ascii_uppercase());
484 next_upper = false;
485 } else {
486 result.push(*x);
487 }
488 }
489 String::from_utf8(result).unwrap()
490}
491
492pub fn to_kebab_case(str: &str) -> String {
494 let mut result = Vec::with_capacity(str.len());
495 for x in str.as_bytes() {
496 if x.is_ascii_uppercase() {
497 if !result.is_empty() {
498 result.push(b'-');
499 }
500 result.push(x.to_ascii_lowercase());
501 } else {
502 result.push(*x);
503 }
504 }
505 String::from_utf8(result).unwrap()
506}
507
508#[test]
509fn case_conversions() {
510 assert_eq!(to_kebab_case("HelloWorld"), "hello-world");
511 assert_eq!(to_pascal_case("hello-world"), "HelloWorld");
512}