Slint: make the abs work with unit types

This commit is contained in:
Olivier Goffart 2024-05-08 17:44:25 +02:00
parent 8dcd9713ff
commit 0929e3dfc1
6 changed files with 96 additions and 3 deletions

View file

@ -90,9 +90,9 @@ against the constants below.
These functions are available both in the global scope and in the `Math` namespace.
### `abs(float) -> float`
### `abs(T) -> T`
Return the absolute value.
Return the absolute value, where T is a numeric type.
### `acos(float) -> angle`, `asin(float) -> angle`, `atan(float) -> angle`, `cos(angle) -> float`, `sin(angle) -> float`, `tan(angle) -> float`

View file

@ -26,6 +26,7 @@ pub fn lower_macro(
BuiltinMacroFunction::Max => min_max_macro(n, MinMaxOp::Max, sub_expr.collect(), diag),
BuiltinMacroFunction::Clamp => clamp_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::Mod => mod_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::Abs => abs_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::Debug => debug_macro(n, sub_expr.collect(), diag),
BuiltinMacroFunction::CubicBezier => {
let mut has_error = None;
@ -183,6 +184,47 @@ fn mod_macro(
}
}
fn abs_macro(
node: Option<NodeOrToken>,
args: Vec<(Expression, Option<NodeOrToken>)>,
diag: &mut BuildDiagnostics,
) -> Expression {
if args.len() != 1 {
diag.push_error("Needs 1 argument".into(), &node);
return Expression::Invalid;
}
let ty = args[0].0.ty();
let ty = if ty.default_unit().is_some() || matches!(ty, Type::UnitProduct(_)) {
ty
} else {
Type::Float32
};
let source_location = node.map(|n| n.to_source_location());
let function = Box::new(Expression::BuiltinFunctionReference(
BuiltinFunction::Abs,
source_location.clone(),
));
if matches!(ty, Type::Float32) {
let arguments =
args.into_iter().map(|(e, n)| e.maybe_convert_to(ty.clone(), &n, diag)).collect();
Expression::FunctionCall { function, arguments, source_location }
} else {
Expression::Cast {
from: Expression::FunctionCall {
function,
arguments: args
.into_iter()
.map(|(a, _)| Expression::Cast { from: a.into(), to: Type::Float32 })
.collect(),
source_location,
}
.into(),
to: ty,
}
}
}
fn rgb_macro(
node: Option<NodeOrToken>,
args: Vec<(Expression, Option<NodeOrToken>)>,

View file

@ -85,6 +85,8 @@ pub enum BuiltinMacroFunction {
Clamp,
/// Add the right conversion operations so that the return type is the same as the argument type
Mod,
/// Add the right conversion operations so that the return type is the same as the argument type
Abs,
CubicBezier,
/// The argument can be r,g,b,a or r,g,b and they can be percentages or integer.
/// transform the argument so it is always rgb(r, g, b, a) with r, g, b between 0 and 255.

View file

@ -786,7 +786,7 @@ impl LookupObject for MathFunctions {
.or_else(|| f("ceil", BuiltinFunctionReference(BuiltinFunction::Ceil, sl())))
.or_else(|| f("floor", BuiltinFunctionReference(BuiltinFunction::Floor, sl())))
.or_else(|| f("clamp", BuiltinMacroReference(BuiltinMacroFunction::Clamp, t.clone())))
.or_else(|| f("abs", BuiltinFunctionReference(BuiltinFunction::Abs, sl())))
.or_else(|| f("abs", BuiltinMacroReference(BuiltinMacroFunction::Abs, t.clone())))
.or_else(|| f("sqrt", BuiltinFunctionReference(BuiltinFunction::Sqrt, sl())))
.or_else(|| f("max", BuiltinMacroReference(BuiltinMacroFunction::Max, t.clone())))
.or_else(|| f("min", BuiltinMacroReference(BuiltinMacroFunction::Min, t.clone())))

View file

@ -0,0 +1,44 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial
export component Foo {
property <float> m1: mod(4);
// ^error{Needs 2 arguments}
property <float> m2: mod(4, 5, 5);
// ^error{Needs 2 arguments}
property <float> m3: mod("455", "465");
// ^error{Cannot convert string to float}
// ^^error{Cannot convert string to float}
property <float> m4: mod(455, "465");
// ^error{Cannot convert string to float}
property <length> m5: mod(45px, 4);
// ^error{Cannot convert float to length}
property <length> m6: mod(45px, 4ms);
// ^error{Cannot convert duration to length}
property <duration> m7: mod(5, 4ms);
// ^error{Cannot convert float to duration}
property <float> a1: abs();
// ^error{Needs 1 argument}
property <float> a2: abs(4, 5, 5);
// ^error{Needs 1 argument}
property <float> a3: abs(1, 2);
// ^error{Needs 1 argument}
property <float> a4: abs("465");
// ^error{Cannot convert string to float}
property <string> a5: abs(45px);
// ^error{Cannot convert length to string}
}

View file

@ -6,6 +6,8 @@
property<float> t2: abs(-42.3);
property<int> t3: abs(42.3);
property<int> t4: abs(-42.3);
out property <bool> test: abs(-45.5px) == 45.5px && abs(78.5deg) == abs(78.5deg) && abs(-1.2s) == 1200ms;
}
/*
```cpp
@ -15,6 +17,7 @@ assert(std::abs(instance.get_t1() - 42.3) < 0.0001);
assert(std::abs(instance.get_t2() - 42.3) < 0.0001);
assert_eq(instance.get_t3(), 42);
assert_eq(instance.get_t4(), 42);
assert(instance.get_test());
```
```rust
@ -23,6 +26,7 @@ assert_eq!(instance.get_t1(), 42.3);
assert_eq!(instance.get_t2(), 42.3);
assert_eq!(instance.get_t3(), 42);
assert_eq!(instance.get_t4(), 42);
assert!(instance.get_test());
```
```js
@ -31,5 +35,6 @@ assert(Math.abs(instance.t1 - 42.3) < 0.0001);
assert(Math.abs(instance.t2 - 42.3) < 0.0001);
assert.equal(instance.t3, 42);
assert.equal(instance.t4, 42);
assert(instance.test);
```
*/