Skip to content

Commit

Permalink
Add native support for min/max
Browse files Browse the repository at this point in the history
  • Loading branch information
Guiguiprim committed Jul 21, 2023
1 parent cc36915 commit 3620eed
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 40 deletions.
29 changes: 6 additions & 23 deletions internal/compiler/builtin_macros.rs
Expand Up @@ -6,7 +6,7 @@

use crate::diagnostics::{BuildDiagnostics, Spanned};
use crate::expression_tree::{
BuiltinFunction, BuiltinMacroFunction, EasingCurve, Expression, Unit,
BuiltinFunction, BuiltinMacroFunction, EasingCurve, Expression, MinMaxOp, Unit,
};
use crate::langtype::{EnumerationValue, Type};
use crate::parser::NodeOrToken;
Expand All @@ -22,8 +22,8 @@ pub fn lower_macro(
diag: &mut BuildDiagnostics,
) -> Expression {
match mac {
BuiltinMacroFunction::Min => min_max_macro(n, '<', sub_expr.collect(), diag),
BuiltinMacroFunction::Max => min_max_macro(n, '>', sub_expr.collect(), diag),
BuiltinMacroFunction::Min => min_max_macro(n, MinMaxOp::Min, sub_expr.collect(), diag),
BuiltinMacroFunction::Max => min_max_macro(n, MinMaxOp::Max, sub_expr.collect(), diag),
BuiltinMacroFunction::Mod => mod_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::Debug => debug_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::CubicBezier => {
Expand Down Expand Up @@ -67,7 +67,7 @@ pub fn lower_macro(

fn min_max_macro(
node: Option<NodeOrToken>,
op: char,
op: MinMaxOp,
args: Vec<(Expression, Option<NodeOrToken>)>,
diag: &mut BuildDiagnostics,
) -> Expression {
Expand Down Expand Up @@ -345,24 +345,7 @@ fn to_debug_string(
/// Generate an expression which is like `min(lhs, rhs)` if op is '<' or `max(lhs, rhs)` if op is '>'.
/// counter is an unique id.
/// The rhs and lhs of the expression must have the same numerical type
pub fn min_max_expression(lhs: Expression, rhs: Expression, op: char) -> Expression {
pub fn min_max_expression(lhs: Expression, rhs: Expression, op: MinMaxOp) -> Expression {
let ty = lhs.ty();
let id = COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let n1 = format!("minmax_lhs{}", id);
let n2 = format!("minmax_rhs{}", id);
let a1 = Box::new(Expression::ReadLocalVariable { name: n1.clone(), ty: ty.clone() });
let a2 = Box::new(Expression::ReadLocalVariable { name: n2.clone(), ty });
Expression::CodeBlock(vec![
Expression::StoreLocalVariable { name: n1, value: Box::new(lhs) },
Expression::StoreLocalVariable { name: n2, value: Box::new(rhs) },
Expression::Condition {
condition: Box::new(Expression::BinaryExpression {
lhs: a1.clone(),
rhs: a2.clone(),
op,
}),
true_expr: a1,
false_expr: a2,
},
])
Expression::MinMax { ty, op, lhs: Box::new(lhs), rhs: Box::new(rhs) }
}
33 changes: 33 additions & 0 deletions internal/compiler/expression_tree.rs
Expand Up @@ -429,6 +429,12 @@ impl Default for Unit {
}
}

#[derive(Debug, Clone, Copy)]
pub enum MinMaxOp {
Min,
Max,
}

/// The Expression is hold by properties, so it should not hold any strong references to node from the object_tree
#[derive(Debug, Clone, Default)]
pub enum Expression {
Expand Down Expand Up @@ -612,6 +618,13 @@ pub enum Expression {
/// The orientation is the orientation of the cache, not the orientation of the layout
ComputeLayoutInfo(crate::layout::Layout, crate::layout::Orientation),
SolveLayout(crate::layout::Layout, crate::layout::Orientation),

MinMax {
ty: Type,
op: MinMaxOp,
lhs: Box<Expression>,
rhs: Box<Expression>,
},
}

impl Expression {
Expand Down Expand Up @@ -738,6 +751,7 @@ impl Expression {
Expression::LayoutCacheAccess { .. } => Type::LogicalLength,
Expression::ComputeLayoutInfo(..) => crate::layout::layout_info_type(),
Expression::SolveLayout(..) => Type::LayoutCache,
Expression::MinMax { ty, .. } => ty.clone(),
}
}

Expand Down Expand Up @@ -836,6 +850,10 @@ impl Expression {
}
Expression::ComputeLayoutInfo(..) => {}
Expression::SolveLayout(..) => {}
Expression::MinMax { lhs, rhs, .. } => {
visitor(lhs);
visitor(rhs);
}
}
}

Expand Down Expand Up @@ -936,6 +954,10 @@ impl Expression {
}
Expression::ComputeLayoutInfo(..) => {}
Expression::SolveLayout(..) => {}
Expression::MinMax { lhs, rhs, .. } => {
visitor(lhs);
visitor(rhs);
}
}
}

Expand Down Expand Up @@ -1010,6 +1032,7 @@ impl Expression {
Expression::LayoutCacheAccess { .. } => false,
Expression::ComputeLayoutInfo(..) => false,
Expression::SolveLayout(..) => false,
Expression::MinMax { lhs, rhs, .. } => lhs.is_constant() && rhs.is_constant(),
}
}

Expand Down Expand Up @@ -1623,5 +1646,15 @@ pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std
}
Expression::ComputeLayoutInfo(..) => write!(f, "layout_info(..)"),
Expression::SolveLayout(..) => write!(f, "solve_layout(..)"),
Expression::MinMax { ty: _, op, lhs, rhs } => {
match op {
MinMaxOp::Min => write!(f, "min(")?,
MinMaxOp::Max => write!(f, "max(")?,
}
pretty_print(f, lhs)?;
write!(f, ", ")?;
pretty_print(f, rhs)?;
write!(f, ")")
}
}
}
17 changes: 16 additions & 1 deletion internal/compiler/generator/cpp.rs
Expand Up @@ -309,7 +309,7 @@ mod cpp_ast {
}
}

use crate::expression_tree::{BuiltinFunction, EasingCurve};
use crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp};
use crate::langtype::{ElementType, Enumeration, EnumerationValue, NativeClass, Type};
use crate::layout::Orientation;
use crate::llr::{
Expand Down Expand Up @@ -2776,6 +2776,21 @@ fn compile_expression(expr: &llr::Expression, ctx: &EvaluationContext) -> String
)

}
Expression::MinMax { ty, op, lhs, rhs } => {
let ident = match op {
MinMaxOp::Min => "min",
MinMaxOp::Max => "max",
};
let lhs_code = return_compile_expression(lhs, ctx, Some(&ty));
let rhs_code = return_compile_expression(rhs, ctx, Some(&ty));
format!(
r#"[&]() -> {} {{ using namespace std; return {}({}, {}); }}()"#,
ty.cpp_type().unwrap_or_else(|| "void".to_string()),
ident,
lhs_code,
rhs_code
)
}
}
}

Expand Down
19 changes: 18 additions & 1 deletion internal/compiler/generator/rust.rs
Expand Up @@ -12,7 +12,7 @@ Some convention used in the generated code:
this is usually a local variable to the init code that shouldn't rbe relied upon by the binding code.
*/

use crate::expression_tree::{BuiltinFunction, EasingCurve, OperatorClass};
use crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp, OperatorClass};
use crate::langtype::{ElementType, Enumeration, EnumerationValue, Type};
use crate::layout::Orientation;
use crate::llr::{
Expand Down Expand Up @@ -2189,6 +2189,23 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
let #cells_variable = sp::Slice::from_slice(&#cells_variable);
}
}
Expression::MinMax { ty, op, lhs, rhs } => {
let t = rust_primitive_type(ty);
let wrap = |expr| match &t {
Some(t) => quote!((#expr as #t)),
None => expr,
};
let lhs = wrap(compile_expression(lhs, ctx));
let rhs = wrap(compile_expression(rhs, ctx));
match op {
MinMaxOp::Min => {
quote!(#lhs.min(#rhs))
}
MinMaxOp::Max => {
quote!(#lhs.max(#rhs))
}
}
}
}
}

Expand Down
14 changes: 13 additions & 1 deletion internal/compiler/llr/expression.rs
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial

use super::PropertyReference;
use crate::expression_tree::{BuiltinFunction, OperatorClass};
use crate::expression_tree::{BuiltinFunction, MinMaxOp, OperatorClass};
use crate::langtype::Type;
use crate::layout::Orientation;
use itertools::Either;
Expand Down Expand Up @@ -180,6 +180,13 @@ pub enum Expression {
/// This is an Expression::Array
unsorted_cells: Box<Expression>,
},

MinMax {
ty: Type,
op: MinMaxOp,
lhs: Box<Expression>,
rhs: Box<Expression>,
},
}

impl Expression {
Expand Down Expand Up @@ -292,6 +299,7 @@ impl Expression {
Self::ComputeDialogLayoutCells { .. } => {
Type::Array(super::lower_expression::grid_layout_cell_data_ty().into())
}
Self::MinMax { ty, .. } => ty.clone(),
}
}
}
Expand Down Expand Up @@ -374,6 +382,10 @@ macro_rules! visit_impl {
$visitor(roles);
$visitor(unsorted_cells);
}
Expression::MinMax { ty: _, op: _, lhs, rhs } => {
$visitor(lhs);
$visitor(rhs);
}
}
};
}
Expand Down
6 changes: 6 additions & 0 deletions internal/compiler/llr/lower_expression.rs
Expand Up @@ -197,6 +197,12 @@ pub fn lower_expression(
}
tree_Expression::ComputeLayoutInfo(l, o) => compute_layout_info(l, *o, ctx),
tree_Expression::SolveLayout(l, o) => solve_layout(l, *o, ctx),
tree_Expression::MinMax { ty, op, lhs, rhs } => llr_Expression::MinMax {
ty: ty.clone(),
op: *op,
lhs: Box::new(lower_expression(lhs, ctx)),
rhs: Box::new(lower_expression(rhs, ctx)),
},
}
}

Expand Down
1 change: 1 addition & 0 deletions internal/compiler/llr/optim_passes/inline_expressions.rs
Expand Up @@ -54,6 +54,7 @@ fn expression_cost(exp: &Expression, ctx: &EvaluationContext) -> isize {
Expression::LayoutCacheAccess { .. } => PROPERTY_ACCESS_COST,
Expression::BoxLayoutFunction { .. } => return isize::MAX,
Expression::ComputeDialogLayoutCells { .. } => return isize::MAX,
Expression::MinMax { .. } => 10,
};

exp.visit(|e| cost = cost.saturating_add(expression_cost(e, ctx)));
Expand Down
6 changes: 6 additions & 0 deletions internal/compiler/llr/pretty_print.rs
Expand Up @@ -5,6 +5,8 @@ use std::fmt::{Display, Result, Write};

use itertools::Itertools;

use crate::expression_tree::MinMaxOp;

use super::{
EvaluationContext, Expression, ParentCtx, PropertyReference, PublicComponent, SubComponent,
};
Expand Down Expand Up @@ -250,6 +252,10 @@ impl<'a, T> Display for DisplayExpression<'a, T> {
Expression::ComputeDialogLayoutCells { .. } => {
write!(f, "ComputeDialogLayoutCells(TODO)",)
}
Expression::MinMax { ty: _, op, lhs, rhs } => match op {
MinMaxOp::Min => write!(f, "min({}, {})", e(lhs), e(rhs)),
MinMaxOp::Max => write!(f, "max({}, {})", e(lhs), e(rhs)),
},
}
}
}
4 changes: 2 additions & 2 deletions internal/compiler/passes/default_geometry.rs
Expand Up @@ -14,7 +14,7 @@ use std::rc::Rc;

use crate::diagnostics::{BuildDiagnostics, Spanned};
use crate::expression_tree::{
BindingExpression, BuiltinFunction, Expression, NamedReference, Unit,
BindingExpression, BuiltinFunction, Expression, MinMaxOp, NamedReference, Unit,
};
use crate::langtype::{BuiltinElement, DefaultSizeBinding, PropertyLookupResult, Type};
use crate::layout::{implicit_layout_info_call, LayoutConstraints, Orientation};
Expand Down Expand Up @@ -297,7 +297,7 @@ fn make_default_implicit(elem: &ElementRc, property: &str) {
&format!("preferred-{}", property),
)),
Expression::PropertyReference(NamedReference::new(elem, &format!("min-{}", property))),
'>',
MinMaxOp::Max,
);
elem.borrow_mut().set_binding_if_not_set(property.into(), || e);
}
Expand Down
16 changes: 8 additions & 8 deletions internal/compiler/passes/flickable.rs
Expand Up @@ -13,7 +13,7 @@
use std::cell::RefCell;
use std::rc::Rc;

use crate::expression_tree::{BindingExpression, Expression, NamedReference};
use crate::expression_tree::{BindingExpression, Expression, MinMaxOp, NamedReference};
use crate::langtype::{ElementType, NativeClass};
use crate::object_tree::{Component, Element, ElementRc};
use crate::typeregister::TypeRegister;
Expand Down Expand Up @@ -85,7 +85,7 @@ fn create_viewport_element(flickable: &ElementRc, native_empty: &Rc<NativeClass>
}

fn fixup_geometry(flickable_elem: &ElementRc) {
let forward_minmax_of = |prop: &str, op: char| {
let forward_minmax_of = |prop: &str, op: MinMaxOp| {
set_binding_if_not_explicit(flickable_elem, prop, || {
flickable_elem
.borrow()
Expand All @@ -100,12 +100,12 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
};

if !flickable_elem.borrow().bindings.contains_key("height") {
forward_minmax_of("max-height", '<');
forward_minmax_of("preferred-height", '<');
forward_minmax_of("max-height", MinMaxOp::Min);
forward_minmax_of("preferred-height", MinMaxOp::Min);
}
if !flickable_elem.borrow().bindings.contains_key("width") {
forward_minmax_of("max-width", '<');
forward_minmax_of("preferred-width", '<');
forward_minmax_of("max-width", MinMaxOp::Min);
forward_minmax_of("preferred-width", MinMaxOp::Min);
}
set_binding_if_not_explicit(flickable_elem, "viewport-width", || {
Some(
Expand All @@ -119,7 +119,7 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-width")))
.fold(
Expression::PropertyReference(NamedReference::new(flickable_elem, "width")),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max),
),
)
});
Expand All @@ -135,7 +135,7 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-height")))
.fold(
Expression::PropertyReference(NamedReference::new(flickable_elem, "height")),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max),
),
)
});
Expand Down
6 changes: 3 additions & 3 deletions internal/compiler/passes/lower_tabwidget.rs
Expand Up @@ -9,7 +9,7 @@
//! be further inlined as it may expends to native widget that needs inlining

use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{BindingExpression, Expression, NamedReference, Unit};
use crate::expression_tree::{BindingExpression, Expression, MinMaxOp, NamedReference, Unit};
use crate::langtype::{ElementType, Type};
use crate::object_tree::*;
use std::cell::RefCell;
Expand Down Expand Up @@ -167,14 +167,14 @@ fn process_tabwidget(
if let Some(expr) = children
.iter()
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-width")))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max))
{
elem.borrow_mut().bindings.insert("content-min-width".into(), RefCell::new(expr.into()));
};
if let Some(expr) = children
.iter()
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min-height")))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'))
.reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max))
{
elem.borrow_mut().bindings.insert("content-min-height".into(), RefCell::new(expr.into()));
};
Expand Down

0 comments on commit 3620eed

Please sign in to comment.