llr: don't store Rc<SubComponent> but an index instead

The goal eventually is to serialize the LLR and we can't do it if it
uses Rc inside.
This commit is contained in:
Olivier Goffart 2025-01-25 14:16:53 +01:00
parent c739f1e9ba
commit 55bafbb51b
9 changed files with 328 additions and 261 deletions

View file

@ -86,8 +86,11 @@ fn access_item_rc(pr: &llr::PropertyReference, ctx: &EvaluationContext) -> Strin
match pr {
llr::PropertyReference::InNativeItem { sub_component_path, item_index, prop_name } => {
assert!(prop_name.is_empty());
let (sub_compo_path, sub_component) =
follow_sub_component_path(ctx.current_sub_component.unwrap(), sub_component_path);
let (sub_compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
ctx.current_sub_component.unwrap(),
sub_component_path,
);
if !sub_component_path.is_empty() {
component_access += &sub_compo_path;
}
@ -724,12 +727,12 @@ pub fn generate(
let conditional_includes = ConditionalIncludes::default();
for sub_compo in &llr.sub_components {
let sub_compo_id = ident(&sub_compo.name);
for sub_compo in &llr.used_sub_components {
let sub_compo_id = ident(&llr.sub_components[*sub_compo].name);
let mut sub_compo_struct = Struct { name: sub_compo_id.clone(), ..Default::default() };
generate_sub_component(
&mut sub_compo_struct,
sub_compo,
*sub_compo,
&llr,
None,
Access::Public,
@ -820,7 +823,7 @@ pub fn generate(
file.declarations.push(Declaration::Struct(globals_struct));
if let Some(popup_menu) = &llr.popup_menu {
let component_id = ident(&popup_menu.item_tree.root.name);
let component_id = ident(&llr.sub_components[popup_menu.item_tree.root].name);
let mut popup_struct = Struct { name: component_id.clone(), ..Default::default() };
generate_item_tree(
&mut popup_struct,
@ -1200,7 +1203,7 @@ fn generate_public_component(
let ctx = EvaluationContext {
compilation_unit: unit,
current_sub_component: Some(&component.item_tree.root),
current_sub_component: Some(component.item_tree.root),
current_global: None,
generator_state: CppGeneratorContext {
global_access: "(&this->m_globals)".to_string(),
@ -1285,17 +1288,23 @@ fn generate_public_component(
component_struct.friends.push("slint::private_api::WindowAdapterRc".into());
add_friends(&mut component_struct.friends, &component.item_tree.root, true);
add_friends(&mut component_struct.friends, unit, component.item_tree.root, true);
fn add_friends(friends: &mut Vec<SmolStr>, sc: &llr::SubComponent, is_root: bool) {
fn add_friends(
friends: &mut Vec<SmolStr>,
unit: &llr::CompilationUnit,
c: llr::SubComponentIndex,
is_root: bool,
) {
let sc = &unit.sub_components[c];
if !is_root {
friends.push(ident(&sc.name));
}
for repeater in &sc.repeated {
add_friends(friends, &repeater.sub_tree.root, false)
add_friends(friends, unit, repeater.sub_tree.root, false)
}
for popup in &sc.popup_windows {
add_friends(friends, &popup.item_tree.root, false)
add_friends(friends, unit, popup.item_tree.root, false)
}
}
@ -1321,7 +1330,7 @@ fn generate_item_tree(
generate_sub_component(
target_struct,
&sub_tree.root,
sub_tree.root,
root,
parent_ctx,
field_access,
@ -1338,10 +1347,10 @@ fn generate_item_tree(
if node.repeated {
assert_eq!(node.children.len(), 0);
let mut repeater_index = node.item_index;
let mut sub_component = &sub_tree.root;
let mut sub_component = &root.sub_components[sub_tree.root];
for i in &node.sub_component_path {
repeater_index += sub_component.sub_components[*i].repeater_offset;
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &root.sub_components[sub_component.sub_components[*i].ty];
}
item_tree_array.push(format!(
"slint::private_api::make_dyn_node({}, {})",
@ -1349,7 +1358,7 @@ fn generate_item_tree(
));
} else {
let mut compo_offset = String::new();
let mut sub_component = &sub_tree.root;
let mut sub_component = &root.sub_components[sub_tree.root];
for i in &node.sub_component_path {
let next_sub_component_name = ident(&sub_component.sub_components[*i].name);
write!(
@ -1359,7 +1368,7 @@ fn generate_item_tree(
next_sub_component_name
)
.unwrap();
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &root.sub_components[sub_component.sub_components[*i].ty];
}
let item = &sub_component.items[node.item_index as usize];
@ -1473,7 +1482,7 @@ fn generate_item_tree(
.and_then(|parent| {
parent
.repeater_index
.map(|idx| parent.ctx.current_sub_component.unwrap().repeated[idx as usize].index_in_tree)
.map(|idx| parent.ctx.current_sub_component().unwrap().repeated[idx as usize].index_in_tree)
}).map(|parent_index|
vec![
format!(
@ -1713,7 +1722,7 @@ fn generate_item_tree(
if let Some(parent) = &parent_ctx {
let parent_type =
format!("class {} const *", ident(&parent.ctx.current_sub_component.unwrap().name));
format!("class {} const *", ident(&parent.ctx.current_sub_component().unwrap().name));
create_parameters.push(format!("{} parent", parent_type));
init_parent_parameters = ", parent";
@ -1805,7 +1814,7 @@ fn generate_item_tree(
fn generate_sub_component(
target_struct: &mut Struct,
component: &llr::SubComponent,
component: llr::SubComponentIndex,
root: &llr::CompilationUnit,
parent_ctx: Option<ParentCtx>,
field_access: Access,
@ -1866,7 +1875,7 @@ fn generate_sub_component(
if let Some(parent_ctx) = &parent_ctx {
let parent_type = format_smolstr!(
"class {} const *",
ident(&parent_ctx.ctx.current_sub_component.unwrap().name)
ident(&parent_ctx.ctx.current_sub_component().unwrap().name)
);
init_parameters.push(format!("{} parent", parent_type));
@ -1884,8 +1893,10 @@ fn generate_sub_component(
parent_ctx,
);
let component = &root.sub_components[component];
component.popup_windows.iter().for_each(|popup| {
let component_id = ident(&popup.item_tree.root.name);
let component_id = ident(&root.sub_components[popup.item_tree.root].name);
let mut popup_struct = Struct { name: component_id.clone(), ..Default::default() };
generate_item_tree(
&mut popup_struct,
@ -1943,6 +1954,7 @@ fn generate_sub_component(
for sub in &component.sub_components {
let field_name = ident(&sub.name);
let sub_sc = &root.sub_components[sub.ty];
let local_tree_index: u32 = sub.index_in_tree as _;
let local_index_of_first_child: u32 = sub.index_of_first_child_in_tree as _;
@ -1965,7 +1977,7 @@ fn generate_sub_component(
));
user_init.push(format!("this->{}.user_init();", field_name));
let sub_component_repeater_count = sub.ty.repeater_count();
let sub_component_repeater_count = sub_sc.repeater_count(root);
if sub_component_repeater_count > 0 {
let mut case_code = String::new();
let repeater_offset = sub.repeater_offset;
@ -2004,7 +2016,7 @@ fn generate_sub_component(
target_struct.members.push((
field_access,
Declaration::Var(Var {
ty: ident(&sub.ty.name),
ty: ident(&sub_sc.name),
name: field_name,
..Default::default()
}),
@ -2033,7 +2045,7 @@ fn generate_sub_component(
let mut properties_init_code = Vec::new();
for (prop, expression) in &component.property_init {
if expression.use_count.get() > 0 && component.prop_used(prop) {
if expression.use_count.get() > 0 && component.prop_used(prop, root) {
handle_property_init(prop, expression, &mut properties_init_code, &ctx)
}
}
@ -2052,8 +2064,9 @@ fn generate_sub_component(
for (idx, repeated) in component.repeated.iter().enumerate() {
let idx = idx as u32;
let sc = &root.sub_components[repeated.sub_tree.root];
let data_type = if let Some(data_prop) = repeated.data_prop {
repeated.sub_tree.root.properties[data_prop].ty.clone()
sc.properties[data_prop].ty.clone()
} else {
Type::Int32
};
@ -2132,7 +2145,7 @@ fn generate_sub_component(
Declaration::Var(Var {
ty: format_smolstr!(
"slint::private_api::Repeater<class {}, {}>",
ident(&repeated.sub_tree.root.name),
ident(&sc.name),
data_type.cpp_type().unwrap(),
),
name: repeater_id,
@ -2240,7 +2253,8 @@ fn generate_sub_component(
let mut else_ = "";
for sub in &component.sub_components {
let sub_items_count = sub.ty.child_item_count();
let sub_sc = &ctx.compilation_unit.sub_components[sub.ty];
let sub_items_count = sub_sc.child_item_count(ctx.compilation_unit);
code.push(format!("{else_}if (index == {}) {{", sub.index_in_tree,));
code.push(format!(" return self->{}.{name}(0{forward_args});", ident(&sub.name)));
if sub_items_count > 1 {
@ -2248,7 +2262,7 @@ fn generate_sub_component(
"}} else if (index >= {} && index < {}) {{",
sub.index_of_first_child_in_tree,
sub.index_of_first_child_in_tree + sub_items_count - 1
+ sub.ty.repeater_count()
+ sub_sc.repeater_count(ctx.compilation_unit)
));
code.push(format!(
" return self->{}.{name}(index - {}{forward_args});",
@ -2425,7 +2439,7 @@ fn generate_repeated_component(
file: &mut File,
conditional_includes: &ConditionalIncludes,
) {
let repeater_id = ident(&repeated.sub_tree.root.name);
let repeater_id = ident(&root.sub_components[repeated.sub_tree.root].name);
let mut repeater_struct = Struct { name: repeater_id.clone(), ..Default::default() };
generate_item_tree(
&mut repeater_struct,
@ -2441,7 +2455,7 @@ fn generate_repeated_component(
let ctx = EvaluationContext {
compilation_unit: root,
current_sub_component: Some(&repeated.sub_tree.root),
current_sub_component: Some(repeated.sub_tree.root),
current_global: None,
generator_state: CppGeneratorContext { global_access: "self".into(), conditional_includes },
parent: Some(parent_ctx),
@ -2840,15 +2854,16 @@ fn generate_public_api_for_properties(
}
fn follow_sub_component_path<'a>(
root: &'a llr::SubComponent,
compilation_unit: &'a llr::CompilationUnit,
root: llr::SubComponentIndex,
sub_component_path: &[usize],
) -> (String, &'a llr::SubComponent) {
let mut compo_path = String::new();
let mut sub_component = root;
let mut sub_component = &compilation_unit.sub_components[root];
for i in sub_component_path {
let sub_component_name = ident(&sub_component.sub_components[*i].name);
write!(compo_path, "{}.", sub_component_name).unwrap();
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &compilation_unit.sub_components[sub_component.sub_components[*i].ty];
}
(compo_path, sub_component)
}
@ -2877,8 +2892,11 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
prop_name: &str,
path: &str,
) -> String {
let (compo_path, sub_component) =
follow_sub_component_path(ctx.current_sub_component.unwrap(), sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
ctx.current_sub_component.unwrap(),
sub_component_path,
);
let item_name = ident(&sub_component.items[item_index as usize].name);
if prop_name.is_empty() {
// then this is actually a reference to the element itself
@ -2893,8 +2911,11 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
match reference {
llr::PropertyReference::Local { sub_component_path, property_index } => {
if let Some(sub_component) = ctx.current_sub_component {
let (compo_path, sub_component) =
follow_sub_component_path(sub_component, sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
sub_component,
sub_component_path,
);
let property_name = ident(&sub_component.properties[*property_index].name);
format!("self->{}{}", compo_path, property_name)
} else if let Some(current_global) = ctx.current_global {
@ -2905,8 +2926,11 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
}
llr::PropertyReference::Function { sub_component_path, function_index } => {
if let Some(sub_component) = ctx.current_sub_component {
let (compo_path, sub_component) =
follow_sub_component_path(sub_component, sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
sub_component,
sub_component_path,
);
let name = ident(&sub_component.functions[*function_index].name);
format!("self->{compo_path}fn_{name}")
} else if let Some(current_global) = ctx.current_global {
@ -2929,15 +2953,21 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
match &**parent_reference {
llr::PropertyReference::Local { sub_component_path, property_index } => {
let sub_component = ctx.current_sub_component.unwrap();
let (compo_path, sub_component) =
follow_sub_component_path(sub_component, sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
sub_component,
sub_component_path,
);
let property_name = ident(&sub_component.properties[*property_index].name);
format!("{}->{}{}", path, compo_path, property_name)
}
llr::PropertyReference::Function { sub_component_path, function_index } => {
let sub_component = ctx.current_sub_component.unwrap();
let (compo_path, sub_component) =
follow_sub_component_path(sub_component, sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
sub_component,
sub_component_path,
);
let name = ident(&sub_component.functions[*function_index].name);
format!("{path}->{compo_path}fn_{name}")
}
@ -2982,10 +3012,11 @@ fn native_item<'a>(
) -> &'a NativeClass {
match item_ref {
llr::PropertyReference::InNativeItem { sub_component_path, item_index, prop_name: _ } => {
let mut sub_component = ctx.current_sub_component.unwrap();
for i in sub_component_path {
sub_component = &sub_component.sub_components[*i].ty;
}
let (_, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
ctx.current_sub_component.unwrap(),
sub_component_path,
);
&sub_component.items[*item_index as usize].ty
}
llr::PropertyReference::InParent { level, parent_reference } => {
@ -3192,7 +3223,7 @@ fn compile_expression(expr: &llr::Expression, ctx: &EvaluationContext) -> String
let repeater_index = repeater_index.unwrap();
let mut index_prop = llr::PropertyReference::Local {
sub_component_path: vec![],
property_index: ctx2.current_sub_component.unwrap().repeated[repeater_index as usize]
property_index: ctx2.current_sub_component().unwrap().repeated[repeater_index as usize]
.index_prop
.unwrap(),
};
@ -3669,14 +3700,14 @@ fn compile_builtin_function_call(
};
let window = access_window_field(ctx);
let current_sub_component = parent_ctx.current_sub_component.unwrap();
let current_sub_component = parent_ctx.current_sub_component().unwrap();
let popup = &current_sub_component.popup_windows[*popup_index as usize];
let popup_window_id =
ident(&popup.item_tree.root.name);
ident(&ctx.compilation_unit.sub_components[popup.item_tree.root].name);
let parent_component = access_item_rc(parent_ref, ctx);
let popup_ctx = EvaluationContext::new_sub_component(
ctx.compilation_unit,
&popup.item_tree.root,
popup.item_tree.root,
CppGeneratorContext { global_access: "self->globals".into(), conditional_includes: ctx.generator_state.conditional_includes },
Some(ParentCtx::new(&ctx, None)),
);
@ -3722,12 +3753,12 @@ fn compile_builtin_function_call(
.popup_menu
.as_ref()
.expect("there should be a popup menu if we want to show it");
let popup_id = ident(&popup.item_tree.root.name);
let popup_id = ident(&ctx.compilation_unit.sub_components[popup.item_tree.root].name);
let window = access_window_field(ctx);
let popup_ctx = EvaluationContext::new_sub_component(
ctx.compilation_unit,
&popup.item_tree.root,
popup.item_tree.root,
CppGeneratorContext { global_access: "self->globals".into(), conditional_includes: ctx.generator_state.conditional_includes },
None,
);

View file

@ -179,9 +179,9 @@ pub fn generate(
}
let sub_compos = llr
.sub_components
.used_sub_components
.iter()
.map(|sub_compo| generate_sub_component(sub_compo, &llr, None, None, false))
.map(|sub_compo| generate_sub_component(*sub_compo, &llr, None, None, false))
.collect::<Vec<_>>();
let public_components =
llr.public_components.iter().map(|p| generate_public_component(p, &llr));
@ -251,13 +251,13 @@ fn generate_public_component(
unit: &llr::CompilationUnit,
) -> TokenStream {
let public_component_id = ident(&llr.name);
let inner_component_id = inner_component_id(&llr.item_tree.root);
let inner_component_id = inner_component_id(&unit.sub_components[llr.item_tree.root]);
let component = generate_item_tree(&llr.item_tree, unit, None, None, false);
let ctx = EvaluationContext {
compilation_unit: unit,
current_sub_component: Some(&llr.item_tree.root),
current_sub_component: Some(llr.item_tree.root),
current_global: None,
generator_state: RustGeneratorContext {
global_access: quote!(_self.globals.get().unwrap()),
@ -668,17 +668,18 @@ fn public_api(
/// Generate the rust code for the given component.
fn generate_sub_component(
component: &llr::SubComponent,
component_idx: llr::SubComponentIndex,
root: &llr::CompilationUnit,
parent_ctx: Option<ParentCtx>,
index_property: Option<llr::PropertyIndex>,
pinned_drop: bool,
) -> TokenStream {
let component = &root.sub_components[component_idx];
let inner_component_id = inner_component_id(component);
let ctx = EvaluationContext::new_sub_component(
root,
component,
component_idx,
RustGeneratorContext { global_access: quote!(_self.globals.get().unwrap()) },
parent_ctx,
);
@ -775,7 +776,8 @@ fn generate_sub_component(
ParentCtx::new(&ctx, Some(idx)),
));
let repeater_id = format_ident!("repeater{}", idx);
let rep_inner_component_id = self::inner_component_id(&repeated.sub_tree.root);
let rep_inner_component_id =
self::inner_component_id(&root.sub_components[repeated.sub_tree.root]);
let mut model = compile_expression(&repeated.model.borrow(), &ctx);
if repeated.model.ty(&ctx) == Type::Bool {
@ -932,7 +934,8 @@ fn generate_sub_component(
for sub in &component.sub_components {
let field_name = ident(&sub.name);
let sub_component_id = self::inner_component_id(&sub.ty);
let sc = &root.sub_components[sub.ty];
let sub_component_id = self::inner_component_id(sc);
let local_tree_index: u32 = sub.index_in_tree as _;
let local_index_of_first_child: u32 = sub.index_of_first_child_in_tree as _;
let global_access = &ctx.generator_state.global_access;
@ -960,7 +963,7 @@ fn generate_sub_component(
sp::VRcMapped::map(self_rc.clone(), |x| #sub_compo_field.apply_pin(x)),
);));
let sub_component_repeater_count = sub.ty.repeater_count();
let sub_component_repeater_count = sc.repeater_count(root);
if sub_component_repeater_count > 0 {
let repeater_offset = sub.repeater_offset;
let last_repeater = repeater_offset + sub_component_repeater_count - 1;
@ -981,7 +984,7 @@ fn generate_sub_component(
));
}
let sub_items_count = sub.ty.child_item_count();
let sub_items_count = sc.child_item_count(root);
accessible_role_branch.push(quote!(
#local_tree_index => #sub_compo_field.apply_pin(_self).accessible_role(0),
));
@ -996,7 +999,7 @@ fn generate_sub_component(
));
if sub_items_count > 1 {
let range_begin = local_index_of_first_child;
let range_end = range_begin + sub_items_count - 2 + sub.ty.repeater_count();
let range_end = range_begin + sub_items_count - 2 + sc.repeater_count(root);
accessible_role_branch.push(quote!(
#range_begin..=#range_end => #sub_compo_field.apply_pin(_self).accessible_role(index - #range_begin + 1),
));
@ -1032,12 +1035,12 @@ fn generate_sub_component(
}
for (prop, expression) in &component.property_init {
if expression.use_count.get() > 0 && component.prop_used(prop) {
if expression.use_count.get() > 0 && component.prop_used(prop, root) {
handle_property_init(prop, expression, &mut init, &ctx)
}
}
for prop in &component.const_properties {
if component.prop_used(prop) {
if component.prop_used(prop, root) {
let rust_property = access_member(prop, &ctx).unwrap();
init.push(quote!(#rust_property.set_constant();))
}
@ -1045,7 +1048,7 @@ fn generate_sub_component(
let parent_component_type = parent_ctx.iter().map(|parent| {
let parent_component_id =
self::inner_component_id(parent.ctx.current_sub_component.unwrap());
self::inner_component_id(parent.ctx.current_sub_component().unwrap());
quote!(sp::VWeakMapped::<sp::ItemTreeVTable, #parent_component_id>)
});
@ -1493,13 +1496,13 @@ fn generate_item_tree(
index_property: Option<llr::PropertyIndex>,
is_popup_menu: bool,
) -> TokenStream {
let sub_comp = generate_sub_component(&sub_tree.root, root, parent_ctx, index_property, true);
let inner_component_id = self::inner_component_id(&sub_tree.root);
let sub_comp = generate_sub_component(sub_tree.root, root, parent_ctx, index_property, true);
let inner_component_id = self::inner_component_id(&root.sub_components[sub_tree.root]);
let parent_component_type = parent_ctx
.iter()
.map(|parent| {
let parent_component_id =
self::inner_component_id(parent.ctx.current_sub_component.unwrap());
self::inner_component_id(parent.ctx.current_sub_component().unwrap());
quote!(sp::VWeakMapped::<sp::ItemTreeVTable, #parent_component_id>)
})
.collect::<Vec<_>>();
@ -1521,7 +1524,7 @@ fn generate_item_tree(
let parent_item_expression = parent_ctx.and_then(|parent| {
parent.repeater_index.map(|idx| {
let sub_component_offset = parent.ctx.current_sub_component.unwrap().repeated[idx as usize].index_in_tree;
let sub_component_offset = parent.ctx.current_sub_component().unwrap().repeated[idx as usize].index_in_tree;
quote!(if let Some((parent_component, parent_index)) = self
.parent
@ -1538,14 +1541,15 @@ fn generate_item_tree(
let mut item_array = vec![];
sub_tree.tree.visit_in_array(&mut |node, children_offset, parent_index| {
let parent_index = parent_index as u32;
let (path, component) = follow_sub_component_path(&sub_tree.root, &node.sub_component_path);
let (path, component) =
follow_sub_component_path(root, sub_tree.root, &node.sub_component_path);
if node.repeated || node.component_container {
assert_eq!(node.children.len(), 0);
let mut repeater_index = node.item_index;
let mut sub_component = &sub_tree.root;
let mut sub_component = &root.sub_components[sub_tree.root];
for i in &node.sub_component_path {
repeater_index += sub_component.sub_components[*i].repeater_offset;
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &root.sub_components[sub_component.sub_components[*i].ty];
}
item_tree_array.push(quote!(
sp::ItemTreeNode::DynamicTree {
@ -1756,14 +1760,15 @@ fn generate_repeated_component(
let ctx = EvaluationContext {
compilation_unit: unit,
current_sub_component: Some(&repeated.sub_tree.root),
current_sub_component: Some(repeated.sub_tree.root),
current_global: None,
generator_state: RustGeneratorContext { global_access: quote!(_self) },
parent: Some(parent_ctx),
argument_types: &[],
};
let inner_component_id = self::inner_component_id(&repeated.sub_tree.root);
let root_sc = &unit.sub_components[repeated.sub_tree.root];
let inner_component_id = self::inner_component_id(&root_sc);
let extra_fn = if let Some(listview) = &repeated.listview {
let p_y = access_member(&listview.prop_y, &ctx).unwrap();
@ -1791,7 +1796,7 @@ fn generate_repeated_component(
};
let data_type = if let Some(data_prop) = repeated.data_prop {
rust_primitive_type(&repeated.sub_tree.root.properties[data_prop].ty).unwrap()
rust_primitive_type(&root_sc.properties[data_prop].ty).unwrap()
} else {
quote!(())
};
@ -1884,8 +1889,11 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
prop_name: &str,
path: TokenStream,
) -> TokenStream {
let (compo_path, sub_component) =
follow_sub_component_path(ctx.current_sub_component.unwrap(), sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
ctx.current_sub_component.unwrap(),
sub_component_path,
);
let component_id = inner_component_id(sub_component);
let item_name = ident(&sub_component.items[item_index as usize].name);
let item_field = access_component_field_offset(&component_id, &item_name);
@ -1901,8 +1909,11 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
match reference {
llr::PropertyReference::Local { sub_component_path, property_index } => {
if let Some(sub_component) = ctx.current_sub_component {
let (compo_path, sub_component) =
follow_sub_component_path(sub_component, sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
sub_component,
sub_component_path,
);
let component_id = inner_component_id(sub_component);
let property_name = ident(&sub_component.properties[*property_index].name);
let property_field = access_component_field_offset(&component_id, &property_name);
@ -1936,8 +1947,11 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
match &**parent_reference {
llr::PropertyReference::Local { sub_component_path, property_index } => {
let sub_component = ctx.current_sub_component.unwrap();
let (compo_path, sub_component) =
follow_sub_component_path(sub_component, sub_component_path);
let (compo_path, sub_component) = follow_sub_component_path(
ctx.compilation_unit,
sub_component,
sub_component_path,
);
let component_id = inner_component_id(sub_component);
let property_name = ident(&sub_component.properties[*property_index].name);
MemberAccess::Option(
@ -1959,14 +1973,15 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
MemberAccess::Option(quote!(#path.as_ref().map(|x| #in_native)))
}
llr::PropertyReference::Function { sub_component_path, function_index } => {
let mut sub_component = ctx.current_sub_component.unwrap();
let mut sub_component = ctx.current_sub_component().unwrap();
let mut compo_path = quote!(x.as_pin_ref());
for i in sub_component_path {
let component_id = inner_component_id(sub_component);
let sub_component_name = ident(&sub_component.sub_components[*i].name);
compo_path = quote!( #component_id::FIELD_OFFSETS.#sub_component_name.apply_pin(#compo_path));
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &ctx.compilation_unit.sub_components
[sub_component.sub_components[*i].ty];
}
let fn_id =
ident(&format!("fn_{}", sub_component.functions[*function_index].name));
@ -1992,13 +2007,14 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
)
}
llr::PropertyReference::Function { sub_component_path, function_index } => {
if let Some(mut sub_component) = ctx.current_sub_component {
if let Some(mut sub_component) = ctx.current_sub_component() {
let mut compo_path = quote!(_self);
for i in sub_component_path {
let component_id = inner_component_id(sub_component);
let sub_component_name = ident(&sub_component.sub_components[*i].name);
compo_path = quote!( #component_id::FIELD_OFFSETS.#sub_component_name.apply_pin(#compo_path));
sub_component = &sub_component.sub_components[*i].ty;
sub_component =
&ctx.compilation_unit.sub_components[sub_component.sub_components[*i].ty];
}
let fn_id = ident(&format!("fn_{}", sub_component.functions[*function_index].name));
MemberAccess::Direct(quote!(#compo_path.#fn_id))
@ -2087,16 +2103,17 @@ impl MemberAccess {
}
fn follow_sub_component_path<'a>(
root: &'a llr::SubComponent,
compilation_unit: &'a llr::CompilationUnit,
root: llr::SubComponentIndex,
sub_component_path: &[usize],
) -> (TokenStream, &'a llr::SubComponent) {
let mut compo_path = quote!();
let mut sub_component = root;
let mut sub_component = &compilation_unit.sub_components[root];
for i in sub_component_path {
let component_id = inner_component_id(sub_component);
let sub_component_name = ident(&sub_component.sub_components[*i].name);
compo_path = quote!(#compo_path {#component_id::FIELD_OFFSETS.#sub_component_name} +);
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &compilation_unit.sub_components[sub_component.sub_components[*i].ty];
}
(compo_path, sub_component)
}
@ -2128,12 +2145,13 @@ fn access_item_rc(pr: &llr::PropertyReference, ctx: &EvaluationContext) -> Token
llr::PropertyReference::InNativeItem { sub_component_path, item_index, prop_name } => {
assert!(prop_name.is_empty());
let root = ctx.current_sub_component.unwrap();
let root = ctx.current_sub_component().unwrap();
let mut sub_component = root;
for i in sub_component_path {
let sub_component_name = ident(&sub_component.sub_components[*i].name);
component_access_tokens = quote!(#component_access_tokens . #sub_component_name);
sub_component = &sub_component.sub_components[*i].ty;
sub_component =
&ctx.compilation_unit.sub_components[sub_component.sub_components[*i].ty];
}
let component_rc_tokens = quote!(sp::VRcMapped::origin(&#component_access_tokens.self_weak.get().unwrap().upgrade().unwrap()));
let item_index_in_tree = sub_component.items[*item_index as usize].index_in_tree;
@ -2325,7 +2343,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
let repeater_index = repeater_index.unwrap();
let mut index_prop = llr::PropertyReference::Local {
sub_component_path: vec![],
property_index: ctx2.current_sub_component.unwrap().repeated
property_index: ctx2.current_sub_component().unwrap().repeated
[repeater_index as usize]
.index_prop
.unwrap(),
@ -2336,7 +2354,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
}
let index_access = access_member(&index_prop, ctx).get_property();
let repeater = access_component_field_offset(
&inner_component_id(ctx2.current_sub_component.unwrap()),
&inner_component_id(ctx2.current_sub_component().unwrap()),
&format_ident!("repeater{}", repeater_index),
);
quote!(#repeater.apply_pin(#path.as_pin_ref()).model_set_row_data(#index_access as _, #value as _))
@ -2674,14 +2692,15 @@ fn compile_builtin_function_call(
parent_ctx = parent_ctx.parent.as_ref().unwrap().ctx;
}
}
let current_sub_component = parent_ctx.current_sub_component.unwrap();
let current_sub_component = parent_ctx.current_sub_component().unwrap();
let popup = &current_sub_component.popup_windows[*popup_index as usize];
let popup_window_id = inner_component_id(&popup.item_tree.root);
let popup_window_id =
inner_component_id(&ctx.compilation_unit.sub_components[popup.item_tree.root]);
let parent_component = access_item_rc(parent_ref, ctx);
let popup_ctx = EvaluationContext::new_sub_component(
ctx.compilation_unit,
&popup.item_tree.root,
popup.item_tree.root,
RustGeneratorContext { global_access: quote!(_self.globals.get().unwrap()) },
Some(ParentCtx::new(&ctx, None)),
);
@ -2750,12 +2769,13 @@ fn compile_builtin_function_call(
.popup_menu
.as_ref()
.expect("there should be a popup menu if we want to show it");
let popup_id = inner_component_id(&popup.item_tree.root);
let popup_id =
inner_component_id(&ctx.compilation_unit.sub_components[popup.item_tree.root]);
let window_adapter_tokens = access_window_adapter_field(ctx);
let popup_ctx = EvaluationContext::new_sub_component(
ctx.compilation_unit,
&popup.item_tree.root,
popup.item_tree.root,
RustGeneratorContext { global_access: quote!(_self.globals.get().unwrap()) },
None,
);
@ -3005,7 +3025,7 @@ fn compile_builtin_function_call(
let entries = compile_expression(entries, ctx);
let sub_menu = access_member(sub_menu, ctx).unwrap();
let activated = access_member(activated, ctx).unwrap();
let inner_component_id = self::inner_component_id(ctx.current_sub_component.unwrap());
let inner_component_id = self::inner_component_id(ctx.current_sub_component().unwrap());
quote! {
if sp::WindowInner::from_pub(#window_adapter_tokens.window()).supports_native_menu_bar() {
// May seem overkill to have an instance of the struct for each call, but there should only be one call per component anyway
@ -3107,7 +3127,7 @@ fn box_layout_function(
ctx: &EvaluationContext,
) -> TokenStream {
let repeated_indices = repeated_indices.map(ident);
let inner_component_id = self::inner_component_id(ctx.current_sub_component.unwrap());
let inner_component_id = self::inner_component_id(ctx.current_sub_component().unwrap());
let mut fixed_count = 0usize;
let mut repeated_count = quote!();
let mut push_code = vec![];
@ -3122,7 +3142,12 @@ fn box_layout_function(
Either::Right(repeater) => {
let repeater_id = format_ident!("repeater{}", repeater);
let rep_inner_component_id = self::inner_component_id(
&ctx.current_sub_component.unwrap().repeated[*repeater as usize].sub_tree.root,
&ctx.compilation_unit.sub_components[ctx
.current_sub_component()
.unwrap()
.repeated[*repeater as usize]
.sub_tree
.root],
);
repeated_count = quote!(#repeated_count + _self.#repeater_id.len());
let ri = repeated_indices.as_ref().map(|ri| {

View file

@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
use super::PropertyReference;
use super::{PropertyReference, SubComponentIndex};
use crate::expression_tree::{BuiltinFunction, MinMaxOp, OperatorClass};
use crate::langtype::Type;
use crate::layout::Orientation;
@ -481,7 +481,7 @@ impl<'a, T> ParentCtx<'a, T> {
#[derive(Clone)]
pub struct EvaluationContext<'a, T = ()> {
pub compilation_unit: &'a super::CompilationUnit,
pub current_sub_component: Option<&'a super::SubComponent>,
pub current_sub_component: Option<SubComponentIndex>,
pub current_global: Option<&'a super::GlobalComponent>,
pub generator_state: T,
/// The repeater parent
@ -494,7 +494,7 @@ pub struct EvaluationContext<'a, T = ()> {
impl<'a, T> EvaluationContext<'a, T> {
pub fn new_sub_component(
compilation_unit: &'a super::CompilationUnit,
sub_component: &'a super::SubComponent,
sub_component: SubComponentIndex,
generator_state: T,
parent: Option<ParentCtx<'a, T>>,
) -> Self {
@ -525,6 +525,7 @@ impl<'a, T> EvaluationContext<'a, T> {
pub(crate) fn property_info<'b>(&'b self, prop: &PropertyReference) -> PropertyInfoResult<'b> {
fn match_in_sub_component<'b>(
cu: &'b super::CompilationUnit,
sc: &'b super::SubComponent,
prop: &PropertyReference,
map: ContextMap,
@ -533,7 +534,7 @@ impl<'a, T> EvaluationContext<'a, T> {
if let PropertyReference::Local { property_index, sub_component_path } = &prop {
let mut sc = sc;
for i in sub_component_path {
sc = &sc.sub_components[*i].ty;
sc = &cu.sub_components[sc.sub_components[*i].ty];
}
Some(&sc.properties[*property_index])
} else {
@ -570,7 +571,8 @@ impl<'a, T> EvaluationContext<'a, T> {
};
let idx = sub_component_path[0];
return apply_analysis(match_in_sub_component(
&sc.sub_components[idx].ty,
cu,
&cu.sub_components[sc.sub_components[idx].ty],
&prop2,
map.deeper_in_sub_component(idx),
));
@ -585,7 +587,8 @@ impl<'a, T> EvaluationContext<'a, T> {
};
let idx = sub_component_path[0];
return apply_analysis(match_in_sub_component(
&sc.sub_components[idx].ty,
cu,
&cu.sub_components[sc.sub_components[idx].ty],
&prop2,
map.deeper_in_sub_component(idx),
));
@ -610,15 +613,21 @@ impl<'a, T> EvaluationContext<'a, T> {
animation: None,
property_decl: Some(&g.properties[*property_index]),
};
} else if let Some(sc) = self.current_sub_component.as_ref() {
return match_in_sub_component(sc, prop, ContextMap::Identity);
} else if let Some(sc) = self.current_sub_component() {
return match_in_sub_component(
self.compilation_unit,
sc,
prop,
ContextMap::Identity,
);
} else {
unreachable!()
}
}
PropertyReference::InNativeItem { .. } => {
return match_in_sub_component(
self.current_sub_component.as_ref().unwrap(),
self.compilation_unit,
self.current_sub_component().unwrap(),
prop,
ContextMap::Identity,
);
@ -661,15 +670,20 @@ impl<'a, T> EvaluationContext<'a, T> {
}
}
}
pub fn current_sub_component(&self) -> Option<&super::SubComponent> {
self.current_sub_component.and_then(|i| self.compilation_unit.sub_components.get(i))
}
}
impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
fn property_ty(&self, prop: &PropertyReference) -> &Type {
match prop {
PropertyReference::Local { sub_component_path, property_index } => {
if let Some(mut sub_component) = self.current_sub_component {
if let Some(mut sub_component) = self.current_sub_component() {
for i in sub_component_path {
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &self.compilation_unit.sub_components
[sub_component.sub_components[*i].ty];
}
&sub_component.properties[*property_index].ty
} else if let Some(current_global) = self.current_global {
@ -684,9 +698,10 @@ impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
return &Type::PathData;
}
let mut sub_component = self.current_sub_component.unwrap();
let mut sub_component = self.current_sub_component().unwrap();
for i in sub_component_path {
sub_component = &sub_component.sub_components[*i].ty;
sub_component =
&self.compilation_unit.sub_components[sub_component.sub_components[*i].ty];
}
sub_component.items[*item_index as usize].ty.lookup_property(prop_name).unwrap()
@ -702,9 +717,10 @@ impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
&self.compilation_unit.globals[*global_index].properties[*property_index].ty
}
PropertyReference::Function { sub_component_path, function_index } => {
if let Some(mut sub_component) = self.current_sub_component {
if let Some(mut sub_component) = self.current_sub_component() {
for i in sub_component_path {
sub_component = &sub_component.sub_components[*i].ty;
sub_component = &self.compilation_unit.sub_components
[sub_component.sub_components[*i].ty];
}
&sub_component.functions[*function_index].ret_ty
} else if let Some(current_global) = self.current_global {
@ -840,7 +856,7 @@ impl ContextMap {
} else {
let mut e = ctx.current_sub_component.unwrap();
for i in path {
e = &e.sub_components[*i].ty;
e = ctx.compilation_unit.sub_components[e].sub_components[*i].ty;
}
EvaluationContext::new_sub_component(ctx.compilation_unit, e, (), None)
}

View file

@ -11,6 +11,8 @@ use std::rc::Rc;
// Index in the `SubComponent::properties`
pub type PropertyIndex = usize;
// Index in CompilationUint::sub_components
pub type SubComponentIndex = usize;
#[derive(Debug, Clone, derive_more::Deref)]
pub struct MutExpression(RefCell<Expression>);
@ -297,29 +299,29 @@ pub struct PropAnalysis {
impl SubComponent {
/// total count of repeater, including in sub components
pub fn repeater_count(&self) -> u32 {
pub fn repeater_count(&self, cu: &CompilationUnit) -> u32 {
let mut count = (self.repeated.len() + self.component_containers.len()) as u32;
for x in self.sub_components.iter() {
count += x.ty.repeater_count();
count += cu.sub_components[x.ty].repeater_count(cu);
}
count
}
/// total count of items, including in sub components
pub fn child_item_count(&self) -> u32 {
pub fn child_item_count(&self, cu: &CompilationUnit) -> u32 {
let mut count = self.items.len() as u32;
for x in self.sub_components.iter() {
count += x.ty.child_item_count();
count += cu.sub_components[x.ty].child_item_count(cu);
}
count
}
/// Return if a local property is used. (unused property shouldn't be generated)
pub fn prop_used(&self, prop: &PropertyReference) -> bool {
pub fn prop_used(&self, prop: &PropertyReference, cu: &CompilationUnit) -> bool {
if let PropertyReference::Local { property_index, sub_component_path } = prop {
let mut sc = self;
for i in sub_component_path {
sc = &sc.sub_components[*i].ty;
sc = &cu.sub_components[sc.sub_components[*i].ty];
}
if sc.properties[*property_index].use_count.get() == 0 {
return false;
@ -329,30 +331,18 @@ impl SubComponent {
}
}
#[derive(Debug)]
pub struct SubComponentInstance {
pub ty: Rc<SubComponent>,
pub ty: SubComponentIndex,
pub name: SmolStr,
pub index_in_tree: u32,
pub index_of_first_child_in_tree: u32,
pub repeater_offset: u32,
}
impl std::fmt::Debug for SubComponentInstance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SubComponentInstance")
// only dump ty.name, not the whole structure
.field("ty", &self.ty.name)
.field("name", &self.name)
.field("index_in_tree", &self.index_in_tree)
.field("index_of_first_child_in_tree", &self.index_of_first_child_in_tree)
.field("repeater_offset", &self.repeater_offset)
.finish()
}
}
#[derive(Debug)]
pub struct ItemTree {
pub root: SubComponent,
pub root: SubComponentIndex,
pub tree: TreeNode,
/// This tree has a parent. e.g: it is a Repeater or a PopupWindow whose property can access
/// the parent ItemTree.
@ -371,7 +361,10 @@ pub struct PublicComponent {
#[derive(Debug)]
pub struct CompilationUnit {
pub public_components: Vec<PublicComponent>,
pub sub_components: Vec<Rc<SubComponent>>,
/// Storage for all sub-components
pub sub_components: Vec<SubComponent>,
/// The sub-components that are not item-tree root
pub used_sub_components: Vec<SubComponentIndex>,
pub globals: Vec<GlobalComponent>,
pub popup_menu: Option<PopupMenu>,
pub has_debug_info: bool,
@ -386,37 +379,38 @@ impl CompilationUnit {
) {
fn visit_component<'a>(
root: &'a CompilationUnit,
c: &'a SubComponent,
c: SubComponentIndex,
visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),
parent: Option<ParentCtx<'_>>,
) {
let ctx = EvaluationContext::new_sub_component(root, c, (), parent);
visitor(c, &ctx);
for (idx, r) in c.repeated.iter().enumerate() {
let sc = &root.sub_components[c];
visitor(sc, &ctx);
for (idx, r) in sc.repeated.iter().enumerate() {
visit_component(
root,
&r.sub_tree.root,
r.sub_tree.root,
visitor,
Some(ParentCtx::new(&ctx, Some(idx as u32))),
);
}
for popup in &c.popup_windows {
for popup in &sc.popup_windows {
visit_component(
root,
&popup.item_tree.root,
popup.item_tree.root,
visitor,
Some(ParentCtx::new(&ctx, None)),
);
}
}
for c in &self.sub_components {
visit_component(self, c, visitor, None);
for c in &self.used_sub_components {
visit_component(self, *c, visitor, None);
}
for p in &self.public_components {
visit_component(self, &p.item_tree.root, visitor, None);
visit_component(self, p.item_tree.root, visitor, None);
}
if let Some(p) = &self.popup_menu {
visit_component(self, &p.item_tree.root, visitor, None);
visit_component(self, p.item_tree.root, visitor, None);
}
}

View file

@ -20,11 +20,17 @@ use crate::namedreference::NamedReference;
use crate::object_tree::{Element, ElementRc, PropertyAnimation};
use crate::typeregister::BUILTIN;
pub struct ExpressionContext<'a> {
pub struct ExpressionContextInner<'a> {
pub component: &'a Rc<crate::object_tree::Component>,
/// The mapping for the current component
pub mapping: &'a LoweredSubComponentMapping,
pub state: &'a LoweringState,
pub parent: Option<&'a ExpressionContext<'a>>,
pub parent: Option<&'a ExpressionContextInner<'a>>,
}
#[derive(derive_more::Deref)]
pub struct ExpressionContext<'a> {
pub state: &'a mut LoweringState,
#[deref]
pub inner: ExpressionContextInner<'a>,
}
impl ExpressionContext<'_> {
@ -32,7 +38,7 @@ impl ExpressionContext<'_> {
let element = from.element();
let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();
if !enclosing.is_global() {
let mut map = self;
let mut map = &self.inner;
let mut level = 0;
while !Rc::ptr_eq(enclosing, map.component) {
map = map.parent.unwrap();

View file

@ -3,7 +3,7 @@
use by_address::ByAddress;
use super::lower_expression::ExpressionContext;
use super::lower_expression::{ExpressionContext, ExpressionContextInner};
use crate::expression_tree::Expression as tree_Expression;
use crate::langtype::{ElementType, Struct, Type};
use crate::llr::item_tree::*;
@ -41,22 +41,24 @@ pub fn lower_to_item_tree(
}
for c in &document.used_types.borrow().sub_components {
let sc = lower_sub_component(c, &state, None, compiler_config);
state.sub_components.insert(ByAddress(c.clone()), sc);
let sc = lower_sub_component(c, &mut state, None, compiler_config);
state.sub_component_mapping.insert(ByAddress(c.clone()), state.sub_components.len());
state.sub_components.push(sc);
}
let public_components = document
.exported_roots()
.map(|component| {
let sc = lower_sub_component(&component, &state, None, compiler_config);
let mut sc = lower_sub_component(&component, &mut state, None, compiler_config);
let public_properties = public_properties(&component, &sc.mapping, &state);
let mut item_tree = ItemTree {
let item_tree = ItemTree {
tree: make_tree(&state, &component.root_element, &sc, &[]),
root: Rc::try_unwrap(sc.sub_component).unwrap(),
root: state.sub_components.len(),
parent_context: None,
};
sc.sub_component.name = component.id.clone();
state.sub_components.push(sc);
// 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,
@ -67,40 +69,38 @@ pub fn lower_to_item_tree(
.collect();
let popup_menu = document.popup_menu_impl.as_ref().map(|c| {
let sc = lower_sub_component(&c, &state, None, compiler_config);
let sc = lower_sub_component(&c, &mut state, None, compiler_config);
let item_tree = ItemTree {
tree: make_tree(&state, &c.root_element, &sc, &[]),
root: Rc::try_unwrap(sc.sub_component).unwrap(),
root: state.sub_components.len(),
parent_context: None,
};
PopupMenu {
item_tree,
sub_menu: sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("sub-menu")),
&state,
),
activated: sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("activated")),
&state,
),
entries: sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("entries")),
&state,
),
}
let sub_menu = sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("sub-menu")),
&state,
);
let activated = sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("activated")),
&state,
);
let entries = sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("entries")),
&state,
);
state.sub_components.push(sc);
PopupMenu { item_tree, sub_menu, activated, entries }
});
let root = CompilationUnit {
public_components,
globals,
sub_components: document
sub_components: state.sub_components.into_iter().map(|sc| sc.sub_component).collect(),
used_sub_components: document
.used_types
.borrow()
.sub_components
.iter()
.map(|tree_sub_compo| {
state.sub_components[&ByAddress(tree_sub_compo.clone())].sub_component.clone()
})
.map(|tree_sub_compo| state.sub_component_mapping[&ByAddress(tree_sub_compo.clone())])
.collect(),
has_debug_info: compiler_config.debug_info,
popup_menu,
@ -111,14 +111,6 @@ pub fn lower_to_item_tree(
Ok(root)
}
#[derive(Default)]
pub struct LoweringState {
global_properties: HashMap<NamedReference, PropertyReference>,
sub_components: HashMap<ByAddress<Rc<Component>>, LoweredSubComponent>,
#[cfg(feature = "bundle-translations")]
pub translation_builder: Option<std::cell::RefCell<super::translations::TranslationsBuilder>>,
}
#[derive(Debug, Clone)]
pub enum LoweredElement {
SubComponent { sub_component_index: usize },
@ -183,10 +175,19 @@ impl LoweredSubComponentMapping {
}
pub struct LoweredSubComponent {
sub_component: Rc<SubComponent>,
sub_component: SubComponent,
mapping: LoweredSubComponentMapping,
}
#[derive(Default)]
pub struct LoweringState {
global_properties: HashMap<NamedReference, PropertyReference>,
sub_components: Vec<LoweredSubComponent>,
sub_component_mapping: HashMap<ByAddress<Rc<Component>>, SubComponentIndex>,
#[cfg(feature = "bundle-translations")]
pub translation_builder: Option<std::cell::RefCell<super::translations::TranslationsBuilder>>,
}
impl LoweringState {
pub fn map_property_reference(&self, from: &NamedReference) -> PropertyReference {
if let Some(x) = self.global_properties.get(from) {
@ -194,12 +195,21 @@ impl LoweringState {
}
let element = from.element();
let enclosing = self
.sub_components
.get(&element.borrow().enclosing_component.upgrade().unwrap().into())
.unwrap();
let sc = self.sub_component(&element.borrow().enclosing_component.upgrade().unwrap());
sc.mapping.map_property_reference(from, self)
}
enclosing.mapping.map_property_reference(from, self)
fn sub_component<'a>(&'a self, component: &Rc<Component>) -> &'a LoweredSubComponent {
&self.sub_components[self.sub_component_idx(component)]
}
fn sub_component_idx(&self, component: &Rc<Component>) -> usize {
self.sub_component_mapping[&ByAddress(component.clone())]
}
fn push_sub_component(&mut self, sc: LoweredSubComponent) -> SubComponentIndex {
self.sub_components.push(sc);
self.sub_components.len() - 1
}
}
@ -220,12 +230,6 @@ fn property_reference_within_sub_component(
prop_ref
}
impl LoweringState {
fn sub_component(&self, component: &Rc<Component>) -> &LoweredSubComponent {
&self.sub_components[&ByAddress(component.clone())]
}
}
fn component_id(component: &Rc<Component>) -> SmolStr {
if component.is_global() {
component.root_element.borrow().id.clone()
@ -238,8 +242,8 @@ fn component_id(component: &Rc<Component>) -> SmolStr {
fn lower_sub_component(
component: &Rc<Component>,
state: &LoweringState,
parent_context: Option<&ExpressionContext>,
state: &mut LoweringState,
parent_context: Option<&ExpressionContextInner>,
compiler_config: &CompilerConfiguration,
) -> LoweredSubComponent {
let mut sub_component = SubComponent {
@ -349,8 +353,7 @@ fn lower_sub_component(
}
match &elem.base_type {
ElementType::Component(comp) => {
let lc = state.sub_component(comp);
let ty = lc.sub_component.clone();
let ty = state.sub_component_idx(comp);
let sub_component_index = sub_component.sub_components.len();
mapping.element_mapping.insert(
element.clone().into(),
@ -363,7 +366,7 @@ fn lower_sub_component(
index_of_first_child_in_tree: *elem.item_index_of_first_children.get().unwrap(),
repeater_offset,
});
repeater_offset += ty.repeater_count();
repeater_offset += comp.repeater_count();
}
ElementType::Native(n) => {
@ -400,7 +403,8 @@ fn lower_sub_component(
Some(element.clone())
});
let ctx = ExpressionContext { mapping: &mapping, state, parent: parent_context, component };
let inner = ExpressionContextInner { mapping: &mapping, parent: parent_context, component };
let mut ctx = ExpressionContext { inner, state };
crate::generator::handle_property_bindings_init(component, |e, p, binding| {
let nr = NamedReference::new(e, p.clone());
let prop = ctx.map_property_reference(&nr);
@ -481,7 +485,7 @@ fn lower_sub_component(
.collect();
sub_component.repeated = repeated
.into_iter()
.map(|elem| lower_repeated_component(&elem, &ctx, compiler_config))
.map(|elem| lower_repeated_component(&elem, &mut ctx, compiler_config))
.collect();
for s in &mut sub_component.sub_components {
s.repeater_offset +=
@ -492,7 +496,7 @@ fn lower_sub_component(
.popup_windows
.borrow()
.iter()
.map(|popup| lower_popup_component(popup, &ctx, compiler_config))
.map(|popup| lower_popup_component(popup, &mut ctx, compiler_config))
.collect();
sub_component.timers = component.timers.borrow().iter().map(|t| lower_timer(t, &ctx)).collect();
@ -583,7 +587,7 @@ fn lower_sub_component(
sub_component.geometries[item_index] = Some(lower_geometry(geom, &ctx).into());
});
LoweredSubComponent { sub_component: Rc::new(sub_component), mapping }
LoweredSubComponent { sub_component, mapping }
}
fn lower_geometry(
@ -636,15 +640,14 @@ fn get_property_analysis(elem: &ElementRc, p: &str) -> crate::object_tree::Prope
fn lower_repeated_component(
elem: &ElementRc,
ctx: &ExpressionContext,
ctx: &mut ExpressionContext,
compiler_config: &CompilerConfiguration,
) -> RepeatedElement {
let e = elem.borrow();
let component = e.base_type.as_component().clone();
let repeated = e.repeated.as_ref().unwrap();
let sc: LoweredSubComponent =
lower_sub_component(&component, ctx.state, Some(ctx), compiler_config);
let sc = lower_sub_component(&component, ctx.state, Some(&ctx.inner), compiler_config);
let geom = component.root_element.borrow().geometry_props.clone().unwrap();
@ -662,7 +665,7 @@ fn lower_repeated_component(
model: super::lower_expression::lower_expression(&repeated.model, ctx).into(),
sub_tree: ItemTree {
tree: make_tree(ctx.state, &component.root_element, &sc, &[]),
root: Rc::try_unwrap(sc.sub_component).unwrap(),
root: ctx.state.push_sub_component(sc),
parent_context: Some(e.enclosing_component.upgrade().unwrap().id.clone()),
},
index_prop: (!repeated.is_conditional_element).then_some(1),
@ -695,13 +698,22 @@ fn lower_component_container(
fn lower_popup_component(
popup: &object_tree::PopupWindow,
ctx: &ExpressionContext,
ctx: &mut ExpressionContext,
compiler_config: &CompilerConfiguration,
) -> PopupWindow {
let sc = lower_sub_component(&popup.component, ctx.state, Some(ctx), compiler_config);
let sc = lower_sub_component(&popup.component, ctx.state, Some(&ctx.inner), compiler_config);
use super::Expression::PropertyReference as PR;
let position = super::lower_expression::make_struct(
"LogicalPosition",
[
("x", Type::LogicalLength, PR(sc.mapping.map_property_reference(&popup.x, ctx.state))),
("y", Type::LogicalLength, PR(sc.mapping.map_property_reference(&popup.y, ctx.state))),
],
);
let item_tree = ItemTree {
tree: make_tree(ctx.state, &popup.component.root_element, &sc, &[]),
root: Rc::try_unwrap(sc.sub_component).unwrap(),
root: ctx.state.push_sub_component(sc),
parent_context: Some(
popup
.component
@ -716,16 +728,6 @@ fn lower_popup_component(
.clone(),
),
};
use super::Expression::PropertyReference as PR;
let position = super::lower_expression::make_struct(
"LogicalPosition",
[
("x", Type::LogicalLength, PR(sc.mapping.map_property_reference(&popup.x, ctx.state))),
("y", Type::LogicalLength, PR(sc.mapping.map_property_reference(&popup.y, ctx.state))),
],
);
PopupWindow { item_tree, position: position.into() }
}
@ -854,7 +856,8 @@ fn lower_global_expressions(
) {
// Note that this mapping doesn't contain anything useful, everything is in the state
let mapping = LoweredSubComponentMapping::default();
let ctx = ExpressionContext { mapping: &mapping, state, parent: None, component: global };
let inner = ExpressionContextInner { mapping: &mapping, parent: None, component: global };
let ctx = ExpressionContext { inner, state };
for (prop, binding) in &global.root_element.borrow().bindings {
assert!(binding.borrow().two_way_bindings.is_empty());
@ -863,7 +866,7 @@ fn lower_global_expressions(
super::lower_expression::lower_expression(&binding.borrow().expression, &ctx);
let nr = NamedReference::new(&global.root_element, prop.clone());
let property_index = match state.global_properties[&nr] {
let property_index = match ctx.state.global_properties[&nr] {
PropertyReference::Global { property_index, .. } => property_index,
PropertyReference::GlobalFunction { function_index, .. } => {
lowered.functions[function_index].code = expression;
@ -883,7 +886,7 @@ fn lower_global_expressions(
for (prop, expr) in &global.root_element.borrow().change_callbacks {
let nr = NamedReference::new(&global.root_element, prop.clone());
let property_index = match state.global_properties[&nr] {
let property_index = match ctx.state.global_properties[&nr] {
PropertyReference::Global { property_index, .. } => property_index,
_ => unreachable!(),
};

View file

@ -14,7 +14,7 @@ pub fn count_property_use(root: &CompilationUnit) {
// Visit the root properties that are used.
// 1. the public properties
for c in &root.public_components {
let root_ctx = EvaluationContext::new_sub_component(root, &c.item_tree.root, (), None);
let root_ctx = EvaluationContext::new_sub_component(root, c.item_tree.root, (), None);
for p in c.public_properties.iter().filter(|p| {
!matches!(
p.prop,
@ -43,7 +43,7 @@ pub fn count_property_use(root: &CompilationUnit) {
PropertyReference::Local { sub_component_path, property_index } => {
let mut sc = sc;
for i in sub_component_path {
sc = &sc.sub_components[*i].ty;
sc = &ctx.compilation_unit.sub_components[sc.sub_components[*i].ty];
}
if sc.properties[*property_index].use_count.get() == 0 {
continue;
@ -74,7 +74,7 @@ pub fn count_property_use(root: &CompilationUnit) {
let rep_ctx = EvaluationContext::new_sub_component(
root,
&r.sub_tree.root,
r.sub_tree.root,
(),
Some(ParentCtx::new(ctx, Some(idx as u32))),
);
@ -83,7 +83,7 @@ pub fn count_property_use(root: &CompilationUnit) {
}
for idx in r.data_prop.iter().chain(r.index_prop.iter()) {
// prevent optimizing model properties
let p = &r.sub_tree.root.properties[*idx];
let p = &root.sub_components[r.sub_tree.root].properties[*idx];
p.use_count.set(2);
}
}
@ -121,7 +121,7 @@ pub fn count_property_use(root: &CompilationUnit) {
for popup in &sc.popup_windows {
let popup_ctx = EvaluationContext::new_sub_component(
root,
&popup.item_tree.root,
popup.item_tree.root,
(),
Some(ParentCtx::new(&ctx, None)),
);
@ -144,7 +144,7 @@ pub fn count_property_use(root: &CompilationUnit) {
}
if let Some(p) = &root.popup_menu {
let ctx = EvaluationContext::new_sub_component(&root, &p.item_tree.root, (), None);
let ctx = EvaluationContext::new_sub_component(&root, p.item_tree.root, (), None);
visit_property(&p.entries, &ctx);
visit_property(&p.sub_menu, &ctx);
visit_property(&p.activated, &ctx);

View file

@ -8,21 +8,13 @@ use itertools::Itertools;
use crate::expression_tree::MinMaxOp;
use super::{
CompilationUnit, EvaluationContext, Expression, ParentCtx, PropertyReference, SubComponent,
CompilationUnit, EvaluationContext, Expression, ParentCtx, PropertyReference, SubComponentIndex,
};
pub fn pretty_print(root: &CompilationUnit, writer: &mut dyn Write) -> Result {
PrettyPrinter { writer, indentation: 0 }.print_root(root)
}
pub fn pretty_print_component(
root: &CompilationUnit,
component: &SubComponent,
writer: &mut dyn Write,
) -> Result {
PrettyPrinter { writer, indentation: 0 }.print_component(root, component, None)
}
struct PrettyPrinter<'a> {
writer: &'a mut dyn Write,
indentation: usize,
@ -35,22 +27,21 @@ impl<'a> PrettyPrinter<'a> {
self.print_global(root, g)?;
}
}
for c in &root.sub_components {
for c in 0..root.sub_components.len() {
self.print_component(root, c, None)?
}
for p in &root.public_components {
self.print_component(root, &p.item_tree.root, None)?
}
Ok(())
}
fn print_component(
&mut self,
root: &CompilationUnit,
sc: &SubComponent,
sc_idx: SubComponentIndex,
parent: Option<ParentCtx<'_>>,
) -> Result {
let ctx = EvaluationContext::new_sub_component(root, sc, (), parent);
let ctx = EvaluationContext::new_sub_component(root, sc_idx, (), parent);
let sc = &root.sub_components[sc_idx];
writeln!(self.writer, "component {} {{", sc.name)?;
self.indentation += 1;
for p in &sc.properties {
@ -98,7 +89,7 @@ impl<'a> PrettyPrinter<'a> {
}
for ssc in &sc.sub_components {
self.indent()?;
writeln!(self.writer, "{} := {} {{}};", ssc.name, ssc.ty.name)?;
writeln!(self.writer, "{} := {} {{}};", ssc.name, root.sub_components[ssc.ty].name)?;
}
for (item, geom) in std::iter::zip(&sc.items, &sc.geometries) {
self.indent()?;
@ -112,13 +103,13 @@ impl<'a> PrettyPrinter<'a> {
write!(self.writer, "for in {} : ", DisplayExpression(&r.model.borrow(), &ctx))?;
self.print_component(
root,
&r.sub_tree.root,
r.sub_tree.root,
Some(ParentCtx::new(&ctx, Some(idx as u32))),
)?
}
for w in &sc.popup_windows {
self.indent()?;
self.print_component(root, &w.item_tree.root, Some(ParentCtx::new(&ctx, None)))?
self.print_component(root, w.item_tree.root, Some(ParentCtx::new(&ctx, None)))?
}
self.indentation -= 1;
self.indent()?;
@ -196,19 +187,19 @@ impl<T> Display for DisplayPropertyRef<'_, T> {
if let Some(g) = ctx.current_global {
write!(f, "{}.{}", g.name, g.properties[*property_index].name)
} else {
let mut sc = ctx.current_sub_component.unwrap();
let mut sc = ctx.current_sub_component().unwrap();
for i in sub_component_path {
write!(f, "{}.", sc.sub_components[*i].name)?;
sc = &sc.sub_components[*i].ty;
sc = &ctx.compilation_unit.sub_components[sc.sub_components[*i].ty];
}
write!(f, "{}", sc.properties[*property_index].name)
}
}
PropertyReference::InNativeItem { sub_component_path, item_index, prop_name } => {
let mut sc = ctx.current_sub_component.unwrap();
let mut sc = ctx.current_sub_component().unwrap();
for i in sub_component_path {
write!(f, "{}.", sc.sub_components[*i].name)?;
sc = &sc.sub_components[*i].ty;
sc = &ctx.compilation_unit.sub_components[sc.sub_components[*i].ty];
}
let i = &sc.items[*item_index as usize];
write!(f, "{}.{}", i.name, prop_name)
@ -227,10 +218,10 @@ impl<T> Display for DisplayPropertyRef<'_, T> {
if let Some(g) = ctx.current_global {
write!(f, "{}.{}", g.name, g.functions[*function_index].name)
} else {
let mut sc = ctx.current_sub_component.unwrap();
let mut sc = ctx.current_sub_component().unwrap();
for i in sub_component_path {
write!(f, "{}.", sc.sub_components[*i].name)?;
sc = &sc.sub_components[*i].ty;
sc = &ctx.compilation_unit.sub_components[sc.sub_components[*i].ty];
}
write!(f, "{}", sc.functions[*function_index].name)
}

View file

@ -387,6 +387,7 @@ mod plural_rule_parser {
compilation_unit: &crate::llr::CompilationUnit {
public_components: Vec::new(),
sub_components: Vec::new(),
used_sub_components: Vec::new(),
globals: Vec::new(),
has_debug_info: false,
translations: None,