Compare commits

...

4 Commits

13 changed files with 5665 additions and 13 deletions

View File

@ -59,6 +59,7 @@ layout: manual
* [`legAngX`](kcl/legAngX)
* [`legAngY`](kcl/legAngY)
* [`legLen`](kcl/legLen)
* [`len`](kcl/len)
* [`line`](kcl/line)
* [`lineTo`](kcl/lineTo)
* [`ln`](kcl/ln)

37
docs/kcl/len.md Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1755,3 +1755,24 @@ mod array_elem_pop_fail {
super::execute(TEST_NAME, false).await
}
}
mod array_length {
const TEST_NAME: &str = "array_length";
/// Test parsing KCL.
#[test]
fn parse() {
super::parse(TEST_NAME)
}
/// Test that parsing and unparsing KCL produces the original KCL input.
#[test]
fn unparse() {
super::unparse(TEST_NAME)
}
/// Test that KCL is executed correctly.
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_execute() {
super::execute(TEST_NAME, false).await
}
}

View File

@ -308,3 +308,40 @@ pub async fn pop(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
inner_pop(array, &args).await
}
/// Get the length of an array.
///
/// Returns the number of elements in an array.
///
/// ```no_run
/// arr = [1, 2, 3]
/// length = len(arr)
/// assertEqual(length, 3, 0.00001, "The length of the array is 3")
/// ```
#[stdlib {
name = "len",
keywords = true,
unlabeled_first = true,
arg_docs = {
array = "The array to get the length of.",
}
}]
async fn inner_len(array: Vec<KclValue>, args: &Args) -> Result<KclValue, KclError> {
Ok(KclValue::Number {
value: array.len() as f64,
meta: vec![args.source_range.into()],
})
}
pub async fn len(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let val = args.get_unlabeled_kw_arg("array")?;
let meta = vec![args.source_range];
let KclValue::Array { value: array, meta: _ } = val else {
let actual_type = val.human_friendly_type();
return Err(KclError::Semantic(KclErrorDetails {
source_ranges: meta,
message: format!("You can't get the length of a value of type {actual_type}, only an array"),
}));
};
inner_len(array, &args).await
}

View File

@ -108,6 +108,7 @@ lazy_static! {
Box::new(crate::std::array::Reduce),
Box::new(crate::std::array::Map),
Box::new(crate::std::array::Push),
Box::new(crate::std::array::Len),
Box::new(crate::std::array::Pop),
Box::new(crate::std::chamfer::Chamfer),
Box::new(crate::std::fillet::Fillet),

View File

@ -0,0 +1,284 @@
---
source: kcl/src/simulation_tests.rs
description: Artifact commands array_length.kcl
---
[
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "plane_set_color",
"plane_id": "[uuid]",
"color": {
"r": 0.7,
"g": 0.28,
"b": 0.28,
"a": 0.4
}
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "plane_set_color",
"plane_id": "[uuid]",
"color": {
"r": 0.28,
"g": 0.7,
"b": 0.28,
"a": 0.4
}
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "plane_set_color",
"plane_id": "[uuid]",
"color": {
"r": 0.28,
"g": 0.28,
"b": 0.7,
"a": 0.4
}
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": -1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 0.0,
"y": -1.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": -1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"size": 100.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "edge_lines_visible",
"hidden": false
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "object_visible",
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [
0,
0,
0
],
"command": {
"type": "object_visible",
"object_id": "[uuid]",
"hidden": true
}
}
]

View File

@ -0,0 +1,282 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing array_length.kcl
---
{
"Ok": {
"body": [
{
"declaration": {
"end": 15,
"id": {
"end": 3,
"name": "arr",
"start": 0,
"type": "Identifier"
},
"init": {
"elements": [
{
"end": 8,
"raw": "1",
"start": 7,
"type": "Literal",
"type": "Literal",
"value": 1.0
},
{
"end": 11,
"raw": "2",
"start": 10,
"type": "Literal",
"type": "Literal",
"value": 2.0
},
{
"end": 14,
"raw": "3",
"start": 13,
"type": "Literal",
"type": "Literal",
"value": 3.0
}
],
"end": 15,
"start": 6,
"type": "ArrayExpression",
"type": "ArrayExpression"
},
"start": 0,
"type": "VariableDeclarator"
},
"end": 15,
"kind": "const",
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"declaration": {
"end": 34,
"id": {
"end": 23,
"name": "arr_len",
"start": 16,
"type": "Identifier"
},
"init": {
"arguments": [
{
"end": 33,
"name": "arr",
"start": 30,
"type": "Identifier",
"type": "Identifier"
}
],
"callee": {
"end": 29,
"name": "len",
"start": 26,
"type": "Identifier"
},
"end": 34,
"start": 26,
"type": "CallExpression",
"type": "CallExpression"
},
"start": 16,
"type": "VariableDeclarator"
},
"end": 34,
"kind": "const",
"start": 16,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"end": 99,
"expression": {
"arguments": [
{
"end": 54,
"name": "arr_len",
"start": 47,
"type": "Identifier",
"type": "Identifier"
},
{
"end": 57,
"raw": "3",
"start": 56,
"type": "Literal",
"type": "Literal",
"value": 3.0
},
{
"end": 66,
"raw": "0.00001",
"start": 59,
"type": "Literal",
"type": "Literal",
"value": 0.00001
},
{
"end": 98,
"raw": "\"The length of the array is 3\"",
"start": 68,
"type": "Literal",
"type": "Literal",
"value": "The length of the array is 3"
}
],
"callee": {
"end": 46,
"name": "assertEqual",
"start": 35,
"type": "Identifier"
},
"end": 99,
"start": 35,
"type": "CallExpression",
"type": "CallExpression"
},
"start": 35,
"type": "ExpressionStatement",
"type": "ExpressionStatement"
},
{
"declaration": {
"end": 115,
"id": {
"end": 110,
"name": "arr_empty",
"start": 101,
"type": "Identifier"
},
"init": {
"elements": [],
"end": 115,
"start": 113,
"type": "ArrayExpression",
"type": "ArrayExpression"
},
"start": 101,
"type": "VariableDeclarator"
},
"end": 115,
"kind": "const",
"start": 101,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"declaration": {
"end": 142,
"id": {
"end": 125,
"name": "len_empty",
"start": 116,
"type": "Identifier"
},
"init": {
"arguments": [
{
"end": 141,
"name": "arr_empty",
"start": 132,
"type": "Identifier",
"type": "Identifier"
}
],
"callee": {
"end": 131,
"name": "len",
"start": 128,
"type": "Identifier"
},
"end": 142,
"start": 128,
"type": "CallExpression",
"type": "CallExpression"
},
"start": 116,
"type": "VariableDeclarator"
},
"end": 142,
"kind": "const",
"start": 116,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"end": 209,
"expression": {
"arguments": [
{
"end": 164,
"name": "len_empty",
"start": 155,
"type": "Identifier",
"type": "Identifier"
},
{
"end": 167,
"raw": "0",
"start": 166,
"type": "Literal",
"type": "Literal",
"value": 0.0
},
{
"end": 176,
"raw": "0.00001",
"start": 169,
"type": "Literal",
"type": "Literal",
"value": 0.00001
},
{
"end": 208,
"raw": "\"The length of the array is 0\"",
"start": 178,
"type": "Literal",
"type": "Literal",
"value": "The length of the array is 0"
}
],
"callee": {
"end": 154,
"name": "assertEqual",
"start": 143,
"type": "Identifier"
},
"end": 209,
"start": 143,
"type": "CallExpression",
"type": "CallExpression"
},
"start": 143,
"type": "ExpressionStatement",
"type": "ExpressionStatement"
}
],
"end": 210,
"nonCodeMeta": {
"nonCodeNodes": {
"2": [
{
"end": 101,
"start": 99,
"type": "NonCodeNode",
"value": {
"type": "newLine"
}
}
]
},
"startNodes": []
},
"start": 0
}
}

View File

@ -0,0 +1,7 @@
arr = [1, 2, 3]
arr_len = len(arr)
assertEqual(arr_len, 3, 0.00001, "The length of the array is 3")
arr_empty = []
len_empty = len(arr_empty)
assertEqual(len_empty, 0, 0.00001, "The length of the array is 0")

View File

@ -0,0 +1,5 @@
---
source: kcl/src/simulation_tests.rs
description: Operations executed array_length.kcl
---
[]

View File

@ -0,0 +1,127 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing array_length.kcl
---
{
"environments": [
{
"bindings": {
"HALF_TURN": {
"type": "Number",
"value": 180.0,
"__meta": []
},
"QUARTER_TURN": {
"type": "Number",
"value": 90.0,
"__meta": []
},
"THREE_QUARTER_TURN": {
"type": "Number",
"value": 270.0,
"__meta": []
},
"ZERO": {
"type": "Number",
"value": 0.0,
"__meta": []
},
"arr": {
"type": "Array",
"value": [
{
"type": "Number",
"value": 1.0,
"__meta": [
{
"sourceRange": [
7,
8,
0
]
}
]
},
{
"type": "Number",
"value": 2.0,
"__meta": [
{
"sourceRange": [
10,
11,
0
]
}
]
},
{
"type": "Number",
"value": 3.0,
"__meta": [
{
"sourceRange": [
13,
14,
0
]
}
]
}
],
"__meta": [
{
"sourceRange": [
6,
15,
0
]
}
]
},
"arr_empty": {
"type": "Array",
"value": [],
"__meta": [
{
"sourceRange": [
113,
115,
0
]
}
]
},
"arr_len": {
"type": "Number",
"value": 3.0,
"__meta": [
{
"sourceRange": [
26,
34,
0
]
}
]
},
"len_empty": {
"type": "Number",
"value": 0.0,
"__meta": [
{
"sourceRange": [
128,
142,
0
]
}
]
}
},
"parent": null
}
],
"currentEnv": 0,
"return": null
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1169,25 +1169,25 @@ async fn kcl_test_plumbus_fillets() {
return sg
}
fn pentagon = (len) => {
fn pentagon = (sideLen) => {
sg = startSketchOn('XY')
|> startProfileAt([-len / 2, -len / 2], %)
|> angledLine({ angle: 0, length: len }, %, $a)
|> startProfileAt([-sideLen / 2, -sideLen / 2], %)
|> angledLine({ angle: 0, length: sideLen }, %, $a)
|> angledLine({
angle: segAng(a) + 180 - 108,
length: len
length: sideLen
}, %, $b)
|> angledLine({
angle: segAng(b) + 180 - 108,
length: len
length: sideLen
}, %, $c)
|> angledLine({
angle: segAng(c) + 180 - 108,
length: len
length: sideLen
}, %, $d)
|> angledLine({
angle: segAng(d) + 180 - 108,
length: len
length: sideLen
}, %)
return sg
@ -1653,17 +1653,17 @@ part001 = cube([0,0], 20)
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_duplicate_tags_should_error() {
let code = r#"fn triangle = (len) => {
let code = r#"fn triangle = (sideLen) => {
return startSketchOn('XY')
|> startProfileAt([-len / 2, -len / 2], %)
|> angledLine({ angle: 0, length: len }, %, $a)
|> startProfileAt([-sideLen / 2, -sideLen / 2], %)
|> angledLine({ angle: 0, length: sideLen }, %, $a)
|> angledLine({
angle: segAng(a) + 120,
length: len
length: sideLen
}, %, $b)
|> angledLine({
angle: segAng(b) + 120,
length: len
length: sideLen
}, %, $a)
}
@ -1674,7 +1674,7 @@ let p = triangle(200)
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"value already defined: KclErrorDetails { source_ranges: [SourceRange([311, 313, 0]), SourceRange([326, 339, 0])], message: "Cannot redefine `a`" }"#
r#"value already defined: KclErrorDetails { source_ranges: [SourceRange([335, 337, 0]), SourceRange([350, 363, 0])], message: "Cannot redefine `a`" }"#
);
}