Skip to content

Commit

Permalink
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Browse files Browse the repository at this point in the history
Part of #4600.

PR: #4826

# Changes to KCL stdlib

- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@Sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@Sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@Sketch, length)`

Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:

```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```

Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as

```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```

Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main

The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:

```
 line\(([^=]*), %\)
 line(end = $1)

 line\((.*), %, (.*)\)
 line(end = $1, tag = $2)

 lineTo\((.*), %\)
 line(endAbsolute = $1)

 lineTo\((.*), %, (.*)\)
 line(endAbsolute = $1, tag = $2)

 extrude\((.*), %\)
 extrude(length = $1)

extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)

 close\(%, (.*)\)
 close(tag = $1)
```

# Selected notes from commits before I squash them all

* Fix test 'yRelative to horizontal distance'

Fixes:
 - Make a lineTo helper
 - Fix pathToNode to go through the labeled arg .arg property

* Fix test by changing lookups into transformMap

Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.

So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.

* Stop asserting on exact source ranges

When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.

* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.

* Fixed another queryAst test

There were 2 problems:
 - Test was looking for the old style of `line` call to choose an offset
   for pathToNode
 - Test assumed that the `tag` param was always the third one, but in
   a kwarg call, you have to look it up by label

* Fix test: traverse was not handling CallExpressionKw

* Fix another test, addTagKw

addTag helper was not aware of kw args.

* Convert close from positional to kwargs

If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.

But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.

The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.

* Fix the last test

Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.

Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.

* Fix many bad regex find-replaces

I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.

Fixes this.

* Fixes test 'Basic sketch › code pane closed at start'

Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.

This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.

* Fix: Optional args given with wrong type were silently ignored

Optional args don't have to be given. But if the user gives them, they
should be the right type.

Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.

Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.

---------

Signed-off-by: Nick Cameron <[email protected]>
Co-authored-by: Nick Cameron <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <[email protected]>
Co-authored-by: Kevin Nadro <[email protected]>
Co-authored-by: Jonathan Tran <[email protected]>
  • Loading branch information
6 people authored Feb 4, 2025
1 parent f5b8298 commit 8397405
Show file tree
Hide file tree
Showing 553 changed files with 128,754 additions and 125,029 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ yarn-error.log*

.idea
.vscode
.helix
src/wasm-lib/.idea
src/wasm-lib/.vscode

Expand Down
2 changes: 2 additions & 0 deletions .helix/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[editor]
auto-format = true
10 changes: 10 additions & 0 deletions .helix/languages.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[language-server.eslint]
args = ["--stdio"]
command = "vscode-eslint-language-server"

[[language]]
name = "typescript"
auto-format = true
formatter = { command = "node_modules/.bin/prettier", args = ["--parser", "typescript"] }
language-servers = [ { name = "eslint", only-features = [ "diagnostics" ] }, "typescript-language-server" ]

8 changes: 4 additions & 4 deletions docs/kcl/abs.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions docs/kcl/acos.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/kcl/angleToMatchLengthX.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/kcl/angleToMatchLengthY.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/kcl/angledLine.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/kcl/angledLineOfXLength.md

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions docs/kcl/angledLineOfYLength.md

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions docs/kcl/angledLineThatIntersects.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions docs/kcl/angledLineToX.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/kcl/angledLineToY.md

Large diffs are not rendered by default.

76 changes: 38 additions & 38 deletions docs/kcl/appearance.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ appearance(data: AppearanceData, solid_set: SolidSet) -> SolidSet
// Add color to an extruded solid.
exampleSketch = startSketchOn("XZ")
|> startProfileAt([0, 0], %)
|> lineTo([10, 0], %)
|> lineTo([0, 10], %)
|> lineTo([-10, 0], %)
|> close(%)
|> line(endAbsolute = [10, 0])
|> line(endAbsolute = [0, 10])
|> line(endAbsolute = [-10, 0])
|> close()

example = extrude(5, exampleSketch)
example = extrude(exampleSketch, length = 5)
|> appearance({
color = '#ff0000',
metalness = 50,
Expand Down Expand Up @@ -65,11 +65,11 @@ sketch001 = startSketchOn('XY')
fn cube(center) {
return startSketchOn('XY')
|> startProfileAt([center[0] - 10, center[1] - 10], %)
|> lineTo([center[0] + 10, center[1] - 10], %)
|> lineTo([center[0] + 10, center[1] + 10], %)
|> lineTo([center[0] - 10, center[1] + 10], %)
|> close(%)
|> extrude(10, %)
|> line(endAbsolute = [center[0] + 10, center[1] - 10])
|> line(endAbsolute = [center[0] + 10, center[1] + 10])
|> line(endAbsolute = [center[0] - 10, center[1] + 10])
|> close()
|> extrude(length = 10)
}

example0 = cube([0, 0])
Expand All @@ -95,11 +95,11 @@ appearance({
// This example shows setting the appearance _after_ the shell.
firstSketch = startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line([24, 0], %)
|> line([0, -24], %)
|> line([-24, 0], %)
|> close(%)
|> extrude(6, %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)

shell({ faces = ['end'], thickness = 0.25 }, firstSketch)
|> appearance({
Expand All @@ -116,11 +116,11 @@ shell({ faces = ['end'], thickness = 0.25 }, firstSketch)
// This example shows setting the appearance _before_ the shell.
firstSketch = startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line([24, 0], %)
|> line([0, -24], %)
|> line([-24, 0], %)
|> close(%)
|> extrude(6, %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)
|> appearance({
color = '#ff0000',
metalness = 90,
Expand All @@ -137,12 +137,12 @@ shell({ faces = ['end'], thickness = 0.25 }, firstSketch)
// This example shows _before_ the pattern.
exampleSketch = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line([0, 2], %)
|> line([3, 1], %)
|> line([0, -4], %)
|> close(%)
|> line(end = [0, 2])
|> line(end = [3, 1])
|> line(end = [0, -4])
|> close()

example = extrude(1, exampleSketch)
example = extrude(exampleSketch, length = 1)
|> appearance({
color = '#ff0000',
metalness = 90,
Expand All @@ -162,12 +162,12 @@ example = extrude(1, exampleSketch)
// This example shows _after_ the pattern.
exampleSketch = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line([0, 2], %)
|> line([3, 1], %)
|> line([0, -4], %)
|> close(%)
|> line(end = [0, 2])
|> line(end = [3, 1])
|> line(end = [0, -4])
|> close()

example = extrude(1, exampleSketch)
example = extrude(exampleSketch, length = 1)
|> patternLinear3d({
axis = [1, 0, 1],
instances = 7,
Expand All @@ -186,18 +186,18 @@ example = extrude(1, exampleSketch)
// Color the result of a 2D pattern that was extruded.
exampleSketch = startSketchOn('XZ')
|> startProfileAt([.5, 25], %)
|> line([0, 5], %)
|> line([-1, 0], %)
|> line([0, -5], %)
|> close(%)
|> line(end = [0, 5])
|> line(end = [-1, 0])
|> line(end = [0, -5])
|> close()
|> patternCircular2d({
center = [0, 0],
instances = 13,
arcDegrees = 360,
rotateDuplicates = true
}, %)

example = extrude(1, exampleSketch)
example = extrude(exampleSketch, length = 1)
|> appearance({
color = '#ff0000',
metalness = 90,
Expand All @@ -214,11 +214,11 @@ example = extrude(1, exampleSketch)
// Create a path for the sweep.
sweepPath = startSketchOn('XZ')
|> startProfileAt([0.05, 0.05], %)
|> line([0, 7], %)
|> line(end = [0, 7])
|> tangentialArc({ offset = 90, radius = 5 }, %)
|> line([-3, 0], %)
|> line(end = [-3, 0])
|> tangentialArc({ offset = -90, radius = 5 }, %)
|> line([0, 7], %)
|> line(end = [0, 7])

pipeHole = startSketchOn('XY')
|> circle({ center = [0, 0], radius = 1.5 }, %)
Expand Down
6 changes: 3 additions & 3 deletions docs/kcl/arc.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/kcl/arcTo.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/kcl/asin.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/kcl/atan.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/kcl/atan2.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions docs/kcl/bezierCurve.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions docs/kcl/ceil.md

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions docs/kcl/chamfer.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions docs/kcl/circle.md

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions docs/kcl/circleThreePoint.md

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions docs/kcl/close.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/kcl/cos.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/kcl/e.md

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions docs/kcl/extrude.md

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions docs/kcl/fillet.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ filletRadius = 2

mountingPlateSketch = startSketchOn("XY")
|> startProfileAt([-width / 2, -length / 2], %)
|> lineTo([width / 2, -length / 2], %, $edge1)
|> lineTo([width / 2, length / 2], %, $edge2)
|> lineTo([-width / 2, length / 2], %, $edge3)
|> close(%, $edge4)
|> line(endAbsolute = [width / 2, -length / 2], tag = $edge1)
|> line(endAbsolute = [width / 2, length / 2], tag = $edge2)
|> line(endAbsolute = [-width / 2, length / 2], tag = $edge3)
|> close(tag = $edge4)

mountingPlate = extrude(thickness, mountingPlateSketch)
mountingPlate = extrude(mountingPlateSketch, length = thickness)
|> fillet({
radius = filletRadius,
tags = [
Expand All @@ -63,12 +63,12 @@ filletRadius = 1

mountingPlateSketch = startSketchOn("XY")
|> startProfileAt([-width / 2, -length / 2], %)
|> lineTo([width / 2, -length / 2], %, $edge1)
|> lineTo([width / 2, length / 2], %, $edge2)
|> lineTo([-width / 2, length / 2], %, $edge3)
|> close(%, $edge4)
|> line(endAbsolute = [width / 2, -length / 2], tag = $edge1)
|> line(endAbsolute = [width / 2, length / 2], tag = $edge2)
|> line(endAbsolute = [-width / 2, length / 2], tag = $edge3)
|> close(tag = $edge4)

mountingPlate = extrude(thickness, mountingPlateSketch)
mountingPlate = extrude(mountingPlateSketch, length = thickness)
|> fillet({
radius = filletRadius,
tolerance = 0.000001,
Expand Down
8 changes: 4 additions & 4 deletions docs/kcl/floor.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions docs/kcl/getNextAdjacentEdge.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ getNextAdjacentEdge(tag: TagIdentifier) -> Uuid
```js
exampleSketch = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line([10, 0], %)
|> line(end = [10, 0])
|> angledLine({ angle = 60, length = 10 }, %)
|> angledLine({ angle = 120, length = 10 }, %)
|> line([-10, 0], %)
|> line(end = [-10, 0])
|> angledLine({ angle = 240, length = 10 }, %, $referenceEdge)
|> close(%)
|> close()

example = extrude(5, exampleSketch)
example = extrude(exampleSketch, length = 5)
|> fillet({
radius = 3,
tags = [getNextAdjacentEdge(referenceEdge)]
Expand Down
8 changes: 4 additions & 4 deletions docs/kcl/getOppositeEdge.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ getOppositeEdge(tag: TagIdentifier) -> Uuid
```js
exampleSketch = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line([10, 0], %)
|> line(end = [10, 0])
|> angledLine({ angle = 60, length = 10 }, %)
|> angledLine({ angle = 120, length = 10 }, %)
|> line([-10, 0], %)
|> line(end = [-10, 0])
|> angledLine({ angle = 240, length = 10 }, %, $referenceEdge)
|> close(%)
|> close()

example = extrude(5, exampleSketch)
example = extrude(exampleSketch, length = 5)
|> fillet({
radius = 3,
tags = [getOppositeEdge(referenceEdge)]
Expand Down
8 changes: 4 additions & 4 deletions docs/kcl/getPreviousAdjacentEdge.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ getPreviousAdjacentEdge(tag: TagIdentifier) -> Uuid
```js
exampleSketch = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line([10, 0], %)
|> line(end = [10, 0])
|> angledLine({ angle = 60, length = 10 }, %)
|> angledLine({ angle = 120, length = 10 }, %)
|> line([-10, 0], %)
|> line(end = [-10, 0])
|> angledLine({ angle = 240, length = 10 }, %, $referenceEdge)
|> close(%)
|> close()

example = extrude(5, exampleSketch)
example = extrude(exampleSketch, length = 5)
|> fillet({
radius = 3,
tags = [getPreviousAdjacentEdge(referenceEdge)]
Expand Down
2 changes: 1 addition & 1 deletion docs/kcl/helix.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ springSketch = startSketchOn('YZ')
// Create a helix around an edge.
helper001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line([0, 10], %, $edge001)
|> line(end = [0, 10], tag = $edge001)

helixPath = helix({
angleStart = 0,
Expand Down
2 changes: 1 addition & 1 deletion docs/kcl/helixRevolutions.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ helixRevolutions(data: HelixRevolutionsData, solid: Solid) -> Solid
```js
part001 = startSketchOn('XY')
|> circle({ center = [5, 5], radius = 10 }, %)
|> extrude(10, %)
|> extrude(length = 10)
|> helixRevolutions({
angleStart = 0,
ccw = true,
Expand Down
20 changes: 10 additions & 10 deletions docs/kcl/hole.md

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions docs/kcl/hollow.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ hollow(thickness: number, solid: Solid) -> Solid
// Hollow a basic sketch.
firstSketch = startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line([24, 0], %)
|> line([0, -24], %)
|> line([-24, 0], %)
|> close(%)
|> extrude(6, %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)
|> hollow(0.25, %)
```

Expand All @@ -45,11 +45,11 @@ firstSketch = startSketchOn('XY')
// Hollow a basic sketch.
firstSketch = startSketchOn('-XZ')
|> startProfileAt([-12, 12], %)
|> line([24, 0], %)
|> line([0, -24], %)
|> line([-24, 0], %)
|> close(%)
|> extrude(6, %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)
|> hollow(0.5, %)
```

Expand All @@ -60,25 +60,25 @@ firstSketch = startSketchOn('-XZ')
size = 100
case = startSketchOn('-XZ')
|> startProfileAt([-size, -size], %)
|> line([2 * size, 0], %)
|> line([0, 2 * size], %)
|> line(end = [2 * size, 0])
|> line(end = [0, 2 * size])
|> tangentialArcTo([-size, size], %)
|> close(%)
|> extrude(65, %)
|> close()
|> extrude(length = 65)

thing1 = startSketchOn(case, 'end')
|> circle({
center = [-size / 2, -size / 2],
radius = 25
}, %)
|> extrude(50, %)
|> extrude(length = 50)

thing2 = startSketchOn(case, 'end')
|> circle({
center = [size / 2, -size / 2],
radius = 25
}, %)
|> extrude(50, %)
|> extrude(length = 50)

hollow(0.5, case)
```
Expand Down
1 change: 0 additions & 1 deletion docs/kcl/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ layout: manual
* [`legAngY`](kcl/legAngY)
* [`legLen`](kcl/legLen)
* [`line`](kcl/line)
* [`lineTo`](kcl/lineTo)
* [`ln`](kcl/ln)
* [`loft`](kcl/loft)
* [`log`](kcl/log)
Expand Down
2 changes: 1 addition & 1 deletion docs/kcl/int.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ assertEqual(n, 3, 0.0001, "5/2 = 2.5, rounded up makes 3")
// Draw n cylinders.
startSketchOn('XZ')
|> circle({ center = [0, 0], radius = 2 }, %)
|> extrude(5, %)
|> extrude(length = 5)
|> patternTransform(n, fn(id) {
return { translate = [4 * id, 0, 0] }
}, %)
Expand Down
12 changes: 6 additions & 6 deletions docs/kcl/lastSegX.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions docs/kcl/lastSegY.md

Large diffs are not rendered by default.

Loading

0 comments on commit 8397405

Please sign in to comment.