KCL: Make shell stdlib fn use keyword arguments (#5293)

Before:

```
shell({ faces = ['end'], thickness = caseThickness }, case)
```

After:
```
shell(case, faces = ['end'], thickness = caseThickness)
```
This commit is contained in:
Adam Chalmers
2025-02-06 20:03:12 -06:00
committed by GitHub
parent 357bbffce5
commit 61807e7629
23 changed files with 3573 additions and 1595 deletions

View File

@ -242,7 +242,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
let (program, ctx, _) = parse_execute(new).await.unwrap();
@ -273,7 +273,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch) "#;
shell(firstSketch, faces = ['end'], thickness = 0.25) "#;
let new = r#"// Remove the end face for the extrusion.
firstSketch = startSketchOn('XY')
@ -285,7 +285,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
let (program_old, ctx, _) = parse_execute(old).await.unwrap();
@ -318,7 +318,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch) "#;
shell(firstSketch, faces = ['end'], thickness = 0.25) "#;
let new = r#"// Remove the end face for the extrusion.
firstSketch = startSketchOn('XY')
@ -330,7 +330,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
let (program, ctx, _) = parse_execute(old).await.unwrap();
@ -363,7 +363,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch) "#;
shell(firstSketch, faces = ['end'], thickness = 0.25) "#;
let new = r#"// Remove the end face for the extrusion.
firstSketch = startSketchOn('XY')
@ -375,7 +375,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
let (program, ctx, _) = parse_execute(old).await.unwrap();
@ -409,7 +409,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
let (program, mut ctx, _) = parse_execute(new).await.unwrap();
@ -451,7 +451,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
let (program, mut ctx, _) = parse_execute(new).await.unwrap();
@ -486,7 +486,7 @@ firstSketch = startSketchOn('XY')
|> extrude(length = 6)
// Remove the end face for the extrusion.
shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
let (program, mut ctx, _) = parse_execute(new).await.unwrap();

View File

@ -1590,10 +1590,10 @@ let w = f() + f()
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> extrude(length = 40.14)
|> shell({
faces: [seg01],
thickness: 3.14,
}, %)
|> shell(
thickness = 3.14,
faces = [seg01]
)
"#;
let ctx = crate::test_server::new_context(UnitLength::Mm, true, None)
@ -1620,10 +1620,10 @@ let w = f() + f()
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> extrude(length = 40.14)
|> shell({
faces: [seg01],
thickness: 3.14,
}, %)
|> shell(
faces = [seg01],
thickness = 3.14,
)
"#;
// Execute a slightly different program again.

View File

@ -120,10 +120,11 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
/// |> close()
/// |> extrude(length = 6)
///
/// shell({
/// shell(
/// firstSketch,
/// faces = ['end'],
/// thickness = 0.25,
/// }, firstSketch)
/// )
/// |> appearance({
/// color = '#ff0000',
/// metalness = 90,
@ -147,10 +148,11 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
/// roughness = 90
/// }, %)
///
/// shell({
/// shell(
/// firstSketch,
/// faces = ['end'],
/// thickness = 0.25,
/// }, firstSketch)
/// )
/// ```
///
/// ```no_run

View File

@ -1019,15 +1019,6 @@ impl<'a> FromKclValue<'a> for super::sketch::BezierData {
}
}
impl<'a> FromKclValue<'a> for super::shell::ShellData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, thickness);
let_field_of!(obj, faces);
Some(Self { thickness, faces })
}
}
impl<'a> FromKclValue<'a> for super::chamfer::ChamferData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;

View File

@ -4,8 +4,6 @@ use anyhow::Result;
use derive_docs::stdlib;
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
use kittycad_modeling_cmds as kcmc;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
errors::{KclError, KclErrorDetails},
@ -13,22 +11,13 @@ use crate::{
std::{sketch::FaceTag, Args},
};
/// Data for shells.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct ShellData {
/// The thickness of the shell.
pub thickness: f64,
/// The faces you want removed.
pub faces: Vec<FaceTag>,
}
/// Create a shell.
pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, solid_set): (ShellData, SolidSet) = args.get_data_and_solid_set()?;
let solid_set = args.get_unlabeled_kw_arg("solidSet")?;
let thickness = args.get_kw_arg("thickness")?;
let faces = args.get_kw_arg("faces")?;
let result = inner_shell(data, solid_set, exec_state, args).await?;
let result = inner_shell(solid_set, thickness, faces, exec_state, args).await?;
Ok(result.into())
}
@ -47,10 +36,11 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> extrude(length = 6)
///
/// // Remove the end face for the extrusion.
/// shell({
/// shell(
/// firstSketch,
/// faces = ['end'],
/// thickness = 0.25,
/// }, firstSketch)
/// )
/// ```
///
/// ```no_run
@ -64,10 +54,11 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> extrude(length = 6)
///
/// // Remove the start face for the extrusion.
/// shell({
/// shell(
/// firstSketch,
/// faces = ['start'],
/// thickness = 0.25,
/// }, firstSketch)
/// )
/// ```
///
/// ```no_run
@ -81,10 +72,11 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> extrude(length = 6)
///
/// // Remove a tagged face for the extrusion.
/// shell({
/// shell(
/// firstSketch,
/// faces = [myTag],
/// thickness = 0.25,
/// }, firstSketch)
/// )
/// ```
///
/// ```no_run
@ -98,10 +90,11 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> extrude(length = 6)
///
/// // Remove a tagged face and the end face for the extrusion.
/// shell({
/// shell(
/// firstSketch,
/// faces = [myTag, 'end'],
/// thickness = 0.25,
/// }, firstSketch)
/// )
/// ```
///
/// ```no_run
@ -124,7 +117,7 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> extrude(length = 50)
///
/// // We put "case" in the shell function to shell the entire object.
/// shell({ faces = ['start'], thickness = 5 }, case)
/// shell(case, faces = ['start'], thickness = 5)
/// ```
///
/// ```no_run
@ -147,7 +140,7 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> extrude(length = 50)
///
/// // We put "thing1" in the shell function to shell the end face of the object.
/// shell({ faces = ['end'], thickness = 5 }, thing1)
/// shell(thing1, faces = ['end'], thickness = 5)
/// ```
///
/// ```no_run
@ -172,21 +165,29 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> extrude(length = 50)
///
/// // We put "thing1" and "thing2" in the shell function to shell the end face of the object.
/// shell({ faces = ['end'], thickness = 5 }, [thing1, thing2])
/// shell([thing1, thing2], faces = ['end'], thickness = 5)
/// ```
#[stdlib {
name = "shell",
feature_tree_operation = true,
keywords = true,
unlabeled_first = true,
args = {
solid_set = { docs = "Which solid (or solids) to shell out"},
thickness = {docs = "The thickness of the shell"},
faces = {docs = "The faces you want removed"},
}
}]
async fn inner_shell(
data: ShellData,
solid_set: SolidSet,
thickness: f64,
faces: Vec<FaceTag>,
exec_state: &mut ExecState,
args: Args,
) -> Result<SolidSet, KclError> {
if data.faces.is_empty() {
if faces.is_empty() {
return Err(KclError::Type(KclErrorDetails {
message: "Expected at least one face".to_string(),
message: "You must shell at least one face".to_string(),
source_ranges: vec![args.source_range],
}));
}
@ -194,7 +195,7 @@ async fn inner_shell(
let solids: Vec<Box<Solid>> = solid_set.clone().into();
if solids.is_empty() {
return Err(KclError::Type(KclErrorDetails {
message: "Expected at least one solid".to_string(),
message: "You must shell at least one solid".to_string(),
source_ranges: vec![args.source_range],
}));
}
@ -205,7 +206,7 @@ async fn inner_shell(
// If we do not do these for sketch on face, things will fail with face does not exist.
args.flush_batch_for_solid_set(exec_state, solid.clone().into()).await?;
for tag in &data.faces {
for tag in &faces {
let extrude_plane_id = tag.get_face_id(solid, exec_state, &args, false).await?;
face_ids.push(extrude_plane_id);
@ -235,7 +236,7 @@ async fn inner_shell(
hollow: false,
face_ids,
object_id: solids[0].id,
shell_thickness: LengthUnit(data.thickness),
shell_thickness: LengthUnit(thickness),
}),
)
.await?;

View File

@ -2542,7 +2542,7 @@ snapshot_kind: text
"cmdId": "[uuid]",
"range": [
2047,
2110,
2102,
0
],
"command": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing fillet-and-shell.kcl
snapshot_kind: text
---
{
"Ok": {
@ -2582,68 +2583,45 @@ description: Result of parsing fillet-and-shell.kcl
"type": "ExpressionStatement"
},
{
"end": 2110,
"end": 2102,
"expression": {
"arguments": [
{
"end": 2103,
"properties": [
{
"end": 2072,
"key": {
"end": 2062,
"name": "faces",
"start": 2057,
"type": "Identifier"
},
"start": 2057,
"type": "ObjectProperty",
"value": {
"elements": [
{
"end": 2071,
"raw": "'end'",
"start": 2066,
"type": "Literal",
"type": "Literal",
"value": "end"
}
],
"end": 2072,
"start": 2065,
"type": "ArrayExpression",
"type": "ArrayExpression"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "faces"
},
"arg": {
"elements": [
{
"end": 2073,
"raw": "'end'",
"start": 2068,
"type": "Literal",
"type": "Literal",
"value": "end"
}
},
{
"end": 2101,
"key": {
"end": 2085,
"name": "thickness",
"start": 2076,
"type": "Identifier"
},
"start": 2076,
"type": "ObjectProperty",
"value": {
"end": 2101,
"name": "caseThickness",
"start": 2088,
"type": "Identifier",
"type": "Identifier"
}
}
],
"start": 2053,
"type": "ObjectExpression",
"type": "ObjectExpression"
],
"end": 2074,
"start": 2067,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 2109,
"name": "case",
"start": 2105,
"type": "Identifier",
"type": "Identifier"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "thickness"
},
"arg": {
"end": 2101,
"name": "caseThickness",
"start": 2088,
"type": "Identifier",
"type": "Identifier"
}
}
],
"callee": {
@ -2652,17 +2630,24 @@ description: Result of parsing fillet-and-shell.kcl
"start": 2047,
"type": "Identifier"
},
"end": 2110,
"end": 2102,
"start": 2047,
"type": "CallExpression",
"type": "CallExpression"
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": {
"end": 2057,
"name": "case",
"start": 2053,
"type": "Identifier",
"type": "Identifier"
}
},
"start": 2047,
"type": "ExpressionStatement",
"type": "ExpressionStatement"
}
],
"end": 2111,
"end": 2103,
"nonCodeMeta": {
"nonCodeNodes": {
"1": [

View File

@ -74,7 +74,4 @@ m25Screw(border + rpizWidth / 2 + widthBetweenScrews / 2, 0 + border + rpizLengt
m25Screw(border + rpizWidth / 2 + widthBetweenScrews / 2, 0 + border + rpizLength / 2 - (lengthBetweenScrews / 2), screwHeight)
shell({
faces = ['end'],
thickness = caseThickness
}, case)
shell(case, faces = ['end'], thickness = caseThickness)

View File

@ -402,17 +402,17 @@ snapshot_kind: text
},
{
"labeledArgs": {
"data": {
"faces": {
"sourceRange": [
2053,
2103,
2067,
2074,
0
]
},
"solid_set": {
"thickness": {
"sourceRange": [
2105,
2109,
2088,
2101,
0
]
}
@ -420,10 +420,16 @@ snapshot_kind: text
"name": "shell",
"sourceRange": [
2047,
2110,
2102,
0
],
"type": "StdLibCall",
"unlabeledArg": null
"unlabeledArg": {
"sourceRange": [
2053,
2057,
0
]
}
}
]

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Artifact commands import_whole.kcl
snapshot_kind: text
---
[
{
@ -525,7 +526,7 @@ description: Artifact commands import_whole.kcl
"cmdId": "[uuid]",
"range": [
83,
130,
123,
0
],
"command": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing import_whole.kcl
snapshot_kind: text
---
{
"Ok": {
@ -26,7 +27,7 @@ description: Result of parsing import_whole.kcl
},
{
"declaration": {
"end": 130,
"end": 123,
"id": {
"end": 71,
"name": "bar",
@ -45,67 +46,45 @@ description: Result of parsing import_whole.kcl
{
"arguments": [
{
"end": 126,
"properties": [
{
"end": 106,
"key": {
"end": 96,
"name": "faces",
"start": 91,
"type": "Identifier"
},
"start": 91,
"type": "ObjectProperty",
"value": {
"elements": [
{
"end": 105,
"raw": "'end'",
"start": 100,
"type": "Literal",
"type": "Literal",
"value": "end"
}
],
"end": 106,
"start": 99,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 124,
"key": {
"end": 117,
"name": "thickness",
"start": 108,
"type": "Identifier"
},
"start": 108,
"type": "ObjectProperty",
"value": {
"end": 124,
"raw": "0.25",
"start": 120,
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "faces"
},
"arg": {
"elements": [
{
"end": 103,
"raw": "'end'",
"start": 98,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.25,
"suffix": "None"
}
"value": "end"
}
}
],
"start": 89,
"type": "ObjectExpression",
"type": "ObjectExpression"
],
"end": 104,
"start": 97,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 129,
"start": 128,
"type": "PipeSubstitution",
"type": "PipeSubstitution"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "thickness"
},
"arg": {
"end": 122,
"raw": "0.25",
"start": 118,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.25,
"suffix": "None"
}
}
}
],
"callee": {
@ -114,13 +93,14 @@ description: Result of parsing import_whole.kcl
"start": 83,
"type": "Identifier"
},
"end": 130,
"end": 123,
"start": 83,
"type": "CallExpression",
"type": "CallExpression"
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": null
}
],
"end": 130,
"end": 123,
"start": 74,
"type": "PipeExpression",
"type": "PipeExpression"
@ -128,14 +108,14 @@ description: Result of parsing import_whole.kcl
"start": 68,
"type": "VariableDeclarator"
},
"end": 130,
"end": 123,
"kind": "const",
"start": 68,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
}
],
"end": 131,
"end": 124,
"nonCodeMeta": {
"nonCodeNodes": {
"0": [

View File

@ -2,4 +2,4 @@
import "exported_mod.kcl" as foo
bar = foo
|> shell({ faces = ['end'], thickness = 0.25 }, %)
|> shell(faces = ['end'], thickness = 0.25)

View File

@ -1,21 +1,22 @@
---
source: kcl/src/simulation_tests.rs
description: Operations executed import_whole.kcl
snapshot_kind: text
---
[
{
"labeledArgs": {
"data": {
"faces": {
"sourceRange": [
89,
126,
97,
104,
0
]
},
"solid_set": {
"thickness": {
"sourceRange": [
128,
129,
118,
122,
0
]
}
@ -23,7 +24,7 @@ description: Operations executed import_whole.kcl
"name": "shell",
"sourceRange": [
83,
130,
123,
0
],
"type": "StdLibCall",