Some improvements to math::sqrt (#6853)
* Treat number as any rather than default Signed-off-by: Nick Cameron <nrc@ncameron.org> * Don't square root negative numbers Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -28,6 +28,8 @@ Any of the suffixes described above can be used meaning that values with that ty
|
|||||||
|
|
||||||
You can also use `number(Length)`, `number(Angle)`, or `number(Count)`. These types mean a number with any length, angle, or unitless (count) units, respectively (note that `number(_)` and `number(Count)` are equivalent since there is only one kind of unitless-ness).
|
You can also use `number(Length)`, `number(Angle)`, or `number(Count)`. These types mean a number with any length, angle, or unitless (count) units, respectively (note that `number(_)` and `number(Count)` are equivalent since there is only one kind of unitless-ness).
|
||||||
|
|
||||||
|
Using just `number` means accepting any kind of number, even where the units are unknown by KCL.
|
||||||
|
|
||||||
|
|
||||||
## Function calls
|
## Function calls
|
||||||
|
|
||||||
|
@ -2694,4 +2694,13 @@ sketch001 = startSketchOn(XY)
|
|||||||
let ast = r#"foo = tan(0): number(rad) - 4deg"#;
|
let ast = r#"foo = tan(0): number(rad) - 4deg"#;
|
||||||
parse_execute(ast).await.unwrap();
|
parse_execute(ast).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn neg_sqrt() {
|
||||||
|
let ast = r#"bad = sqrt(-2)"#;
|
||||||
|
|
||||||
|
let e = parse_execute(ast).await.unwrap_err();
|
||||||
|
// Make sure we get a useful error message and not an engine error.
|
||||||
|
assert!(e.message().contains("sqrt"), "Error message: '{}'", e.message());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,9 +173,13 @@ impl RuntimeType {
|
|||||||
AstPrimitiveType::Any => RuntimeType::Primitive(PrimitiveType::Any),
|
AstPrimitiveType::Any => RuntimeType::Primitive(PrimitiveType::Any),
|
||||||
AstPrimitiveType::String => RuntimeType::Primitive(PrimitiveType::String),
|
AstPrimitiveType::String => RuntimeType::Primitive(PrimitiveType::String),
|
||||||
AstPrimitiveType::Boolean => RuntimeType::Primitive(PrimitiveType::Boolean),
|
AstPrimitiveType::Boolean => RuntimeType::Primitive(PrimitiveType::Boolean),
|
||||||
AstPrimitiveType::Number(suffix) => RuntimeType::Primitive(PrimitiveType::Number(
|
AstPrimitiveType::Number(suffix) => {
|
||||||
NumericType::from_parsed(suffix, &exec_state.mod_local.settings),
|
let ty = match suffix {
|
||||||
)),
|
NumericSuffix::None => NumericType::Any,
|
||||||
|
_ => NumericType::from_parsed(suffix, &exec_state.mod_local.settings),
|
||||||
|
};
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Number(ty))
|
||||||
|
}
|
||||||
AstPrimitiveType::Named(name) => Self::from_alias(&name.name, exec_state, source_range)?,
|
AstPrimitiveType::Named(name) => Self::from_alias(&name.name, exec_state, source_range)?,
|
||||||
AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag),
|
AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag),
|
||||||
})
|
})
|
||||||
@ -682,6 +686,7 @@ impl NumericType {
|
|||||||
// We don't have enough information to coerce.
|
// We don't have enough information to coerce.
|
||||||
(Unknown, _) => Err(CoercionError::from(val).with_explicit(self.example_ty().unwrap_or("mm".to_owned()))),
|
(Unknown, _) => Err(CoercionError::from(val).with_explicit(self.example_ty().unwrap_or("mm".to_owned()))),
|
||||||
(_, Unknown) => Err(val.into()),
|
(_, Unknown) => Err(val.into()),
|
||||||
|
|
||||||
(Any, _) => Ok(KclValue::Number {
|
(Any, _) => Ok(KclValue::Number {
|
||||||
value: *value,
|
value: *value,
|
||||||
ty: self.clone(),
|
ty: self.clone(),
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::KclError,
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{
|
||||||
types::{ArrayLen, NumericType, RuntimeType},
|
types::{ArrayLen, NumericType, RuntimeType},
|
||||||
ExecState, KclValue,
|
ExecState, KclValue,
|
||||||
@ -54,6 +54,17 @@ pub async fn tan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
|||||||
/// Compute the square root of a number.
|
/// Compute the square root of a number.
|
||||||
pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
||||||
|
|
||||||
|
if input.n < 0.0 {
|
||||||
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
message: format!(
|
||||||
|
"Attempt to take square root (`sqrt`) of a number less than zero ({})",
|
||||||
|
input.n
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
let result = input.n.sqrt();
|
let result = input.n.sqrt();
|
||||||
|
|
||||||
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
||||||
|
Reference in New Issue
Block a user