diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b14f8119da..4a293d83d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ All notable changes to this project will be documented in this file. - Mouse wheel work on the Flickable and derivatives - One can now omit the type of a two way binding property - One can declare callback aliases + - `abs()` function to get the absolute value ### Fixed diff --git a/docs/langref.md b/docs/langref.md index 7b13f46bf93..c98b0a3e3b7 100644 --- a/docs/langref.md +++ b/docs/langref.md @@ -811,6 +811,10 @@ Return the arguments with the minimum (or maximum) value. All arguments must be Perform a modulo operation. + * **`abs(float) -> float`** + +Return the absolute value. + * **`round(float) -> int`** Return the value rounded to the nearest integer diff --git a/sixtyfps_compiler/expression_tree.rs b/sixtyfps_compiler/expression_tree.rs index ceb845b7dea..61a9c5672ef 100644 --- a/sixtyfps_compiler/expression_tree.rs +++ b/sixtyfps_compiler/expression_tree.rs @@ -27,6 +27,7 @@ pub enum BuiltinFunction { Round, Ceil, Floor, + Abs, Sqrt, Cos, Sin, @@ -75,7 +76,7 @@ impl BuiltinFunction { BuiltinFunction::Round | BuiltinFunction::Ceil | BuiltinFunction::Floor => { Type::Function { return_type: Box::new(Type::Int32), args: vec![Type::Float32] } } - BuiltinFunction::Sqrt => { + BuiltinFunction::Sqrt | BuiltinFunction::Abs => { Type::Function { return_type: Box::new(Type::Float32), args: vec![Type::Float32] } } BuiltinFunction::Cos | BuiltinFunction::Sin | BuiltinFunction::Tan => { @@ -133,6 +134,7 @@ impl BuiltinFunction { | BuiltinFunction::Round | BuiltinFunction::Ceil | BuiltinFunction::Floor + | BuiltinFunction::Abs | BuiltinFunction::Sqrt | BuiltinFunction::Cos | BuiltinFunction::Sin diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index 40959087806..e9de58f0602 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -1383,10 +1383,11 @@ fn compile_expression( .into() } BuiltinFunction::Mod => "[](auto a1, auto a2){ return static_cast(a1) % static_cast(a2); }".into(), - BuiltinFunction::Round => "[](float a){ return std::round(a); }".into(), - BuiltinFunction::Ceil => "[](float a){ return std::ceil(a); }".into(), - BuiltinFunction::Floor => "[](float a){ return std::floor(a); }".into(), - BuiltinFunction::Sqrt => "[](float a){ return std::sqrt(a); }".into(), + BuiltinFunction::Round => "std::round".into(), + BuiltinFunction::Ceil => "std::ceil".into(), + BuiltinFunction::Floor => "std::floor".into(), + BuiltinFunction::Sqrt => "std::sqrt".into(), + BuiltinFunction::Abs => "std::abs".into(), BuiltinFunction::Sin => format!("[](float a){{ return std::sin(a * {}); }}", std::f32::consts::PI / 180.), BuiltinFunction::Cos => format!("[](float a){{ return std::cos(a * {}); }}", std::f32::consts::PI / 180.), BuiltinFunction::Tan => format!("[](float a){{ return std::tan(a * {}); }}", std::f32::consts::PI / 180.), diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index d8465cef834..e56f9cd2a23 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -1086,6 +1086,7 @@ fn compile_expression(expr: &Expression, component: &Rc) -> TokenStre BuiltinFunction::Ceil => quote!((|a| (a as f64).ceil())), BuiltinFunction::Floor => quote!((|a| (a as f64).floor())), BuiltinFunction::Sqrt => quote!((|a| (a as f64).sqrt())), + BuiltinFunction::Abs => quote!((|a| (a as f64).abs())), BuiltinFunction::Sin => quote!((|a| (a as f64).to_radians().sin())), BuiltinFunction::Cos => quote!((|a| (a as f64).to_radians().cos())), BuiltinFunction::Tan => quote!((|a| (a as f64).to_radians().tan())), diff --git a/sixtyfps_compiler/lookup.rs b/sixtyfps_compiler/lookup.rs index 604f9f70cad..874964edf49 100644 --- a/sixtyfps_compiler/lookup.rs +++ b/sixtyfps_compiler/lookup.rs @@ -460,6 +460,7 @@ impl LookupObject for BuiltinFunctionLookup { .or_else(|| f("round", BuiltinFunctionReference(BuiltinFunction::Round, sl()))) .or_else(|| f("ceil", BuiltinFunctionReference(BuiltinFunction::Ceil, sl()))) .or_else(|| f("floor", BuiltinFunctionReference(BuiltinFunction::Floor, sl()))) + .or_else(|| f("abs", BuiltinFunctionReference(BuiltinFunction::Abs, sl()))) .or_else(|| f("sqrt", BuiltinFunctionReference(BuiltinFunction::Sqrt, sl()))) .or_else(|| f("rgb", BuiltinMacroReference(BuiltinMacroFunction::Rgb, t.clone()))) .or_else(|| f("rgba", BuiltinMacroReference(BuiltinMacroFunction::Rgb, t.clone()))) diff --git a/sixtyfps_runtime/interpreter/eval.rs b/sixtyfps_runtime/interpreter/eval.rs index 3ee027e40e3..d95fd23624f 100644 --- a/sixtyfps_runtime/interpreter/eval.rs +++ b/sixtyfps_runtime/interpreter/eval.rs @@ -227,6 +227,10 @@ pub fn eval_expression(e: &Expression, local_context: &mut EvalLocalContext) -> let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap(); Value::Number(x.sqrt()) } + Expression::BuiltinFunctionReference(BuiltinFunction::Abs, _) => { + let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap(); + Value::Number(x.abs()) + } Expression::BuiltinFunctionReference(BuiltinFunction::Sin, _) => { let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap(); Value::Number(x.to_radians().sin()) diff --git a/tests/cases/expr/math.60 b/tests/cases/expr/math.60 new file mode 100644 index 00000000000..7968ca56c2b --- /dev/null +++ b/tests/cases/expr/math.60 @@ -0,0 +1,32 @@ +/* LICENSE BEGIN + This file is part of the SixtyFPS Project -- https://sixtyfps.io + Copyright (c) 2020 Olivier Goffart + Copyright (c) 2020 Simon Hausmann + + SPDX-License-Identifier: GPL-3.0-only + This file is also available under commercial licensing terms. + Please contact info@sixtyfps.io for more information. +LICENSE END */ + TestCase := Rectangle { + property test_sqrt: sqrt(100) == 10 && sqrt(1) == 1 && sqrt(6.25) == 2.5; + property test_abs: abs(100.5) == 100.5 && abs(-200.5) == 200.5 && abs(0) == 0; + property test: test_sqrt && test_abs; +} +/* +```cpp +auto handle = TestCase::create(); +const TestCase &instance = *handle; +assert(instance.get_test()); +``` + + +```rust +let instance = TestCase::new(); +assert!(instance.get_test()); +``` + +```js +var instance = new sixtyfps.TestCase({}); +assert(instance.test); +``` +*/ diff --git a/tests/cases/expr/trigo.60 b/tests/cases/expr/trigo.60 index ab0c9fa8697..9f2c0f96efe 100644 --- a/tests/cases/expr/trigo.60 +++ b/tests/cases/expr/trigo.60 @@ -17,8 +17,8 @@ LICENSE END */ round(atan(tan(45deg))/0.1deg) == 450 && round(asin(sin(45deg))/0.1deg) == 450 && round(acos(cos(45deg))/0.1deg) == 450 && - sqrt(100) == 10 && sqrt(1) == 1 && sqrt(6.25) == 2.5 && true; + property test: verify; } /* ```cpp