Add int() function to KCL stdlib (#3116)
This commit is contained in:
@ -38,6 +38,7 @@ layout: manual
|
||||
* [`helix`](kcl/helix)
|
||||
* [`hole`](kcl/hole)
|
||||
* [`import`](kcl/import)
|
||||
* [`int`](kcl/int)
|
||||
* [`lastSegX`](kcl/lastSegX)
|
||||
* [`lastSegY`](kcl/lastSegY)
|
||||
* [`legAngX`](kcl/legAngX)
|
||||
|
43
docs/kcl/int.md
Normal file
43
docs/kcl/int.md
Normal file
File diff suppressed because one or more lines are too long
@ -85702,6 +85702,39 @@
|
||||
"const model = import(\"tests/inputs/cube.step\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "int",
|
||||
"summary": "Converts a number to an integer.",
|
||||
"description": "Callers should use floor(), ceil(), or other rounding function first if they care about how numbers with fractional parts are converted. If the number has a fractional part, it's truncated, moving the number towards zero.\nIf the number is NaN or has a magnitude, either positive or negative, that is too large to fit into the internal integer representation, the result is a runtime error.",
|
||||
"tags": [
|
||||
"convert"
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "num",
|
||||
"type": "number",
|
||||
"schema": {
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"returnValue": {
|
||||
"name": "",
|
||||
"type": "i64",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"unpublished": false,
|
||||
"deprecated": false,
|
||||
"examples": [
|
||||
"const sketch001 = startSketchOn('XZ')\n |> circle([0, 0], 2, %)\nconst extrude001 = extrude(5, sketch001)\n\nconst pattern01 = patternTransform(int(ceil(5 / 2)), (id) => {\n return { translate: [4 * id, 0, 0] }\n}, extrude001)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lastSegX",
|
||||
"summary": "Returns the last segment of x.",
|
||||
|
@ -343,6 +343,7 @@ pub fn get_type_string_from_schema(schema: &schemars::schema::Schema) -> Result<
|
||||
return Ok((Primitive::Uuid.to_string(), false));
|
||||
} else if format == "double"
|
||||
|| format == "uint"
|
||||
|| format == "int32"
|
||||
|| format == "int64"
|
||||
|| format == "uint8"
|
||||
|| format == "uint32"
|
||||
|
@ -125,6 +125,10 @@ impl Args {
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn make_user_val_from_i64(&self, n: i64) -> Result<MemoryItem, KclError> {
|
||||
self.make_user_val_from_json(serde_json::Value::Number(serde_json::Number::from(n)))
|
||||
}
|
||||
|
||||
pub fn make_user_val_from_f64(&self, f: f64) -> Result<MemoryItem, KclError> {
|
||||
self.make_user_val_from_json(serde_json::Value::Number(serde_json::Number::from_f64(f).ok_or_else(
|
||||
|| {
|
||||
|
102
src/wasm-lib/kcl/src/std/convert.rs
Normal file
102
src/wasm-lib/kcl/src/std/convert.rs
Normal file
@ -0,0 +1,102 @@
|
||||
//! Conversions between types.
|
||||
|
||||
use derive_docs::stdlib;
|
||||
use schemars::JsonSchema;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{MemoryItem, SourceRange},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum ConversionError {
|
||||
Nan,
|
||||
TooLarge,
|
||||
}
|
||||
|
||||
impl ConversionError {
|
||||
pub fn into_kcl_error(self, source_range: SourceRange) -> KclError {
|
||||
match self {
|
||||
ConversionError::Nan => KclError::Semantic(KclErrorDetails {
|
||||
message: "NaN cannot be converted to an integer".to_owned(),
|
||||
source_ranges: vec![source_range],
|
||||
}),
|
||||
ConversionError::TooLarge => KclError::Semantic(KclErrorDetails {
|
||||
message: "Number is too large to convert to integer".to_owned(),
|
||||
source_ranges: vec![source_range],
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a number to integer.
|
||||
pub async fn int(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let converted = inner_int(num).map_err(|err| err.into_kcl_error(args.source_range))?;
|
||||
|
||||
args.make_user_val_from_i64(converted)
|
||||
}
|
||||
|
||||
/// Converts a number to an integer.
|
||||
///
|
||||
/// Callers should use floor(), ceil(), or other rounding function first if they
|
||||
/// care about how numbers with fractional parts are converted. If the number
|
||||
/// has a fractional part, it's truncated, moving the number towards zero.
|
||||
///
|
||||
/// If the number is NaN or has a magnitude, either positive or negative, that
|
||||
/// is too large to fit into the internal integer representation, the result is
|
||||
/// a runtime error.
|
||||
///
|
||||
/// ```no_run
|
||||
/// const sketch001 = startSketchOn('XZ')
|
||||
/// |> circle([0, 0], 2, %)
|
||||
/// const extrude001 = extrude(5, sketch001)
|
||||
///
|
||||
/// const pattern01 = patternTransform(int(ceil(5 / 2)), (id) => {
|
||||
/// return { translate: [4 * id, 0, 0] }
|
||||
/// }, extrude001)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "int",
|
||||
tags = ["convert"],
|
||||
}]
|
||||
fn inner_int(num: f64) -> Result<i64, ConversionError> {
|
||||
if num.is_nan() {
|
||||
return Err(ConversionError::Nan);
|
||||
}
|
||||
if num > 2_f64.powi(53) || num < -(2_f64.powi(53)) {
|
||||
// 2^53 is the largest magnitude integer that can be represented in f64
|
||||
// and accurately converted.
|
||||
return Err(ConversionError::TooLarge);
|
||||
}
|
||||
|
||||
Ok(num as i64)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::f64;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_inner_int() {
|
||||
assert_eq!(inner_int(0.0), Ok(0));
|
||||
assert_eq!(inner_int(-0.0), Ok(0));
|
||||
assert_eq!(inner_int(3.0), Ok(3));
|
||||
assert_eq!(inner_int(2.5), Ok(2));
|
||||
assert_eq!(inner_int(-2.5), Ok(-2));
|
||||
assert_eq!(inner_int(f64::NAN), Err(ConversionError::Nan));
|
||||
assert_eq!(inner_int(f64::INFINITY), Err(ConversionError::TooLarge));
|
||||
assert_eq!(inner_int(f64::NEG_INFINITY), Err(ConversionError::TooLarge));
|
||||
assert_eq!(inner_int(2_f64.powi(53)), Ok(2_i64.pow(53)));
|
||||
assert_eq!(inner_int(-(2_f64.powi(53))), Ok(-(2_i64.pow(53))));
|
||||
// Note: 2_f64.powi(53) + 1.0 can't be represented.
|
||||
assert_eq!(inner_int(2_f64.powi(53) + 2.0), Err(ConversionError::TooLarge));
|
||||
assert_eq!(inner_int(-(2_f64.powi(53)) - 2.0), Err(ConversionError::TooLarge));
|
||||
assert_eq!(inner_int(-(2_f64.powi(64))), Err(ConversionError::TooLarge));
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
pub mod args;
|
||||
pub mod chamfer;
|
||||
pub mod convert;
|
||||
pub mod extrude;
|
||||
pub mod fillet;
|
||||
pub mod helix;
|
||||
@ -45,6 +46,7 @@ lazy_static! {
|
||||
Box::new(LegLen),
|
||||
Box::new(LegAngX),
|
||||
Box::new(LegAngY),
|
||||
Box::new(crate::std::convert::Int),
|
||||
Box::new(crate::std::extrude::Extrude),
|
||||
Box::new(crate::std::segment::SegEndX),
|
||||
Box::new(crate::std::segment::SegEndY),
|
||||
|
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_int0.png
Normal file
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_int0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
Reference in New Issue
Block a user