Skip to content

Commit

Permalink
Generate multiple components in Rust and C++ (#5449)
Browse files Browse the repository at this point in the history
When lowering to the LLR, generate one PulbicComponent for each exported
component in the main file

Closes #784
  • Loading branch information
ogoffart committed Jun 24, 2024
1 parent c89ea56 commit 3764312
Show file tree
Hide file tree
Showing 18 changed files with 257 additions and 167 deletions.
5 changes: 0 additions & 5 deletions internal/compiler/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ pub fn generate(
#![allow(unused_variables)]
#![allow(unreachable_code)]

if matches!(doc.root_component.root_element.borrow().base_type, ElementType::Error) {
// empty document, nothing to generate
return Ok(());
}

match format {
#[cfg(feature = "cpp")]
OutputFormat::Cpp(config) => {
Expand Down
10 changes: 1 addition & 9 deletions internal/compiler/generator/cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ mod cpp_ast {
}

use crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp};
use crate::langtype::{ElementType, Enumeration, EnumerationValue, NativeClass, Type};
use crate::langtype::{Enumeration, EnumerationValue, NativeClass, Type};
use crate::layout::Orientation;
use crate::llr::{
self, EvaluationContext as llr_EvaluationContext, ParentCtx as llr_ParentCtx,
Expand Down Expand Up @@ -761,14 +761,6 @@ pub fn generate(
}
}

if matches!(
doc.root_component.root_element.borrow().base_type,
ElementType::Error | ElementType::Global
) {
// empty document, nothing to generate
return file;
}

let llr = llr::lower_to_item_tree::lower_to_item_tree(&doc, compiler_config);

// Forward-declare the root so that sub-components can access singletons, the window, etc.
Expand Down
16 changes: 6 additions & 10 deletions internal/compiler/generator/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Some convention used in the generated code:
*/

use crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp, OperatorClass};
use crate::langtype::{ElementType, Enumeration, EnumerationValue, Type};
use crate::langtype::{Enumeration, EnumerationValue, Type};
use crate::layout::Orientation;
use crate::llr::{
self, EvaluationContext as llr_EvaluationContext, Expression, ParentCtx as llr_ParentCtx,
Expand Down Expand Up @@ -160,16 +160,12 @@ pub fn generate(doc: &Document, compiler_config: &CompilerConfiguration) -> Toke
})
.unzip();

if matches!(
doc.root_component.root_element.borrow().base_type,
ElementType::Error | ElementType::Global
) {
// empty document, nothing to generate
return TokenStream::default();
}

let llr = crate::llr::lower_to_item_tree::lower_to_item_tree(&doc, &compiler_config);

if llr.public_components.is_empty() {
return Default::default();
}

let sub_compos = llr
.sub_components
.iter()
Expand Down Expand Up @@ -213,7 +209,7 @@ pub fn generate(doc: &Document, compiler_config: &CompilerConfiguration) -> Toke
const _THE_SAME_VERSION_MUST_BE_USED_FOR_THE_COMPILER_AND_THE_RUNTIME : slint::#version_check = slint::#version_check;
}
#[allow(unused_imports)]
pub use slint_generated::{#(#compo_ids),* #(,#structs_and_enums_ids)* #(,#globals_ids)* #(,#named_exports)*};
pub use slint_generated::{#(#compo_ids,)* #(#structs_and_enums_ids,)* #(#globals_ids,)* #(#named_exports,)*};
#[allow(unused_imports)]
pub use slint::{ComponentHandle as _, Global as _, ModelExt as _};
}
Expand Down
39 changes: 22 additions & 17 deletions internal/compiler/llr/lower_to_item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ pub fn lower_to_item_tree(
) -> CompilationUnit {
let mut state = LoweringState::default();

let component = &document.root_component;

let mut globals = Vec::new();
for g in &document.used_types.borrow().globals {
let count = globals.len();
Expand All @@ -31,22 +29,29 @@ pub fn lower_to_item_tree(
state.sub_components.insert(ByAddress(c.clone()), sc);
}

let sc = lower_sub_component(component, &state, None, &compiler_config);
let public_properties = public_properties(component, &sc.mapping, &state);
let mut item_tree = ItemTree {
tree: make_tree(&state, &component.root_element, &sc, &[]),
root: Rc::try_unwrap(sc.sub_component).unwrap(),
parent_context: None,
};
// For C++ codegen, the root component must have the same name as the public component
item_tree.root.name = component.id.clone();
let public_components = document
.exported_roots()
.map(|component| {
let sc = lower_sub_component(&component, &state, None, &compiler_config);
let public_properties = public_properties(&component, &sc.mapping, &state);
let mut item_tree = ItemTree {
tree: make_tree(&state, &component.root_element, &sc, &[]),
root: Rc::try_unwrap(sc.sub_component).unwrap(),
parent_context: None,
};
// For C++ codegen, the root component must have the same name as the public component
item_tree.root.name = component.id.clone();
PublicComponent {
item_tree,
public_properties,
private_properties: component.private_properties.borrow().clone(),
name: component.id.clone(),
}
})
.collect();

let root = CompilationUnit {
public_components: vec![PublicComponent {
item_tree,
public_properties,
private_properties: component.private_properties.borrow().clone(),
name: component.id.clone(),
}],
public_components,
globals,
sub_components: document
.used_types
Expand Down
74 changes: 32 additions & 42 deletions internal/compiler/object_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ pub struct Document {
pub node: Option<syntax_nodes::Document>,
pub inner_components: Vec<Rc<Component>>,
pub inner_types: Vec<Type>,
pub root_component: Rc<Component>,
pub local_registry: TypeRegister,
/// A list of paths to .ttf/.ttc files that are supposed to be registered on
/// startup for custom font use.
Expand Down Expand Up @@ -165,23 +164,6 @@ impl Document {
let mut exports = Exports::from_node(&node, &inner_components, &local_registry, diag);
exports.add_reexports(reexports, diag);

let root_component = exports
.last_exported_component
.clone()
.or_else(|| {
node.ImportSpecifier()
.last()
.and_then(|import| {
crate::typeloader::ImportedName::extract_imported_names(&import).last()
})
.and_then(|import| local_registry.lookup_element(&import.internal_name).ok())
.and_then(|c| match c {
ElementType::Component(c) => Some(c),
_ => None,
})
})
.unwrap_or_default();

let custom_fonts = foreign_imports
.into_iter()
.filter_map(|import| {
Expand Down Expand Up @@ -247,7 +229,6 @@ impl Document {

Document {
node: Some(node),
root_component,
inner_components,
inner_types,
local_registry,
Expand All @@ -258,13 +239,42 @@ impl Document {
}
}

pub fn exported_roots(&self) -> impl Iterator<Item = Rc<Component>> + DoubleEndedIterator + '_ {
let mut iter = self
.exports
.iter()
.filter_map(|e| e.1.as_ref().left())
.filter(|c| !c.is_global())
.cloned()
.peekable();
// If that is empty, we return the last import. (We need to chain because we need to return the same type for `impl Iterator`)
let extra = if iter.peek().is_some() {
None
} else {
self.node
.as_ref()
.and_then(|n| n.ImportSpecifier().last())
.and_then(|import| {
crate::typeloader::ImportedName::extract_imported_names(&import).last()
})
.and_then(|import| self.local_registry.lookup_element(&import.internal_name).ok())
.and_then(|c| match c {
ElementType::Component(c) => Some(c),
_ => None,
})
};
iter.chain(extra)
}

/// visit all root and used component (including globals)
pub fn visit_all_used_components(&self, mut v: impl FnMut(&Rc<Component>)) {
let used_types = self.used_types.borrow();
for c in &used_types.sub_components {
v(c);
}
v(&self.root_component);
for c in self.exported_roots() {
v(&c);
}
for c in &used_types.globals {
v(c);
}
Expand Down Expand Up @@ -2394,7 +2404,6 @@ impl ExportedName {
pub struct Exports {
#[deref]
components_or_types: Vec<(ExportedName, Either<Rc<Component>, Type>)>,
last_exported_component: Option<Rc<Component>>,
}

impl Exports {
Expand Down Expand Up @@ -2427,18 +2436,10 @@ impl Exports {
};

let mut sorted_exports_with_duplicates: Vec<(ExportedName, _)> = Vec::new();
let mut last_exported_component = None;

let mut extend_exports =
|it: &mut dyn Iterator<Item = (ExportedName, Either<Rc<Component>, Type>)>| {
for (name, compo_or_type) in it {
match compo_or_type.as_ref().left() {
Some(compo) if !compo.is_global() => {
last_exported_component = Some(compo.clone())
}
_ => {}
}

let pos = sorted_exports_with_duplicates
.partition_point(|(existing_name, _)| existing_name.name <= name.name);
sorted_exports_with_duplicates.insert(pos, (name, compo_or_type));
Expand Down Expand Up @@ -2558,12 +2559,7 @@ impl Exports {
))
}
}

if last_exported_component.is_none() {
last_exported_component = inner_components.last().cloned();
}

Self { components_or_types: sorted_deduped_exports, last_exported_component }
Self { components_or_types: sorted_deduped_exports }
}

pub fn add_reexports(
Expand Down Expand Up @@ -2612,13 +2608,7 @@ impl Exports {
})
.collect();

Self {
components_or_types,
last_exported_component: self
.last_exported_component
.as_ref()
.map(|lec| snapshotter.snapshot_component(lec)),
}
Self { components_or_types }
}
}

Expand Down
21 changes: 7 additions & 14 deletions internal/compiler/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ mod visible;
mod z_order;

use crate::expression_tree::Expression;
use crate::langtype::ElementType;
use crate::namedreference::NamedReference;

pub async fn run_passes(
Expand All @@ -60,14 +59,6 @@ pub async fn run_passes(
keep_raw: bool,
diag: &mut crate::diagnostics::BuildDiagnostics,
) -> Option<crate::typeloader::TypeLoader> {
if matches!(
doc.root_component.root_element.borrow().base_type,
ElementType::Error | ElementType::Global
) {
// If there isn't a root component, we shouldn't do any of these passes
return None;
}

let style_metrics = {
// Ignore import errors
let mut build_diags_to_ignore = crate::diagnostics::BuildDiagnostics::default();
Expand All @@ -78,7 +69,6 @@ pub async fn run_passes(
};

let global_type_registry = type_loader.global_type_registry.clone();
let root_component = &doc.root_component;
run_import_passes(doc, type_loader, diag);
check_public_api::check_public_api(doc, diag);

Expand Down Expand Up @@ -113,9 +103,10 @@ pub async fn run_passes(
inlining::inline(doc, inlining::InlineSelection::InlineOnlyRequiredComponents, diag);
collect_subcomponents::collect_subcomponents(doc);

focus_handling::call_focus_on_init(root_component);

ensure_window::ensure_window(root_component, &doc.local_registry, &style_metrics, diag);
for root_component in doc.exported_roots() {
focus_handling::call_focus_on_init(&root_component);
ensure_window::ensure_window(&root_component, &doc.local_registry, &style_metrics, diag);
}

doc.visit_all_used_components(|component| {
border_radius::handle_border_radius(component, diag);
Expand Down Expand Up @@ -175,7 +166,9 @@ pub async fn run_passes(
}
materialize_fake_properties::materialize_fake_properties(component);
});
lower_layout::check_window_layout(root_component);
for root_component in doc.exported_roots() {
lower_layout::check_window_layout(&root_component);
}
collect_globals::collect_globals(doc, diag);

if type_loader.compiler_config.inline_all_elements {
Expand Down
4 changes: 3 additions & 1 deletion internal/compiler/passes/check_public_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use crate::diagnostics::{BuildDiagnostics, DiagnosticLevel};
use crate::object_tree::{Component, Document, PropertyVisibility};

pub fn check_public_api(doc: &Document, diag: &mut BuildDiagnostics) {
check_public_api_component(&doc.root_component, diag);
for c in doc.exported_roots() {
check_public_api_component(&c, diag);
}
for (export_name, e) in &*doc.exports {
if let Some(c) = e.as_ref().left() {
if c.is_global() {
Expand Down
16 changes: 9 additions & 7 deletions internal/compiler/passes/collect_custom_fonts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ pub fn collect_custom_fonts<'a>(
Box::new(|font_path| Expression::StringLiteral(font_path.clone()))
};

doc.root_component.init_code.borrow_mut().font_registration_code.extend(
all_fonts.into_iter().map(|font_path| Expression::FunctionCall {
function: Box::new(registration_function.clone()),
arguments: vec![prepare_font_registration_argument(font_path)],
source_location: None,
}),
);
for c in doc.exported_roots() {
c.init_code.borrow_mut().font_registration_code.extend(all_fonts.iter().map(|font_path| {
Expression::FunctionCall {
function: Box::new(registration_function.clone()),
arguments: vec![prepare_font_registration_argument(font_path)],
source_location: None,
}
}));
}
}
4 changes: 3 additions & 1 deletion internal/compiler/passes/collect_globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ pub fn collect_globals(doc: &Document, _diag: &mut BuildDiagnostics) {
}
}
}
collect_in_component(&doc.root_component, &mut set, &mut sorted_globals);
for component in doc.exported_roots() {
collect_in_component(&component, &mut set, &mut sorted_globals);
}
for component in &doc.used_types.borrow().sub_components {
collect_in_component(component, &mut set, &mut sorted_globals);
}
Expand Down
6 changes: 3 additions & 3 deletions internal/compiler/passes/collect_subcomponents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use std::rc::Rc;
pub fn collect_subcomponents(doc: &Document) {
let mut result = vec![];
let mut hash = HashSet::new();

collect_subcomponents_recursive(&doc.root_component, &mut result, &mut hash);

for component in doc.exported_roots() {
collect_subcomponents_recursive(&component, &mut result, &mut hash);
}
doc.used_types.borrow_mut().sub_components = result;
}

Expand Down
4 changes: 3 additions & 1 deletion internal/compiler/passes/const_propagation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ export component Foo {
assert!(!diag.has_error());

let out_binding = doc
.root_component
.inner_components
.last()
.unwrap()
.root_element
.borrow()
.bindings
Expand Down
Loading

0 comments on commit 3764312

Please sign in to comment.