Compare commits

..

19 Commits

Author SHA1 Message Date
b5c8ca05a5 Fix whitespace in updater toast (#7331)
pierremtb/adhoc/whitespace-fix-updater-toast
2025-06-03 10:15:42 -04:00
33f7badf41 point and click-ify mounting plate (#7287)
* point and click-ify mounting plate

* Update kcl-samples simulation test output

* Update public/kcl-samples/mounting-plate/main.kcl

* Update public/kcl-samples/mounting-plate/main.kcl

* fix

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-06-03 08:10:37 -04:00
569935c21f Move segment functions to KCL (#7333)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-06-03 15:15:51 +12:00
7680605085 KCL: Fix 'cryptic' error when referencing a variable in its own declaration (#7325)
Previously, `x = cos(x)` would just say "`x` is undefined". Now it says that `x` cannot be referenced in its own definition, try using a different variable instead.

To do this, I've added a new `Option<String>` field to the mod-local executor context, tracking the current variable declaration. This means cloning some strings, implying a small performance hit. I think it's fine, for the better diagnostics.

In the future we could refactor this to use a &str or store variable labels in stack-allocated strings like docs.rs/compact_str or something.

Closes https://github.com/KittyCAD/modeling-app/issues/6072
2025-06-02 18:25:55 -04:00
2bb6c74f42 Update error message after engine change (#7330) 2025-06-02 18:05:46 -04:00
faf4d42b6a Update getSketchExprsFromSelection to use codeRef.pathToNode (#6737) 2025-06-02 16:49:41 -04:00
8dd2a86191 Make sweep tests more point-and-click like and clean up pathToNode retrieval (#6963)
WIP: udpate sweep point-and-click tests and mess with pathToNode
Fixes #6952
2025-06-02 16:49:20 -04:00
13c4de77c3 Fix broken WASM test (#7324)
Previous PR (#7321) was set to automerge, but apparently the npm-unit-test
CI target doesn't block merges if it fails. Fixed now.
2025-06-02 15:56:49 -04:00
e29ee9d1ca KCL: Use named fields for KclError (#7321)
We've changed the unnamed field of `KclError` variants to a named called `details`.

To clarify: previously KCL errors looked like this:

```rust
pub enum KclError {
    Lexical(KclErrorDetails),
    Syntax(KclErrorDetails),
```

Now they look like this:

```rust
pub enum KclError {
    Lexical { details: KclErrorDetails },
    Syntax { details: KclErrorDetails },
}
```

This lets us more easily add fields to the errors. For example, in the UndefinedValue case, adding a field for what the undefined name was. This PR refactors the code to make my PR in https://github.com/KittyCAD/modeling-app/pull/7309 much easier.

Pure refactor, should not change any behaviour.
2025-06-02 14:30:57 -04:00
b7437e949a Update generated output to try to fix flakiness (#7323) 2025-06-02 13:36:41 -04:00
08781ff010 Add transform operations to the Feature Tree (#7307)
* Add transform operations

* Update output

* Add scale icon
2025-06-02 10:32:36 -04:00
eb79b1f746 #7227 Fix project not saving when dragging a segment (#7276)
* fix bug of not saving project when dragging a segment, add a test

* Update e2e/playwright/projects.spec.ts

Co-authored-by: Jace Browning <jacebrowning@gmail.com>

---------

Co-authored-by: Jace Browning <jacebrowning@gmail.com>
2025-06-02 09:28:23 +02:00
8df81b2753 Update URL in Discord Bot (#7306) 2025-05-30 14:36:45 -07:00
e75a604c64 Fix the link for plan upgrades (#7305) 2025-05-30 16:54:07 -04:00
0624e42822 Add more detail to close() docs (#7300)
* Add more detail to close() docs

* Run gen
2025-05-30 16:05:32 -04:00
1c07e8af5b Add hysteresis and EMA to ping to avoid flickering network badge (#7197)
* Don't use WEAK and yellow

* fmt && lint && tsc

* Fix up the rebase & dark mode colors

* Update src/hooks/useNetworkStatus.tsx

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

* Change Weak to Ok

* Change Connected to Strong

* fmt

* Sync selectors for start sketch

* Remove unused test-util brought back in a rebase

* Align the other OKs

* Add an else statement to overallState

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-30 15:50:05 -04:00
5fccaad0e7 KCL: Fix cryptic error on unexpected tokens in fn call (#7295)
This program:
```kcl
1
|> extrude(
  length=depth,
})
```

was giving this bad error:

```
unexpected token |>
```

Now it gives

```kcl
There was an unexpected }. Try removing it.
```

and it correctly puts the diagnostic on the extra }.

Fixes https://github.com/KittyCAD/modeling-app/issues/6126
2025-05-30 14:57:05 -04:00
a506f7f698 KCL: Fix cryptic error when missing commas between arguments (#7297)
Previously, this KCL

```
arc(
    endAbsolute = [0, 50]
    interiorAbsolute = [-50, 0]
)
```

gave the error `This argument has a label, but no value. Put some value after the equals sign`.

Now it gives this much better error `Missing comma between arguments, try adding a comma in`, and its source range (red underline) is on the whitespace which was missing a comma:

<img width="666" src="https://github.com/user-attachments/assets/aa5035f5-f748-4dab-b918-b81b05733323" />

Thanks for reporting this @benjamaan476
2025-05-30 13:20:06 -05:00
1bb96cd878 Release KCL 78 (#7298) 2025-05-30 13:48:17 -04:00
185 changed files with 12130 additions and 9014 deletions

View File

@ -14,7 +14,7 @@ close(
): Sketch ): Sketch
``` ```
If you want to perform some 3-dimensional operation on a sketch, like extrude or sweep, you must `close` it first. `close` must be called even if the end point of the last segment is coincident with the sketch starting point.
### Arguments ### Arguments

View File

@ -8,7 +8,7 @@ layout: manual
Extract the 'x' axis value of the last line segment in the provided 2-d sketch. Extract the 'x' axis value of the last line segment in the provided 2-d sketch.
```kcl ```kcl
lastSegX(@sketch: Sketch): number lastSegX(@sketch: Sketch): number(Length)
``` ```
@ -17,11 +17,11 @@ lastSegX(@sketch: Sketch): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried | Yes | | `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples

View File

@ -8,7 +8,7 @@ layout: manual
Extract the 'y' axis value of the last line segment in the provided 2-d sketch. Extract the 'y' axis value of the last line segment in the provided 2-d sketch.
```kcl ```kcl
lastSegY(@sketch: Sketch): number lastSegY(@sketch: Sketch): number(Length)
``` ```
@ -17,11 +17,11 @@ lastSegY(@sketch: Sketch): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried | Yes | | `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples

View File

@ -8,7 +8,7 @@ layout: manual
Compute the angle (in degrees) of the provided line segment. Compute the angle (in degrees) of the provided line segment.
```kcl ```kcl
segAng(@tag: TagIdentifier): number segAng(@tag: tag): number(Angle)
``` ```
@ -17,11 +17,11 @@ segAng(@tag: TagIdentifier): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Angle)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples

View File

@ -8,7 +8,7 @@ layout: manual
Compute the ending point of the provided line segment. Compute the ending point of the provided line segment.
```kcl ```kcl
segEnd(@tag: TagIdentifier): Point2d segEnd(@tag: tag): Point2d
``` ```
@ -17,7 +17,7 @@ segEnd(@tag: TagIdentifier): Point2d
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
@ -39,9 +39,9 @@ cube = startSketchOn(XY)
fn cylinder(radius, tag) { fn cylinder(radius, tag) {
return startSketchOn(XY) return startSketchOn(XY)
|> startProfile(at = [0, 0]) |> startProfile(at = [0, 0])
|> circle(radius = radius, center = segEnd(tag)) |> circle(radius = radius, center = segEnd(tag) )
|> extrude(length = radius) |> extrude(length = radius)
} }
cylinder(radius = 1, tag = line1) cylinder(radius = 1, tag = line1)

View File

@ -8,7 +8,7 @@ layout: manual
Compute the ending point of the provided line segment along the 'x' axis. Compute the ending point of the provided line segment along the 'x' axis.
```kcl ```kcl
segEndX(@tag: TagIdentifier): number segEndX(@tag: tag): number(Length)
``` ```
@ -17,11 +17,11 @@ segEndX(@tag: TagIdentifier): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples

View File

@ -8,7 +8,7 @@ layout: manual
Compute the ending point of the provided line segment along the 'y' axis. Compute the ending point of the provided line segment along the 'y' axis.
```kcl ```kcl
segEndY(@tag: TagIdentifier): number segEndY(@tag: tag): number(Length)
``` ```
@ -17,11 +17,11 @@ segEndY(@tag: TagIdentifier): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples

View File

@ -8,7 +8,7 @@ layout: manual
Compute the length of the provided line segment. Compute the length of the provided line segment.
```kcl ```kcl
segLen(@tag: TagIdentifier): number segLen(@tag: tag): number(Length)
``` ```
@ -17,11 +17,11 @@ segLen(@tag: TagIdentifier): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples
@ -29,9 +29,16 @@ segLen(@tag: TagIdentifier): number
```kcl ```kcl
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0]) |> startProfile(at = [0, 0])
|> angledLine(angle = 60, length = 10, tag = $thing) |> angledLine(
angle = 60,
length = 10,
tag = $thing,
)
|> tangentialArc(angle = -120, radius = 5) |> tangentialArc(angle = -120, radius = 5)
|> angledLine(angle = -60, length = segLen(thing)) |> angledLine(
angle = -60,
length = segLen(thing),
)
|> close() |> close()
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)

View File

@ -8,7 +8,7 @@ layout: manual
Compute the starting point of the provided line segment. Compute the starting point of the provided line segment.
```kcl ```kcl
segStart(@tag: TagIdentifier): Point2d segStart(@tag: tag): Point2d
``` ```
@ -17,7 +17,7 @@ segStart(@tag: TagIdentifier): Point2d
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
@ -39,9 +39,9 @@ cube = startSketchOn(XY)
fn cylinder(radius, tag) { fn cylinder(radius, tag) {
return startSketchOn(XY) return startSketchOn(XY)
|> startProfile(at = [0, 0]) |> startProfile(at = [0, 0])
|> circle(radius = radius, center = segStart(tag)) |> circle( radius = radius, center = segStart(tag) )
|> extrude(length = radius) |> extrude(length = radius)
} }
cylinder(radius = 1, tag = line1) cylinder(radius = 1, tag = line1)

View File

@ -8,7 +8,7 @@ layout: manual
Compute the starting point of the provided line segment along the 'x' axis. Compute the starting point of the provided line segment along the 'x' axis.
```kcl ```kcl
segStartX(@tag: TagIdentifier): number segStartX(@tag: tag): number(Length)
``` ```
@ -17,11 +17,11 @@ segStartX(@tag: TagIdentifier): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples

View File

@ -8,7 +8,7 @@ layout: manual
Compute the starting point of the provided line segment along the 'y' axis. Compute the starting point of the provided line segment along the 'y' axis.
```kcl ```kcl
segStartY(@tag: TagIdentifier): number segStartY(@tag: tag): number(Length)
``` ```
@ -17,11 +17,11 @@ segStartY(@tag: TagIdentifier): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples
@ -32,7 +32,7 @@ exampleSketch = startSketchOn(XZ)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> line(end = [0, 3], tag = $thing) |> line(end = [0, 3], tag = $thing)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> line(end = [0, 20 - segStartY(thing)]) |> line(end = [0, 20-segStartY(thing)])
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> close() |> close()

View File

@ -8,7 +8,7 @@ layout: manual
Returns the angle coming out of the end of the segment in degrees. Returns the angle coming out of the end of the segment in degrees.
```kcl ```kcl
tangentToEnd(@tag: TagIdentifier): number tangentToEnd(@tag: tag): number(Angle)
``` ```
@ -17,11 +17,11 @@ tangentToEnd(@tag: TagIdentifier): number
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes | | [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
### Returns ### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number. [`number(Angle)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples ### Examples
@ -32,7 +32,10 @@ pillSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0]) |> startProfile(at = [0, 0])
|> line(end = [20, 0]) |> line(end = [20, 0])
|> tangentialArc(end = [0, 10], tag = $arc1) |> tangentialArc(end = [0, 10], tag = $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine(
angle = tangentToEnd(arc1),
length = 20,
)
|> tangentialArc(end = [0, -10]) |> tangentialArc(end = [0, -10])
|> close() |> close()
@ -47,7 +50,10 @@ pillSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0]) |> startProfile(at = [0, 0])
|> line(end = [0, 20]) |> line(end = [0, 20])
|> tangentialArc(endAbsolute = [10, 20], tag = $arc1) |> tangentialArc(endAbsolute = [10, 20], tag = $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine(
angle = tangentToEnd(arc1),
length = 20,
)
|> tangentialArc(end = [-10, 0]) |> tangentialArc(end = [-10, 0])
|> close() |> close()
@ -60,7 +66,10 @@ pillExtrude = extrude(pillSketch, length = 10)
rectangleSketch = startSketchOn(XZ) rectangleSketch = startSketchOn(XZ)
|> startProfile(at = [0, 0]) |> startProfile(at = [0, 0])
|> line(end = [10, 0], tag = $seg1) |> line(end = [10, 0], tag = $seg1)
|> angledLine(angle = tangentToEnd(seg1), length = 10) |> angledLine(
angle = tangentToEnd(seg1),
length = 10,
)
|> line(end = [0, 10]) |> line(end = [0, 10])
|> line(end = [-20, 0]) |> line(end = [-20, 0])
|> close() |> close()
@ -73,7 +82,11 @@ rectangleExtrude = extrude(rectangleSketch, length = 10)
```kcl ```kcl
bottom = startSketchOn(XY) bottom = startSketchOn(XY)
|> startProfile(at = [0, 0]) |> startProfile(at = [0, 0])
|> arc(endAbsolute = [10, 10], interiorAbsolute = [5, 1], tag = $arc1) |> arc(
endAbsolute = [10, 10],
interiorAbsolute = [5, 1],
tag = $arc1,
)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine(angle = tangentToEnd(arc1), length = 20)
|> close() |> close()
``` ```
@ -82,7 +95,7 @@ bottom = startSketchOn(XY)
```kcl ```kcl
circSketch = startSketchOn(XY) circSketch = startSketchOn(XY)
|> circle(center = [0, 0], radius = 3, tag = $circ) |> circle(center = [0, 0], radius= 3, tag = $circ)
triangleSketch = startSketchOn(XY) triangleSketch = startSketchOn(XY)
|> startProfile(at = [-5, 0]) |> startProfile(at = [-5, 0])

View File

@ -60,8 +60,8 @@ layout: manual
* [`getOppositeEdge`](/docs/kcl-std/functions/std-sketch-getOppositeEdge) * [`getOppositeEdge`](/docs/kcl-std/functions/std-sketch-getOppositeEdge)
* [`getPreviousAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getPreviousAdjacentEdge) * [`getPreviousAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getPreviousAdjacentEdge)
* [`involuteCircular`](/docs/kcl-std/involuteCircular) * [`involuteCircular`](/docs/kcl-std/involuteCircular)
* [`lastSegX`](/docs/kcl-std/lastSegX) * [`lastSegX`](/docs/kcl-std/functions/std-sketch-lastSegX)
* [`lastSegY`](/docs/kcl-std/lastSegY) * [`lastSegY`](/docs/kcl-std/functions/std-sketch-lastSegY)
* [`line`](/docs/kcl-std/line) * [`line`](/docs/kcl-std/line)
* [`loft`](/docs/kcl-std/functions/std-sketch-loft) * [`loft`](/docs/kcl-std/functions/std-sketch-loft)
* [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d) * [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d)
@ -72,19 +72,19 @@ layout: manual
* [`profileStartX`](/docs/kcl-std/profileStartX) * [`profileStartX`](/docs/kcl-std/profileStartX)
* [`profileStartY`](/docs/kcl-std/profileStartY) * [`profileStartY`](/docs/kcl-std/profileStartY)
* [`revolve`](/docs/kcl-std/functions/std-sketch-revolve) * [`revolve`](/docs/kcl-std/functions/std-sketch-revolve)
* [`segAng`](/docs/kcl-std/segAng) * [`segAng`](/docs/kcl-std/functions/std-sketch-segAng)
* [`segEnd`](/docs/kcl-std/segEnd) * [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd)
* [`segEndX`](/docs/kcl-std/segEndX) * [`segEndX`](/docs/kcl-std/functions/std-sketch-segEndX)
* [`segEndY`](/docs/kcl-std/segEndY) * [`segEndY`](/docs/kcl-std/functions/std-sketch-segEndY)
* [`segLen`](/docs/kcl-std/segLen) * [`segLen`](/docs/kcl-std/functions/std-sketch-segLen)
* [`segStart`](/docs/kcl-std/segStart) * [`segStart`](/docs/kcl-std/functions/std-sketch-segStart)
* [`segStartX`](/docs/kcl-std/segStartX) * [`segStartX`](/docs/kcl-std/functions/std-sketch-segStartX)
* [`segStartY`](/docs/kcl-std/segStartY) * [`segStartY`](/docs/kcl-std/functions/std-sketch-segStartY)
* [`startProfile`](/docs/kcl-std/startProfile) * [`startProfile`](/docs/kcl-std/startProfile)
* [`startSketchOn`](/docs/kcl-std/startSketchOn) * [`startSketchOn`](/docs/kcl-std/startSketchOn)
* [`subtract2d`](/docs/kcl-std/subtract2d) * [`subtract2d`](/docs/kcl-std/subtract2d)
* [`sweep`](/docs/kcl-std/functions/std-sketch-sweep) * [`sweep`](/docs/kcl-std/functions/std-sketch-sweep)
* [`tangentToEnd`](/docs/kcl-std/tangentToEnd) * [`tangentToEnd`](/docs/kcl-std/functions/std-sketch-tangentToEnd)
* [`tangentialArc`](/docs/kcl-std/tangentialArc) * [`tangentialArc`](/docs/kcl-std/tangentialArc)
* [`xLine`](/docs/kcl-std/xLine) * [`xLine`](/docs/kcl-std/xLine)
* [`yLine`](/docs/kcl-std/yLine) * [`yLine`](/docs/kcl-std/yLine)

View File

@ -25,8 +25,8 @@ This module contains functions for creating and manipulating sketches, and makin
* [`getOppositeEdge`](/docs/kcl-std/functions/std-sketch-getOppositeEdge) * [`getOppositeEdge`](/docs/kcl-std/functions/std-sketch-getOppositeEdge)
* [`getPreviousAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getPreviousAdjacentEdge) * [`getPreviousAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getPreviousAdjacentEdge)
* [`involuteCircular`](/docs/kcl-std/involuteCircular) * [`involuteCircular`](/docs/kcl-std/involuteCircular)
* [`lastSegX`](/docs/kcl-std/lastSegX) * [`lastSegX`](/docs/kcl-std/functions/std-sketch-lastSegX)
* [`lastSegY`](/docs/kcl-std/lastSegY) * [`lastSegY`](/docs/kcl-std/functions/std-sketch-lastSegY)
* [`line`](/docs/kcl-std/line) * [`line`](/docs/kcl-std/line)
* [`loft`](/docs/kcl-std/functions/std-sketch-loft) * [`loft`](/docs/kcl-std/functions/std-sketch-loft)
* [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d) * [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d)
@ -37,19 +37,19 @@ This module contains functions for creating and manipulating sketches, and makin
* [`profileStartX`](/docs/kcl-std/profileStartX) * [`profileStartX`](/docs/kcl-std/profileStartX)
* [`profileStartY`](/docs/kcl-std/profileStartY) * [`profileStartY`](/docs/kcl-std/profileStartY)
* [`revolve`](/docs/kcl-std/functions/std-sketch-revolve) * [`revolve`](/docs/kcl-std/functions/std-sketch-revolve)
* [`segAng`](/docs/kcl-std/segAng) * [`segAng`](/docs/kcl-std/functions/std-sketch-segAng)
* [`segEnd`](/docs/kcl-std/segEnd) * [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd)
* [`segEndX`](/docs/kcl-std/segEndX) * [`segEndX`](/docs/kcl-std/functions/std-sketch-segEndX)
* [`segEndY`](/docs/kcl-std/segEndY) * [`segEndY`](/docs/kcl-std/functions/std-sketch-segEndY)
* [`segLen`](/docs/kcl-std/segLen) * [`segLen`](/docs/kcl-std/functions/std-sketch-segLen)
* [`segStart`](/docs/kcl-std/segStart) * [`segStart`](/docs/kcl-std/functions/std-sketch-segStart)
* [`segStartX`](/docs/kcl-std/segStartX) * [`segStartX`](/docs/kcl-std/functions/std-sketch-segStartX)
* [`segStartY`](/docs/kcl-std/segStartY) * [`segStartY`](/docs/kcl-std/functions/std-sketch-segStartY)
* [`startProfile`](/docs/kcl-std/startProfile) * [`startProfile`](/docs/kcl-std/startProfile)
* [`startSketchOn`](/docs/kcl-std/startSketchOn) * [`startSketchOn`](/docs/kcl-std/startSketchOn)
* [`subtract2d`](/docs/kcl-std/subtract2d) * [`subtract2d`](/docs/kcl-std/subtract2d)
* [`sweep`](/docs/kcl-std/functions/std-sketch-sweep) * [`sweep`](/docs/kcl-std/functions/std-sketch-sweep)
* [`tangentToEnd`](/docs/kcl-std/tangentToEnd) * [`tangentToEnd`](/docs/kcl-std/functions/std-sketch-tangentToEnd)
* [`tangentialArc`](/docs/kcl-std/tangentialArc) * [`tangentialArc`](/docs/kcl-std/tangentialArc)
* [`xLine`](/docs/kcl-std/xLine) * [`xLine`](/docs/kcl-std/xLine)
* [`yLine`](/docs/kcl-std/yLine) * [`yLine`](/docs/kcl-std/yLine)

File diff suppressed because it is too large Load Diff

View File

@ -1766,7 +1766,7 @@ loft001 = loft([sketch001, sketch002])
sketch001 = startSketchOn(YZ) sketch001 = startSketchOn(YZ)
profile001 = circle(sketch001, center = [0, 0], radius = 500) profile001 = circle(sketch001, center = [0, 0], radius = 500)
sketch002 = startSketchOn(XZ) sketch002 = startSketchOn(XZ)
|> startProfile(at = [0, 0]) profile002 = startProfile(sketch002, at = [0, 0])
|> xLine(length = -500) |> xLine(length = -500)
|> tangentialArc(endAbsolute = [-2000, 500])`, |> tangentialArc(endAbsolute = [-2000, 500])`,
}, },
@ -1782,7 +1782,7 @@ profile001 = startProfile(sketch001, at = [-400, -400])
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch002 = startSketchOn(XZ) sketch002 = startSketchOn(XZ)
|> startProfile(at = [0, 0]) profile002 = startProfile(sketch002, at = [0, 0])
|> xLine(length = -500) |> xLine(length = -500)
|> tangentialArc(endAbsolute = [-2000, 500])`, |> tangentialArc(endAbsolute = [-2000, 500])`,
}, },
@ -1810,9 +1810,9 @@ sketch002 = startSketchOn(XZ)
testPoint.x - 50, testPoint.x - 50,
testPoint.y testPoint.y
) )
const sweepDeclaration = 'sweep001 = sweep(profile001, path = sketch002)' const sweepDeclaration = 'sweep001 = sweep(profile001, path = profile002)'
const editedSweepDeclaration = const editedSweepDeclaration =
'sweep001 = sweep(profile001, path = sketch002, sectional = true)' 'sweep001 = sweep(profile001, path = profile002, sectional = true)'
await test.step(`Look for sketch001`, async () => { await test.step(`Look for sketch001`, async () => {
await toolbar.closePane('code') await toolbar.closePane('code')

View File

@ -2116,3 +2116,74 @@ test(
}) })
} }
) )
test(
'segment position changes persist after dragging and reopening project',
{ tag: '@desktop' },
async ({ scene, cmdBar, context, page, editor, toolbar }, testInfo) => {
const projectName = 'segment-drag-test'
await context.folderSetupFn(async (dir) => {
const projectDir = path.join(dir, projectName)
await fsp.mkdir(projectDir, { recursive: true })
await fsp.writeFile(
path.join(projectDir, 'main.kcl'),
`sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [0, 0])
|> line(end = [0, 6])
|> line(end = [10, 0])
|> line(end = [-8, -5])
`
)
})
await page.setBodyDimensions({ width: 1200, height: 600 })
const u = await getUtils(page)
await test.step('Opening the project and entering sketch mode', async () => {
await expect(page.getByText(projectName)).toBeVisible()
await page.getByText(projectName).click()
await scene.settled(cmdBar)
// go to sketch mode
await (await toolbar.getFeatureTreeOperation('Sketch', 0)).dblclick()
// Without this, "add axis n grid" action runs after editing the sketch and invokes codeManager.writeToFile()
// so we wait for that action to run first before we start editing the sketch and making sure it's saving
// because of those edits.
await page.waitForTimeout(2000)
})
const changedLine = 'line(end = [-6.54, -4.99])'
await test.step('Dragging the line endpoint to modify it', async () => {
// Get the last line's endpoint position
const lineEnd = await u.getBoundingBox('[data-overlay-index="3"]')
await page.mouse.move(lineEnd.x, lineEnd.y - 5)
await page.mouse.down()
await page.mouse.move(lineEnd.x + 80, lineEnd.y)
await page.mouse.up()
await editor.expectEditor.toContain(changedLine)
// Exit sketch mode
await page.keyboard.press('Escape')
await page.waitForTimeout(100)
})
await test.step('Going back to dashboard', async () => {
await page.getByTestId('app-logo').click()
await page.waitForTimeout(1000)
})
await test.step('Reopening the project and verifying changes are saved', async () => {
await page.getByText(projectName).click()
await scene.settled(cmdBar)
// Check if new line coordinates were saved
await editor.expectEditor.toContain(changedLine)
})
}
)

View File

@ -823,7 +823,7 @@ test('theme persists', async ({ page, context, homePage }) => {
uploadThroughput: -1, uploadThroughput: -1,
}) })
await expect(networkToggle).toContainText('Connected') await expect(networkToggle).toContainText('Network health (Strong)')
await expect(page.getByText('building scene')).not.toBeVisible() await expect(page.getByText('building scene')).not.toBeVisible()

View File

@ -14,8 +14,10 @@ test.describe('Test network related behaviors', () => {
'simulate network down and network little widget', 'simulate network down and network little widget',
{ tag: '@skipLocalEngine' }, { tag: '@skipLocalEngine' },
async ({ page, homePage }) => { async ({ page, homePage }) => {
const networkToggleConnectedText = page.getByText('Connected') const networkToggleConnectedText = page.getByText(
const networkToggleWeakText = page.getByText('Network health (Weak)') 'Network health (Strong)'
)
const networkToggleWeakText = page.getByText('Network health (Ok)')
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
@ -98,8 +100,10 @@ test.describe('Test network related behaviors', () => {
{ tag: '@skipLocalEngine' }, { tag: '@skipLocalEngine' },
async ({ page, homePage, toolbar, scene, cmdBar }) => { async ({ page, homePage, toolbar, scene, cmdBar }) => {
const networkToggle = page.getByTestId('network-toggle') const networkToggle = page.getByTestId('network-toggle')
const networkToggleConnectedText = page.getByText('Connected') const networkToggleConnectedText = page.getByText(
const networkToggleWeakText = page.getByText('Network health (Weak)') 'Network health (Strong)'
)
const networkToggleWeakText = page.getByText('Network health (Ok)')
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
@ -282,8 +286,10 @@ profile001 = startProfile(sketch001, at = [12.34, -12.34])
{ tag: ['@desktop', '@skipLocalEngine'] }, { tag: ['@desktop', '@skipLocalEngine'] },
async ({ page, homePage, scene, cmdBar, toolbar, tronApp }) => { async ({ page, homePage, scene, cmdBar, toolbar, tronApp }) => {
const networkToggle = page.getByTestId('network-toggle') const networkToggle = page.getByTestId('network-toggle')
const networkToggleConnectedText = page.getByText('Connected') const networkToggleConnectedText = page.getByText(
const networkToggleWeakText = page.getByText('Network health (Weak)') 'Network health (Strong)'
)
const networkToggleWeakText = page.getByText('Network health (Ok)')
if (!tronApp) { if (!tronApp) {
fail() fail()

View File

@ -27,7 +27,7 @@ if len(modified_release_body) > max_length:
# Message to send to Discord # Message to send to Discord
data = { data = {
"content": textwrap.dedent(f''' "content": textwrap.dedent(f'''
**{release_version}** is now available! Check out the latest features and improvements here: <https://zoo.dev/design-studio> **{release_version}** is now available! Check out the latest features and improvements here: <https://zoo.dev/design-studio/download#added>
{modified_release_body} {modified_release_body}
'''), '''),

View File

@ -11,24 +11,20 @@ filletRadius = 0.5
plateThickness = .5 plateThickness = .5
centerHoleDiameter = 2 centerHoleDiameter = 2
// Create a function that defines the body width and length of the mounting plate. Tag the corners so they can be passed through the fillet function.
fn rectShape(pos, w, l) {
rr = startSketchOn(XY)
|> startProfile(at = [pos[0] - (w / 2), pos[1] - (l / 2)])
|> line(endAbsolute = [pos[0] + w / 2, pos[1] - (l / 2)], tag = $edge1)
|> line(endAbsolute = [pos[0] + w / 2, pos[1] + l / 2], tag = $edge2)
|> line(endAbsolute = [pos[0] - (w / 2), pos[1] + l / 2], tag = $edge3)
|> close(tag = $edge4)
return rr
}
// Define the hole radius and x, y location constants // Define the hole radius and x, y location constants
holeRadius = .25 holeRadius = .25
holeIndex = .75 holeIndex = .75
sketch001 = startSketchOn(XY)
rectShape = startProfile(sketch001, at = [-plateWidth / 2, plateLength / 2])
|> angledLine(angle = 0, length = plateWidth, tag = $basePlateEdge1)
|> angledLine(angle = segAng(basePlateEdge1) - 90, length = plateLength, tag = $basePlateEdge2)
|> angledLine(angle = segAng(basePlateEdge1), length = -segLen(basePlateEdge1), tag = $basePlateEdge3)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $basePlateEdge4)
|> close()
// Create the mounting plate extrusion, holes, and fillets // Create the mounting plate extrusion, holes, and fillets
rs = rectShape(pos = [0, 0], w = plateWidth, l = plateLength) part = rectShape
part = rs
|> subtract2d(tool = circle( |> subtract2d(tool = circle(
center = [ center = [
-plateWidth / 2 + holeIndex, -plateWidth / 2 + holeIndex,
@ -62,9 +58,9 @@ part = rs
|> fillet( |> fillet(
radius = filletRadius, radius = filletRadius,
tags = [ tags = [
getPreviousAdjacentEdge(rs.tags.edge1), getCommonEdge(faces = [basePlateEdge3, basePlateEdge2]),
getPreviousAdjacentEdge(rs.tags.edge2), getCommonEdge(faces = [basePlateEdge4, basePlateEdge3]),
getPreviousAdjacentEdge(rs.tags.edge3), getCommonEdge(faces = [basePlateEdge4, basePlateEdge1]),
getPreviousAdjacentEdge(rs.tags.edge4) getCommonEdge(faces = [basePlateEdge2, basePlateEdge1])
], ],
) )

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

20
rust/Cargo.lock generated
View File

@ -1815,7 +1815,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-bumper" name = "kcl-bumper"
version = "0.1.77" version = "0.1.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@ -1826,7 +1826,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-derive-docs" name = "kcl-derive-docs"
version = "0.1.77" version = "0.1.78"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"anyhow", "anyhow",
@ -1845,7 +1845,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-directory-test-macro" name = "kcl-directory-test-macro"
version = "0.1.77" version = "0.1.78"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"proc-macro2", "proc-macro2",
@ -1855,7 +1855,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-language-server" name = "kcl-language-server"
version = "0.2.77" version = "0.2.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@ -1876,7 +1876,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-language-server-release" name = "kcl-language-server-release"
version = "0.1.77" version = "0.1.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@ -1896,7 +1896,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-lib" name = "kcl-lib"
version = "0.2.77" version = "0.2.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"approx 0.5.1", "approx 0.5.1",
@ -1973,7 +1973,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-python-bindings" name = "kcl-python-bindings"
version = "0.3.77" version = "0.3.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"kcl-lib", "kcl-lib",
@ -1988,7 +1988,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-test-server" name = "kcl-test-server"
version = "0.1.77" version = "0.1.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"hyper 0.14.32", "hyper 0.14.32",
@ -2001,7 +2001,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-to-core" name = "kcl-to-core"
version = "0.1.77" version = "0.1.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -2015,7 +2015,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-wasm-lib" name = "kcl-wasm-lib"
version = "0.1.77" version = "0.1.78"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bson", "bson",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "kcl-bumper" name = "kcl-bumper"
version = "0.1.77" version = "0.1.78"
edition = "2021" edition = "2021"
repository = "https://github.com/KittyCAD/modeling-api" repository = "https://github.com/KittyCAD/modeling-api"
rust-version = "1.76" rust-version = "1.76"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "kcl-derive-docs" name = "kcl-derive-docs"
description = "A tool for generating documentation from Rust derive macros" description = "A tool for generating documentation from Rust derive macros"
version = "0.1.77" version = "0.1.78"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -134,6 +134,21 @@ pub const TEST_NAMES: &[&str] = &[
"std-sketch-patternLinear2d-1", "std-sketch-patternLinear2d-1",
"std-sketch-patternCircular2d-0", "std-sketch-patternCircular2d-0",
"std-sketch-circleThreePoint-0", "std-sketch-circleThreePoint-0",
"std-sketch-segStart-0",
"std-sketch-segStartX-0",
"std-sketch-segStartY-0",
"std-sketch-segEnd-0",
"std-sketch-segEndX-0",
"std-sketch-segEndY-0",
"std-sketch-lastSegX-0",
"std-sketch-lastSegY-0",
"std-sketch-segAng-0",
"std-sketch-segLen-0",
"std-sketch-tangentToEnd-0",
"std-sketch-tangentToEnd-1",
"std-sketch-tangentToEnd-2",
"std-sketch-tangentToEnd-3",
"std-sketch-tangentToEnd-4",
"std-solid-appearance-0", "std-solid-appearance-0",
"std-solid-appearance-1", "std-solid-appearance-1",
"std-solid-appearance-2", "std-solid-appearance-2",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "kcl-directory-test-macro" name = "kcl-directory-test-macro"
description = "A tool for generating tests from a directory of kcl files" description = "A tool for generating tests from a directory of kcl files"
version = "0.1.77" version = "0.1.78"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "kcl-language-server-release" name = "kcl-language-server-release"
version = "0.1.77" version = "0.1.78"
edition = "2021" edition = "2021"
authors = ["KittyCAD Inc <kcl@kittycad.io>"] authors = ["KittyCAD Inc <kcl@kittycad.io>"]
publish = false publish = false

View File

@ -2,7 +2,7 @@
name = "kcl-language-server" name = "kcl-language-server"
description = "A language server for KCL." description = "A language server for KCL."
authors = ["KittyCAD Inc <kcl@kittycad.io>"] authors = ["KittyCAD Inc <kcl@kittycad.io>"]
version = "0.2.77" version = "0.2.78"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,7 +1,7 @@
[package] [package]
name = "kcl-lib" name = "kcl-lib"
description = "KittyCAD Language implementation and tools" description = "KittyCAD Language implementation and tools"
version = "0.2.77" version = "0.2.78"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -439,7 +439,7 @@ impl EngineManager for EngineConnection {
request_sent: tx, request_sent: tx,
}) })
.await .await
.map_err(|e| KclError::Engine(KclErrorDetails::new(format!("Failed to send debug: {}", e), vec![])))?; .map_err(|e| KclError::new_engine(KclErrorDetails::new(format!("Failed to send debug: {}", e), vec![])))?;
let _ = rx.await; let _ = rx.await;
Ok(()) Ok(())
@ -474,7 +474,7 @@ impl EngineManager for EngineConnection {
}) })
.await .await
.map_err(|e| { .map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to send modeling command: {}", e), format!("Failed to send modeling command: {}", e),
vec![source_range], vec![source_range],
)) ))
@ -483,13 +483,13 @@ impl EngineManager for EngineConnection {
// Wait for the request to be sent. // Wait for the request to be sent.
rx.await rx.await
.map_err(|e| { .map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("could not send request to the engine actor: {e}"), format!("could not send request to the engine actor: {e}"),
vec![source_range], vec![source_range],
)) ))
})? })?
.map_err(|e| { .map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("could not send request to the engine: {e}"), format!("could not send request to the engine: {e}"),
vec![source_range], vec![source_range],
)) ))
@ -516,12 +516,12 @@ impl EngineManager for EngineConnection {
// Check if we have any pending errors. // Check if we have any pending errors.
let pe = self.pending_errors.read().await; let pe = self.pending_errors.read().await;
if !pe.is_empty() { if !pe.is_empty() {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
pe.join(", ").to_string(), pe.join(", ").to_string(),
vec![source_range], vec![source_range],
))); )));
} else { } else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
"Modeling command failed: websocket closed early".to_string(), "Modeling command failed: websocket closed early".to_string(),
vec![source_range], vec![source_range],
))); )));
@ -543,7 +543,7 @@ impl EngineManager for EngineConnection {
} }
} }
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
format!("Modeling command timed out `{}`", id), format!("Modeling command timed out `{}`", id),
vec![source_range], vec![source_range],
))) )))

View File

@ -147,19 +147,19 @@ impl EngineConnection {
id_to_source_range: HashMap<uuid::Uuid, SourceRange>, id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
) -> Result<(), KclError> { ) -> Result<(), KclError> {
let source_range_str = serde_json::to_string(&source_range).map_err(|e| { let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to serialize source range: {:?}", e), format!("Failed to serialize source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let cmd_str = serde_json::to_string(&cmd).map_err(|e| { let cmd_str = serde_json::to_string(&cmd).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to serialize modeling command: {:?}", e), format!("Failed to serialize modeling command: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| { let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to serialize id to source range: {:?}", e), format!("Failed to serialize id to source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -167,7 +167,7 @@ impl EngineConnection {
self.manager self.manager
.fire_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str) .fire_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str)
.map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?; .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
Ok(()) Ok(())
} }
@ -180,19 +180,19 @@ impl EngineConnection {
id_to_source_range: HashMap<uuid::Uuid, SourceRange>, id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
) -> Result<WebSocketResponse, KclError> { ) -> Result<WebSocketResponse, KclError> {
let source_range_str = serde_json::to_string(&source_range).map_err(|e| { let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to serialize source range: {:?}", e), format!("Failed to serialize source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let cmd_str = serde_json::to_string(&cmd).map_err(|e| { let cmd_str = serde_json::to_string(&cmd).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to serialize modeling command: {:?}", e), format!("Failed to serialize modeling command: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| { let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to serialize id to source range: {:?}", e), format!("Failed to serialize id to source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -201,7 +201,7 @@ impl EngineConnection {
let promise = self let promise = self
.manager .manager
.send_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str) .send_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str)
.map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?; .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
let value = crate::wasm::JsFuture::from(promise).await.map_err(|e| { let value = crate::wasm::JsFuture::from(promise).await.map_err(|e| {
// Try to parse the error as an engine error. // Try to parse the error as an engine error.
@ -209,7 +209,7 @@ impl EngineConnection {
if let Ok(kittycad_modeling_cmds::websocket::FailureWebSocketResponse { errors, .. }) = if let Ok(kittycad_modeling_cmds::websocket::FailureWebSocketResponse { errors, .. }) =
serde_json::from_str(&err_str) serde_json::from_str(&err_str)
{ {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"), errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"),
vec![source_range], vec![source_range],
)) ))
@ -218,7 +218,7 @@ impl EngineConnection {
{ {
if let Some(data) = data.first() { if let Some(data) = data.first() {
// It could also be an array of responses. // It could also be an array of responses.
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
data.errors data.errors
.iter() .iter()
.map(|e| e.message.clone()) .map(|e| e.message.clone())
@ -227,13 +227,13 @@ impl EngineConnection {
vec![source_range], vec![source_range],
)) ))
} else { } else {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
"Received empty response from engine".into(), "Received empty response from engine".into(),
vec![source_range], vec![source_range],
)) ))
} }
} else { } else {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to wait for promise from send modeling command: {:?}", e), format!("Failed to wait for promise from send modeling command: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -241,7 +241,7 @@ impl EngineConnection {
})?; })?;
if value.is_null() || value.is_undefined() { if value.is_null() || value.is_undefined() {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
"Received null or undefined response from engine".into(), "Received null or undefined response from engine".into(),
vec![source_range], vec![source_range],
))); )));
@ -251,7 +251,7 @@ impl EngineConnection {
let data = js_sys::Uint8Array::from(value); let data = js_sys::Uint8Array::from(value);
let ws_result: WebSocketResponse = bson::from_slice(&data.to_vec()).map_err(|e| { let ws_result: WebSocketResponse = bson::from_slice(&data.to_vec()).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to deserialize bson response from engine: {:?}", e), format!("Failed to deserialize bson response from engine: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -308,10 +308,10 @@ impl crate::engine::EngineManager for EngineConnection {
let promise = self let promise = self
.manager .manager
.start_new_session() .start_new_session()
.map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?; .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
crate::wasm::JsFuture::from(promise).await.map_err(|e| { crate::wasm::JsFuture::from(promise).await.map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to wait for promise from start new session: {:?}", e), format!("Failed to wait for promise from start new session: {:?}", e),
vec![source_range], vec![source_range],
)) ))

View File

@ -276,7 +276,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
{ {
let duration = instant::Duration::from_millis(1); let duration = instant::Duration::from_millis(1);
wasm_timer::Delay::new(duration).await.map_err(|err| { wasm_timer::Delay::new(duration).await.map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to sleep: {:?}", err), format!("Failed to sleep: {:?}", err),
vec![source_range], vec![source_range],
)) ))
@ -293,7 +293,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
return Ok(response); return Ok(response);
} }
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
"async command timed out".to_string(), "async command timed out".to_string(),
vec![source_range], vec![source_range],
))) )))
@ -547,7 +547,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
id_to_source_range.insert(Uuid::from(*cmd_id), *range); id_to_source_range.insert(Uuid::from(*cmd_id), *range);
} }
_ => { _ => {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("The request is not a modeling command: {:?}", req), format!("The request is not a modeling command: {:?}", req),
vec![*range], vec![*range],
))); )));
@ -595,7 +595,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
self.parse_batch_responses(last_id.into(), id_to_source_range, responses) self.parse_batch_responses(last_id.into(), id_to_source_range, responses)
} else { } else {
// We should never get here. // We should never get here.
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
format!("Failed to get batch response: {:?}", response), format!("Failed to get batch response: {:?}", response),
vec![source_range], vec![source_range],
))) )))
@ -610,7 +610,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// request so we need the original request source range in case the engine returns // request so we need the original request source range in case the engine returns
// an error. // an error.
let source_range = id_to_source_range.get(cmd_id.as_ref()).cloned().ok_or_else(|| { let source_range = id_to_source_range.get(cmd_id.as_ref()).cloned().ok_or_else(|| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to get source range for command ID: {:?}", cmd_id), format!("Failed to get source range for command ID: {:?}", cmd_id),
vec![], vec![],
)) ))
@ -620,7 +620,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
.await?; .await?;
self.parse_websocket_response(ws_resp, source_range) self.parse_websocket_response(ws_resp, source_range)
} }
_ => Err(KclError::Engine(KclErrorDetails::new( _ => Err(KclError::new_engine(KclErrorDetails::new(
format!("The final request is not a modeling command: {:?}", final_req), format!("The final request is not a modeling command: {:?}", final_req),
vec![source_range], vec![source_range],
))), ))),
@ -729,7 +729,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
for (name, plane_id, color) in plane_settings { for (name, plane_id, color) in plane_settings {
let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| { let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
// We should never get here. // We should never get here.
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to get default plane info for: {:?}", name), format!("Failed to get default plane info for: {:?}", name),
vec![source_range], vec![source_range],
)) ))
@ -763,7 +763,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
WebSocketResponse::Success(success) => Ok(success.resp), WebSocketResponse::Success(success) => Ok(success.resp),
WebSocketResponse::Failure(fail) => { WebSocketResponse::Failure(fail) => {
let _request_id = fail.request_id; let _request_id = fail.request_id;
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
fail.errors fail.errors
.iter() .iter()
.map(|e| e.message.clone()) .map(|e| e.message.clone())
@ -805,12 +805,12 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
BatchResponse::Failure { errors } => { BatchResponse::Failure { errors } => {
// Get the source range for the command. // Get the source range for the command.
let source_range = id_to_source_range.get(cmd_id).cloned().ok_or_else(|| { let source_range = id_to_source_range.get(cmd_id).cloned().ok_or_else(|| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to get source range for command ID: {:?}", cmd_id), format!("Failed to get source range for command ID: {:?}", cmd_id),
vec![], vec![],
)) ))
})?; })?;
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"), errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"),
vec![source_range], vec![source_range],
))); )));
@ -820,7 +820,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// Return an error that we did not get an error or the response we wanted. // Return an error that we did not get an error or the response we wanted.
// This should never happen but who knows. // This should never happen but who knows.
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
format!("Failed to find response for command ID: {:?}", id), format!("Failed to find response for command ID: {:?}", id),
vec![], vec![],
))) )))

View File

@ -91,30 +91,33 @@ pub enum ConnectionError {
#[ts(export)] #[ts(export)]
#[serde(tag = "kind", rename_all = "snake_case")] #[serde(tag = "kind", rename_all = "snake_case")]
pub enum KclError { pub enum KclError {
#[error("lexical: {0:?}")] #[error("lexical: {details:?}")]
Lexical(KclErrorDetails), Lexical { details: KclErrorDetails },
#[error("syntax: {0:?}")] #[error("syntax: {details:?}")]
Syntax(KclErrorDetails), Syntax { details: KclErrorDetails },
#[error("semantic: {0:?}")] #[error("semantic: {details:?}")]
Semantic(KclErrorDetails), Semantic { details: KclErrorDetails },
#[error("import cycle: {0:?}")] #[error("import cycle: {details:?}")]
ImportCycle(KclErrorDetails), ImportCycle { details: KclErrorDetails },
#[error("type: {0:?}")] #[error("type: {details:?}")]
Type(KclErrorDetails), Type { details: KclErrorDetails },
#[error("i/o: {0:?}")] #[error("i/o: {details:?}")]
Io(KclErrorDetails), Io { details: KclErrorDetails },
#[error("unexpected: {0:?}")] #[error("unexpected: {details:?}")]
Unexpected(KclErrorDetails), Unexpected { details: KclErrorDetails },
#[error("value already defined: {0:?}")] #[error("value already defined: {details:?}")]
ValueAlreadyDefined(KclErrorDetails), ValueAlreadyDefined { details: KclErrorDetails },
#[error("undefined value: {0:?}")] #[error("undefined value: {details:?}")]
UndefinedValue(KclErrorDetails), UndefinedValue {
#[error("invalid expression: {0:?}")] details: KclErrorDetails,
InvalidExpression(KclErrorDetails), name: Option<String>,
#[error("engine: {0:?}")] },
Engine(KclErrorDetails), #[error("invalid expression: {details:?}")]
#[error("internal error, please report to KittyCAD team: {0:?}")] InvalidExpression { details: KclErrorDetails },
Internal(KclErrorDetails), #[error("engine: {details:?}")]
Engine { details: KclErrorDetails },
#[error("internal error, please report to KittyCAD team: {details:?}")]
Internal { details: KclErrorDetails },
} }
impl From<KclErrorWithOutputs> for KclError { impl From<KclErrorWithOutputs> for KclError {
@ -296,18 +299,18 @@ pub struct ReportWithOutputs {
impl miette::Diagnostic for ReportWithOutputs { impl miette::Diagnostic for ReportWithOutputs {
fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> { fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
let family = match self.error.error { let family = match self.error.error {
KclError::Lexical(_) => "Lexical", KclError::Lexical { .. } => "Lexical",
KclError::Syntax(_) => "Syntax", KclError::Syntax { .. } => "Syntax",
KclError::Semantic(_) => "Semantic", KclError::Semantic { .. } => "Semantic",
KclError::ImportCycle(_) => "ImportCycle", KclError::ImportCycle { .. } => "ImportCycle",
KclError::Type(_) => "Type", KclError::Type { .. } => "Type",
KclError::Io(_) => "I/O", KclError::Io { .. } => "I/O",
KclError::Unexpected(_) => "Unexpected", KclError::Unexpected { .. } => "Unexpected",
KclError::ValueAlreadyDefined(_) => "ValueAlreadyDefined", KclError::ValueAlreadyDefined { .. } => "ValueAlreadyDefined",
KclError::UndefinedValue(_) => "UndefinedValue", KclError::UndefinedValue { .. } => "UndefinedValue",
KclError::InvalidExpression(_) => "InvalidExpression", KclError::InvalidExpression { .. } => "InvalidExpression",
KclError::Engine(_) => "Engine", KclError::Engine { .. } => "Engine",
KclError::Internal(_) => "Internal", KclError::Internal { .. } => "Internal",
}; };
let error_string = format!("KCL {family} error"); let error_string = format!("KCL {family} error");
Some(Box::new(error_string)) Some(Box::new(error_string))
@ -346,18 +349,18 @@ pub struct Report {
impl miette::Diagnostic for Report { impl miette::Diagnostic for Report {
fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> { fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
let family = match self.error { let family = match self.error {
KclError::Lexical(_) => "Lexical", KclError::Lexical { .. } => "Lexical",
KclError::Syntax(_) => "Syntax", KclError::Syntax { .. } => "Syntax",
KclError::Semantic(_) => "Semantic", KclError::Semantic { .. } => "Semantic",
KclError::ImportCycle(_) => "ImportCycle", KclError::ImportCycle { .. } => "ImportCycle",
KclError::Type(_) => "Type", KclError::Type { .. } => "Type",
KclError::Io(_) => "I/O", KclError::Io { .. } => "I/O",
KclError::Unexpected(_) => "Unexpected", KclError::Unexpected { .. } => "Unexpected",
KclError::ValueAlreadyDefined(_) => "ValueAlreadyDefined", KclError::ValueAlreadyDefined { .. } => "ValueAlreadyDefined",
KclError::UndefinedValue(_) => "UndefinedValue", KclError::UndefinedValue { .. } => "UndefinedValue",
KclError::InvalidExpression(_) => "InvalidExpression", KclError::InvalidExpression { .. } => "InvalidExpression",
KclError::Engine(_) => "Engine", KclError::Engine { .. } => "Engine",
KclError::Internal(_) => "Internal", KclError::Internal { .. } => "Internal",
}; };
let error_string = format!("KCL {family} error"); let error_string = format!("KCL {family} error");
Some(Box::new(error_string)) Some(Box::new(error_string))
@ -410,11 +413,53 @@ impl KclErrorDetails {
impl KclError { impl KclError {
pub fn internal(message: String) -> KclError { pub fn internal(message: String) -> KclError {
KclError::Internal(KclErrorDetails { KclError::Internal {
source_ranges: Default::default(), details: KclErrorDetails {
backtrace: Default::default(), source_ranges: Default::default(),
message, backtrace: Default::default(),
}) message,
},
}
}
pub fn new_internal(details: KclErrorDetails) -> KclError {
KclError::Internal { details }
}
pub fn new_import_cycle(details: KclErrorDetails) -> KclError {
KclError::ImportCycle { details }
}
pub fn new_semantic(details: KclErrorDetails) -> KclError {
KclError::Semantic { details }
}
pub fn new_value_already_defined(details: KclErrorDetails) -> KclError {
KclError::ValueAlreadyDefined { details }
}
pub fn new_syntax(details: KclErrorDetails) -> KclError {
KclError::Syntax { details }
}
pub fn new_io(details: KclErrorDetails) -> KclError {
KclError::Io { details }
}
pub fn new_engine(details: KclErrorDetails) -> KclError {
KclError::Engine { details }
}
pub fn new_lexical(details: KclErrorDetails) -> KclError {
KclError::Lexical { details }
}
pub fn new_undefined_value(details: KclErrorDetails, name: Option<String>) -> KclError {
KclError::UndefinedValue { details, name }
}
pub fn new_type(details: KclErrorDetails) -> KclError {
KclError::Type { details }
} }
/// Get the error message. /// Get the error message.
@ -424,88 +469,88 @@ impl KclError {
pub fn error_type(&self) -> &'static str { pub fn error_type(&self) -> &'static str {
match self { match self {
KclError::Lexical(_) => "lexical", KclError::Lexical { .. } => "lexical",
KclError::Syntax(_) => "syntax", KclError::Syntax { .. } => "syntax",
KclError::Semantic(_) => "semantic", KclError::Semantic { .. } => "semantic",
KclError::ImportCycle(_) => "import cycle", KclError::ImportCycle { .. } => "import cycle",
KclError::Type(_) => "type", KclError::Type { .. } => "type",
KclError::Io(_) => "i/o", KclError::Io { .. } => "i/o",
KclError::Unexpected(_) => "unexpected", KclError::Unexpected { .. } => "unexpected",
KclError::ValueAlreadyDefined(_) => "value already defined", KclError::ValueAlreadyDefined { .. } => "value already defined",
KclError::UndefinedValue(_) => "undefined value", KclError::UndefinedValue { .. } => "undefined value",
KclError::InvalidExpression(_) => "invalid expression", KclError::InvalidExpression { .. } => "invalid expression",
KclError::Engine(_) => "engine", KclError::Engine { .. } => "engine",
KclError::Internal(_) => "internal", KclError::Internal { .. } => "internal",
} }
} }
pub fn source_ranges(&self) -> Vec<SourceRange> { pub fn source_ranges(&self) -> Vec<SourceRange> {
match &self { match &self {
KclError::Lexical(e) => e.source_ranges.clone(), KclError::Lexical { details: e } => e.source_ranges.clone(),
KclError::Syntax(e) => e.source_ranges.clone(), KclError::Syntax { details: e } => e.source_ranges.clone(),
KclError::Semantic(e) => e.source_ranges.clone(), KclError::Semantic { details: e } => e.source_ranges.clone(),
KclError::ImportCycle(e) => e.source_ranges.clone(), KclError::ImportCycle { details: e } => e.source_ranges.clone(),
KclError::Type(e) => e.source_ranges.clone(), KclError::Type { details: e } => e.source_ranges.clone(),
KclError::Io(e) => e.source_ranges.clone(), KclError::Io { details: e } => e.source_ranges.clone(),
KclError::Unexpected(e) => e.source_ranges.clone(), KclError::Unexpected { details: e } => e.source_ranges.clone(),
KclError::ValueAlreadyDefined(e) => e.source_ranges.clone(), KclError::ValueAlreadyDefined { details: e } => e.source_ranges.clone(),
KclError::UndefinedValue(e) => e.source_ranges.clone(), KclError::UndefinedValue { details: e, .. } => e.source_ranges.clone(),
KclError::InvalidExpression(e) => e.source_ranges.clone(), KclError::InvalidExpression { details: e } => e.source_ranges.clone(),
KclError::Engine(e) => e.source_ranges.clone(), KclError::Engine { details: e } => e.source_ranges.clone(),
KclError::Internal(e) => e.source_ranges.clone(), KclError::Internal { details: e } => e.source_ranges.clone(),
} }
} }
/// Get the inner error message. /// Get the inner error message.
pub fn message(&self) -> &str { pub fn message(&self) -> &str {
match &self { match &self {
KclError::Lexical(e) => &e.message, KclError::Lexical { details: e } => &e.message,
KclError::Syntax(e) => &e.message, KclError::Syntax { details: e } => &e.message,
KclError::Semantic(e) => &e.message, KclError::Semantic { details: e } => &e.message,
KclError::ImportCycle(e) => &e.message, KclError::ImportCycle { details: e } => &e.message,
KclError::Type(e) => &e.message, KclError::Type { details: e } => &e.message,
KclError::Io(e) => &e.message, KclError::Io { details: e } => &e.message,
KclError::Unexpected(e) => &e.message, KclError::Unexpected { details: e } => &e.message,
KclError::ValueAlreadyDefined(e) => &e.message, KclError::ValueAlreadyDefined { details: e } => &e.message,
KclError::UndefinedValue(e) => &e.message, KclError::UndefinedValue { details: e, .. } => &e.message,
KclError::InvalidExpression(e) => &e.message, KclError::InvalidExpression { details: e } => &e.message,
KclError::Engine(e) => &e.message, KclError::Engine { details: e } => &e.message,
KclError::Internal(e) => &e.message, KclError::Internal { details: e } => &e.message,
} }
} }
pub fn backtrace(&self) -> Vec<BacktraceItem> { pub fn backtrace(&self) -> Vec<BacktraceItem> {
match self { match self {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e, .. }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => e.backtrace.clone(), | KclError::Internal { details: e } => e.backtrace.clone(),
} }
} }
pub(crate) fn override_source_ranges(&self, source_ranges: Vec<SourceRange>) -> Self { pub(crate) fn override_source_ranges(&self, source_ranges: Vec<SourceRange>) -> Self {
let mut new = self.clone(); let mut new = self.clone();
match &mut new { match &mut new {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e, .. }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => { | KclError::Internal { details: e } => {
e.backtrace = source_ranges e.backtrace = source_ranges
.iter() .iter()
.map(|s| BacktraceItem { .map(|s| BacktraceItem {
@ -523,18 +568,18 @@ impl KclError {
pub(crate) fn set_last_backtrace_fn_name(&self, last_fn_name: Option<String>) -> Self { pub(crate) fn set_last_backtrace_fn_name(&self, last_fn_name: Option<String>) -> Self {
let mut new = self.clone(); let mut new = self.clone();
match &mut new { match &mut new {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e, .. }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => { | KclError::Internal { details: e } => {
if let Some(item) = e.backtrace.last_mut() { if let Some(item) = e.backtrace.last_mut() {
item.fn_name = last_fn_name; item.fn_name = last_fn_name;
} }
@ -547,18 +592,18 @@ impl KclError {
pub(crate) fn add_unwind_location(&self, last_fn_name: Option<String>, source_range: SourceRange) -> Self { pub(crate) fn add_unwind_location(&self, last_fn_name: Option<String>, source_range: SourceRange) -> Self {
let mut new = self.clone(); let mut new = self.clone();
match &mut new { match &mut new {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e, .. }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => { | KclError::Internal { details: e } => {
if let Some(item) = e.backtrace.last_mut() { if let Some(item) = e.backtrace.last_mut() {
item.fn_name = last_fn_name; item.fn_name = last_fn_name;
} }
@ -645,7 +690,7 @@ impl From<String> for KclError {
#[cfg(feature = "pyo3")] #[cfg(feature = "pyo3")]
impl From<pyo3::PyErr> for KclError { impl From<pyo3::PyErr> for KclError {
fn from(error: pyo3::PyErr) -> Self { fn from(error: pyo3::PyErr) -> Self {
KclError::Internal(KclErrorDetails { KclError::new_internal(KclErrorDetails {
source_ranges: vec![], source_ranges: vec![],
backtrace: Default::default(), backtrace: Default::default(),
message: error.to_string(), message: error.to_string(),

View File

@ -70,7 +70,7 @@ pub(super) fn expect_properties<'a>(
) -> Result<&'a [Node<ObjectProperty>], KclError> { ) -> Result<&'a [Node<ObjectProperty>], KclError> {
assert_eq!(annotation.name().unwrap(), for_key); assert_eq!(annotation.name().unwrap(), for_key);
Ok(&**annotation.properties.as_ref().ok_or_else(|| { Ok(&**annotation.properties.as_ref().ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Empty `{for_key}` annotation"), format!("Empty `{for_key}` annotation"),
vec![annotation.as_source_range()], vec![annotation.as_source_range()],
)) ))
@ -84,7 +84,7 @@ pub(super) fn expect_ident(expr: &Expr) -> Result<&str, KclError> {
} }
} }
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
"Unexpected settings value, expected a simple name, e.g., `mm`".to_owned(), "Unexpected settings value, expected a simple name, e.g., `mm`".to_owned(),
vec![expr.into()], vec![expr.into()],
))) )))
@ -98,7 +98,7 @@ pub(super) fn expect_number(expr: &Expr) -> Result<String, KclError> {
} }
} }
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
"Unexpected settings value, expected a number, e.g., `1.0`".to_owned(), "Unexpected settings value, expected a number, e.g., `1.0`".to_owned(),
vec![expr.into()], vec![expr.into()],
))) )))
@ -113,7 +113,7 @@ pub(super) fn get_impl(annotations: &[Node<Annotation>], source_range: SourceRan
if &*p.key.name == IMPL { if &*p.key.name == IMPL {
if let Some(s) = p.value.ident_name() { if let Some(s) = p.value.ident_name() {
return Impl::from_str(s).map(Some).map_err(|_| { return Impl::from_str(s).map(Some).map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Invalid value for {} attribute, expected one of: {}", "Invalid value for {} attribute, expected one of: {}",
IMPL, IMPL,
@ -139,7 +139,7 @@ impl UnitLen {
"inch" | "in" => Ok(UnitLen::Inches), "inch" | "in" => Ok(UnitLen::Inches),
"ft" => Ok(UnitLen::Feet), "ft" => Ok(UnitLen::Feet),
"yd" => Ok(UnitLen::Yards), "yd" => Ok(UnitLen::Yards),
value => Err(KclError::Semantic(KclErrorDetails::new( value => Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unexpected value for length units: `{value}`; expected one of `mm`, `cm`, `m`, `in`, `ft`, `yd`" "Unexpected value for length units: `{value}`; expected one of `mm`, `cm`, `m`, `in`, `ft`, `yd`"
), ),
@ -154,7 +154,7 @@ impl UnitAngle {
match s { match s {
"deg" => Ok(UnitAngle::Degrees), "deg" => Ok(UnitAngle::Degrees),
"rad" => Ok(UnitAngle::Radians), "rad" => Ok(UnitAngle::Radians),
value => Err(KclError::Semantic(KclErrorDetails::new( value => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Unexpected value for angle units: `{value}`; expected one of `deg`, `rad`"), format!("Unexpected value for angle units: `{value}`; expected one of `deg`, `rad`"),
vec![source_range], vec![source_range],
))), ))),

View File

@ -24,7 +24,7 @@ macro_rules! internal_error {
($range:expr, $($rest:tt)*) => {{ ($range:expr, $($rest:tt)*) => {{
let message = format!($($rest)*); let message = format!($($rest)*);
debug_assert!(false, "{}", &message); debug_assert!(false, "{}", &message);
return Err(KclError::Internal(KclErrorDetails::new(message, vec![$range]))); return Err(KclError::new_internal(KclErrorDetails::new(message, vec![$range])));
}}; }};
} }
@ -949,7 +949,7 @@ fn artifacts_to_update(
ModelingCmd::StartPath(_) => { ModelingCmd::StartPath(_) => {
let mut return_arr = Vec::new(); let mut return_arr = Vec::new();
let current_plane_id = path_to_plane_id_map.get(&artifact_command.cmd_id).ok_or_else(|| { let current_plane_id = path_to_plane_id_map.get(&artifact_command.cmd_id).ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Expected a current plane ID when processing StartPath command, but we have none: {id:?}"), format!("Expected a current plane ID when processing StartPath command, but we have none: {id:?}"),
vec![range], vec![range],
)) ))
@ -1137,7 +1137,7 @@ fn artifacts_to_update(
// TODO: Using the first one. Make sure to revisit this // TODO: Using the first one. Make sure to revisit this
// choice, don't think it matters for now. // choice, don't think it matters for now.
path_id: ArtifactId::new(*loft_cmd.section_ids.first().ok_or_else(|| { path_id: ArtifactId::new(*loft_cmd.section_ids.first().ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Expected at least one section ID in Loft command: {id:?}; cmd={cmd:?}"), format!("Expected at least one section ID in Loft command: {id:?}; cmd={cmd:?}"),
vec![range], vec![range],
)) ))
@ -1180,7 +1180,7 @@ fn artifacts_to_update(
}; };
last_path = Some(path); last_path = Some(path);
let path_sweep_id = path.sweep_id.ok_or_else(|| { let path_sweep_id = path.sweep_id.ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!( format!(
"Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" "Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}"
), ),
@ -1234,7 +1234,7 @@ fn artifacts_to_update(
continue; continue;
}; };
let path_sweep_id = path.sweep_id.ok_or_else(|| { let path_sweep_id = path.sweep_id.ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!( format!(
"Expected a sweep ID on the path when processing last path's Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" "Expected a sweep ID on the path when processing last path's Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}"
), ),

View File

@ -131,7 +131,7 @@ impl ExecutorContext {
match statement { match statement {
BodyItem::ImportStatement(import_stmt) => { BodyItem::ImportStatement(import_stmt) => {
if !matches!(body_type, BodyType::Root) { if !matches!(body_type, BodyType::Root) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Imports are only supported at the top-level of a file.".to_owned(), "Imports are only supported at the top-level of a file.".to_owned(),
vec![import_stmt.into()], vec![import_stmt.into()],
))); )));
@ -164,15 +164,18 @@ impl ExecutorContext {
let mut mod_value = mem.get_from(&mod_name, env_ref, import_item.into(), 0).cloned(); let mut mod_value = mem.get_from(&mod_name, env_ref, import_item.into(), 0).cloned();
if value.is_err() && ty.is_err() && mod_value.is_err() { if value.is_err() && ty.is_err() && mod_value.is_err() {
return Err(KclError::UndefinedValue(KclErrorDetails::new( return Err(KclError::new_undefined_value(
format!("{} is not defined in module", import_item.name.name), KclErrorDetails::new(
vec![SourceRange::from(&import_item.name)], format!("{} is not defined in module", import_item.name.name),
))); vec![SourceRange::from(&import_item.name)],
),
None,
));
} }
// Check that the item is allowed to be imported (in at least one namespace). // Check that the item is allowed to be imported (in at least one namespace).
if value.is_ok() && !module_exports.contains(&import_item.name.name) { if value.is_ok() && !module_exports.contains(&import_item.name.name) {
value = Err(KclError::Semantic(KclErrorDetails::new( value = Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.", "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name import_item.name.name
@ -182,7 +185,7 @@ impl ExecutorContext {
} }
if ty.is_ok() && !module_exports.contains(&ty_name) { if ty.is_ok() && !module_exports.contains(&ty_name) {
ty = Err(KclError::Semantic(KclErrorDetails::new(format!( ty = Err(KclError::new_semantic(KclErrorDetails::new(format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.", "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name import_item.name.name
), ),
@ -190,7 +193,7 @@ impl ExecutorContext {
} }
if mod_value.is_ok() && !module_exports.contains(&mod_name) { if mod_value.is_ok() && !module_exports.contains(&mod_name) {
mod_value = Err(KclError::Semantic(KclErrorDetails::new(format!( mod_value = Err(KclError::new_semantic(KclErrorDetails::new(format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.", "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name import_item.name.name
), ),
@ -253,7 +256,7 @@ impl ExecutorContext {
.memory .memory
.get_from(name, env_ref, source_range, 0) .get_from(name, env_ref, source_range, 0)
.map_err(|_err| { .map_err(|_err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("{} is not defined in module (but was exported?)", name), format!("{} is not defined in module (but was exported?)", name),
vec![source_range], vec![source_range],
)) ))
@ -301,7 +304,10 @@ impl ExecutorContext {
let annotations = &variable_declaration.outer_attrs; let annotations = &variable_declaration.outer_attrs;
let value = self // During the evaluation of the variable's LHS, set context that this is all happening inside a variable
// declaration, for the given name. This helps improve user-facing error messages.
exec_state.mod_local.being_declared = Some(variable_declaration.inner.name().to_owned());
let rhs_result = self
.execute_expr( .execute_expr(
&variable_declaration.declaration.init, &variable_declaration.declaration.init,
exec_state, exec_state,
@ -309,10 +315,14 @@ impl ExecutorContext {
annotations, annotations,
StatementKind::Declaration { name: &var_name }, StatementKind::Declaration { name: &var_name },
) )
.await?; .await;
// Declaration over, so unset this context.
exec_state.mod_local.being_declared = None;
let rhs = rhs_result?;
exec_state exec_state
.mut_stack() .mut_stack()
.add(var_name.clone(), value.clone(), source_range)?; .add(var_name.clone(), rhs.clone(), source_range)?;
// Track exports. // Track exports.
if let ItemVisibility::Export = variable_declaration.visibility { if let ItemVisibility::Export = variable_declaration.visibility {
@ -326,7 +336,7 @@ impl ExecutorContext {
} }
} }
// Variable declaration can be the return value of a module. // Variable declaration can be the return value of a module.
last_expr = matches!(body_type, BodyType::Root).then_some(value); last_expr = matches!(body_type, BodyType::Root).then_some(rhs);
} }
BodyItem::TypeDeclaration(ty) => { BodyItem::TypeDeclaration(ty) => {
let metadata = Metadata::from(&**ty); let metadata = Metadata::from(&**ty);
@ -336,7 +346,7 @@ impl ExecutorContext {
let std_path = match &exec_state.mod_local.path { let std_path = match &exec_state.mod_local.path {
ModulePath::Std { value } => value, ModulePath::Std { value } => value,
ModulePath::Local { .. } | ModulePath::Main => { ModulePath::Local { .. } | ModulePath::Main => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"User-defined types are not yet supported.".to_owned(), "User-defined types are not yet supported.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))); )));
@ -352,7 +362,7 @@ impl ExecutorContext {
.mut_stack() .mut_stack()
.add(name_in_mem.clone(), value, metadata.source_range) .add(name_in_mem.clone(), value, metadata.source_range)
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Redefinition of type {}.", ty.name.name), format!("Redefinition of type {}.", ty.name.name),
vec![metadata.source_range], vec![metadata.source_range],
)) ))
@ -373,7 +383,7 @@ impl ExecutorContext {
exec_state, exec_state,
metadata.source_range, metadata.source_range,
) )
.map_err(|e| KclError::Semantic(e.into()))?, .map_err(|e| KclError::new_semantic(e.into()))?,
), ),
meta: vec![metadata], meta: vec![metadata],
}; };
@ -382,7 +392,7 @@ impl ExecutorContext {
.mut_stack() .mut_stack()
.add(name_in_mem.clone(), value, metadata.source_range) .add(name_in_mem.clone(), value, metadata.source_range)
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Redefinition of type {}.", ty.name.name), format!("Redefinition of type {}.", ty.name.name),
vec![metadata.source_range], vec![metadata.source_range],
)) ))
@ -393,7 +403,7 @@ impl ExecutorContext {
} }
} }
None => { None => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"User-defined types are not yet supported.".to_owned(), "User-defined types are not yet supported.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))) )))
@ -407,7 +417,7 @@ impl ExecutorContext {
let metadata = Metadata::from(return_statement); let metadata = Metadata::from(return_statement);
if matches!(body_type, BodyType::Root) { if matches!(body_type, BodyType::Root) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Cannot return from outside a function.".to_owned(), "Cannot return from outside a function.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))); )));
@ -426,7 +436,7 @@ impl ExecutorContext {
.mut_stack() .mut_stack()
.add(memory::RETURN_NAME.to_owned(), value, metadata.source_range) .add(memory::RETURN_NAME.to_owned(), value, metadata.source_range)
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
"Multiple returns from a single function.".to_owned(), "Multiple returns from a single function.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
)) ))
@ -531,7 +541,7 @@ impl ExecutorContext {
*cache = Some((val, er, items.clone())); *cache = Some((val, er, items.clone()));
(er, items) (er, items)
}), }),
ModuleRepr::Foreign(geom, _) => Err(KclError::Semantic(KclErrorDetails::new( ModuleRepr::Foreign(geom, _) => Err(KclError::new_semantic(KclErrorDetails::new(
"Cannot import items from foreign modules".to_owned(), "Cannot import items from foreign modules".to_owned(),
vec![geom.source_range], vec![geom.source_range],
))), ))),
@ -605,12 +615,12 @@ impl ExecutorContext {
exec_state.global.mod_loader.leave_module(path); exec_state.global.mod_loader.leave_module(path);
result.map_err(|err| { result.map_err(|err| {
if let KclError::ImportCycle(_) = err { if let KclError::ImportCycle { .. } = err {
// It was an import cycle. Keep the original message. // It was an import cycle. Keep the original message.
err.override_source_ranges(vec![source_range]) err.override_source_ranges(vec![source_range])
} else { } else {
// TODO would be great to have line/column for the underlying error here // TODO would be great to have line/column for the underlying error here
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Error loading imported file ({path}). Open it to view more details.\n {}", "Error loading imported file ({path}). Open it to view more details.\n {}",
err.message() err.message()
@ -677,7 +687,7 @@ impl ExecutorContext {
meta: vec![metadata.to_owned()], meta: vec![metadata.to_owned()],
} }
} else { } else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Rust implementation of functions is restricted to the standard library".to_owned(), "Rust implementation of functions is restricted to the standard library".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))); )));
@ -704,7 +714,7 @@ impl ExecutorContext {
"you cannot declare variable {name} as %, because % can only be used in function calls" "you cannot declare variable {name} as %, because % can only be used in function calls"
); );
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
message, message,
vec![pipe_substitution.into()], vec![pipe_substitution.into()],
))); )));
@ -712,7 +722,7 @@ impl ExecutorContext {
StatementKind::Expression => match exec_state.mod_local.pipe_value.clone() { StatementKind::Expression => match exec_state.mod_local.pipe_value.clone() {
Some(x) => x, Some(x) => x,
None => { None => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"cannot use % outside a pipe expression".to_owned(), "cannot use % outside a pipe expression".to_owned(),
vec![pipe_substitution.into()], vec![pipe_substitution.into()],
))); )));
@ -761,7 +771,7 @@ fn apply_ascription(
source_range: SourceRange, source_range: SourceRange,
) -> Result<KclValue, KclError> { ) -> Result<KclValue, KclError> {
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into()) let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into())
.map_err(|e| KclError::Semantic(e.into()))?; .map_err(|e| KclError::new_semantic(e.into()))?;
value.coerce(&ty, false, exec_state).map_err(|_| { value.coerce(&ty, false, exec_state).map_err(|_| {
let suggestion = if ty == RuntimeType::length() { let suggestion = if ty == RuntimeType::length() {
@ -771,7 +781,7 @@ fn apply_ascription(
} else { } else {
"" ""
}; };
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"could not coerce value of type {} to type {ty}{suggestion}", "could not coerce value of type {} to type {ty}{suggestion}",
value.human_friendly_type() value.human_friendly_type()
@ -804,7 +814,7 @@ impl Node<Name> {
ctx: &ExecutorContext, ctx: &ExecutorContext,
) -> Result<&'a KclValue, KclError> { ) -> Result<&'a KclValue, KclError> {
if self.abs_path { if self.abs_path {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Absolute paths (names beginning with `::` are not yet supported)".to_owned(), "Absolute paths (names beginning with `::` are not yet supported)".to_owned(),
self.as_source_ranges(), self.as_source_ranges(),
))); )));
@ -825,7 +835,7 @@ impl Node<Name> {
let value = match mem_spec { let value = match mem_spec {
Some((env, exports)) => { Some((env, exports)) => {
if !exports.contains(&p.name) { if !exports.contains(&p.name) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Item {} not found in module's exported items", p.name), format!("Item {} not found in module's exported items", p.name),
p.as_source_ranges(), p.as_source_ranges(),
))); )));
@ -842,7 +852,7 @@ impl Node<Name> {
}; };
let KclValue::Module { value: module_id, .. } = value else { let KclValue::Module { value: module_id, .. } = value else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Identifier in path must refer to a module, found {}", "Identifier in path must refer to a module, found {}",
value.human_friendly_type() value.human_friendly_type()
@ -888,7 +898,7 @@ impl Node<Name> {
// Either item or module is defined, but not exported. // Either item or module is defined, but not exported.
debug_assert!((item_value.is_ok() && !item_exported) || (mod_value.is_ok() && !mod_exported)); debug_assert!((item_value.is_ok() && !item_exported) || (mod_value.is_ok() && !mod_exported));
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
format!("Item {} not found in module's exported items", self.name.name), format!("Item {} not found in module's exported items", self.name.name),
self.name.as_source_ranges(), self.name.as_source_ranges(),
))) )))
@ -913,14 +923,17 @@ impl Node<MemberExpression> {
if let Some(value) = map.get(&property) { if let Some(value) = map.get(&property) {
Ok(value.to_owned()) Ok(value.to_owned())
} else { } else {
Err(KclError::UndefinedValue(KclErrorDetails::new( Err(KclError::new_undefined_value(
format!("Property '{property}' not found in object"), KclErrorDetails::new(
vec![self.clone().into()], format!("Property '{property}' not found in object"),
))) vec![self.clone().into()],
),
None,
))
} }
} }
(KclValue::Object { .. }, Property::String(property), true) => { (KclValue::Object { .. }, Property::String(property), true) => {
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
format!("Cannot index object with string; use dot notation instead, e.g. `obj.{property}`"), format!("Cannot index object with string; use dot notation instead, e.g. `obj.{property}`"),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -928,7 +941,7 @@ impl Node<MemberExpression> {
(KclValue::Object { .. }, p, _) => { (KclValue::Object { .. }, p, _) => {
let t = p.type_name(); let t = p.type_name();
let article = article_for(t); let article = article_for(t);
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
format!("Only strings can be used as the property of an object, but you're using {article} {t}",), format!("Only strings can be used as the property of an object, but you're using {article} {t}",),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -938,10 +951,13 @@ impl Node<MemberExpression> {
if let Some(value) = value_of_arr { if let Some(value) = value_of_arr {
Ok(value.to_owned()) Ok(value.to_owned())
} else { } else {
Err(KclError::UndefinedValue(KclErrorDetails::new( Err(KclError::new_undefined_value(
format!("The array doesn't have any item at index {index}"), KclErrorDetails::new(
vec![self.clone().into()], format!("The array doesn't have any item at index {index}"),
))) vec![self.clone().into()],
),
None,
))
} }
} }
// Singletons and single-element arrays should be interchangeable, but only indexing by 0 should work. // Singletons and single-element arrays should be interchangeable, but only indexing by 0 should work.
@ -950,7 +966,7 @@ impl Node<MemberExpression> {
(KclValue::HomArray { .. }, p, _) => { (KclValue::HomArray { .. }, p, _) => {
let t = p.type_name(); let t = p.type_name();
let article = article_for(t); let article = article_for(t);
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
format!("Only integers >= 0 can be used as the index of an array, but you're using {article} {t}",), format!("Only integers >= 0 can be used as the index of an array, but you're using {article} {t}",),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -971,7 +987,7 @@ impl Node<MemberExpression> {
(being_indexed, _, _) => { (being_indexed, _, _) => {
let t = being_indexed.human_friendly_type(); let t = being_indexed.human_friendly_type();
let article = article_for(&t); let article = article_for(&t);
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
format!("Only arrays can be indexed, but you're trying to index {article} {t}"), format!("Only arrays can be indexed, but you're trying to index {article} {t}"),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -1049,7 +1065,7 @@ impl Node<BinaryExpression> {
meta: _, meta: _,
} = left_value } = left_value
else { else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Cannot apply logical operator to non-boolean value: {}", "Cannot apply logical operator to non-boolean value: {}",
left_value.human_friendly_type() left_value.human_friendly_type()
@ -1062,7 +1078,7 @@ impl Node<BinaryExpression> {
meta: _, meta: _,
} = right_value } = right_value
else { else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Cannot apply logical operator to non-boolean value: {}", "Cannot apply logical operator to non-boolean value: {}",
right_value.human_friendly_type() right_value.human_friendly_type()
@ -1168,7 +1184,7 @@ impl Node<UnaryExpression> {
meta: _, meta: _,
} = value } = value
else { else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Cannot apply unary operator ! to non-boolean value: {}", "Cannot apply unary operator ! to non-boolean value: {}",
value.human_friendly_type() value.human_friendly_type()
@ -1189,7 +1205,7 @@ impl Node<UnaryExpression> {
let value = &self.argument.get_result(exec_state, ctx).await?; let value = &self.argument.get_result(exec_state, ctx).await?;
let err = || { let err = || {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"You can only negate numbers, planes, or lines, but this is a {}", "You can only negate numbers, planes, or lines, but this is a {}",
value.human_friendly_type() value.human_friendly_type()
@ -1292,7 +1308,7 @@ pub(crate) async fn execute_pipe_body(
ctx: &ExecutorContext, ctx: &ExecutorContext,
) -> Result<KclValue, KclError> { ) -> Result<KclValue, KclError> {
let Some((first, body)) = body.split_first() else { let Some((first, body)) = body.split_first() else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Pipe expressions cannot be empty".to_owned(), "Pipe expressions cannot be empty".to_owned(),
vec![source_range], vec![source_range],
))); )));
@ -1330,7 +1346,7 @@ async fn inner_execute_pipe_body(
) -> Result<KclValue, KclError> { ) -> Result<KclValue, KclError> {
for expression in body { for expression in body {
if let Expr::TagDeclarator(_) = expression { if let Expr::TagDeclarator(_) = expression {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("This cannot be in a PipeExpression: {:?}", expression), format!("This cannot be in a PipeExpression: {:?}", expression),
vec![expression.into()], vec![expression.into()],
))); )));
@ -1404,7 +1420,7 @@ impl Node<ArrayRangeExpression> {
.await?; .await?;
let (start, start_ty) = start_val let (start, start_ty) = start_val
.as_int_with_ty() .as_int_with_ty()
.ok_or(KclError::Semantic(KclErrorDetails::new( .ok_or(KclError::new_semantic(KclErrorDetails::new(
format!("Expected int but found {}", start_val.human_friendly_type()), format!("Expected int but found {}", start_val.human_friendly_type()),
vec![self.into()], vec![self.into()],
)))?; )))?;
@ -1412,24 +1428,26 @@ impl Node<ArrayRangeExpression> {
let end_val = ctx let end_val = ctx
.execute_expr(&self.end_element, exec_state, &metadata, &[], StatementKind::Expression) .execute_expr(&self.end_element, exec_state, &metadata, &[], StatementKind::Expression)
.await?; .await?;
let (end, end_ty) = end_val.as_int_with_ty().ok_or(KclError::Semantic(KclErrorDetails::new( let (end, end_ty) = end_val
format!("Expected int but found {}", end_val.human_friendly_type()), .as_int_with_ty()
vec![self.into()], .ok_or(KclError::new_semantic(KclErrorDetails::new(
)))?; format!("Expected int but found {}", end_val.human_friendly_type()),
vec![self.into()],
)))?;
if start_ty != end_ty { if start_ty != end_ty {
let start = start_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: start_ty }); let start = start_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: start_ty });
let start = fmt::human_display_number(start.n, start.ty); let start = fmt::human_display_number(start.n, start.ty);
let end = end_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: end_ty }); let end = end_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: end_ty });
let end = fmt::human_display_number(end.n, end.ty); let end = fmt::human_display_number(end.n, end.ty);
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Range start and end must be of the same type, but found {start} and {end}"), format!("Range start and end must be of the same type, but found {start} and {end}"),
vec![self.into()], vec![self.into()],
))); )));
} }
if end < start { if end < start {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Range start is greater than range end: {start} .. {end}"), format!("Range start is greater than range end: {start} .. {end}"),
vec![self.into()], vec![self.into()],
))); )));
@ -1493,7 +1511,7 @@ fn article_for<S: AsRef<str>>(s: S) -> &'static str {
fn number_as_f64(v: &KclValue, source_range: SourceRange) -> Result<TyF64, KclError> { fn number_as_f64(v: &KclValue, source_range: SourceRange) -> Result<TyF64, KclError> {
v.as_ty_f64().ok_or_else(|| { v.as_ty_f64().ok_or_else(|| {
let actual_type = v.human_friendly_type(); let actual_type = v.human_friendly_type();
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Expected a number, but found {actual_type}",), format!("Expected a number, but found {actual_type}",),
vec![source_range], vec![source_range],
)) ))
@ -1585,13 +1603,13 @@ impl Property {
if let Some(x) = crate::try_f64_to_usize(value) { if let Some(x) = crate::try_f64_to_usize(value) {
Ok(Property::UInt(x)) Ok(Property::UInt(x))
} else { } else {
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
format!("{value} is not a valid index, indices must be whole numbers >= 0"), format!("{value} is not a valid index, indices must be whole numbers >= 0"),
property_sr, property_sr,
))) )))
} }
} }
_ => Err(KclError::Semantic(KclErrorDetails::new( _ => Err(KclError::new_semantic(KclErrorDetails::new(
"Only numbers (>= 0) can be indexes".to_owned(), "Only numbers (>= 0) can be indexes".to_owned(),
vec![sr], vec![sr],
))), ))),
@ -1602,7 +1620,8 @@ impl Property {
} }
fn jvalue_to_prop(value: &KclValue, property_sr: Vec<SourceRange>, name: &str) -> Result<Property, KclError> { fn jvalue_to_prop(value: &KclValue, property_sr: Vec<SourceRange>, name: &str) -> Result<Property, KclError> {
let make_err = |message: String| Err::<Property, _>(KclError::Semantic(KclErrorDetails::new(message, property_sr))); let make_err =
|message: String| Err::<Property, _>(KclError::new_semantic(KclErrorDetails::new(message, property_sr)));
match value { match value {
KclValue::Number{value: num, .. } => { KclValue::Number{value: num, .. } => {
let num = *num; let num = *num;
@ -1846,7 +1865,7 @@ d = b + c
crate::engine::conn_mock::EngineConnection::new() crate::engine::conn_mock::EngineConnection::new()
.await .await
.map_err(|err| { .map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to create mock engine connection: {}", err), format!("Failed to create mock engine connection: {}", err),
vec![SourceRange::default()], vec![SourceRange::default()],
)) ))

View File

@ -295,7 +295,7 @@ impl Node<CallExpressionKw> {
let func = fn_name.get_result(exec_state, ctx).await?.clone(); let func = fn_name.get_result(exec_state, ctx).await?.clone();
let Some(fn_src) = func.as_function() else { let Some(fn_src) = func.as_function() else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"cannot call this because it isn't a function".to_string(), "cannot call this because it isn't a function".to_string(),
vec![callsite], vec![callsite],
))); )));
@ -318,10 +318,13 @@ impl Node<CallExpressionKw> {
if let KclValue::Function { meta, .. } = func { if let KclValue::Function { meta, .. } = func {
source_ranges = meta.iter().map(|m| m.source_range).collect(); source_ranges = meta.iter().map(|m| m.source_range).collect();
}; };
KclError::UndefinedValue(KclErrorDetails::new( KclError::new_undefined_value(
format!("Result of user-defined function {} is undefined", fn_name), KclErrorDetails::new(
source_ranges, format!("Result of user-defined function {} is undefined", fn_name),
)) source_ranges,
),
None,
)
})?; })?;
Ok(result) Ok(result)
@ -500,7 +503,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
let tag_id = if let Some(t) = value.sketch.tags.get(&tag.name) { let tag_id = if let Some(t) = value.sketch.tags.get(&tag.name) {
let mut t = t.clone(); let mut t = t.clone();
let Some(info) = t.get_cur_info() else { let Some(info) = t.get_cur_info() else {
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
format!("Tag {} does not have path info", tag.name), format!("Tag {} does not have path info", tag.name),
vec![tag.into()], vec![tag.into()],
))); )));
@ -605,7 +608,7 @@ fn type_check_params_kw(
arg.value = arg arg.value = arg
.value .value
.coerce( .coerce(
&RuntimeType::from_parsed(ty.clone(), exec_state, arg.source_range).map_err(|e| KclError::Semantic(e.into()))?, &RuntimeType::from_parsed(ty.clone(), exec_state, arg.source_range).map_err(|e| KclError::new_semantic(e.into()))?,
true, true,
exec_state, exec_state,
) )
@ -619,7 +622,7 @@ fn type_check_params_kw(
// TODO if we have access to the AST for the argument we could choose which example to suggest. // TODO if we have access to the AST for the argument we could choose which example to suggest.
message = format!("{message}\n\nYou may need to add information about the type of the argument, for example:\n using a numeric suffix: `42{ty}`\n or using type ascription: `foo(): number({ty})`"); message = format!("{message}\n\nYou may need to add information about the type of the argument, for example:\n using a numeric suffix: `42{ty}`\n or using type ascription: `foo(): number({ty})`");
} }
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
message, message,
vec![arg.source_range], vec![arg.source_range],
)) ))
@ -670,7 +673,7 @@ fn type_check_params_kw(
let first = errors.next().unwrap(); let first = errors.next().unwrap();
errors.for_each(|e| exec_state.err(e)); errors.for_each(|e| exec_state.err(e));
return Err(KclError::Semantic(first.into())); return Err(KclError::new_semantic(first.into()));
} }
if let Some(arg) = &mut args.unlabeled { if let Some(arg) = &mut args.unlabeled {
@ -680,12 +683,12 @@ fn type_check_params_kw(
.value .value
.coerce( .coerce(
&RuntimeType::from_parsed(ty.clone(), exec_state, arg.1.source_range) &RuntimeType::from_parsed(ty.clone(), exec_state, arg.1.source_range)
.map_err(|e| KclError::Semantic(e.into()))?, .map_err(|e| KclError::new_semantic(e.into()))?,
true, true,
exec_state, exec_state,
) )
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"The input argument of {} requires a value with type `{}`, but found {}", "The input argument of {} requires a value with type `{}`, but found {}",
fn_name fn_name
@ -742,7 +745,7 @@ fn assign_args_to_params_kw(
.add(name.clone(), value, default_val.source_range())?; .add(name.clone(), value, default_val.source_range())?;
} }
None => { None => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"This function requires a parameter {}, but you haven't passed it one.", "This function requires a parameter {}, but you haven't passed it one.",
name name
@ -759,12 +762,12 @@ fn assign_args_to_params_kw(
let Some(unlabeled) = unlabelled else { let Some(unlabeled) = unlabelled else {
return Err(if args.kw_args.labeled.contains_key(param_name) { return Err(if args.kw_args.labeled.contains_key(param_name) {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("The function does declare a parameter named '{param_name}', but this parameter doesn't use a label. Try removing the `{param_name}:`"), format!("The function does declare a parameter named '{param_name}', but this parameter doesn't use a label. Try removing the `{param_name}:`"),
source_ranges, source_ranges,
)) ))
} else { } else {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
"This function expects an unlabeled first parameter, but you haven't passed it one.".to_owned(), "This function expects an unlabeled first parameter, but you haven't passed it one.".to_owned(),
source_ranges, source_ranges,
)) ))
@ -788,9 +791,9 @@ fn coerce_result_type(
if let Ok(Some(val)) = result { if let Ok(Some(val)) = result {
if let Some(ret_ty) = &fn_def.return_type { if let Some(ret_ty) = &fn_def.return_type {
let ty = RuntimeType::from_parsed(ret_ty.inner.clone(), exec_state, ret_ty.as_source_range()) let ty = RuntimeType::from_parsed(ret_ty.inner.clone(), exec_state, ret_ty.as_source_range())
.map_err(|e| KclError::Semantic(e.into()))?; .map_err(|e| KclError::new_semantic(e.into()))?;
let val = val.coerce(&ty, true, exec_state).map_err(|_| { let val = val.coerce(&ty, true, exec_state).map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"This function requires its result to be of type `{}`, but found {}", "This function requires its result to be of type `{}`, but found {}",
ty.human_friendly_type(), ty.human_friendly_type(),
@ -874,7 +877,7 @@ mod test {
"all params required, none given, should error", "all params required, none given, should error",
vec![req_param("x")], vec![req_param("x")],
vec![], vec![],
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
"This function requires a parameter x, but you haven't passed it one.".to_owned(), "This function requires a parameter x, but you haven't passed it one.".to_owned(),
vec![SourceRange::default()], vec![SourceRange::default()],
))), ))),
@ -889,7 +892,7 @@ mod test {
"mixed params, too few given", "mixed params, too few given",
vec![req_param("x"), opt_param("y")], vec![req_param("x"), opt_param("y")],
vec![], vec![],
Err(KclError::Semantic(KclErrorDetails::new( Err(KclError::new_semantic(KclErrorDetails::new(
"This function requires a parameter x, but you haven't passed it one.".to_owned(), "This function requires a parameter x, but you haven't passed it one.".to_owned(),
vec![SourceRange::default()], vec![SourceRange::default()],
))), ))),

View File

@ -469,7 +469,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
PlaneData::NegYZ => PlaneName::NegYz, PlaneData::NegYZ => PlaneName::NegYz,
PlaneData::Plane(_) => { PlaneData::Plane(_) => {
// We will never get here since we already checked for PlaneData::Plane. // We will never get here since we already checked for PlaneData::Plane.
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
format!("PlaneData {:?} not found", value), format!("PlaneData {:?} not found", value),
Default::default(), Default::default(),
))); )));
@ -477,7 +477,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
}; };
let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| { let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Plane {} not found", name), format!("Plane {} not found", name),
Default::default(), Default::default(),
)) ))

View File

@ -37,25 +37,25 @@ pub async fn import_foreign(
) -> Result<PreImportedGeometry, KclError> { ) -> Result<PreImportedGeometry, KclError> {
// Make sure the file exists. // Make sure the file exists.
if !ctxt.fs.exists(file_path, source_range).await? { if !ctxt.fs.exists(file_path, source_range).await? {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("File `{}` does not exist.", file_path.display()), format!("File `{}` does not exist.", file_path.display()),
vec![source_range], vec![source_range],
))); )));
} }
let ext_format = get_import_format_from_extension(file_path.extension().ok_or_else(|| { let ext_format = get_import_format_from_extension(file_path.extension().ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("No file extension found for `{}`", file_path.display()), format!("No file extension found for `{}`", file_path.display()),
vec![source_range], vec![source_range],
)) ))
})?) })?)
.map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?; .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
// Get the format type from the extension of the file. // Get the format type from the extension of the file.
let format = if let Some(format) = format { let format = if let Some(format) = format {
// Validate the given format with the extension format. // Validate the given format with the extension format.
validate_extension_format(ext_format, format.clone()) validate_extension_format(ext_format, format.clone())
.map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?; .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
format format
} else { } else {
ext_format ext_format
@ -66,11 +66,11 @@ pub async fn import_foreign(
.fs .fs
.read(file_path, source_range) .read(file_path, source_range)
.await .await
.map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?; .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
// We want the file_path to be without the parent. // We want the file_path to be without the parent.
let file_name = file_path.file_name().map(|p| p.to_string()).ok_or_else(|| { let file_name = file_path.file_name().map(|p| p.to_string()).ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Could not get the file name from the path `{}`", file_path.display()), format!("Could not get the file name from the path `{}`", file_path.display()),
vec![source_range], vec![source_range],
)) ))
@ -87,7 +87,7 @@ pub async fn import_foreign(
// file. // file.
if !file_contents.starts_with(b"glTF") { if !file_contents.starts_with(b"glTF") {
let json = gltf_json::Root::from_slice(&file_contents) let json = gltf_json::Root::from_slice(&file_contents)
.map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?; .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
// Read the gltf file and check if there is a bin file. // Read the gltf file and check if there is a bin file.
for buffer in json.buffers.iter() { for buffer in json.buffers.iter() {
@ -95,16 +95,15 @@ pub async fn import_foreign(
if !uri.starts_with("data:") { if !uri.starts_with("data:") {
// We want this path relative to the file_path given. // We want this path relative to the file_path given.
let bin_path = file_path.parent().map(|p| p.join(uri)).ok_or_else(|| { let bin_path = file_path.parent().map(|p| p.join(uri)).ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Could not get the parent path of the file `{}`", file_path.display()), format!("Could not get the parent path of the file `{}`", file_path.display()),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let bin_contents = let bin_contents = ctxt.fs.read(&bin_path, source_range).await.map_err(|e| {
ctxt.fs.read(&bin_path, source_range).await.map_err(|e| { KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range]))
KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])) })?;
})?;
import_files.push(ImportFile { import_files.push(ImportFile {
path: uri.to_string(), path: uri.to_string(),
@ -141,7 +140,7 @@ pub(super) fn format_from_annotations(
if p.key.name == annotations::IMPORT_FORMAT { if p.key.name == annotations::IMPORT_FORMAT {
result = Some( result = Some(
get_import_format_from_extension(annotations::expect_ident(&p.value)?).map_err(|_| { get_import_format_from_extension(annotations::expect_ident(&p.value)?).map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unknown format for import, expected one of: {}", "Unknown format for import, expected one of: {}",
crate::IMPORT_FILE_EXTENSIONS.join(", ") crate::IMPORT_FILE_EXTENSIONS.join(", ")
@ -159,7 +158,7 @@ pub(super) fn format_from_annotations(
path.extension() path.extension()
.and_then(|ext| get_import_format_from_extension(ext).ok()) .and_then(|ext| get_import_format_from_extension(ext).ok())
}) })
.ok_or(KclError::Semantic(KclErrorDetails::new( .ok_or(KclError::new_semantic(KclErrorDetails::new(
"Unknown or missing extension, and no specified format for imported file".to_owned(), "Unknown or missing extension, and no specified format for imported file".to_owned(),
vec![import_source_range], vec![import_source_range],
)))?; )))?;
@ -174,7 +173,7 @@ pub(super) fn format_from_annotations(
} }
annotations::IMPORT_FORMAT => {} annotations::IMPORT_FORMAT => {}
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unexpected annotation for import, expected one of: {}, {}, {}", "Unexpected annotation for import, expected one of: {}, {}, {}",
annotations::IMPORT_FORMAT, annotations::IMPORT_FORMAT,
@ -199,7 +198,7 @@ fn set_coords(fmt: &mut InputFormat3d, coords_str: &str, source_range: SourceRan
} }
let Some(coords) = coords else { let Some(coords) = coords else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unknown coordinate system: {coords_str}, expected one of: {}", "Unknown coordinate system: {coords_str}, expected one of: {}",
annotations::IMPORT_COORDS_VALUES annotations::IMPORT_COORDS_VALUES
@ -217,7 +216,7 @@ fn set_coords(fmt: &mut InputFormat3d, coords_str: &str, source_range: SourceRan
InputFormat3d::Ply(opts) => opts.coords = coords, InputFormat3d::Ply(opts) => opts.coords = coords,
InputFormat3d::Stl(opts) => opts.coords = coords, InputFormat3d::Stl(opts) => opts.coords = coords,
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"`{}` option cannot be applied to the specified format", "`{}` option cannot be applied to the specified format",
annotations::IMPORT_COORDS annotations::IMPORT_COORDS
@ -238,7 +237,7 @@ fn set_length_unit(fmt: &mut InputFormat3d, units_str: &str, source_range: Sourc
InputFormat3d::Ply(opts) => opts.units = units.into(), InputFormat3d::Ply(opts) => opts.units = units.into(),
InputFormat3d::Stl(opts) => opts.units = units.into(), InputFormat3d::Stl(opts) => opts.units = units.into(),
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"`{}` option cannot be applied to the specified format", "`{}` option cannot be applied to the specified format",
annotations::IMPORT_LENGTH_UNIT annotations::IMPORT_LENGTH_UNIT

View File

@ -574,7 +574,7 @@ impl KclValue {
pub fn get_tag_identifier(&self) -> Result<TagIdentifier, KclError> { pub fn get_tag_identifier(&self) -> Result<TagIdentifier, KclError> {
match self { match self {
KclValue::TagIdentifier(t) => Ok(*t.clone()), KclValue::TagIdentifier(t) => Ok(*t.clone()),
_ => Err(KclError::Semantic(KclErrorDetails::new( _ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag identifier: {:?}", self), format!("Not a tag identifier: {:?}", self),
self.clone().into(), self.clone().into(),
))), ))),
@ -585,7 +585,7 @@ impl KclValue {
pub fn get_tag_declarator(&self) -> Result<TagNode, KclError> { pub fn get_tag_declarator(&self) -> Result<TagNode, KclError> {
match self { match self {
KclValue::TagDeclarator(t) => Ok((**t).clone()), KclValue::TagDeclarator(t) => Ok((**t).clone()),
_ => Err(KclError::Semantic(KclErrorDetails::new( _ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag declarator: {:?}", self), format!("Not a tag declarator: {:?}", self),
self.clone().into(), self.clone().into(),
))), ))),
@ -595,7 +595,7 @@ impl KclValue {
/// If this KCL value is a bool, retrieve it. /// If this KCL value is a bool, retrieve it.
pub fn get_bool(&self) -> Result<bool, KclError> { pub fn get_bool(&self) -> Result<bool, KclError> {
self.as_bool().ok_or_else(|| { self.as_bool().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected bool, found {}", self.human_friendly_type()), format!("Expected bool, found {}", self.human_friendly_type()),
self.into(), self.into(),
)) ))

View File

@ -367,10 +367,10 @@ impl ProgramMemory {
let name = var.trim_start_matches(TYPE_PREFIX).trim_start_matches(MODULE_PREFIX); let name = var.trim_start_matches(TYPE_PREFIX).trim_start_matches(MODULE_PREFIX);
Err(KclError::UndefinedValue(KclErrorDetails::new( Err(KclError::new_undefined_value(
format!("`{name}` is not defined"), KclErrorDetails::new(format!("`{name}` is not defined"), vec![source_range]),
vec![source_range], Some(name.to_owned()),
))) ))
} }
/// Iterate over all key/value pairs in the specified environment which satisfy the provided /// Iterate over all key/value pairs in the specified environment which satisfy the provided
@ -488,10 +488,10 @@ impl ProgramMemory {
}; };
} }
Err(KclError::UndefinedValue(KclErrorDetails::new( Err(KclError::new_undefined_value(
format!("`{}` is not defined", var), KclErrorDetails::new(format!("`{}` is not defined", var), vec![]),
vec![], Some(var.to_owned()),
))) ))
} }
} }
@ -646,7 +646,7 @@ impl Stack {
pub fn add(&mut self, key: String, value: KclValue, source_range: SourceRange) -> Result<(), KclError> { pub fn add(&mut self, key: String, value: KclValue, source_range: SourceRange) -> Result<(), KclError> {
let env = self.memory.get_env(self.current_env.index()); let env = self.memory.get_env(self.current_env.index());
if env.contains_key(&key) { if env.contains_key(&key) {
return Err(KclError::ValueAlreadyDefined(KclErrorDetails::new( return Err(KclError::new_value_already_defined(KclErrorDetails::new(
format!("Cannot redefine `{}`", key), format!("Cannot redefine `{}`", key),
vec![source_range], vec![source_range],
))); )));

View File

@ -858,7 +858,7 @@ impl ExecutorContext {
for module in modules { for module in modules {
let Some((import_stmt, module_id, module_path, repr)) = universe.get(&module) else { let Some((import_stmt, module_id, module_path, repr)) = universe.get(&module) else {
return Err(KclErrorWithOutputs::no_outputs(KclError::Internal( return Err(KclErrorWithOutputs::no_outputs(KclError::new_internal(
KclErrorDetails::new(format!("Module {module} not found in universe"), Default::default()), KclErrorDetails::new(format!("Module {module} not found in universe"), Default::default()),
))); )));
}; };
@ -920,7 +920,7 @@ impl ExecutorContext {
result.map(|val| ModuleRepr::Foreign(geom.clone(), val)) result.map(|val| ModuleRepr::Foreign(geom.clone(), val))
} }
ModuleRepr::Dummy | ModuleRepr::Root => Err(KclError::Internal(KclErrorDetails::new( ModuleRepr::Dummy | ModuleRepr::Root => Err(KclError::new_internal(KclErrorDetails::new(
format!("Module {module_path} not found in universe"), format!("Module {module_path} not found in universe"),
vec![source_range], vec![source_range],
))), ))),
@ -1283,7 +1283,7 @@ impl ExecutorContext {
.await?; .await?;
let kittycad_modeling_cmds::websocket::OkWebSocketResponseData::Export { files } = resp else { let kittycad_modeling_cmds::websocket::OkWebSocketResponseData::Export { files } = resp else {
return Err(KclError::Internal(crate::errors::KclErrorDetails::new( return Err(KclError::new_internal(crate::errors::KclErrorDetails::new(
format!("Expected Export response, got {resp:?}",), format!("Expected Export response, got {resp:?}",),
vec![SourceRange::default()], vec![SourceRange::default()],
))); )));
@ -1303,7 +1303,7 @@ impl ExecutorContext {
coords: *kittycad_modeling_cmds::coord::KITTYCAD, coords: *kittycad_modeling_cmds::coord::KITTYCAD,
created: if deterministic_time { created: if deterministic_time {
Some("2021-01-01T00:00:00Z".parse().map_err(|e| { Some("2021-01-01T00:00:00Z".parse().map_err(|e| {
KclError::Internal(crate::errors::KclErrorDetails::new( KclError::new_internal(crate::errors::KclErrorDetails::new(
format!("Failed to parse date: {}", e), format!("Failed to parse date: {}", e),
vec![SourceRange::default()], vec![SourceRange::default()],
)) ))
@ -1383,7 +1383,7 @@ pub(crate) async fn parse_execute_with_project_dir(
let exec_ctxt = ExecutorContext { let exec_ctxt = ExecutorContext {
engine: Arc::new(Box::new( engine: Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new().await.map_err(|err| { crate::engine::conn_mock::EngineConnection::new().await.map_err(|err| {
KclError::Internal(crate::errors::KclErrorDetails::new( KclError::new_internal(crate::errors::KclErrorDetails::new(
format!("Failed to create mock engine connection: {}", err), format!("Failed to create mock engine connection: {}", err),
vec![SourceRange::default()], vec![SourceRange::default()],
)) ))
@ -1799,7 +1799,7 @@ foo
let err = result.unwrap_err(); let err = result.unwrap_err();
assert_eq!( assert_eq!(
err, err,
KclError::Syntax(KclErrorDetails::new( KclError::new_syntax(KclErrorDetails::new(
"Unexpected token: #".to_owned(), "Unexpected token: #".to_owned(),
vec![SourceRange::new(14, 15, ModuleId::default())], vec![SourceRange::new(14, 15, ModuleId::default())],
)), )),
@ -2058,7 +2058,7 @@ notTagIdentifier = !myTag";
// TODO: We don't currently parse this, but we should. It should be // TODO: We don't currently parse this, but we should. It should be
// a runtime error instead. // a runtime error instead.
parse_execute(code10).await.unwrap_err(), parse_execute(code10).await.unwrap_err(),
KclError::Syntax(KclErrorDetails::new( KclError::new_syntax(KclErrorDetails::new(
"Unexpected token: !".to_owned(), "Unexpected token: !".to_owned(),
vec![SourceRange::new(10, 11, ModuleId::default())], vec![SourceRange::new(10, 11, ModuleId::default())],
)) ))
@ -2071,9 +2071,9 @@ notPipeSub = 1 |> identity(!%))";
// TODO: We don't currently parse this, but we should. It should be // TODO: We don't currently parse this, but we should. It should be
// a runtime error instead. // a runtime error instead.
parse_execute(code11).await.unwrap_err(), parse_execute(code11).await.unwrap_err(),
KclError::Syntax(KclErrorDetails::new( KclError::new_syntax(KclErrorDetails::new(
"Unexpected token: |>".to_owned(), "There was an unexpected !. Try removing it.".to_owned(),
vec![SourceRange::new(44, 46, ModuleId::default())], vec![SourceRange::new(56, 57, ModuleId::default())],
)) ))
); );

View File

@ -80,6 +80,11 @@ pub(super) struct ModuleState {
/// The current value of the pipe operator returned from the previous /// The current value of the pipe operator returned from the previous
/// expression. If we're not currently in a pipeline, this will be None. /// expression. If we're not currently in a pipeline, this will be None.
pub pipe_value: Option<KclValue>, pub pipe_value: Option<KclValue>,
/// The closest variable declaration being executed in any parent node in the AST.
/// This is used to provide better error messages, e.g. noticing when the user is trying
/// to use the variable `length` inside the RHS of its own definition, like `length = tan(length)`.
/// TODO: Make this a reference.
pub being_declared: Option<String>,
/// Identifiers that have been exported from the current module. /// Identifiers that have been exported from the current module.
pub module_exports: Vec<String>, pub module_exports: Vec<String>,
/// Settings specified from annotations. /// Settings specified from annotations.
@ -276,7 +281,7 @@ impl ExecState {
} }
pub(super) fn circular_import_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError { pub(super) fn circular_import_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError {
KclError::ImportCycle(KclErrorDetails::new( KclError::new_import_cycle(KclErrorDetails::new(
format!( format!(
"circular import of modules is not allowed: {} -> {}", "circular import of modules is not allowed: {} -> {}",
self.global self.global
@ -342,6 +347,7 @@ impl ModuleState {
id_generator: IdGenerator::new(module_id), id_generator: IdGenerator::new(module_id),
stack: memory.new_stack(), stack: memory.new_stack(),
pipe_value: Default::default(), pipe_value: Default::default(),
being_declared: Default::default(),
module_exports: Default::default(), module_exports: Default::default(),
explicit_length_units: false, explicit_length_units: false,
path, path,
@ -389,7 +395,7 @@ impl MetaSettings {
self.kcl_version = value; self.kcl_version = value;
} }
name => { name => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unexpected settings key: `{name}`; expected one of `{}`, `{}`", "Unexpected settings key: `{name}`; expected one of `{}`, `{}`",
annotations::SETTINGS_UNIT_LENGTH, annotations::SETTINGS_UNIT_LENGTH,

View File

@ -28,7 +28,7 @@ impl Default for FileManager {
impl FileSystem for FileManager { impl FileSystem for FileManager {
async fn read(&self, path: &TypedPath, source_range: SourceRange) -> Result<Vec<u8>, KclError> { async fn read(&self, path: &TypedPath, source_range: SourceRange) -> Result<Vec<u8>, KclError> {
tokio::fs::read(&path.0).await.map_err(|e| { tokio::fs::read(&path.0).await.map_err(|e| {
KclError::Io(KclErrorDetails::new( KclError::new_io(KclErrorDetails::new(
format!("Failed to read file `{}`: {}", path.display(), e), format!("Failed to read file `{}`: {}", path.display(), e),
vec![source_range], vec![source_range],
)) ))
@ -37,7 +37,7 @@ impl FileSystem for FileManager {
async fn read_to_string(&self, path: &TypedPath, source_range: SourceRange) -> Result<String, KclError> { async fn read_to_string(&self, path: &TypedPath, source_range: SourceRange) -> Result<String, KclError> {
tokio::fs::read_to_string(&path.0).await.map_err(|e| { tokio::fs::read_to_string(&path.0).await.map_err(|e| {
KclError::Io(KclErrorDetails::new( KclError::new_io(KclErrorDetails::new(
format!("Failed to read file `{}`: {}", path.display(), e), format!("Failed to read file `{}`: {}", path.display(), e),
vec![source_range], vec![source_range],
)) ))
@ -49,7 +49,7 @@ impl FileSystem for FileManager {
if e.kind() == std::io::ErrorKind::NotFound { if e.kind() == std::io::ErrorKind::NotFound {
Ok(false) Ok(false)
} else { } else {
Err(KclError::Io(KclErrorDetails::new( Err(KclError::new_io(KclErrorDetails::new(
format!("Failed to check if file `{}` exists: {}", path.display(), e), format!("Failed to check if file `{}` exists: {}", path.display(), e),
vec![source_range], vec![source_range],
))) )))
@ -71,7 +71,7 @@ impl FileSystem for FileManager {
} }
let mut read_dir = tokio::fs::read_dir(&path).await.map_err(|e| { let mut read_dir = tokio::fs::read_dir(&path).await.map_err(|e| {
KclError::Io(KclErrorDetails::new( KclError::new_io(KclErrorDetails::new(
format!("Failed to read directory `{}`: {}", path.display(), e), format!("Failed to read directory `{}`: {}", path.display(), e),
vec![source_range], vec![source_range],
)) ))

View File

@ -49,10 +49,10 @@ impl FileSystem for FileManager {
let promise = self let promise = self
.manager .manager
.read_file(path.to_string_lossy()) .read_file(path.to_string_lossy())
.map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?; .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
let value = JsFuture::from(promise).await.map_err(|e| { let value = JsFuture::from(promise).await.map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to wait for promise from engine: {:?}", e), format!("Failed to wait for promise from engine: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -67,7 +67,7 @@ impl FileSystem for FileManager {
async fn read_to_string(&self, path: &TypedPath, source_range: SourceRange) -> Result<String, KclError> { async fn read_to_string(&self, path: &TypedPath, source_range: SourceRange) -> Result<String, KclError> {
let bytes = self.read(path, source_range).await?; let bytes = self.read(path, source_range).await?;
let string = String::from_utf8(bytes).map_err(|e| { let string = String::from_utf8(bytes).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to convert bytes to string: {:?}", e), format!("Failed to convert bytes to string: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -80,17 +80,17 @@ impl FileSystem for FileManager {
let promise = self let promise = self
.manager .manager
.exists(path.to_string_lossy()) .exists(path.to_string_lossy())
.map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?; .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
let value = JsFuture::from(promise).await.map_err(|e| { let value = JsFuture::from(promise).await.map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to wait for promise from engine: {:?}", e), format!("Failed to wait for promise from engine: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let it_exists = value.as_bool().ok_or_else(|| { let it_exists = value.as_bool().ok_or_else(|| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
"Failed to convert value to bool".to_string(), "Failed to convert value to bool".to_string(),
vec![source_range], vec![source_range],
)) ))
@ -107,24 +107,24 @@ impl FileSystem for FileManager {
let promise = self let promise = self
.manager .manager
.get_all_files(path.to_string_lossy()) .get_all_files(path.to_string_lossy())
.map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?; .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
let value = JsFuture::from(promise).await.map_err(|e| { let value = JsFuture::from(promise).await.map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to wait for promise from javascript: {:?}", e), format!("Failed to wait for promise from javascript: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let s = value.as_string().ok_or_else(|| { let s = value.as_string().ok_or_else(|| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to get string from response from javascript: `{:?}`", value), format!("Failed to get string from response from javascript: `{:?}`", value),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let files: Vec<String> = serde_json::from_str(&s).map_err(|e| { let files: Vec<String> = serde_json::from_str(&s).map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to parse json from javascript: `{}` `{:?}`", s, e), format!("Failed to parse json from javascript: `{}` `{:?}`", s, e),
vec![source_range], vec![source_range],
)) ))

View File

@ -58,7 +58,7 @@ impl ModuleLoader {
} }
pub(crate) fn import_cycle_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError { pub(crate) fn import_cycle_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError {
KclError::ImportCycle(KclErrorDetails::new( KclError::new_import_cycle(KclErrorDetails::new(
format!( format!(
"circular import of modules is not allowed: {} -> {}", "circular import of modules is not allowed: {} -> {}",
self.import_stack self.import_stack
@ -163,7 +163,7 @@ impl ModulePath {
ModulePath::Std { value: name } => Ok(ModuleSource { ModulePath::Std { value: name } => Ok(ModuleSource {
source: read_std(name) source: read_std(name)
.ok_or_else(|| { .ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Cannot find standard library module to import: std::{name}."), format!("Cannot find standard library module to import: std::{name}."),
vec![source_range], vec![source_range],
)) ))
@ -202,7 +202,7 @@ impl ModulePath {
ModulePath::Std { .. } => { ModulePath::Std { .. } => {
let message = format!("Cannot import a non-std KCL file from std: {path}."); let message = format!("Cannot import a non-std KCL file from std: {path}.");
debug_assert!(false, "{}", &message); debug_assert!(false, "{}", &message);
return Err(KclError::Internal(KclErrorDetails::new(message, vec![]))); return Err(KclError::new_internal(KclErrorDetails::new(message, vec![])));
} }
}; };
@ -217,7 +217,7 @@ impl ModulePath {
if path.len() != 2 || path[0] != "std" { if path.len() != 2 || path[0] != "std" {
let message = format!("Invalid std import path: {path:?}."); let message = format!("Invalid std import path: {path:?}.");
debug_assert!(false, "{}", &message); debug_assert!(false, "{}", &message);
return Err(KclError::Internal(KclErrorDetails::new(message, vec![]))); return Err(KclError::new_internal(KclErrorDetails::new(message, vec![])));
} }
Ok(ModulePath::Std { value: path[1].clone() }) Ok(ModulePath::Std { value: path[1].clone() })

View File

@ -51,7 +51,7 @@ pub fn parse_tokens(mut tokens: TokenStream) -> ParseResult {
} else { } else {
format!("found unknown tokens [{}]", token_list.join(", ")) format!("found unknown tokens [{}]", token_list.join(", "))
}; };
return KclError::Lexical(KclErrorDetails::new(message, source_ranges)).into(); return KclError::new_lexical(KclErrorDetails::new(message, source_ranges)).into();
} }
// Important, to not call this before the unknown tokens check. // Important, to not call this before the unknown tokens check.
@ -110,7 +110,7 @@ impl ParseResult {
let (p, errs) = self.0?; let (p, errs) = self.0?;
if let Some(err) = errs.iter().find(|e| e.severity.is_err()) { if let Some(err) = errs.iter().find(|e| e.severity.is_err()) {
return Err(KclError::Syntax(err.clone().into())); return Err(KclError::new_syntax(err.clone().into()));
} }
match p { match p {
Some(p) => Ok(p), Some(p) => Ok(p),

View File

@ -979,12 +979,18 @@ fn property_separator(i: &mut TokenSlice) -> ModalResult<()> {
} }
/// Match something that separates the labeled arguments of a fn call. /// Match something that separates the labeled arguments of a fn call.
fn labeled_arg_separator(i: &mut TokenSlice) -> ModalResult<()> { /// Returns the source range of the erroneous separator, if any was found.
fn labeled_arg_separator(i: &mut TokenSlice) -> ModalResult<Option<SourceRange>> {
alt(( alt((
// Normally you need a comma. // Normally you need a comma.
comma_sep, comma_sep.map(|_| None),
// But, if the argument list is ending, no need for a comma. // But, if the argument list is ending, no need for a comma.
peek(preceded(opt(whitespace), close_paren)).void(), peek(preceded(opt(whitespace), close_paren)).void().map(|_| None),
whitespace.map(|mut tokens| {
// Safe to unwrap here because `whitespace` is guaranteed to return at least 1 whitespace.
let first_token = tokens.pop().unwrap();
Some(SourceRange::from(&first_token))
}),
)) ))
.parse_next(i) .parse_next(i)
} }
@ -3135,7 +3141,7 @@ fn binding_name(i: &mut TokenSlice) -> ModalResult<Node<Identifier>> {
/// Either a positional or keyword function call. /// Either a positional or keyword function call.
fn fn_call_pos_or_kw(i: &mut TokenSlice) -> ModalResult<Expr> { fn fn_call_pos_or_kw(i: &mut TokenSlice) -> ModalResult<Expr> {
alt((fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),)).parse_next(i) fn_call_kw.map(Box::new).map(Expr::CallExpressionKw).parse_next(i)
} }
fn labelled_fn_call(i: &mut TokenSlice) -> ModalResult<Expr> { fn labelled_fn_call(i: &mut TokenSlice) -> ModalResult<Expr> {
@ -3198,7 +3204,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> ModalResult<Node<CallExpressionKw>> {
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
enum ArgPlace { enum ArgPlace {
NonCode(Node<NonCodeNode>), NonCode(Node<NonCodeNode>),
LabeledArg(LabeledArg), LabeledArg((LabeledArg, Option<SourceRange>)),
UnlabeledArg(Expr), UnlabeledArg(Expr),
Keyword(Token), Keyword(Token),
} }
@ -3208,7 +3214,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> ModalResult<Node<CallExpressionKw>> {
alt(( alt((
terminated(non_code_node.map(ArgPlace::NonCode), whitespace), terminated(non_code_node.map(ArgPlace::NonCode), whitespace),
terminated(any_keyword.map(ArgPlace::Keyword), whitespace), terminated(any_keyword.map(ArgPlace::Keyword), whitespace),
terminated(labeled_argument, labeled_arg_separator).map(ArgPlace::LabeledArg), (labeled_argument, labeled_arg_separator).map(ArgPlace::LabeledArg),
expression.map(ArgPlace::UnlabeledArg), expression.map(ArgPlace::UnlabeledArg),
)), )),
) )
@ -3220,7 +3226,16 @@ fn fn_call_kw(i: &mut TokenSlice) -> ModalResult<Node<CallExpressionKw>> {
ArgPlace::NonCode(x) => { ArgPlace::NonCode(x) => {
non_code_nodes.insert(index, vec![x]); non_code_nodes.insert(index, vec![x]);
} }
ArgPlace::LabeledArg(x) => { ArgPlace::LabeledArg((x, bad_token_source_range)) => {
if let Some(bad_token_source_range) = bad_token_source_range {
return Err(ErrMode::Cut(
CompilationError::fatal(
bad_token_source_range,
"Missing comma between arguments, try adding a comma in",
)
.into(),
));
}
args.push(x); args.push(x);
} }
ArgPlace::Keyword(kw) => { ArgPlace::Keyword(kw) => {
@ -3255,7 +3270,22 @@ fn fn_call_kw(i: &mut TokenSlice) -> ModalResult<Node<CallExpressionKw>> {
)?; )?;
ignore_whitespace(i); ignore_whitespace(i);
opt(comma_sep).parse_next(i)?; opt(comma_sep).parse_next(i)?;
let end = close_paren.parse_next(i)?.end; let end = match close_paren.parse_next(i) {
Ok(tok) => tok.end,
Err(e) => {
if let Some(tok) = i.next_token() {
return Err(ErrMode::Cut(
CompilationError::fatal(
SourceRange::from(&tok),
format!("There was an unexpected {}. Try removing it.", tok.value),
)
.into(),
));
} else {
return Err(e);
}
}
};
// Validate there aren't any duplicate labels. // Validate there aren't any duplicate labels.
let mut counted_labels = IndexMap::with_capacity(args.len()); let mut counted_labels = IndexMap::with_capacity(args.len());
@ -3376,8 +3406,7 @@ mod tests {
fn kw_call_as_operand() { fn kw_call_as_operand() {
let tokens = crate::parsing::token::lex("f(x = 1)", ModuleId::default()).unwrap(); let tokens = crate::parsing::token::lex("f(x = 1)", ModuleId::default()).unwrap();
let tokens = tokens.as_slice(); let tokens = tokens.as_slice();
let op = operand.parse(tokens).unwrap(); operand.parse(tokens).unwrap();
println!("{op:#?}");
} }
#[test] #[test]
@ -4383,7 +4412,7 @@ secondExtrude = startSketchOn(XY)
#[test] #[test]
fn test_parse_parens_unicode() { fn test_parse_parens_unicode() {
let result = crate::parsing::top_level_parse(""); let result = crate::parsing::top_level_parse("");
let KclError::Lexical(details) = result.0.unwrap_err() else { let KclError::Lexical { details } = result.0.unwrap_err() else {
panic!(); panic!();
}; };
// TODO: Better errors when program cannot tokenize. // TODO: Better errors when program cannot tokenize.
@ -4417,8 +4446,8 @@ z(-[["#,
assert_err( assert_err(
r#"z r#"z
(--#"#, (--#"#,
"Unexpected token: (", "There was an unexpected -. Try removing it.",
[2, 3], [3, 4],
); );
} }
@ -5133,6 +5162,27 @@ bar = 1
assert_eq!(actual.operator, UnaryOperator::Not); assert_eq!(actual.operator, UnaryOperator::Not);
crate::parsing::top_level_parse(some_program_string).unwrap(); // Updated import path crate::parsing::top_level_parse(some_program_string).unwrap(); // Updated import path
} }
#[test]
fn test_sensible_error_when_missing_comma_between_fn_args() {
let program_source = "startSketchOn(XY)
|> arc(
endAbsolute = [0, 50]
interiorAbsolute = [-50, 0]
)";
let expected_src_start = program_source.find("]").unwrap();
let tokens = crate::parsing::token::lex(program_source, ModuleId::default()).unwrap();
ParseContext::init();
let err = program
.parse(tokens.as_slice())
.expect_err("Program succeeded, but it should have failed");
let cause = err
.inner()
.cause
.as_ref()
.expect("Found an error, but there was no cause. Add a cause.");
assert_eq!(cause.message, "Missing comma between arguments, try adding a comma in",);
assert_eq!(cause.source_range.start() - 1, expected_src_start);
}
#[test] #[test]
fn test_sensible_error_when_missing_rhs_of_kw_arg() { fn test_sensible_error_when_missing_rhs_of_kw_arg() {
@ -5152,14 +5202,32 @@ bar = 1
} }
} }
#[test]
fn test_sensible_error_when_unexpected_token_in_fn_call() {
let program_source = "1
|> extrude(
length=depth,
})";
let expected_src_start = program_source.find("}").expect("Program should have an extraneous }");
let tokens = crate::parsing::token::lex(program_source, ModuleId::default()).unwrap();
ParseContext::init();
let err = program.parse(tokens.as_slice()).unwrap_err();
let cause = err
.inner()
.cause
.as_ref()
.expect("Found an error, but there was no cause. Add a cause.");
assert_eq!(cause.message, "There was an unexpected }. Try removing it.",);
assert_eq!(cause.source_range.start(), expected_src_start);
}
#[test] #[test]
fn test_sensible_error_when_using_keyword_as_arg_label() { fn test_sensible_error_when_using_keyword_as_arg_label() {
for (i, program) in ["pow(2, fn = 8)"].into_iter().enumerate() { for (i, program) in ["pow(2, fn = 8)"].into_iter().enumerate() {
let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap(); let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap();
let err = match fn_call_kw.parse(tokens.as_slice()) { let err = match fn_call_kw.parse(tokens.as_slice()) {
Err(e) => e, Err(e) => e,
Ok(ast) => { Ok(_ast) => {
eprintln!("{ast:#?}");
panic!("Expected this to error but it didn't"); panic!("Expected this to error but it didn't");
} }
}; };

View File

@ -597,7 +597,7 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
// This is an offset, not an index, and may point to // This is an offset, not an index, and may point to
// the end of input (input.len()) on eof errors. // the end of input (input.len()) on eof errors.
return KclError::Lexical(crate::errors::KclErrorDetails::new( return KclError::new_lexical(crate::errors::KclErrorDetails::new(
"unexpected EOF while parsing".to_owned(), "unexpected EOF while parsing".to_owned(),
vec![SourceRange::new(offset, offset, module_id)], vec![SourceRange::new(offset, offset, module_id)],
)); ));
@ -608,7 +608,7 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
let bad_token = &input[offset]; let bad_token = &input[offset];
// TODO: Add the Winnow parser context to the error. // TODO: Add the Winnow parser context to the error.
// See https://github.com/KittyCAD/modeling-app/issues/784 // See https://github.com/KittyCAD/modeling-app/issues/784
KclError::Lexical(crate::errors::KclErrorDetails::new( KclError::new_lexical(crate::errors::KclErrorDetails::new(
format!("found unknown token '{}'", bad_token), format!("found unknown token '{}'", bad_token),
vec![SourceRange::new(offset, offset + 1, module_id)], vec![SourceRange::new(offset, offset + 1, module_id)],
)) ))

View File

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

View File

@ -30,7 +30,7 @@ pub async fn hex_string(exec_state: &mut ExecState, args: Args) -> Result<KclVal
// Make sure the color if set is valid. // Make sure the color if set is valid.
if let Some(component) = rgb.iter().find(|component| component.n < 0.0 || component.n > 255.0) { if let Some(component) = rgb.iter().find(|component| component.n < 0.0 || component.n > 255.0) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Colors are given between 0 and 255, so {} is invalid", component.n), format!("Colors are given between 0 and 255, so {} is invalid", component.n),
vec![args.source_range], vec![args.source_range],
))); )));
@ -62,7 +62,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
// Make sure the color if set is valid. // Make sure the color if set is valid.
if !HEX_REGEX.is_match(&color) { if !HEX_REGEX.is_match(&color) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Invalid hex color (`{}`), try something like `#fff000`", color), format!("Invalid hex color (`{}`), try something like `#fff000`", color),
vec![args.source_range], vec![args.source_range],
))); )));
@ -93,7 +93,7 @@ async fn inner_appearance(
for solid_id in solids.ids(&args.ctx).await? { for solid_id in solids.ids(&args.ctx).await? {
// Set the material properties. // Set the material properties.
let rgb = rgba_simple::RGB::<f32>::from_hex(&color).map_err(|err| { let rgb = rgba_simple::RGB::<f32>::from_hex(&color).map_err(|err| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Invalid hex color (`{color}`): {err}"), format!("Invalid hex color (`{color}`): {err}"),
vec![args.source_range], vec![args.source_range],
)) ))

View File

@ -123,7 +123,7 @@ impl Args {
} }
T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| { T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!( format!(
"The arg {label} was given, but it was the wrong type. It should be type {} but it was {}", "The arg {label} was given, but it was the wrong type. It should be type {} but it was {}",
tynm::type_name::<T>(), tynm::type_name::<T>(),
@ -156,7 +156,7 @@ impl Args {
T: FromKclValue<'a>, T: FromKclValue<'a>,
{ {
self.get_kw_arg_opt(label)?.ok_or_else(|| { self.get_kw_arg_opt(label)?.ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("This function requires a keyword argument '{label}'"), format!("This function requires a keyword argument '{label}'"),
vec![self.source_range], vec![self.source_range],
)) ))
@ -173,7 +173,7 @@ impl Args {
T: for<'a> FromKclValue<'a>, T: for<'a> FromKclValue<'a>,
{ {
let Some(arg) = self.kw_args.labeled.get(label) else { let Some(arg) = self.kw_args.labeled.get(label) else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("This function requires a keyword argument '{label}'"), format!("This function requires a keyword argument '{label}'"),
vec![self.source_range], vec![self.source_range],
))); )));
@ -207,7 +207,7 @@ impl Args {
if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") { if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}"); message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
} }
KclError::Semantic(KclErrorDetails::new(message, arg.source_ranges())) KclError::new_semantic(KclErrorDetails::new(message, arg.source_ranges()))
})?; })?;
// TODO unnecessary cloning // TODO unnecessary cloning
@ -221,7 +221,7 @@ impl Args {
label: &str, label: &str,
) -> Result<Vec<(EdgeReference, SourceRange)>, KclError> { ) -> Result<Vec<(EdgeReference, SourceRange)>, KclError> {
let Some(arg) = self.kw_args.labeled.get(label) else { let Some(arg) = self.kw_args.labeled.get(label) else {
let err = KclError::Semantic(KclErrorDetails::new( let err = KclError::new_semantic(KclErrorDetails::new(
format!("This function requires a keyword argument '{label}'"), format!("This function requires a keyword argument '{label}'"),
vec![self.source_range], vec![self.source_range],
)); ));
@ -234,7 +234,7 @@ impl Args {
.map(|item| { .map(|item| {
let source = SourceRange::from(item); let source = SourceRange::from(item);
let val = FromKclValue::from_kcl_val(item).ok_or_else(|| { let val = FromKclValue::from_kcl_val(item).ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Expected an Edge but found {}", arg.value.human_friendly_type()), format!("Expected an Edge but found {}", arg.value.human_friendly_type()),
arg.source_ranges(), arg.source_ranges(),
)) ))
@ -270,7 +270,7 @@ impl Args {
{ {
let arg = self let arg = self
.unlabeled_kw_arg_unconverted() .unlabeled_kw_arg_unconverted()
.ok_or(KclError::Semantic(KclErrorDetails::new( .ok_or(KclError::new_semantic(KclErrorDetails::new(
format!("This function requires a value for the special unlabeled first parameter, '{label}'"), format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
vec![self.source_range], vec![self.source_range],
)))?; )))?;
@ -304,11 +304,11 @@ impl Args {
if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") { if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}"); message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
} }
KclError::Semantic(KclErrorDetails::new(message, arg.source_ranges())) KclError::new_semantic(KclErrorDetails::new(message, arg.source_ranges()))
})?; })?;
T::from_kcl_val(&arg).ok_or_else(|| { T::from_kcl_val(&arg).ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Mismatch between type coercion and value extraction (this isn't your fault).\nTo assist in bug-reporting, expected type: {ty:?}; actual value: {arg:?}"), format!("Mismatch between type coercion and value extraction (this isn't your fault).\nTo assist in bug-reporting, expected type: {ty:?}; actual value: {arg:?}"),
vec![self.source_range], vec![self.source_range],
)) ))
@ -354,14 +354,14 @@ impl Args {
exec_state.stack().get_from_call_stack(&tag.value, self.source_range)? exec_state.stack().get_from_call_stack(&tag.value, self.source_range)?
{ {
let info = t.get_info(epoch).ok_or_else(|| { let info = t.get_info(epoch).ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Tag `{}` does not have engine info", tag.value), format!("Tag `{}` does not have engine info", tag.value),
vec![self.source_range], vec![self.source_range],
)) ))
})?; })?;
Ok(info) Ok(info)
} else { } else {
Err(KclError::Type(KclErrorDetails::new( Err(KclError::new_type(KclErrorDetails::new(
format!("Tag `{}` does not exist", tag.value), format!("Tag `{}` does not exist", tag.value),
vec![self.source_range], vec![self.source_range],
))) )))
@ -493,7 +493,7 @@ impl Args {
must_be_planar: bool, must_be_planar: bool,
) -> Result<uuid::Uuid, KclError> { ) -> Result<uuid::Uuid, KclError> {
if tag.value.is_empty() { if tag.value.is_empty() {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Expected a non-empty tag for the face".to_string(), "Expected a non-empty tag for the face".to_string(),
vec![self.source_range], vec![self.source_range],
))); )));
@ -502,7 +502,7 @@ impl Args {
let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?; let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?;
let surface = engine_info.surface.as_ref().ok_or_else(|| { let surface = engine_info.surface.as_ref().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Tag `{}` does not have a surface", tag.value), format!("Tag `{}` does not have a surface", tag.value),
vec![self.source_range], vec![self.source_range],
)) ))
@ -521,7 +521,7 @@ impl Args {
} }
} }
// The must be planar check must be called before the arc check. // The must be planar check must be called before the arc check.
ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails::new( ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::new_type(KclErrorDetails::new(
format!("Tag `{}` is a non-planar surface", tag.value), format!("Tag `{}` is a non-planar surface", tag.value),
vec![self.source_range], vec![self.source_range],
)))), )))),
@ -548,7 +548,7 @@ impl Args {
} }
} }
// The must be planar check must be called before the fillet check. // The must be planar check must be called before the fillet check.
ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails::new( ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::new_type(KclErrorDetails::new(
format!("Tag `{}` is a non-planar surface", tag.value), format!("Tag `{}` is a non-planar surface", tag.value),
vec![self.source_range], vec![self.source_range],
)))), )))),
@ -568,7 +568,7 @@ impl Args {
} }
// If we still haven't found the face, return an error. // If we still haven't found the face, return an error.
Err(KclError::Type(KclErrorDetails::new( Err(KclError::new_type(KclErrorDetails::new(
format!("Expected a face with the tag `{}`", tag.value), format!("Expected a face with the tag `{}`", tag.value),
vec![self.source_range], vec![self.source_range],
))) )))
@ -593,13 +593,13 @@ where
{ {
fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> { fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
let Some(arg) = args.args.get(i) else { let Some(arg) = args.args.get(i) else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Expected an argument at index {i}"), format!("Expected an argument at index {i}"),
vec![args.source_range], vec![args.source_range],
))); )));
}; };
let Some(val) = T::from_kcl_val(&arg.value) else { let Some(val) = T::from_kcl_val(&arg.value) else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Argument at index {i} was supposed to be type {} but found {}", "Argument at index {i} was supposed to be type {} but found {}",
tynm::type_name::<T>(), tynm::type_name::<T>(),
@ -622,7 +622,7 @@ where
return Ok(None); return Ok(None);
} }
let Some(val) = T::from_kcl_val(&arg.value) else { let Some(val) = T::from_kcl_val(&arg.value) else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Argument at index {i} was supposed to be type Option<{}> but found {}", "Argument at index {i} was supposed to be type Option<{}> but found {}",
tynm::type_name::<T>(), tynm::type_name::<T>(),

View File

@ -58,7 +58,7 @@ async fn call_map_closure(
let output = map_fn.call_kw(None, exec_state, ctxt, args, source_range).await?; let output = map_fn.call_kw(None, exec_state, ctxt, args, source_range).await?;
let source_ranges = vec![source_range]; let source_ranges = vec![source_range];
let output = output.ok_or_else(|| { let output = output.ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
"Map function must return a value".to_owned(), "Map function must return a value".to_owned(),
source_ranges, source_ranges,
)) ))
@ -118,7 +118,7 @@ async fn call_reduce_closure(
// Unpack the returned transform object. // Unpack the returned transform object.
let source_ranges = vec![source_range]; let source_ranges = vec![source_range];
let out = transform_fn_return.ok_or_else(|| { let out = transform_fn_return.ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
"Reducer function must return a value".to_string(), "Reducer function must return a value".to_string(),
source_ranges.clone(), source_ranges.clone(),
)) ))
@ -138,7 +138,7 @@ pub async fn push(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
pub async fn pop(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn pop(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (mut array, ty) = args.get_unlabeled_kw_arg_array_and_type("array", exec_state)?; let (mut array, ty) = args.get_unlabeled_kw_arg_array_and_type("array", exec_state)?;
if array.is_empty() { if array.is_empty() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Cannot pop from an empty array".to_string(), "Cannot pop from an empty array".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -11,7 +11,7 @@ use crate::{
async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError> { async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError> {
if !value { if !value {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
format!("assert failed: {}", message), format!("assert failed: {}", message),
vec![args.source_range], vec![args.source_range],
))); )));
@ -72,14 +72,14 @@ async fn inner_assert(
.iter() .iter()
.all(|cond| cond.is_none()); .all(|cond| cond.is_none());
if no_condition_given { if no_condition_given {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"You must provide at least one condition in this assert (for example, isEqualTo)".to_owned(), "You must provide at least one condition in this assert (for example, isEqualTo)".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if tolerance.is_some() && is_equal_to.is_none() { if tolerance.is_some() && is_equal_to.is_none() {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"The `tolerance` arg is only used with `isEqualTo`. Either remove `tolerance` or add an `isEqualTo` arg." "The `tolerance` arg is only used with `isEqualTo`. Either remove `tolerance` or add an `isEqualTo` arg."
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],

View File

@ -41,7 +41,7 @@ async fn inner_chamfer(
// If you try and tag multiple edges with a tagged chamfer, we want to return an // If you try and tag multiple edges with a tagged chamfer, we want to return an
// error to the user that they can only tag one edge at a time. // error to the user that they can only tag one edge at a time.
if tag.is_some() && tags.len() > 1 { if tag.is_some() && tags.len() > 1 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"You can only tag one edge at a time with a tagged chamfer. Either delete the tag for the chamfer fn if you don't need it OR separate into individual chamfer functions for each tag.".to_string(), "You can only tag one edge at a time with a tagged chamfer. Either delete the tag for the chamfer fn if you don't need it OR separate into individual chamfer functions for each tag.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -84,7 +84,7 @@ async fn inner_clone(
fix_tags_and_references(&mut new_geometry, old_id, exec_state, &args) fix_tags_and_references(&mut new_geometry, old_id, exec_state, &args)
.await .await
.map_err(|e| { .map_err(|e| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("failed to fix tags and references: {:?}", e), format!("failed to fix tags and references: {:?}", e),
vec![args.source_range], vec![args.source_range],
)) ))

View File

@ -23,7 +23,7 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?; let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
if solids.len() < 2 { if solids.len() < 2 {
return Err(KclError::UndefinedValue(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"At least two solids are required for a union operation.".to_string(), "At least two solids are required for a union operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -66,7 +66,7 @@ pub(crate) async fn inner_union(
modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }), modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }),
} = result } = result
else { else {
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
"Failed to get the result of the union operation.".to_string(), "Failed to get the result of the union operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -88,7 +88,7 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?; let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
if solids.len() < 2 { if solids.len() < 2 {
return Err(KclError::UndefinedValue(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"At least two solids are required for an intersect operation.".to_string(), "At least two solids are required for an intersect operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -131,7 +131,7 @@ pub(crate) async fn inner_intersect(
modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }), modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }),
} = result } = result
else { else {
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
"Failed to get the result of the intersection operation.".to_string(), "Failed to get the result of the intersection operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -193,7 +193,7 @@ pub(crate) async fn inner_subtract(
modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }), modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }),
} = result } = result
else { else {
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
"Failed to get the result of the subtract operation.".to_string(), "Failed to get the result of the subtract operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -52,7 +52,7 @@ async fn inner_get_opposite_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge), modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp), format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));
@ -100,7 +100,7 @@ async fn inner_get_next_adjacent_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge), modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!( format!(
"mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}", "mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}",
resp resp
@ -110,7 +110,7 @@ async fn inner_get_next_adjacent_edge(
}; };
adjacent_edge.edge.ok_or_else(|| { adjacent_edge.edge.ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("No edge found next adjacent to tag: `{}`", edge.value), format!("No edge found next adjacent to tag: `{}`", edge.value),
vec![args.source_range], vec![args.source_range],
)) ))
@ -155,7 +155,7 @@ async fn inner_get_previous_adjacent_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge), modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!( format!(
"mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}", "mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}",
resp resp
@ -165,7 +165,7 @@ async fn inner_get_previous_adjacent_edge(
}; };
adjacent_edge.edge.ok_or_else(|| { adjacent_edge.edge.ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("No edge found previous adjacent to tag: `{}`", edge.value), format!("No edge found previous adjacent to tag: `{}`", edge.value),
vec![args.source_range], vec![args.source_range],
)) ))
@ -198,7 +198,7 @@ async fn inner_get_common_edge(
} }
if faces.len() != 2 { if faces.len() != 2 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"getCommonEdge requires exactly two tags for faces".to_string(), "getCommonEdge requires exactly two tags for faces".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -210,7 +210,7 @@ async fn inner_get_common_edge(
let second_tagged_path = args.get_tag_engine_info(exec_state, &faces[1])?; let second_tagged_path = args.get_tag_engine_info(exec_state, &faces[1])?;
if first_tagged_path.sketch != second_tagged_path.sketch { if first_tagged_path.sketch != second_tagged_path.sketch {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"getCommonEdge requires the faces to be in the same original sketch".to_string(), "getCommonEdge requires the faces to be in the same original sketch".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -239,14 +239,14 @@ async fn inner_get_common_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetCommonEdge(common_edge), modeling_response: OkModelingCmdResponse::Solid3dGetCommonEdge(common_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp), format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));
}; };
common_edge.edge.ok_or_else(|| { common_edge.edge.ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!( format!(
"No common edge was found between `{}` and `{}`", "No common edge was found between `{}` and `{}`",
faces[0].value, faces[1].value faces[0].value, faces[1].value

View File

@ -66,7 +66,7 @@ async fn inner_extrude(
let mut solids = Vec::new(); let mut solids = Vec::new();
if symmetric.unwrap_or(false) && bidirectional_length.is_some() { if symmetric.unwrap_or(false) && bidirectional_length.is_some() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other" "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -153,7 +153,7 @@ pub(crate) async fn do_post_extrude<'a>(
// The "get extrusion face info" API call requires *any* edge on the sketch being extruded. // The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
// So, let's just use the first one. // So, let's just use the first one.
let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else { let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Expected a non-empty sketch".to_owned(), "Expected a non-empty sketch".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -278,7 +278,7 @@ pub(crate) async fn do_post_extrude<'a>(
// Add the tags for the start or end caps. // Add the tags for the start or end caps.
if let Some(tag_start) = named_cap_tags.start { if let Some(tag_start) = named_cap_tags.start {
let Some(start_cap_id) = start_cap_id else { let Some(start_cap_id) = start_cap_id else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
format!( format!(
"Expected a start cap ID for tag `{}` for extrusion of sketch {:?}", "Expected a start cap ID for tag `{}` for extrusion of sketch {:?}",
tag_start.name, sketch.id tag_start.name, sketch.id
@ -298,7 +298,7 @@ pub(crate) async fn do_post_extrude<'a>(
} }
if let Some(tag_end) = named_cap_tags.end { if let Some(tag_end) = named_cap_tags.end {
let Some(end_cap_id) = end_cap_id else { let Some(end_cap_id) = end_cap_id else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
format!( format!(
"Expected an end cap ID for tag `{}` for extrusion of sketch {:?}", "Expected an end cap ID for tag `{}` for extrusion of sketch {:?}",
tag_end.name, sketch.id tag_end.name, sketch.id

View File

@ -49,7 +49,7 @@ pub(super) fn validate_unique<T: Eq + std::hash::Hash>(tags: &[(T, SourceRange)]
} }
} }
if !duplicate_tags_source.is_empty() { if !duplicate_tags_source.is_empty() {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge" "The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge"
.to_string(), .to_string(),
duplicate_tags_source, duplicate_tags_source,
@ -85,14 +85,14 @@ async fn inner_fillet(
// If you try and tag multiple edges with a tagged fillet, we want to return an // If you try and tag multiple edges with a tagged fillet, we want to return an
// error to the user that they can only tag one edge at a time. // error to the user that they can only tag one edge at a time.
if tag.is_some() && tags.len() > 1 { if tag.is_some() && tags.len() > 1 {
return Err(KclError::Type(KclErrorDetails { return Err(KclError::new_type(KclErrorDetails {
message: "You can only tag one edge at a time with a tagged fillet. Either delete the tag for the fillet fn if you don't need it OR separate into individual fillet functions for each tag.".to_string(), message: "You can only tag one edge at a time with a tagged fillet. Either delete the tag for the fillet fn if you don't need it OR separate into individual fillet functions for each tag.".to_string(),
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
backtrace: Default::default(), backtrace: Default::default(),
})); }));
} }
if tags.is_empty() { if tags.is_empty() {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::new_semantic(KclErrorDetails {
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
message: "You must fillet at least one tag".to_owned(), message: "You must fillet at least one tag".to_owned(),
backtrace: Default::default(), backtrace: Default::default(),

View File

@ -33,7 +33,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
// Make sure we have a radius if we don't have a cylinder. // Make sure we have a radius if we don't have a cylinder.
if radius.is_none() && cylinder.is_none() { if radius.is_none() && cylinder.is_none() {
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new( return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
"Radius is required when creating a helix without a cylinder.".to_string(), "Radius is required when creating a helix without a cylinder.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -41,7 +41,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
// Make sure we don't have a radius if we have a cylinder. // Make sure we don't have a radius if we have a cylinder.
if radius.is_some() && cylinder.is_some() { if radius.is_some() && cylinder.is_some() {
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new( return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
"Radius is not allowed when creating a helix with a cylinder.".to_string(), "Radius is not allowed when creating a helix with a cylinder.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -49,7 +49,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
// Make sure we have an axis if we don't have a cylinder. // Make sure we have an axis if we don't have a cylinder.
if axis.is_none() && cylinder.is_none() { if axis.is_none() && cylinder.is_none() {
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new( return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
"Axis is required when creating a helix without a cylinder.".to_string(), "Axis is required when creating a helix without a cylinder.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -57,7 +57,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
// Make sure we don't have an axis if we have a cylinder. // Make sure we don't have an axis if we have a cylinder.
if axis.is_some() && cylinder.is_some() { if axis.is_some() && cylinder.is_some() {
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new( return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
"Axis is not allowed when creating a helix with a cylinder.".to_string(), "Axis is not allowed when creating a helix with a cylinder.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -65,7 +65,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
// Make sure we have a radius if we have an axis. // Make sure we have a radius if we have an axis.
if radius.is_none() && axis.is_some() { if radius.is_none() && axis.is_some() {
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new( return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
"Radius is required when creating a helix around an axis.".to_string(), "Radius is required when creating a helix around an axis.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -73,7 +73,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
// Make sure we have an axis if we have a radius. // Make sure we have an axis if we have a radius.
if axis.is_none() && radius.is_some() { if axis.is_none() && radius.is_some() {
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new( return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
"Axis is required when creating a helix around an axis.".to_string(), "Axis is required when creating a helix around an axis.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -140,7 +140,7 @@ async fn inner_helix(
Axis3dOrEdgeReference::Axis { direction, origin } => { Axis3dOrEdgeReference::Axis { direction, origin } => {
// Make sure they gave us a length. // Make sure they gave us a length.
let Some(length) = length else { let Some(length) = length else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Length is required when creating a helix around an axis.".to_owned(), "Length is required when creating a helix around an axis.".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -68,7 +68,7 @@ async fn inner_loft(
) -> Result<Box<Solid>, KclError> { ) -> Result<Box<Solid>, KclError> {
// Make sure we have at least two sketches. // Make sure we have at least two sketches.
if sketches.len() < 2 { if sketches.len() < 2 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Loft requires at least two sketches, but only {} were provided.", "Loft requires at least two sketches, but only {} were provided.",
sketches.len() sketches.len()

View File

@ -56,7 +56,7 @@ pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
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 { if input.n < 0.0 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Attempt to take square root (`sqrt`) of a number less than zero ({})", "Attempt to take square root (`sqrt`) of a number less than zero ({})",
input.n input.n

View File

@ -101,7 +101,7 @@ async fn inner_mirror_2d(
OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }), OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }),
} = response } = response
else { else {
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
"Expected a successful response from EntityGetAllChildUuids".to_string(), "Expected a successful response from EntityGetAllChildUuids".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -112,7 +112,7 @@ async fn inner_mirror_2d(
let child_id = child_ids[1]; let child_id = child_ids[1];
sketch.mirror = Some(child_id); sketch.mirror = Some(child_id);
} else { } else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Expected child uuids to be >= 2".to_string(), "Expected child uuids to be >= 2".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -45,17 +45,6 @@ pub type StdFn = fn(
lazy_static! { lazy_static! {
static ref CORE_FNS: Vec<Box<dyn StdLibFn>> = vec![ static ref CORE_FNS: Vec<Box<dyn StdLibFn>> = vec![
Box::new(crate::std::segment::SegEnd),
Box::new(crate::std::segment::SegEndX),
Box::new(crate::std::segment::SegEndY),
Box::new(crate::std::segment::SegStart),
Box::new(crate::std::segment::SegStartX),
Box::new(crate::std::segment::SegStartY),
Box::new(crate::std::segment::LastSegX),
Box::new(crate::std::segment::LastSegY),
Box::new(crate::std::segment::SegLen),
Box::new(crate::std::segment::SegAng),
Box::new(crate::std::segment::TangentToEnd),
Box::new(crate::std::sketch::InvoluteCircular), Box::new(crate::std::sketch::InvoluteCircular),
Box::new(crate::std::sketch::Line), Box::new(crate::std::sketch::Line),
Box::new(crate::std::sketch::XLine), Box::new(crate::std::sketch::XLine),
@ -210,15 +199,15 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
), ),
("transform", "translate") => ( ("transform", "translate") => (
|e, a| Box::pin(crate::std::transform::translate(e, a)), |e, a| Box::pin(crate::std::transform::translate(e, a)),
StdFnProps::default("std::transform::translate"), StdFnProps::default("std::transform::translate").include_in_feature_tree(),
), ),
("transform", "rotate") => ( ("transform", "rotate") => (
|e, a| Box::pin(crate::std::transform::rotate(e, a)), |e, a| Box::pin(crate::std::transform::rotate(e, a)),
StdFnProps::default("std::transform::rotate"), StdFnProps::default("std::transform::rotate").include_in_feature_tree(),
), ),
("transform", "scale") => ( ("transform", "scale") => (
|e, a| Box::pin(crate::std::transform::scale(e, a)), |e, a| Box::pin(crate::std::transform::scale(e, a)),
StdFnProps::default("std::transform::scale"), StdFnProps::default("std::transform::scale").include_in_feature_tree(),
), ),
("prelude", "offsetPlane") => ( ("prelude", "offsetPlane") => (
|e, a| Box::pin(crate::std::planes::offset_plane(e, a)), |e, a| Box::pin(crate::std::planes::offset_plane(e, a)),
@ -352,6 +341,50 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
|e, a| Box::pin(crate::std::patterns::pattern_circular_2d(e, a)), |e, a| Box::pin(crate::std::patterns::pattern_circular_2d(e, a)),
StdFnProps::default("std::sketch::patternCircular2d"), StdFnProps::default("std::sketch::patternCircular2d"),
), ),
("sketch", "segEnd") => (
|e, a| Box::pin(crate::std::segment::segment_end(e, a)),
StdFnProps::default("std::sketch::segEnd"),
),
("sketch", "segEndX") => (
|e, a| Box::pin(crate::std::segment::segment_end_x(e, a)),
StdFnProps::default("std::sketch::segEndX"),
),
("sketch", "segEndY") => (
|e, a| Box::pin(crate::std::segment::segment_end_y(e, a)),
StdFnProps::default("std::sketch::segEndY"),
),
("sketch", "segStart") => (
|e, a| Box::pin(crate::std::segment::segment_start(e, a)),
StdFnProps::default("std::sketch::segStart"),
),
("sketch", "segStartX") => (
|e, a| Box::pin(crate::std::segment::segment_start_x(e, a)),
StdFnProps::default("std::sketch::segStartX"),
),
("sketch", "segStartY") => (
|e, a| Box::pin(crate::std::segment::segment_start_y(e, a)),
StdFnProps::default("std::sketch::segStartY"),
),
("sketch", "lastSegX") => (
|e, a| Box::pin(crate::std::segment::last_segment_x(e, a)),
StdFnProps::default("std::sketch::lastSegX"),
),
("sketch", "lastSegY") => (
|e, a| Box::pin(crate::std::segment::last_segment_y(e, a)),
StdFnProps::default("std::sketch::lastSegY"),
),
("sketch", "segLen") => (
|e, a| Box::pin(crate::std::segment::segment_length(e, a)),
StdFnProps::default("std::sketch::segLen"),
),
("sketch", "segAng") => (
|e, a| Box::pin(crate::std::segment::segment_angle(e, a)),
StdFnProps::default("std::sketch::segAng"),
),
("sketch", "tangentToEnd") => (
|e, a| Box::pin(crate::std::segment::tangent_to_end(e, a)),
StdFnProps::default("std::sketch::tangentToEnd"),
),
("appearance", "hexString") => ( ("appearance", "hexString") => (
|e, a| Box::pin(crate::std::appearance::hex_string(e, a)), |e, a| Box::pin(crate::std::appearance::hex_string(e, a)),
StdFnProps::default("std::appearance::hexString"), StdFnProps::default("std::appearance::hexString"),

View File

@ -66,7 +66,7 @@ async fn inner_pattern_transform<'a>(
// Build the vec of transforms, one for each repetition. // Build the vec of transforms, one for each repetition.
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap()); let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
if instances < 1 { if instances < 1 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
MUST_HAVE_ONE_INSTANCE.to_owned(), MUST_HAVE_ONE_INSTANCE.to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -96,7 +96,7 @@ async fn inner_pattern_transform_2d<'a>(
// Build the vec of transforms, one for each repetition. // Build the vec of transforms, one for each repetition.
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap()); let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
if instances < 1 { if instances < 1 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
MUST_HAVE_ONE_INSTANCE.to_owned(), MUST_HAVE_ONE_INSTANCE.to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -176,7 +176,7 @@ async fn send_pattern_transform<T: GeometryTrait>(
} }
&mock_ids &mock_ids
} else { } else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("EntityLinearPattern response was not as expected: {:?}", resp), format!("EntityLinearPattern response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));
@ -222,7 +222,7 @@ async fn make_transform<T: GeometryTrait>(
// Unpack the returned transform object. // Unpack the returned transform object.
let source_ranges = vec![source_range]; let source_ranges = vec![source_range];
let transform_fn_return = transform_fn_return.ok_or_else(|| { let transform_fn_return = transform_fn_return.ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
"Transform function must return a value".to_string(), "Transform function must return a value".to_string(),
source_ranges.clone(), source_ranges.clone(),
)) ))
@ -233,7 +233,7 @@ async fn make_transform<T: GeometryTrait>(
let transforms: Vec<_> = value let transforms: Vec<_> = value
.into_iter() .into_iter()
.map(|val| { .map(|val| {
val.into_object().ok_or(KclError::Semantic(KclErrorDetails::new( val.into_object().ok_or(KclError::new_semantic(KclErrorDetails::new(
"Transform function must return a transform object".to_string(), "Transform function must return a transform object".to_string(),
source_ranges.clone(), source_ranges.clone(),
))) )))
@ -242,7 +242,7 @@ async fn make_transform<T: GeometryTrait>(
transforms transforms
} }
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Transform function must return a transform object".to_string(), "Transform function must return a transform object".to_string(),
source_ranges.clone(), source_ranges.clone(),
))) )))
@ -265,7 +265,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
Some(KclValue::Bool { value: true, .. }) => true, Some(KclValue::Bool { value: true, .. }) => true,
Some(KclValue::Bool { value: false, .. }) => false, Some(KclValue::Bool { value: false, .. }) => false,
Some(_) => { Some(_) => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"The 'replicate' key must be a bool".to_string(), "The 'replicate' key must be a bool".to_string(),
source_ranges.clone(), source_ranges.clone(),
))); )));
@ -297,7 +297,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
let mut rotation = Rotation::default(); let mut rotation = Rotation::default();
if let Some(rot) = transform.get("rotation") { if let Some(rot) = transform.get("rotation") {
let KclValue::Object { value: rot, meta: _ } = rot else { let KclValue::Object { value: rot, meta: _ } = rot else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"The 'rotation' key must be an object (with optional fields 'angle', 'axis' and 'origin')".to_owned(), "The 'rotation' key must be an object (with optional fields 'angle', 'axis' and 'origin')".to_owned(),
source_ranges.clone(), source_ranges.clone(),
))); )));
@ -311,7 +311,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
rotation.angle = Angle::from_degrees(*number); rotation.angle = Angle::from_degrees(*number);
} }
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"The 'rotation.angle' key must be a number (of degrees)".to_owned(), "The 'rotation.angle' key must be a number (of degrees)".to_owned(),
source_ranges.clone(), source_ranges.clone(),
))); )));
@ -345,7 +345,7 @@ fn array_to_point3d(
) -> Result<[TyF64; 3], KclError> { ) -> Result<[TyF64; 3], KclError> {
val.coerce(&RuntimeType::point3d(), true, exec_state) val.coerce(&RuntimeType::point3d(), true, exec_state)
.map_err(|e| { .map_err(|e| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Expected an array of 3 numbers (i.e., a 3D point), found {}", "Expected an array of 3 numbers (i.e., a 3D point), found {}",
e.found e.found
@ -365,7 +365,7 @@ fn array_to_point2d(
) -> Result<[TyF64; 2], KclError> { ) -> Result<[TyF64; 2], KclError> {
val.coerce(&RuntimeType::point2d(), true, exec_state) val.coerce(&RuntimeType::point2d(), true, exec_state)
.map_err(|e| { .map_err(|e| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Expected an array of 2 numbers (i.e., a 2D point), found {}", "Expected an array of 2 numbers (i.e., a 2D point), found {}",
e.found e.found
@ -534,7 +534,7 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
let axis = axis.to_point2d(); let axis = axis.to_point2d();
if axis[0].n == 0.0 && axis[1].n == 0.0 { if axis[0].n == 0.0 && axis[1].n == 0.0 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place." "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -594,7 +594,7 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
let axis = axis.to_point3d(); let axis = axis.to_point3d();
if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 { if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place." "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -803,7 +803,7 @@ async fn inner_pattern_circular_2d(
.await?; .await?;
let Geometries::Sketches(new_sketches) = geometries else { let Geometries::Sketches(new_sketches) = geometries else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected a vec of sketches".to_string(), "Expected a vec of sketches".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -901,7 +901,7 @@ async fn inner_pattern_circular_3d(
.await?; .await?;
let Geometries::Solids(new_solids) = geometries else { let Geometries::Solids(new_solids) = geometries else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected a vec of solids".to_string(), "Expected a vec of solids".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -926,7 +926,7 @@ async fn pattern_circular(
return Ok(Geometries::from(geometry)); return Ok(Geometries::from(geometry));
} }
RepetitionsNeeded::Invalid => { RepetitionsNeeded::Invalid => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
MUST_HAVE_ONE_INSTANCE.to_owned(), MUST_HAVE_ONE_INSTANCE.to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -971,7 +971,7 @@ async fn pattern_circular(
} }
&mock_ids &mock_ids
} else { } else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("EntityCircularPattern response was not as expected: {:?}", resp), format!("EntityCircularPattern response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -75,7 +75,7 @@ async fn inner_revolve(
// We don't use validate() here because we want to return a specific error message that is // We don't use validate() here because we want to return a specific error message that is
// nice and we use the other data in the docs, so we still need use the derive above for the json schema. // nice and we use the other data in the docs, so we still need use the derive above for the json schema.
if !(-360.0..=360.0).contains(&angle) || angle == 0.0 { if !(-360.0..=360.0).contains(&angle) || angle == 0.0 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Expected angle to be between -360 and 360 and not 0, found `{}`", angle), format!("Expected angle to be between -360 and 360 and not 0, found `{}`", angle),
vec![args.source_range], vec![args.source_range],
))); )));
@ -87,7 +87,7 @@ async fn inner_revolve(
// We don't use validate() here because we want to return a specific error message that is // We don't use validate() here because we want to return a specific error message that is
// nice and we use the other data in the docs, so we still need use the derive above for the json schema. // nice and we use the other data in the docs, so we still need use the derive above for the json schema.
if !(-360.0..=360.0).contains(&bidirectional_angle) || bidirectional_angle == 0.0 { if !(-360.0..=360.0).contains(&bidirectional_angle) || bidirectional_angle == 0.0 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Expected bidirectional angle to be between -360 and 360 and not 0, found `{}`", "Expected bidirectional angle to be between -360 and 360 and not 0, found `{}`",
bidirectional_angle bidirectional_angle
@ -99,7 +99,7 @@ async fn inner_revolve(
if let Some(angle) = angle { if let Some(angle) = angle {
let ang = angle.signum() * bidirectional_angle + angle; let ang = angle.signum() * bidirectional_angle + angle;
if !(-360.0..=360.0).contains(&ang) { if !(-360.0..=360.0).contains(&ang) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Combined angle and bidirectional must be between -360 and 360, found '{}'", "Combined angle and bidirectional must be between -360 and 360, found '{}'",
ang ang
@ -111,7 +111,7 @@ async fn inner_revolve(
} }
if symmetric.unwrap_or(false) && bidirectional_angle.is_some() { if symmetric.unwrap_or(false) && bidirectional_angle.is_some() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other" "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],

View File

@ -1,7 +1,6 @@
//! Functions related to line segments. //! Functions related to line segments.
use anyhow::Result; use anyhow::Result;
use kcl_derive_docs::stdlib;
use kittycad_modeling_cmds::shared::Angle; use kittycad_modeling_cmds::shared::Angle;
use super::utils::untype_point; use super::utils::untype_point;
@ -22,43 +21,10 @@ pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclVa
args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone()) args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
} }
/// Compute the ending point of the provided line segment.
///
/// ```no_run
/// w = 15
/// cube = startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> line(end = [w, 0], tag = $line1)
/// |> line(end = [0, w], tag = $line2)
/// |> line(end = [-w, 0], tag = $line3)
/// |> line(end = [0, -w], tag = $line4)
/// |> close()
/// |> extrude(length = 5)
///
/// fn cylinder(radius, tag) {
/// return startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> circle(radius = radius, center = segEnd(tag) )
/// |> extrude(length = radius)
/// }
///
/// cylinder(radius = 1, tag = line1)
/// cylinder(radius = 2, tag = line2)
/// cylinder(radius = 3, tag = line3)
/// cylinder(radius = 4, tag = line4)
/// ```
#[stdlib {
name = "segEnd",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> { fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -78,31 +44,10 @@ pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<Kcl
Ok(args.make_user_val_from_f64_with_type(result)) Ok(args.make_user_val_from_f64_with_type(result))
} }
/// Compute the ending point of the provided line segment along the 'x' axis.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0], tag = $thing)
/// |> line(end = [0, 5])
/// |> line(end = [segEndX(thing), 0])
/// |> line(end = [-20, 10])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
#[stdlib {
name = "segEndX",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> { fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -119,32 +64,10 @@ pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<Kcl
Ok(args.make_user_val_from_f64_with_type(result)) Ok(args.make_user_val_from_f64_with_type(result))
} }
/// Compute the ending point of the provided line segment along the 'y' axis.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0])
/// |> line(end = [0, 3], tag = $thing)
/// |> line(end = [-10, 0])
/// |> line(end = [0, segEndY(thing)])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
#[stdlib {
name = "segEndY",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> { fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -161,43 +84,10 @@ pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<Kcl
args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone()) args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
} }
/// Compute the starting point of the provided line segment.
///
/// ```no_run
/// w = 15
/// cube = startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> line(end = [w, 0], tag = $line1)
/// |> line(end = [0, w], tag = $line2)
/// |> line(end = [-w, 0], tag = $line3)
/// |> line(end = [0, -w], tag = $line4)
/// |> close()
/// |> extrude(length = 5)
///
/// fn cylinder(radius, tag) {
/// return startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> circle( radius = radius, center = segStart(tag) )
/// |> extrude(length = radius)
/// }
///
/// cylinder(radius = 1, tag = line1)
/// cylinder(radius = 2, tag = line2)
/// cylinder(radius = 3, tag = line3)
/// cylinder(radius = 4, tag = line4)
/// ```
#[stdlib {
name = "segStart",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> { fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -217,31 +107,10 @@ pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<K
Ok(args.make_user_val_from_f64_with_type(result)) Ok(args.make_user_val_from_f64_with_type(result))
} }
/// Compute the starting point of the provided line segment along the 'x' axis.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0], tag = $thing)
/// |> line(end = [0, 5])
/// |> line(end = [20 - segStartX(thing), 0])
/// |> line(end = [-20, 10])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
#[stdlib {
name = "segStartX",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> { fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -258,32 +127,10 @@ pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<K
Ok(args.make_user_val_from_f64_with_type(result)) Ok(args.make_user_val_from_f64_with_type(result))
} }
/// Compute the starting point of the provided line segment along the 'y' axis.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0])
/// |> line(end = [0, 3], tag = $thing)
/// |> line(end = [-10, 0])
/// |> line(end = [0, 20-segStartY(thing)])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
#[stdlib {
name = "segStartY",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> { fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -300,34 +147,12 @@ pub async fn last_segment_x(exec_state: &mut ExecState, args: Args) -> Result<Kc
Ok(args.make_user_val_from_f64_with_type(result)) Ok(args.make_user_val_from_f64_with_type(result))
} }
/// Extract the 'x' axis value of the last line segment in the provided 2-d
/// sketch.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [5, 0])
/// |> line(end = [20, 5])
/// |> line(end = [lastSegX(%), 0])
/// |> line(end = [-15, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
#[stdlib {
name = "lastSegX",
unlabeled_first = true,
args = {
sketch = { docs = "The sketch whose line segment is being queried"},
},
tags = ["sketch"]
}]
fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> { fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
let last_line = sketch let last_line = sketch
.paths .paths
.last() .last()
.ok_or_else(|| { .ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a Sketch with at least one segment, found `{:?}`", sketch), format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
vec![args.source_range], vec![args.source_range],
)) ))
@ -346,34 +171,12 @@ pub async fn last_segment_y(exec_state: &mut ExecState, args: Args) -> Result<Kc
Ok(args.make_user_val_from_f64_with_type(result)) Ok(args.make_user_val_from_f64_with_type(result))
} }
/// Extract the 'y' axis value of the last line segment in the provided 2-d
/// sketch.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [5, 0])
/// |> line(end = [20, 5])
/// |> line(end = [0, lastSegY(%)])
/// |> line(end = [-15, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
#[stdlib {
name = "lastSegY",
unlabeled_first = true,
args = {
sketch = { docs = "The sketch whose line segment is being queried"},
},
tags = ["sketch"]
}]
fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> { fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
let last_line = sketch let last_line = sketch
.paths .paths
.last() .last()
.ok_or_else(|| { .ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a Sketch with at least one segment, found `{:?}`", sketch), format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
vec![args.source_range], vec![args.source_range],
)) ))
@ -390,37 +193,10 @@ pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<Kc
Ok(args.make_user_val_from_f64_with_type(result)) Ok(args.make_user_val_from_f64_with_type(result))
} }
/// Compute the length of the provided line segment.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 60,
/// length = 10,
/// tag = $thing,
/// )
/// |> tangentialArc(angle = -120, radius = 5)
/// |> angledLine(
/// angle = -60,
/// length = segLen(thing),
/// )
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
#[stdlib {
name = "segLen",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> { fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -437,33 +213,10 @@ pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<Kcl
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees()))) Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
} }
/// Compute the angle (in degrees) of the provided line segment.
///
/// ```no_run
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [10, 0])
/// |> line(end = [5, 10], tag = $seg01)
/// |> line(end = [-10, 0])
/// |> angledLine(angle = segAng(seg01), length = 10)
/// |> line(end = [-10, 0])
/// |> angledLine(angle = segAng(seg01), length = -15)
/// |> close()
///
/// example = extrude(exampleSketch, length = 4)
/// ```
#[stdlib {
name = "segAng",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> { fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -482,89 +235,10 @@ pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<Kc
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees()))) Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
} }
/// Returns the angle coming out of the end of the segment in degrees.
///
/// ```no_run
/// // Horizontal pill.
/// pillSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0])
/// |> tangentialArc(end = [0, 10], tag = $arc1)
/// |> angledLine(
/// angle = tangentToEnd(arc1),
/// length = 20,
/// )
/// |> tangentialArc(end = [0, -10])
/// |> close()
///
/// pillExtrude = extrude(pillSketch, length = 10)
/// ```
///
/// ```no_run
/// // Vertical pill. Use absolute coordinate for arc.
/// pillSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [0, 20])
/// |> tangentialArc(endAbsolute = [10, 20], tag = $arc1)
/// |> angledLine(
/// angle = tangentToEnd(arc1),
/// length = 20,
/// )
/// |> tangentialArc(end = [-10, 0])
/// |> close()
///
/// pillExtrude = extrude(pillSketch, length = 10)
/// ```
///
/// ```no_run
/// rectangleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [10, 0], tag = $seg1)
/// |> angledLine(
/// angle = tangentToEnd(seg1),
/// length = 10,
/// )
/// |> line(end = [0, 10])
/// |> line(end = [-20, 0])
/// |> close()
///
/// rectangleExtrude = extrude(rectangleSketch, length = 10)
/// ```
///
/// ```no_run
/// bottom = startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> arc(
/// endAbsolute = [10, 10],
/// interiorAbsolute = [5, 1],
/// tag = $arc1,
/// )
/// |> angledLine(angle = tangentToEnd(arc1), length = 20)
/// |> close()
/// ```
///
/// ```no_run
/// circSketch = startSketchOn(XY)
/// |> circle( center= [0, 0], radius= 3 , tag= $circ)
///
/// triangleSketch = startSketchOn(XY)
/// |> startProfile(at = [-5, 0])
/// |> angledLine(angle = tangentToEnd(circ), length = 10)
/// |> line(end = [-15, 0])
/// |> close()
/// ```
#[stdlib {
name = "tangentToEnd",
unlabeled_first = true,
args = {
tag = { docs = "The line segment being queried by its tag"},
},
tags = ["sketch"]
}]
async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> { async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
let line = args.get_tag_engine_info(exec_state, tag)?; let line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { let path = line.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a line segment with a path, found `{:?}`", line), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))

View File

@ -271,14 +271,14 @@ async fn inner_polygon(
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
if num_sides < 3 { if num_sides < 3 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Polygon must have at least 3 sides".to_string(), "Polygon must have at least 3 sides".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if radius.n <= 0.0 { if radius.n <= 0.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Radius must be greater than 0".to_string(), "Radius must be greater than 0".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -407,11 +407,11 @@ pub(crate) fn get_radius(
match (radius, diameter) { match (radius, diameter) {
(Some(radius), None) => Ok(radius), (Some(radius), None) => Ok(radius),
(None, Some(diameter)) => Ok(TyF64::new(diameter.n / 2.0, diameter.ty)), (None, Some(diameter)) => Ok(TyF64::new(diameter.n / 2.0, diameter.ty)),
(None, None) => Err(KclError::Type(KclErrorDetails::new( (None, None) => Err(KclError::new_type(KclErrorDetails::new(
"This function needs either `diameter` or `radius`".to_string(), "This function needs either `diameter` or `radius`".to_string(),
vec![source_range], vec![source_range],
))), ))),
(Some(_), Some(_)) => Err(KclError::Type(KclErrorDetails::new( (Some(_), Some(_)) => Err(KclError::new_type(KclErrorDetails::new(
"You cannot specify both `diameter` and `radius`, please remove one".to_string(), "You cannot specify both `diameter` and `radius`, please remove one".to_string(),
vec![source_range], vec![source_range],
))), ))),

View File

@ -36,14 +36,14 @@ async fn inner_shell(
args: Args, args: Args,
) -> Result<Vec<Solid>, KclError> { ) -> Result<Vec<Solid>, KclError> {
if faces.is_empty() { if faces.is_empty() {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"You must shell at least one face".to_owned(), "You must shell at least one face".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if solids.is_empty() { if solids.is_empty() {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"You must shell at least one solid".to_owned(), "You must shell at least one solid".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -63,7 +63,7 @@ async fn inner_shell(
} }
if face_ids.is_empty() { if face_ids.is_empty() {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Expected at least one valid face".to_owned(), "Expected at least one valid face".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -72,7 +72,7 @@ async fn inner_shell(
// Make sure all the solids have the same id, as we are going to shell them all at // Make sure all the solids have the same id, as we are going to shell them all at
// once. // once.
if !solids.iter().all(|eg| eg.id == solids[0].id) { if !solids.iter().all(|eg| eg.id == solids[0].id) {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"All solids stem from the same root object, like multiple sketch on face extrusions, etc.".to_owned(), "All solids stem from the same root object, like multiple sketch on face extrusions, etc.".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -12,6 +12,7 @@ use parse_display::{Display, FromStr};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::shapes::get_radius;
#[cfg(feature = "artifact-graph")] #[cfg(feature = "artifact-graph")]
use crate::execution::{Artifact, ArtifactId, CodeRef, StartSketchOnFace, StartSketchOnPlane}; use crate::execution::{Artifact, ArtifactId, CodeRef, StartSketchOnFace, StartSketchOnPlane};
use crate::{ use crate::{
@ -32,8 +33,6 @@ use crate::{
}, },
}; };
use super::shapes::get_radius;
/// A tag for a face. /// A tag for a face.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
@ -66,13 +65,13 @@ impl FaceTag {
match self { match self {
FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(exec_state, t, must_be_planar).await, FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(exec_state, t, must_be_planar).await,
FaceTag::StartOrEnd(StartOrEnd::Start) => solid.start_cap_id.ok_or_else(|| { FaceTag::StartOrEnd(StartOrEnd::Start) => solid.start_cap_id.ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
"Expected a start face".to_string(), "Expected a start face".to_string(),
vec![args.source_range], vec![args.source_range],
)) ))
}), }),
FaceTag::StartOrEnd(StartOrEnd::End) => solid.end_cap_id.ok_or_else(|| { FaceTag::StartOrEnd(StartOrEnd::End) => solid.end_cap_id.ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
"Expected an end face".to_string(), "Expected an end face".to_string(),
vec![args.source_range], vec![args.source_range],
)) ))
@ -329,7 +328,7 @@ async fn straight_line(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
let (point, is_absolute) = match (end_absolute, end) { let (point, is_absolute) = match (end_absolute, end) {
(Some(_), Some(_)) => { (Some(_), Some(_)) => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(), "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -337,7 +336,7 @@ async fn straight_line(
(Some(end_absolute), None) => (end_absolute, true), (Some(end_absolute), None) => (end_absolute, true),
(None, Some(end)) => (end, false), (None, Some(end)) => (end, false),
(None, None) => { (None, None) => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("You must supply either `{relative_name}` or `endAbsolute` arguments"), format!("You must supply either `{relative_name}` or `endAbsolute` arguments"),
vec![args.source_range], vec![args.source_range],
))); )));
@ -604,7 +603,7 @@ async fn inner_angled_line(
.filter(|x| x.is_some()) .filter(|x| x.is_some())
.count(); .count();
if options_given > 1 { if options_given > 1 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
" one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_string(), " one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -632,11 +631,11 @@ async fn inner_angled_line(
(None, None, None, None, Some(end_absolute_y)) => { (None, None, None, None, Some(end_absolute_y)) => {
inner_angled_line_to_y(angle_degrees, end_absolute_y, sketch, tag, exec_state, args).await inner_angled_line_to_y(angle_degrees, end_absolute_y, sketch, tag, exec_state, args).await
} }
(None, None, None, None, None) => Err(KclError::Type(KclErrorDetails::new( (None, None, None, None, None) => Err(KclError::new_type(KclErrorDetails::new(
"One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` must be given".to_string(), "One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` must be given".to_string(),
vec![args.source_range], vec![args.source_range],
))), ))),
_ => Err(KclError::Type(KclErrorDetails::new( _ => Err(KclError::new_type(KclErrorDetails::new(
"Only One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_owned(), "Only One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_owned(),
vec![args.source_range], vec![args.source_range],
))), ))),
@ -710,14 +709,14 @@ async fn inner_angled_line_of_x_length(
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
if angle_degrees.abs() == 270.0 { if angle_degrees.abs() == 270.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have an x constrained angle of 270 degrees".to_string(), "Cannot have an x constrained angle of 270 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 90.0 { if angle_degrees.abs() == 90.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have an x constrained angle of 90 degrees".to_string(), "Cannot have an x constrained angle of 90 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -742,14 +741,14 @@ async fn inner_angled_line_to_x(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
if angle_degrees.abs() == 270.0 { if angle_degrees.abs() == 270.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have an x constrained angle of 270 degrees".to_string(), "Cannot have an x constrained angle of 270 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 90.0 { if angle_degrees.abs() == 90.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have an x constrained angle of 90 degrees".to_string(), "Cannot have an x constrained angle of 90 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -777,14 +776,14 @@ async fn inner_angled_line_of_y_length(
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
if angle_degrees.abs() == 0.0 { if angle_degrees.abs() == 0.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have a y constrained angle of 0 degrees".to_string(), "Cannot have a y constrained angle of 0 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 180.0 { if angle_degrees.abs() == 180.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have a y constrained angle of 180 degrees".to_string(), "Cannot have a y constrained angle of 180 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -809,14 +808,14 @@ async fn inner_angled_line_to_y(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
if angle_degrees.abs() == 0.0 { if angle_degrees.abs() == 0.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have a y constrained angle of 0 degrees".to_string(), "Cannot have a y constrained angle of 0 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 180.0 { if angle_degrees.abs() == 180.0 {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Cannot have a y constrained angle of 180 degrees".to_string(), "Cannot have a y constrained angle of 180 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -893,7 +892,7 @@ pub async fn inner_angled_line_that_intersects(
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?; let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?;
let path = intersect_path.path.clone().ok_or_else(|| { let path = intersect_path.path.clone().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected an intersect path with a path, found `{:?}`", intersect_path), format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
vec![args.source_range], vec![args.source_range],
)) ))
@ -1170,7 +1169,7 @@ async fn inner_start_sketch_on(
SketchData::Plane(plane) => { SketchData::Plane(plane) => {
if plane.value == crate::exec::PlaneType::Uninit { if plane.value == crate::exec::PlaneType::Uninit {
if plane.info.origin.units == UnitLen::Unknown { if plane.info.origin.units == UnitLen::Unknown {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Origin of plane has unknown units".to_string(), "Origin of plane has unknown units".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -1194,7 +1193,7 @@ async fn inner_start_sketch_on(
} }
SketchData::Solid(solid) => { SketchData::Solid(solid) => {
let Some(tag) = face else { let Some(tag) = face else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Expected a tag for the face to sketch on".to_string(), "Expected a tag for the face to sketch on".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -1544,6 +1543,11 @@ pub async fn close(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// Construct a line segment from the current origin back to the profile's /// Construct a line segment from the current origin back to the profile's
/// origin, ensuring the resulting 2-dimensional sketch is not open-ended. /// origin, ensuring the resulting 2-dimensional sketch is not open-ended.
/// ///
/// If you want to perform some 3-dimensional operation on a sketch, like
/// extrude or sweep, you must `close` it first. `close` must be called even
/// if the end point of the last segment is coincident with the sketch
/// starting point.
///
/// ```no_run /// ```no_run
/// startSketchOn(XZ) /// startSketchOn(XZ)
/// |> startProfile(at = [0, 0]) /// |> startProfile(at = [0, 0])
@ -1713,7 +1717,7 @@ pub(crate) async fn inner_arc(
absolute_arc(&args, id, exec_state, sketch, from, interior_absolute, end_absolute, tag).await absolute_arc(&args, id, exec_state, sketch, from, interior_absolute, end_absolute, tag).await
} }
_ => { _ => {
Err(KclError::Type(KclErrorDetails::new( Err(KclError::new_type(KclErrorDetails::new(
"Invalid combination of arguments. Either provide (angleStart, angleEnd, radius) or (endAbsolute, interiorAbsolute)".to_owned(), "Invalid combination of arguments. Either provide (angleStart, angleEnd, radius) or (endAbsolute, interiorAbsolute)".to_owned(),
vec![args.source_range], vec![args.source_range],
))) )))
@ -1800,7 +1804,7 @@ pub async fn relative_arc(
let radius = radius.to_length_units(from.units); let radius = radius.to_length_units(from.units);
let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius); let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius);
if a_start == a_end { if a_start == a_end {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Arc start and end angles must be different".to_string(), "Arc start and end angles must be different".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -1968,11 +1972,11 @@ async fn inner_tangential_arc(
let data = TangentialArcData::RadiusAndOffset { radius, offset: angle }; let data = TangentialArcData::RadiusAndOffset { radius, offset: angle };
inner_tangential_arc_radius_angle(data, sketch, tag, exec_state, args).await inner_tangential_arc_radius_angle(data, sketch, tag, exec_state, args).await
} }
(Some(_), Some(_), None, None, None) => Err(KclError::Semantic(KclErrorDetails::new( (Some(_), Some(_), None, None, None) => Err(KclError::new_semantic(KclErrorDetails::new(
"You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(), "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
vec![args.source_range], vec![args.source_range],
))), ))),
(_, _, _, _, _) => Err(KclError::Semantic(KclErrorDetails::new( (_, _, _, _, _) => Err(KclError::new_semantic(KclErrorDetails::new(
"You must supply `end`, `endAbsolute`, or both `angle` and `radius`/`diameter` arguments".to_owned(), "You must supply `end`, `endAbsolute`, or both `angle` and `radius`/`diameter` arguments".to_owned(),
vec![args.source_range], vec![args.source_range],
))), ))),
@ -2126,13 +2130,13 @@ async fn inner_tangential_arc_to_point(
}); });
if result.center[0].is_infinite() { if result.center[0].is_infinite() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"could not sketch tangential arc, because its center would be infinitely far away in the X direction" "could not sketch tangential arc, because its center would be infinitely far away in the X direction"
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
} else if result.center[1].is_infinite() { } else if result.center[1].is_infinite() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"could not sketch tangential arc, because its center would be infinitely far away in the Y direction" "could not sketch tangential arc, because its center would be infinitely far away in the Y direction"
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -2310,7 +2314,7 @@ async fn inner_bezier_curve(
to to
} }
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"You must either give `control1`, `control2` and `end`, or `control1Absolute`, `control2Absolute` and `endAbsolute`.".to_owned(), "You must either give `control1`, `control2` and `end`, or `control1Absolute`, `control2Absolute` and `endAbsolute`.".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -75,7 +75,7 @@ async fn inner_sweep(
Some("sketchPlane") => RelativeTo::SketchPlane, Some("sketchPlane") => RelativeTo::SketchPlane,
Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve, Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve,
Some(_) => { Some(_) => {
return Err(KclError::Syntax(crate::errors::KclErrorDetails::new( return Err(KclError::new_syntax(crate::errors::KclErrorDetails::new(
"If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(), "If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(),
vec![args.source_range], vec![args.source_range],
))) )))

View File

@ -37,7 +37,7 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
// Ensure at least one scale value is provided. // Ensure at least one scale value is provided.
if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() { if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected `x`, `y`, or `z` to be provided.".to_string(), "Expected `x`, `y`, or `z` to be provided.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -119,7 +119,7 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
// Ensure at least one translation value is provided. // Ensure at least one translation value is provided.
if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() { if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected `x`, `y`, or `z` to be provided.".to_string(), "Expected `x`, `y`, or `z` to be provided.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -202,7 +202,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
// Check if no rotation values are provided. // Check if no rotation values are provided.
if roll.is_none() && pitch.is_none() && yaw.is_none() && axis.is_none() && angle.is_none() { if roll.is_none() && pitch.is_none() && yaw.is_none() && axis.is_none() && angle.is_none() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected `roll`, `pitch`, and `yaw` or `axis` and `angle` to be provided.".to_string(), "Expected `roll`, `pitch`, and `yaw` or `axis` and `angle` to be provided.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -212,7 +212,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
if roll.is_some() || pitch.is_some() || yaw.is_some() { if roll.is_some() || pitch.is_some() || yaw.is_some() {
// Ensure they didn't also provide an axis or angle. // Ensure they didn't also provide an axis or angle.
if axis.is_some() || angle.is_some() { if axis.is_some() || angle.is_some() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected `axis` and `angle` to not be provided when `roll`, `pitch`, and `yaw` are provided." "Expected `axis` and `angle` to not be provided when `roll`, `pitch`, and `yaw` are provided."
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -223,13 +223,13 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
// If they give us an axis or angle, they must give us both. // If they give us an axis or angle, they must give us both.
if axis.is_some() || angle.is_some() { if axis.is_some() || angle.is_some() {
if axis.is_none() { if axis.is_none() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected `axis` to be provided when `angle` is provided.".to_string(), "Expected `axis` to be provided when `angle` is provided.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle.is_none() { if angle.is_none() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected `angle` to be provided when `axis` is provided.".to_string(), "Expected `angle` to be provided when `axis` is provided.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -237,7 +237,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
// Ensure they didn't also provide a roll, pitch, or yaw. // Ensure they didn't also provide a roll, pitch, or yaw.
if roll.is_some() || pitch.is_some() || yaw.is_some() { if roll.is_some() || pitch.is_some() || yaw.is_some() {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Expected `roll`, `pitch`, and `yaw` to not be provided when `axis` and `angle` are provided." "Expected `roll`, `pitch`, and `yaw` to not be provided when `axis` and `angle` are provided."
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -248,7 +248,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
// Validate the roll, pitch, and yaw values. // Validate the roll, pitch, and yaw values.
if let Some(roll) = &roll { if let Some(roll) = &roll {
if !(-360.0..=360.0).contains(&roll.n) { if !(-360.0..=360.0).contains(&roll.n) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Expected roll to be between -360 and 360, found `{}`", roll.n), format!("Expected roll to be between -360 and 360, found `{}`", roll.n),
vec![args.source_range], vec![args.source_range],
))); )));
@ -256,7 +256,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
} }
if let Some(pitch) = &pitch { if let Some(pitch) = &pitch {
if !(-360.0..=360.0).contains(&pitch.n) { if !(-360.0..=360.0).contains(&pitch.n) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Expected pitch to be between -360 and 360, found `{}`", pitch.n), format!("Expected pitch to be between -360 and 360, found `{}`", pitch.n),
vec![args.source_range], vec![args.source_range],
))); )));
@ -264,7 +264,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
} }
if let Some(yaw) = &yaw { if let Some(yaw) = &yaw {
if !(-360.0..=360.0).contains(&yaw.n) { if !(-360.0..=360.0).contains(&yaw.n) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Expected yaw to be between -360 and 360, found `{}`", yaw.n), format!("Expected yaw to be between -360 and 360, found `{}`", yaw.n),
vec![args.source_range], vec![args.source_range],
))); )));
@ -274,7 +274,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
// Validate the axis and angle values. // Validate the axis and angle values.
if let Some(angle) = &angle { if let Some(angle) = &angle {
if !(-360.0..=360.0).contains(&angle.n) { if !(-360.0..=360.0).contains(&angle.n) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!("Expected angle to be between -360 and 360, found `{}`", angle.n), format!("Expected angle to be between -360 and 360, found `{}`", angle.n),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -93,7 +93,7 @@ async fn do_execute_and_snapshot(
for e in exec_state.errors() { for e in exec_state.errors() {
if e.severity.is_err() { if e.severity.is_err() {
return Err(ExecErrorWithState::new( return Err(ExecErrorWithState::new(
KclErrorWithOutputs::no_outputs(KclError::Semantic(e.clone().into())).into(), KclErrorWithOutputs::no_outputs(KclError::new_semantic(e.clone().into())).into(),
exec_state.clone(), exec_state.clone(),
)); ));
} }
@ -164,7 +164,7 @@ pub async fn execute_and_export_step(
for e in exec_state.errors() { for e in exec_state.errors() {
if e.severity.is_err() { if e.severity.is_err() {
return Err(ExecErrorWithState::new( return Err(ExecErrorWithState::new(
KclErrorWithOutputs::no_outputs(KclError::Semantic(e.clone().into())).into(), KclErrorWithOutputs::no_outputs(KclError::new_semantic(e.clone().into())).into(),
exec_state.clone(), exec_state.clone(),
)); ));
} }

View File

@ -883,7 +883,7 @@ pub async fn walk_dir(dir: &std::path::PathBuf) -> Result<Vec<std::path::PathBuf
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub async fn recast_dir(dir: &std::path::Path, options: &crate::FormatOptions) -> Result<(), anyhow::Error> { pub async fn recast_dir(dir: &std::path::Path, options: &crate::FormatOptions) -> Result<(), anyhow::Error> {
let files = walk_dir(&dir.to_path_buf()).await.map_err(|err| { let files = walk_dir(&dir.to_path_buf()).await.map_err(|err| {
crate::KclError::Internal(crate::errors::KclErrorDetails::new( crate::KclError::new_internal(crate::errors::KclErrorDetails::new(
format!("Failed to walk directory `{}`: {:?}", dir.display(), err), format!("Failed to walk directory `{}`: {:?}", dir.display(), err),
vec![crate::SourceRange::default()], vec![crate::SourceRange::default()],
)) ))
@ -912,7 +912,7 @@ pub async fn recast_dir(dir: &std::path::Path, options: &crate::FormatOptions) -
if ce.severity != crate::errors::Severity::Warning { if ce.severity != crate::errors::Severity::Warning {
let report = crate::Report { let report = crate::Report {
kcl_source: contents.to_string(), kcl_source: contents.to_string(),
error: crate::KclError::Semantic(ce.clone().into()), error: crate::KclError::new_semantic(ce.clone().into()),
filename: file.to_string_lossy().to_string(), filename: file.to_string_lossy().to_string(),
}; };
let report = miette::Report::new(report); let report = miette::Report::new(report);

View File

@ -96,7 +96,7 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>, KclEr
if stage_modules.is_empty() { if stage_modules.is_empty() {
waiting_modules.sort(); waiting_modules.sort();
return Err(KclError::ImportCycle(KclErrorDetails::new( return Err(KclError::new_import_cycle(KclErrorDetails::new(
format!("circular import of modules not allowed: {}", waiting_modules.join(", ")), format!("circular import of modules not allowed: {}", waiting_modules.join(", ")),
// TODO: we can get the right import lines from the AST, but we don't // TODO: we can get the right import lines from the AST, but we don't
vec![SourceRange::default()], vec![SourceRange::default()],
@ -146,7 +146,7 @@ pub(crate) fn import_dependencies(
// This is a bit of a hack, but it works for now. // This is a bit of a hack, but it works for now.
ret.lock() ret.lock()
.map_err(|err| { .map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err), format!("Failed to lock mutex: {}", err),
Default::default(), Default::default(),
)) ))
@ -156,7 +156,7 @@ pub(crate) fn import_dependencies(
ImportPath::Foreign { path } => { ImportPath::Foreign { path } => {
ret.lock() ret.lock()
.map_err(|err| { .map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err), format!("Failed to lock mutex: {}", err),
Default::default(), Default::default(),
)) ))
@ -178,7 +178,7 @@ pub(crate) fn import_dependencies(
walk(ret.clone(), prog.into(), path, ctx)?; walk(ret.clone(), prog.into(), path, ctx)?;
let ret = ret.lock().map_err(|err| { let ret = ret.lock().map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err), format!("Failed to lock mutex: {}", err),
Default::default(), Default::default(),
)) ))
@ -223,7 +223,7 @@ pub(crate) async fn import_universe(
let repr = { let repr = {
let Some(module_info) = exec_state.get_module(module_id) else { let Some(module_info) = exec_state.get_module(module_id) else {
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
format!("Module {} not found", module_id), format!("Module {} not found", module_id),
vec![import_stmt.into()], vec![import_stmt.into()],
))); )));

View File

@ -895,3 +895,304 @@ export fn patternCircular2d(
/// If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. /// If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid.
useOriginal?: bool = false, useOriginal?: bool = false,
): [Sketch; 1+] {} ): [Sketch; 1+] {}
/// Compute the ending point of the provided line segment.
///
/// ```kcl
/// w = 15
/// cube = startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> line(end = [w, 0], tag = $line1)
/// |> line(end = [0, w], tag = $line2)
/// |> line(end = [-w, 0], tag = $line3)
/// |> line(end = [0, -w], tag = $line4)
/// |> close()
/// |> extrude(length = 5)
///
/// fn cylinder(radius, tag) {
/// return startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> circle(radius = radius, center = segEnd(tag) )
/// |> extrude(length = radius)
/// }
///
/// cylinder(radius = 1, tag = line1)
/// cylinder(radius = 2, tag = line2)
/// cylinder(radius = 3, tag = line3)
/// cylinder(radius = 4, tag = line4)
/// ```
@(impl = std_rust)
export fn segEnd(
/// The line segment being queried by its tag.
@tag: tag,
): Point2d {}
/// Compute the ending point of the provided line segment along the 'x' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0], tag = $thing)
/// |> line(end = [0, 5])
/// |> line(end = [segEndX(thing), 0])
/// |> line(end = [-20, 10])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn segEndX(
/// The line segment being queried by its tag.
@tag: tag,
): number(Length) {}
/// Compute the ending point of the provided line segment along the 'y' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0])
/// |> line(end = [0, 3], tag = $thing)
/// |> line(end = [-10, 0])
/// |> line(end = [0, segEndY(thing)])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn segEndY(
/// The line segment being queried by its tag.
@tag: tag,
): number(Length) {}
/// Compute the starting point of the provided line segment.
///
/// ```kcl
/// w = 15
/// cube = startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> line(end = [w, 0], tag = $line1)
/// |> line(end = [0, w], tag = $line2)
/// |> line(end = [-w, 0], tag = $line3)
/// |> line(end = [0, -w], tag = $line4)
/// |> close()
/// |> extrude(length = 5)
///
/// fn cylinder(radius, tag) {
/// return startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> circle( radius = radius, center = segStart(tag) )
/// |> extrude(length = radius)
/// }
///
/// cylinder(radius = 1, tag = line1)
/// cylinder(radius = 2, tag = line2)
/// cylinder(radius = 3, tag = line3)
/// cylinder(radius = 4, tag = line4)
/// ```
@(impl = std_rust)
export fn segStart(
/// The line segment being queried by its tag.
@tag: tag,
): Point2d {}
/// Compute the starting point of the provided line segment along the 'x' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0], tag = $thing)
/// |> line(end = [0, 5])
/// |> line(end = [20 - segStartX(thing), 0])
/// |> line(end = [-20, 10])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn segStartX(
/// The line segment being queried by its tag.
@tag: tag,
): number(Length) {}
/// Compute the starting point of the provided line segment along the 'y' axis.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0])
/// |> line(end = [0, 3], tag = $thing)
/// |> line(end = [-10, 0])
/// |> line(end = [0, 20-segStartY(thing)])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn segStartY(
/// The line segment being queried by its tag.
@tag: tag,
): number(Length) {}
/// Extract the 'x' axis value of the last line segment in the provided 2-d sketch.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [5, 0])
/// |> line(end = [20, 5])
/// |> line(end = [lastSegX(%), 0])
/// |> line(end = [-15, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn lastSegX(
/// The sketch whose line segment is being queried.
@sketch: Sketch,
): number(Length) {}
/// Extract the 'y' axis value of the last line segment in the provided 2-d sketch.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [5, 0])
/// |> line(end = [20, 5])
/// |> line(end = [0, lastSegY(%)])
/// |> line(end = [-15, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn lastSegY(
/// The sketch whose line segment is being queried.
@sketch: Sketch,
): number(Length) {}
/// Compute the length of the provided line segment.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 60,
/// length = 10,
/// tag = $thing,
/// )
/// |> tangentialArc(angle = -120, radius = 5)
/// |> angledLine(
/// angle = -60,
/// length = segLen(thing),
/// )
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn segLen(
/// The line segment being queried by its tag.
@tag: tag,
): number(Length) {}
/// Compute the angle (in degrees) of the provided line segment.
///
/// ```kcl
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [10, 0])
/// |> line(end = [5, 10], tag = $seg01)
/// |> line(end = [-10, 0])
/// |> angledLine(angle = segAng(seg01), length = 10)
/// |> line(end = [-10, 0])
/// |> angledLine(angle = segAng(seg01), length = -15)
/// |> close()
///
/// example = extrude(exampleSketch, length = 4)
/// ```
@(impl = std_rust)
export fn segAng(
/// The line segment being queried by its tag.
@tag: tag,
): number(Angle) {}
/// Returns the angle coming out of the end of the segment in degrees.
///
/// ```kcl
/// // Horizontal pill.
/// pillSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [20, 0])
/// |> tangentialArc(end = [0, 10], tag = $arc1)
/// |> angledLine(
/// angle = tangentToEnd(arc1),
/// length = 20,
/// )
/// |> tangentialArc(end = [0, -10])
/// |> close()
///
/// pillExtrude = extrude(pillSketch, length = 10)
/// ```
///
/// ```kcl
/// // Vertical pill. Use absolute coordinate for arc.
/// pillSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [0, 20])
/// |> tangentialArc(endAbsolute = [10, 20], tag = $arc1)
/// |> angledLine(
/// angle = tangentToEnd(arc1),
/// length = 20,
/// )
/// |> tangentialArc(end = [-10, 0])
/// |> close()
///
/// pillExtrude = extrude(pillSketch, length = 10)
/// ```
///
/// ```kcl
/// rectangleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [10, 0], tag = $seg1)
/// |> angledLine(
/// angle = tangentToEnd(seg1),
/// length = 10,
/// )
/// |> line(end = [0, 10])
/// |> line(end = [-20, 0])
/// |> close()
///
/// rectangleExtrude = extrude(rectangleSketch, length = 10)
/// ```
///
/// ```kcl
/// bottom = startSketchOn(XY)
/// |> startProfile(at = [0, 0])
/// |> arc(
/// endAbsolute = [10, 10],
/// interiorAbsolute = [5, 1],
/// tag = $arc1,
/// )
/// |> angledLine(angle = tangentToEnd(arc1), length = 20)
/// |> close()
/// ```
///
/// ```kcl
/// circSketch = startSketchOn(XY)
/// |> circle(center = [0, 0], radius= 3, tag = $circ)
///
/// triangleSketch = startSketchOn(XY)
/// |> startProfile(at = [-5, 0])
/// |> angledLine(angle = tangentToEnd(circ), length = 10)
/// |> line(end = [-15, 0])
/// |> close()
/// ```
@(impl = std_rust)
export fn tangentToEnd(
/// The line segment being queried by its tag.
@tag: tag,
): number(Angle) {}

View File

@ -797,6 +797,36 @@ description: Operations executed import_async.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {
"y": {
"value": {
"type": "Number",
"value": 10.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "GroupEnd" "type": "GroupEnd"
}, },

View File

@ -37,6 +37,7 @@ flowchart LR
25["SweepEdge Adjacent"] 25["SweepEdge Adjacent"]
26["SweepEdge Adjacent"] 26["SweepEdge Adjacent"]
27["SweepEdge Adjacent"] 27["SweepEdge Adjacent"]
28["SweepEdge Adjacent"]
1 --- 2 1 --- 2
2 --- 3 2 --- 3
2 --- 4 2 --- 4
@ -50,28 +51,28 @@ flowchart LR
2 ---- 12 2 ---- 12
12 <--x 3 12 <--x 3
3 --- 16 3 --- 16
3 x--> 21 3 --- 21
12 <--x 4 12 <--x 4
4 --- 15 4 --- 15
4 --- 21 4 --- 22
12 <--x 5 12 <--x 5
5 --- 13 5 --- 13
5 --- 22 5 --- 23
12 <--x 6 12 <--x 6
6 --- 20 6 --- 20
6 --- 23 6 --- 24
12 <--x 7 12 <--x 7
7 --- 17 7 --- 17
7 --- 24 7 --- 25
12 <--x 8 12 <--x 8
8 --- 19 8 --- 19
8 --- 25 8 --- 26
12 <--x 9 12 <--x 9
9 --- 14 9 --- 14
9 --- 26 9 --- 27
12 <--x 10 12 <--x 10
10 --- 18 10 --- 18
10 --- 27 10 --- 28
12 --- 13 12 --- 13
12 --- 14 12 --- 14
12 --- 15 12 --- 15
@ -87,18 +88,21 @@ flowchart LR
12 --- 25 12 --- 25
12 --- 26 12 --- 26
12 --- 27 12 --- 27
13 --- 22 12 --- 28
25 <--x 14 22 <--x 13
14 --- 26 13 --- 23
15 --- 21 26 <--x 14
14 --- 27
21 <--x 15
15 --- 22
16 --- 21 16 --- 21
27 <--x 16 28 <--x 16
23 <--x 17 24 <--x 17
17 --- 24 17 --- 25
26 <--x 18 27 <--x 18
18 --- 27 18 --- 28
24 <--x 19 25 <--x 19
19 --- 25 19 --- 26
22 <--x 20 23 <--x 20
20 --- 23 20 --- 24
``` ```

View File

@ -14,7 +14,7 @@ description: Operations executed import_mesh_clone.kcl
}, },
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "clone", "name": "translate",
"unlabeledArg": { "unlabeledArg": {
"value": { "value": {
"type": "ImportedGeometry", "type": "ImportedGeometry",
@ -22,7 +22,40 @@ description: Operations executed import_mesh_clone.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
"labeledArgs": {}, "labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": -2000.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": -2000.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": [] "sourceRange": []
}, },
{ {
@ -38,6 +71,36 @@ description: Operations executed import_mesh_clone.kcl
"labeledArgs": {}, "labeledArgs": {},
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 4000.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "clone", "name": "clone",
@ -51,6 +114,79 @@ description: Operations executed import_mesh_clone.kcl
"labeledArgs": {}, "labeledArgs": {},
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {
"y": {
"value": {
"type": "Number",
"value": 4000.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{
"type": "StdLibCall",
"name": "clone",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {},
"sourceRange": []
},
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {
"y": {
"value": {
"type": "Number",
"value": 4000.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "GroupEnd" "type": "GroupEnd"
} }

View File

@ -12,6 +12,177 @@ description: Operations executed import_transform.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "rotate",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {
"pitch": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"roll": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"yaw": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{
"type": "StdLibCall",
"name": "scale",
"unlabeledArg": {
"value": {
"type": "ImportedGeometry",
"artifact_id": "[uuid]"
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Known",
"type": "Count"
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Known",
"type": "Count"
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 3.14,
"ty": {
"type": "Known",
"type": "Count"
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "GroupEnd" "type": "GroupEnd"
} }

View File

@ -12,6 +12,38 @@ description: Operations executed import_whole_simple.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"z": {
"value": {
"type": "Number",
"value": 1.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "GroupEnd" "type": "GroupEnd"
} }

View File

@ -12,6 +12,38 @@ description: Operations executed import_whole_transitive_import.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"z": {
"value": {
"type": "Number",
"value": 1.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "GroupEnd" "type": "GroupEnd"
} }

View File

@ -217,6 +217,38 @@ description: Operations executed intersect_cubes.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"z": {
"value": {
"type": "Number",
"value": 1.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "intersect", "name": "intersect",

View File

@ -369,8 +369,9 @@ flowchart LR
264["SweepEdge Adjacent"] 264["SweepEdge Adjacent"]
265["SweepEdge Adjacent"] 265["SweepEdge Adjacent"]
266["SweepEdge Adjacent"] 266["SweepEdge Adjacent"]
267["EdgeCut Fillet<br>[5131, 5642, 1]"] 267["SweepEdge Adjacent"]
268["EdgeCut Fillet<br>[412, 470, 3]"] 268["EdgeCut Fillet<br>[5131, 5642, 1]"]
269["EdgeCut Fillet<br>[412, 470, 3]"]
1 --- 8 1 --- 8
1 --- 9 1 --- 9
1 --- 10 1 --- 10
@ -518,155 +519,155 @@ flowchart LR
41 --- 158 41 --- 158
41 x--> 184 41 x--> 184
41 --- 196 41 --- 196
41 --- 240 41 --- 241
42 --- 151 42 --- 151
42 x--> 184 42 x--> 184
42 --- 197 42 --- 197
42 --- 241 42 --- 242
43 --- 157 43 --- 157
43 x--> 184 43 x--> 184
43 --- 198 43 --- 198
43 --- 242 43 --- 243
44 --- 155 44 --- 155
44 x--> 184 44 x--> 184
44 --- 199 44 --- 199
44 --- 243 44 --- 244
45 --- 156 45 --- 156
45 x--> 184 45 x--> 184
45 --- 200 45 --- 200
45 --- 244 45 --- 245
46 --- 154 46 --- 154
46 x--> 184 46 x--> 184
46 --- 201 46 --- 201
46 --- 245 46 --- 246
47 --- 152 47 --- 152
47 x--> 184 47 x--> 184
47 --- 202 47 --- 202
47 --- 246 47 --- 247
48 --- 153 48 --- 153
48 x--> 184 48 x--> 184
48 --- 203 48 --- 203
48 --- 247 48 --- 248
50 --- 163 50 --- 163
50 x--> 184 50 x--> 184
50 --- 204 50 --- 204
50 --- 248 50 --- 249
51 --- 161 51 --- 161
51 x--> 184 51 x--> 184
51 --- 205 51 --- 205
51 --- 249 51 --- 250
52 --- 159 52 --- 159
52 x--> 184 52 x--> 184
52 --- 206 52 --- 206
52 --- 250 52 --- 251
53 --- 166 53 --- 166
53 x--> 184 53 x--> 184
53 --- 207 53 --- 207
53 --- 251 53 --- 252
54 --- 164 54 --- 164
54 x--> 184 54 x--> 184
54 --- 208 54 --- 208
54 --- 252 54 --- 253
55 --- 165 55 --- 165
55 x--> 184 55 x--> 184
55 --- 209 55 --- 209
55 --- 253 55 --- 254
56 --- 160 56 --- 160
56 x--> 184 56 x--> 184
56 --- 210 56 --- 210
56 --- 254 56 --- 255
57 --- 162 57 --- 162
57 x--> 184 57 x--> 184
57 --- 211 57 --- 211
57 --- 255 57 --- 256
58 --- 177 58 --- 177
58 x--> 185 58 x--> 185
58 --- 222 58 --- 222
58 --- 266 58 --- 267
59 --- 172 59 --- 172
59 x--> 180 59 x--> 180
59 --- 216 59 --- 216
59 --- 260 59 --- 261
60 --- 171 60 --- 171
60 x--> 180 60 x--> 180
60 --- 217 60 --- 217
60 --- 261 60 --- 262
61 --- 174 61 --- 174
61 x--> 180 61 x--> 180
61 --- 218 61 --- 218
61 --- 262 61 --- 263
62 --- 173 62 --- 173
62 x--> 180 62 x--> 180
62 --- 219 62 --- 219
62 --- 263 62 --- 264
69 --- 150 69 --- 150
69 x--> 184 69 x--> 184
69 --- 195 69 --- 195
69 --- 239 69 --- 240
70 --- 176 70 --- 176
70 x--> 183 70 x--> 183
70 --- 221 70 --- 221
70 --- 265 70 --- 266
71 --- 175 71 --- 175
71 x--> 178 71 x--> 178
71 --- 220 71 --- 220
71 --- 264 71 --- 265
72 --- 149 72 --- 149
72 x--> 181 72 x--> 181
72 --- 194 72 --- 194
72 --- 238 72 --- 239
131 <--x 73 131 <--x 73
73 --- 141 73 --- 141
73 x--> 227 73 --- 227
131 <--x 74 131 <--x 74
74 --- 137 74 --- 137
74 --- 227 74 --- 228
131 <--x 75 131 <--x 75
75 --- 145 75 --- 145
75 --- 228 75 --- 229
131 <--x 76 131 <--x 76
76 --- 139 76 --- 139
76 --- 229 76 --- 230
131 <--x 77 131 <--x 77
77 --- 146 77 --- 146
77 --- 230 77 --- 231
131 <--x 78 131 <--x 78
78 --- 138 78 --- 138
78 --- 231 78 --- 232
131 <--x 79 131 <--x 79
79 --- 147 79 --- 147
79 --- 232 79 --- 233
131 <--x 80 131 <--x 80
80 --- 148 80 --- 148
80 --- 233 80 --- 234
131 <--x 81 131 <--x 81
81 --- 140 81 --- 140
81 --- 234 81 --- 235
131 <--x 82 131 <--x 82
82 --- 143 82 --- 143
82 --- 235 82 --- 236
131 <--x 83 131 <--x 83
83 --- 142 83 --- 142
83 --- 236 83 --- 237
131 <--x 84 131 <--x 84
84 --- 144 84 --- 144
84 --- 237 84 --- 238
86 --- 168 86 --- 168
86 x--> 188 86 x--> 188
86 --- 212 86 --- 212
86 --- 256 86 --- 257
88 --- 169 88 --- 169
88 x--> 188 88 x--> 188
88 --- 213 88 --- 213
88 --- 257 88 --- 258
90 --- 167 90 --- 167
90 x--> 188 90 x--> 188
90 --- 214 90 --- 214
90 --- 258 90 --- 259
92 --- 170 92 --- 170
92 x--> 188 92 x--> 188
92 --- 215 92 --- 215
92 --- 259 92 --- 260
119 --- 133 119 --- 133
119 --- 134 119 --- 134
119 --- 135 119 --- 135
@ -697,7 +698,6 @@ flowchart LR
122 --- 201 122 --- 201
122 --- 202 122 --- 202
122 --- 203 122 --- 203
122 --- 240
122 --- 241 122 --- 241
122 --- 242 122 --- 242
122 --- 243 122 --- 243
@ -705,6 +705,7 @@ flowchart LR
122 --- 245 122 --- 245
122 --- 246 122 --- 246
122 --- 247 122 --- 247
122 --- 248
124 --- 159 124 --- 159
124 --- 160 124 --- 160
124 --- 161 124 --- 161
@ -722,7 +723,6 @@ flowchart LR
124 --- 209 124 --- 209
124 --- 210 124 --- 210
124 --- 211 124 --- 211
124 --- 248
124 --- 249 124 --- 249
124 --- 250 124 --- 250
124 --- 251 124 --- 251
@ -730,9 +730,10 @@ flowchart LR
124 --- 253 124 --- 253
124 --- 254 124 --- 254
124 --- 255 124 --- 255
124 --- 256
125 --- 177 125 --- 177
125 --- 222 125 --- 222
125 --- 266 125 --- 267
126 --- 171 126 --- 171
126 --- 172 126 --- 172
126 --- 173 126 --- 173
@ -743,27 +744,27 @@ flowchart LR
126 --- 217 126 --- 217
126 --- 218 126 --- 218
126 --- 219 126 --- 219
126 --- 260
126 --- 261 126 --- 261
126 --- 262 126 --- 262
126 --- 263 126 --- 263
126 --- 264
127 --- 150 127 --- 150
127 --- 183 127 --- 183
127 --- 195 127 --- 195
127 --- 239 127 --- 240
128 --- 176 128 --- 176
128 --- 221 128 --- 221
128 --- 265 128 --- 266
129 --- 175 129 --- 175
129 --- 178 129 --- 178
129 --- 182 129 --- 182
129 --- 220 129 --- 220
129 --- 264 129 --- 265
130 --- 149 130 --- 149
130 --- 181 130 --- 181
130 --- 187 130 --- 187
130 --- 194 130 --- 194
130 --- 238 130 --- 239
131 --- 137 131 --- 137
131 --- 138 131 --- 138
131 --- 139 131 --- 139
@ -787,6 +788,7 @@ flowchart LR
131 --- 235 131 --- 235
131 --- 236 131 --- 236
131 --- 237 131 --- 237
131 --- 238
132 --- 167 132 --- 167
132 --- 168 132 --- 168
132 --- 169 132 --- 169
@ -797,10 +799,10 @@ flowchart LR
132 --- 213 132 --- 213
132 --- 214 132 --- 214
132 --- 215 132 --- 215
132 --- 256
132 --- 257 132 --- 257
132 --- 258 132 --- 258
132 --- 259 132 --- 259
132 --- 260
133 --- 192 133 --- 192
224 <--x 133 224 <--x 133
133 --- 225 133 --- 225
@ -813,110 +815,112 @@ flowchart LR
136 --- 193 136 --- 193
225 <--x 136 225 <--x 136
136 --- 226 136 --- 226
137 --- 227 227 <--x 137
230 <--x 138 137 --- 228
138 --- 231 231 <--x 138
228 <--x 139 138 --- 232
139 --- 229 229 <--x 139
233 <--x 140 139 --- 230
140 --- 234 234 <--x 140
140 --- 235
141 --- 227 141 --- 227
237 <--x 141 238 <--x 141
235 <--x 142 236 <--x 142
142 --- 236 142 --- 237
234 <--x 143 235 <--x 143
143 --- 235 143 --- 236
236 <--x 144 237 <--x 144
144 --- 237 144 --- 238
145 --- 228 228 <--x 145
229 <--x 146 145 --- 229
146 --- 230 230 <--x 146
231 <--x 147 146 --- 231
147 --- 232 232 <--x 147
232 <--x 148 147 --- 233
148 --- 233 233 <--x 148
148 --- 234
149 --- 194 149 --- 194
149 --- 238 149 --- 239
150 --- 195 150 --- 195
150 --- 239 150 --- 240
151 --- 197 151 --- 197
151 --- 241 241 <--x 151
242 <--x 151 151 --- 242
152 --- 202 152 --- 202
152 --- 246 246 <--x 152
247 <--x 152 152 --- 247
153 --- 203 153 --- 203
240 <--x 153 247 <--x 153
153 --- 247 153 --- 248
154 --- 201 154 --- 201
154 --- 245 245 <--x 154
246 <--x 154 154 --- 246
155 --- 199 155 --- 199
155 --- 243 243 <--x 155
244 <--x 155 155 --- 244
156 --- 200 156 --- 200
156 --- 244 244 <--x 156
245 <--x 156 156 --- 245
157 --- 198 157 --- 198
157 --- 242 242 <--x 157
243 <--x 157 157 --- 243
158 --- 196 158 --- 196
158 --- 240 158 --- 241
241 <--x 158 248 <--x 158
159 --- 206 159 --- 206
249 <--x 159 250 <--x 159
159 --- 250 159 --- 251
160 --- 210 160 --- 210
253 <--x 160 254 <--x 160
160 --- 254 160 --- 255
161 --- 205 161 --- 205
248 <--x 161 249 <--x 161
161 --- 249 161 --- 250
162 --- 211 162 --- 211
254 <--x 162 255 <--x 162
162 --- 255 162 --- 256
163 --- 204 163 --- 204
163 --- 248 163 --- 249
255 <--x 163 256 <--x 163
164 --- 208 164 --- 208
251 <--x 164 252 <--x 164
164 --- 252 164 --- 253
165 --- 209 165 --- 209
252 <--x 165 253 <--x 165
165 --- 253 165 --- 254
166 --- 207 166 --- 207
250 <--x 166 251 <--x 166
166 --- 251 166 --- 252
167 --- 214 167 --- 214
167 --- 258 167 --- 259
259 <--x 167 260 <--x 167
168 --- 212 168 --- 212
168 --- 256 168 --- 257
257 <--x 168 258 <--x 168
169 --- 213 169 --- 213
169 --- 257 169 --- 258
258 <--x 169 259 <--x 169
170 --- 215 170 --- 215
256 <--x 170 257 <--x 170
170 --- 259 170 --- 260
171 --- 217 171 --- 217
260 <--x 171 261 <--x 171
171 --- 261 171 --- 262
172 --- 216 172 --- 216
172 --- 260 172 --- 261
263 <--x 172 264 <--x 172
173 --- 219 173 --- 219
262 <--x 173 263 <--x 173
173 --- 263 173 --- 264
174 --- 218 174 --- 218
261 <--x 174 262 <--x 174
174 --- 262 174 --- 263
175 --- 220 175 --- 220
175 --- 264 175 --- 265
176 --- 221 176 --- 221
176 --- 265 176 --- 266
177 --- 222 177 --- 222
177 --- 266 177 --- 267
196 <--x 179 196 <--x 179
197 <--x 179 197 <--x 179
198 <--x 179 198 <--x 179
@ -950,6 +954,6 @@ flowchart LR
213 <--x 189 213 <--x 189
214 <--x 189 214 <--x 189
215 <--x 189 215 <--x 189
220 <--x 268 220 <--x 269
223 <--x 267 223 <--x 268
``` ```

View File

@ -122,6 +122,7 @@ flowchart LR
61["SweepEdge Adjacent"] 61["SweepEdge Adjacent"]
62["SweepEdge Adjacent"] 62["SweepEdge Adjacent"]
63["SweepEdge Adjacent"] 63["SweepEdge Adjacent"]
64["SweepEdge Adjacent"]
1 <--x 6 1 <--x 6
1 --- 8 1 --- 8
1 --- 9 1 --- 9
@ -157,25 +158,25 @@ flowchart LR
15 --- 41 15 --- 41
15 x--> 47 15 x--> 47
15 --- 54 15 --- 54
15 --- 58 15 --- 59
34 <--x 17 34 <--x 17
17 --- 40 17 --- 40
17 x--> 57 17 --- 57
34 <--x 18 34 <--x 18
18 --- 39 18 --- 39
18 --- 57 18 --- 58
35 <--x 19 35 <--x 19
19 --- 45 19 --- 45
19 --- 59 19 --- 60
35 <--x 20 35 <--x 20
20 --- 43 20 --- 43
20 --- 60 20 --- 61
35 <--x 21 35 <--x 21
21 --- 42 21 --- 42
21 --- 61 21 --- 62
35 <--x 22 35 <--x 22
22 --- 44 22 --- 44
22 --- 62 22 --- 63
23 --- 38 23 --- 38
23 x--> 49 23 x--> 49
23 --- 53 23 --- 53
@ -183,23 +184,24 @@ flowchart LR
24 --- 46 24 --- 46
24 x--> 48 24 x--> 48
24 --- 55 24 --- 55
24 --- 63 24 --- 64
33 --- 41 33 --- 41
33 --- 47 33 --- 47
33 --- 50 33 --- 50
33 --- 54 33 --- 54
33 --- 58 33 --- 59
34 --- 39 34 --- 39
34 --- 40 34 --- 40
34 --- 57 34 --- 57
34 --- 58
35 --- 42 35 --- 42
35 --- 43 35 --- 43
35 --- 44 35 --- 44
35 --- 45 35 --- 45
35 --- 59
35 --- 60 35 --- 60
35 --- 61 35 --- 61
35 --- 62 35 --- 62
35 --- 63
36 --- 38 36 --- 38
36 --- 49 36 --- 49
36 --- 52 36 --- 52
@ -209,23 +211,25 @@ flowchart LR
37 --- 48 37 --- 48
37 --- 51 37 --- 51
37 --- 55 37 --- 55
37 --- 63 37 --- 64
38 --- 53 38 --- 53
38 --- 56 38 --- 56
39 --- 57 57 <--x 39
39 --- 58
40 --- 57 40 --- 57
58 <--x 40
41 --- 54 41 --- 54
41 --- 58 41 --- 59
60 <--x 42 61 <--x 42
42 --- 61 42 --- 62
59 <--x 43 60 <--x 43
43 --- 60 43 --- 61
61 <--x 44 62 <--x 44
44 --- 62 44 --- 63
45 --- 59 45 --- 60
62 <--x 45 63 <--x 45
46 --- 55 46 --- 55
46 --- 63 46 --- 64
54 <--x 50 54 <--x 50
55 <--x 51 55 <--x 51
53 <--x 52 53 <--x 52

View File

@ -210,9 +210,10 @@ flowchart LR
116["SweepEdge Adjacent"] 116["SweepEdge Adjacent"]
117["SweepEdge Adjacent"] 117["SweepEdge Adjacent"]
118["SweepEdge Adjacent"] 118["SweepEdge Adjacent"]
119["EdgeCut Fillet<br>[3993, 4061, 0]"] 119["SweepEdge Adjacent"]
120["EdgeCut Fillet<br>[3993, 4061, 0]"]
%% [ProgramBodyItem { index: 31 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 2 }] %% [ProgramBodyItem { index: 31 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 2 }]
120["EdgeCut Fillet<br>[4067, 4135, 0]"] 121["EdgeCut Fillet<br>[4067, 4135, 0]"]
%% [ProgramBodyItem { index: 31 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 3 }] %% [ProgramBodyItem { index: 31 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 3 }]
1 --- 8 1 --- 8
2 --- 9 2 --- 9
@ -268,75 +269,75 @@ flowchart LR
13 --- 54 13 --- 54
48 <--x 14 48 <--x 14
14 --- 63 14 --- 63
14 x--> 100 14 --- 100
48 <--x 15 48 <--x 15
15 --- 61 15 --- 61
15 --- 100 15 --- 101
48 <--x 16 48 <--x 16
16 --- 60 16 --- 60
16 --- 101 16 --- 102
48 <--x 17 48 <--x 17
17 --- 62 17 --- 62
17 --- 102 17 --- 103
49 <--x 19 49 <--x 19
19 --- 75 19 --- 75
19 --- 112 19 --- 113
49 <--x 20 49 <--x 20
20 --- 74 20 --- 74
20 --- 113 20 --- 114
49 <--x 21 49 <--x 21
21 --- 76 21 --- 76
21 --- 114 21 --- 115
49 <--x 22 49 <--x 22
22 --- 73 22 --- 73
22 --- 115 22 --- 116
50 <--x 24 50 <--x 24
24 --- 80 24 --- 80
24 --- 116 24 --- 117
50 <--x 25 50 <--x 25
25 --- 78 25 --- 78
25 --- 117 25 --- 118
50 <--x 26 50 <--x 26
26 --- 77 26 --- 77
26 --- 118 26 --- 119
50 <--x 27 50 <--x 27
27 --- 79 27 --- 79
30 --- 71 30 --- 71
30 x--> 82 30 x--> 82
30 --- 89 30 --- 89
30 --- 103 30 --- 104
31 --- 69 31 --- 69
31 x--> 82 31 x--> 82
31 --- 90 31 --- 90
31 --- 104 31 --- 105
32 --- 64 32 --- 64
32 x--> 82 32 x--> 82
32 --- 91 32 --- 91
32 --- 105 32 --- 106
33 --- 66 33 --- 66
33 x--> 82 33 x--> 82
33 --- 92 33 --- 92
33 --- 106 33 --- 107
34 --- 68 34 --- 68
34 x--> 82 34 x--> 82
34 --- 93 34 --- 93
34 --- 107 34 --- 108
35 --- 65 35 --- 65
35 x--> 82 35 x--> 82
35 --- 94 35 --- 94
35 --- 108 35 --- 109
36 --- 67 36 --- 67
36 x--> 82 36 x--> 82
36 --- 95 36 --- 95
36 --- 109 36 --- 110
37 --- 70 37 --- 70
37 x--> 82 37 x--> 82
37 --- 96 37 --- 96
37 --- 110 37 --- 111
38 --- 72 38 --- 72
38 x--> 82 38 x--> 82
38 --- 97 38 --- 97
38 --- 111 38 --- 112
40 --- 58 40 --- 58
40 x--> 81 40 x--> 81
40 --- 87 40 --- 87
@ -352,21 +353,22 @@ flowchart LR
48 --- 100 48 --- 100
48 --- 101 48 --- 101
48 --- 102 48 --- 102
48 --- 103
49 --- 73 49 --- 73
49 --- 74 49 --- 74
49 --- 75 49 --- 75
49 --- 76 49 --- 76
49 --- 112
49 --- 113 49 --- 113
49 --- 114 49 --- 114
49 --- 115 49 --- 115
49 --- 116
50 --- 77 50 --- 77
50 --- 78 50 --- 78
50 --- 79 50 --- 79
50 --- 80 50 --- 80
50 --- 116
50 --- 117 50 --- 117
50 --- 118 50 --- 118
50 --- 119
51 --- 64 51 --- 64
51 --- 65 51 --- 65
51 --- 66 51 --- 66
@ -387,7 +389,6 @@ flowchart LR
51 --- 95 51 --- 95
51 --- 96 51 --- 96
51 --- 97 51 --- 97
51 --- 103
51 --- 104 51 --- 104
51 --- 105 51 --- 105
51 --- 106 51 --- 106
@ -396,6 +397,7 @@ flowchart LR
51 --- 109 51 --- 109
51 --- 110 51 --- 110
51 --- 111 51 --- 111
51 --- 112
52 --- 58 52 --- 58
52 --- 81 52 --- 81
52 --- 84 52 --- 84
@ -413,53 +415,55 @@ flowchart LR
58 --- 98 58 --- 98
59 --- 88 59 --- 88
59 --- 99 59 --- 99
60 --- 101 101 <--x 60
61 --- 100 60 --- 102
101 <--x 62 100 <--x 61
62 --- 102 61 --- 101
102 <--x 62
62 --- 103
63 --- 100 63 --- 100
102 <--x 63 103 <--x 63
64 --- 91 64 --- 91
104 <--x 64 105 <--x 64
64 --- 105 64 --- 106
65 --- 94 65 --- 94
107 <--x 65 108 <--x 65
65 --- 108 65 --- 109
66 --- 92 66 --- 92
105 <--x 66 106 <--x 66
66 --- 106 66 --- 107
67 --- 95 67 --- 95
108 <--x 67 109 <--x 67
67 --- 109 67 --- 110
68 --- 93 68 --- 93
106 <--x 68 107 <--x 68
68 --- 107 68 --- 108
69 --- 90 69 --- 90
103 <--x 69 104 <--x 69
69 --- 104 69 --- 105
70 --- 96 70 --- 96
109 <--x 70 110 <--x 70
70 --- 110 70 --- 111
71 --- 89 71 --- 89
71 --- 103 71 --- 104
111 <--x 71 112 <--x 71
72 --- 97 72 --- 97
110 <--x 72 111 <--x 72
72 --- 111 72 --- 112
114 <--x 73 115 <--x 73
73 --- 115 73 --- 116
112 <--x 74 113 <--x 74
74 --- 113 74 --- 114
75 --- 112 75 --- 113
115 <--x 75 116 <--x 75
113 <--x 76 114 <--x 76
76 --- 114 76 --- 115
117 <--x 77 118 <--x 77
77 --- 118 77 --- 119
116 <--x 78 117 <--x 78
78 --- 117 78 --- 118
118 <--x 79 119 <--x 79
80 --- 116 80 --- 117
87 <--x 84 87 <--x 84
89 <--x 85 89 <--x 85
90 <--x 85 90 <--x 85
@ -471,6 +475,6 @@ flowchart LR
96 <--x 85 96 <--x 85
97 <--x 85 97 <--x 85
88 <--x 86 88 <--x 86
105 <--x 119 106 <--x 120
108 <--x 120 109 <--x 121
``` ```

View File

@ -553,6 +553,70 @@ description: Operations executed ball-joint-rod-end.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 20.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "fillet", "name": "fillet",
@ -712,6 +776,70 @@ description: Operations executed ball-joint-rod-end.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": -50.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "subtract", "name": "subtract",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -87,20 +87,20 @@ flowchart LR
27 --- 4 27 --- 4
8 --- 20 8 --- 20
8 x--> 25 8 x--> 25
8 --- 29 8 --- 31
8 --- 35 8 --- 37
9 --- 21 9 --- 21
9 x--> 25 9 x--> 25
9 --- 33 9 --- 33
9 --- 39 9 --- 39
10 --- 22 10 --- 22
10 x--> 25 10 x--> 25
10 --- 30 10 --- 29
10 --- 36 10 --- 35
11 --- 23 11 --- 23
11 x--> 25 11 x--> 25
11 --- 31 11 --- 30
11 --- 37 11 --- 36
12 --- 24 12 --- 24
12 x--> 25 12 x--> 25
12 --- 32 12 --- 32
@ -132,18 +132,18 @@ flowchart LR
18 --- 34 18 --- 34
19 --- 28 19 --- 28
19 --- 34 19 --- 34
20 --- 29 20 --- 31
20 --- 35 20 --- 37
36 <--x 20 38 <--x 20
21 --- 33 21 --- 33
35 <--x 21 35 <--x 21
21 --- 39 21 --- 39
22 --- 30 22 --- 29
22 --- 36 22 --- 35
37 <--x 22 36 <--x 22
23 --- 31 23 --- 30
23 --- 37 23 --- 36
38 <--x 23 37 <--x 23
24 --- 32 24 --- 32
24 --- 38 24 --- 38
39 <--x 24 39 <--x 24

View File

@ -213,7 +213,8 @@ flowchart LR
109["SweepEdge Adjacent"] 109["SweepEdge Adjacent"]
110["SweepEdge Adjacent"] 110["SweepEdge Adjacent"]
111["SweepEdge Adjacent"] 111["SweepEdge Adjacent"]
112["EdgeCut Fillet<br>[3014, 3304, 0]"] 112["SweepEdge Adjacent"]
113["EdgeCut Fillet<br>[3014, 3304, 0]"]
%% [ProgramBodyItem { index: 26 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] %% [ProgramBodyItem { index: 26 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }]
1 --- 8 1 --- 8
1 --- 9 1 --- 9
@ -277,7 +278,7 @@ flowchart LR
27 --- 83 27 --- 83
27 x--> 86 27 x--> 86
27 --- 96 27 --- 96
27 --- 111 27 --- 112
28 --- 68 28 --- 68
28 x--> 85 28 x--> 85
28 --- 90 28 --- 90
@ -300,31 +301,31 @@ flowchart LR
34 --- 98 34 --- 98
62 <--x 36 62 <--x 36
36 --- 78 36 --- 78
36 x--> 103 36 --- 103
62 <--x 37 62 <--x 37
37 --- 77 37 --- 77
37 --- 103 37 --- 104
62 <--x 38 62 <--x 38
38 --- 82 38 --- 82
38 --- 104 38 --- 105
62 <--x 39 62 <--x 39
39 --- 79 39 --- 79
39 --- 105 39 --- 106
62 <--x 40 62 <--x 40
40 --- 74 40 --- 74
40 --- 106 40 --- 107
62 <--x 41 62 <--x 41
41 --- 81 41 --- 81
41 --- 107 41 --- 108
62 <--x 42 62 <--x 42
42 --- 76 42 --- 76
42 --- 108 42 --- 109
62 <--x 43 62 <--x 43
43 --- 75 43 --- 75
43 --- 109 43 --- 110
62 <--x 44 62 <--x 44
44 --- 80 44 --- 80
44 --- 110 44 --- 111
45 --- 73 45 --- 73
45 x--> 82 45 x--> 82
45 --- 95 45 --- 95
@ -338,7 +339,7 @@ flowchart LR
60 --- 86 60 --- 86
60 --- 89 60 --- 89
60 --- 96 60 --- 96
60 --- 111 60 --- 112
61 --- 69 61 --- 69
61 --- 70 61 --- 70
61 --- 71 61 --- 71
@ -370,6 +371,7 @@ flowchart LR
62 --- 108 62 --- 108
62 --- 109 62 --- 109
62 --- 110 62 --- 110
62 --- 111
64 --- 73 64 --- 73
64 --- 95 64 --- 95
64 --- 102 64 --- 102
@ -390,29 +392,31 @@ flowchart LR
73 --- 95 73 --- 95
73 --- 102 73 --- 102
95 <--x 74 95 <--x 74
105 <--x 74 106 <--x 74
74 --- 106 74 --- 107
108 <--x 75 109 <--x 75
75 --- 109 75 --- 110
107 <--x 76 108 <--x 76
76 --- 108 76 --- 109
77 --- 103 103 <--x 77
77 --- 104
78 --- 103 78 --- 103
110 <--x 78 111 <--x 78
104 <--x 79 105 <--x 79
79 --- 105 79 --- 106
109 <--x 80 110 <--x 80
80 --- 110 80 --- 111
106 <--x 81 107 <--x 81
81 --- 107 81 --- 108
82 --- 104 104 <--x 82
82 --- 105
83 --- 96 83 --- 96
83 --- 111 83 --- 112
91 <--x 87 91 <--x 87
92 <--x 87 92 <--x 87
93 <--x 87 93 <--x 87
94 <--x 87 94 <--x 87
90 <--x 88 90 <--x 88
96 <--x 89 96 <--x 89
98 <--x 112 98 <--x 113
``` ```

View File

@ -647,6 +647,7 @@ flowchart LR
481["SweepEdge Adjacent"] 481["SweepEdge Adjacent"]
482["SweepEdge Adjacent"] 482["SweepEdge Adjacent"]
483["SweepEdge Adjacent"] 483["SweepEdge Adjacent"]
484["SweepEdge Adjacent"]
1 --- 11 1 --- 11
1 --- 12 1 --- 12
2 --- 17 2 --- 17
@ -828,7 +829,7 @@ flowchart LR
36 --- 286 36 --- 286
36 x--> 330 36 x--> 330
36 --- 373 36 --- 373
36 --- 447 36 --- 448
38 --- 224 38 --- 224
38 x--> 341 38 x--> 341
38 --- 342 38 --- 342
@ -836,7 +837,7 @@ flowchart LR
39 --- 317 39 --- 317
39 x--> 332 39 x--> 332
39 --- 380 39 --- 380
39 --- 478 39 --- 479
176 <--x 40 176 <--x 40
40 --- 247 40 --- 247
40 --- 408 40 --- 408
@ -864,167 +865,167 @@ flowchart LR
50 --- 264 50 --- 264
50 x--> 339 50 x--> 339
50 --- 366 50 --- 366
50 --- 426 50 --- 427
51 --- 291 51 --- 291
51 x--> 326 51 x--> 326
51 --- 378 51 --- 378
51 --- 452 51 --- 453
52 --- 290 52 --- 290
52 x--> 326 52 x--> 326
52 --- 377 52 --- 377
52 --- 451 52 --- 452
53 --- 265 53 --- 265
53 x--> 339 53 x--> 339
53 --- 365 53 --- 365
53 --- 425 53 --- 426
54 --- 288 54 --- 288
54 x--> 326 54 x--> 326
54 --- 376 54 --- 376
54 --- 450 54 --- 451
55 --- 263 55 --- 263
55 x--> 339 55 x--> 339
55 --- 364 55 --- 364
55 --- 424 55 --- 425
56 --- 262 56 --- 262
56 x--> 339 56 x--> 339
56 --- 363 56 --- 363
56 --- 423 56 --- 424
57 --- 289 57 --- 289
57 x--> 326 57 x--> 326
57 --- 375 57 --- 375
57 --- 449 57 --- 450
180 <--x 60 180 <--x 60
60 --- 308 60 --- 308
60 --- 454 60 --- 455
180 <--x 61 180 <--x 61
61 --- 310 61 --- 310
61 --- 455 61 --- 456
180 <--x 62 180 <--x 62
62 --- 311 62 --- 311
62 --- 456 62 --- 457
180 <--x 63 180 <--x 63
63 --- 301 63 --- 301
63 --- 457 63 --- 458
180 <--x 64 180 <--x 64
64 --- 316 64 --- 316
64 --- 458 64 --- 459
180 <--x 65 180 <--x 65
65 --- 315 65 --- 315
65 --- 459 65 --- 460
180 <--x 66 180 <--x 66
66 --- 295 66 --- 295
66 --- 460 66 --- 461
180 <--x 67 180 <--x 67
67 --- 303 67 --- 303
67 --- 461 67 --- 462
180 <--x 68 180 <--x 68
68 --- 297 68 --- 297
68 --- 462 68 --- 463
180 <--x 69 180 <--x 69
69 --- 300 69 --- 300
69 --- 463 69 --- 464
180 <--x 70 180 <--x 70
70 --- 309 70 --- 309
70 --- 464 70 --- 465
180 <--x 71 180 <--x 71
71 --- 298 71 --- 298
71 --- 465 71 --- 466
180 <--x 72 180 <--x 72
72 --- 293 72 --- 293
72 --- 466 72 --- 467
180 <--x 73 180 <--x 73
73 --- 294 73 --- 294
73 --- 467 73 --- 468
180 <--x 74 180 <--x 74
74 --- 305 74 --- 305
74 --- 468 74 --- 469
180 <--x 75 180 <--x 75
75 --- 306 75 --- 306
75 --- 469 75 --- 470
180 <--x 76 180 <--x 76
76 --- 307 76 --- 307
76 --- 470 76 --- 471
180 <--x 77 180 <--x 77
77 --- 296 77 --- 296
77 --- 471 77 --- 472
180 <--x 78 180 <--x 78
78 --- 302 78 --- 302
78 --- 472 78 --- 473
180 <--x 79 180 <--x 79
79 --- 304 79 --- 304
79 --- 473 79 --- 474
180 <--x 80 180 <--x 80
80 --- 313 80 --- 313
80 --- 474 80 --- 475
180 <--x 81 180 <--x 81
81 --- 299 81 --- 299
81 --- 475 81 --- 476
180 <--x 82 180 <--x 82
82 --- 312 82 --- 312
82 --- 476 82 --- 477
180 <--x 83 180 <--x 83
83 --- 314 83 --- 314
83 --- 477 83 --- 478
84 --- 285 84 --- 285
84 x--> 324 84 x--> 324
84 --- 372 84 --- 372
84 --- 446 84 --- 447
85 --- 280 85 --- 280
85 x--> 333 85 x--> 333
85 --- 367 85 --- 367
85 --- 441 85 --- 442
86 --- 260 86 --- 260
86 x--> 338 86 x--> 338
86 --- 361 86 --- 361
86 --- 421 86 --- 422
87 --- 292 87 --- 292
87 x--> 324 87 x--> 324
87 --- 379 87 --- 379
87 --- 453 87 --- 454
88 --- 322 88 --- 322
88 x--> 329 88 x--> 329
88 --- 385 88 --- 385
88 --- 483 88 --- 484
89 --- 261 89 --- 261
89 x--> 340 89 x--> 340
89 --- 362 89 --- 362
89 --- 422 89 --- 423
90 --- 287 90 --- 287
90 x--> 324 90 x--> 324
90 --- 374 90 --- 374
90 --- 448 90 --- 449
91 --- 282 91 --- 282
91 x--> 324 91 x--> 324
91 --- 368 91 --- 368
91 --- 442 91 --- 443
92 --- 281 92 --- 281
92 x--> 324 92 x--> 324
92 --- 369 92 --- 369
92 --- 443 92 --- 444
93 --- 283 93 --- 283
93 x--> 324 93 x--> 324
93 --- 370 93 --- 370
93 --- 444 93 --- 445
94 --- 284 94 --- 284
94 x--> 324 94 x--> 324
94 --- 371 94 --- 371
94 --- 445 94 --- 446
96 --- 318 96 --- 318
96 x--> 340 96 x--> 340
96 --- 384 96 --- 384
96 --- 482 96 --- 483
97 --- 321 97 --- 321
97 x--> 340 97 x--> 340
97 --- 383 97 --- 383
97 --- 481 97 --- 482
98 --- 320 98 --- 320
98 x--> 340 98 x--> 340
98 --- 382 98 --- 382
98 --- 480 98 --- 481
99 --- 319 99 --- 319
99 x--> 340 99 x--> 340
99 --- 381 99 --- 381
99 --- 479 99 --- 480
101 --- 233 101 --- 233
101 x--> 337 101 x--> 337
101 --- 343 101 --- 343
@ -1095,73 +1096,73 @@ flowchart LR
117 --- 403 117 --- 403
222 <--x 118 222 <--x 118
118 --- 252 118 --- 252
118 x--> 413 118 --- 413
222 <--x 119 222 <--x 119
119 --- 255 119 --- 255
119 --- 413 119 --- 414
222 <--x 120 222 <--x 120
120 --- 259 120 --- 259
120 --- 414 120 --- 415
222 <--x 121 222 <--x 121
121 --- 253 121 --- 253
121 --- 415 121 --- 416
222 <--x 122 222 <--x 122
122 --- 256 122 --- 256
122 --- 416 122 --- 417
222 <--x 123 222 <--x 123
123 --- 257 123 --- 257
123 --- 417 123 --- 418
222 <--x 124 222 <--x 124
124 --- 254 124 --- 254
124 --- 418 124 --- 419
222 <--x 125 222 <--x 125
125 --- 258 125 --- 258
125 --- 419 125 --- 420
222 <--x 126 222 <--x 126
126 --- 251 126 --- 251
126 --- 420 126 --- 421
223 <--x 127 223 <--x 127
127 --- 275 127 --- 275
127 --- 427 127 --- 428
223 <--x 128 223 <--x 128
128 --- 277 128 --- 277
128 --- 428 128 --- 429
223 <--x 129 223 <--x 129
129 --- 269 129 --- 269
129 --- 429 129 --- 430
223 <--x 130 223 <--x 130
130 --- 276 130 --- 276
130 --- 430 130 --- 431
223 <--x 131 223 <--x 131
131 --- 266 131 --- 266
131 --- 431 131 --- 432
223 <--x 132 223 <--x 132
132 --- 279 132 --- 279
132 --- 432 132 --- 433
223 <--x 133 223 <--x 133
133 --- 270 133 --- 270
133 --- 433 133 --- 434
223 <--x 134 223 <--x 134
134 --- 278 134 --- 278
134 --- 434 134 --- 435
223 <--x 135 223 <--x 135
135 --- 267 135 --- 267
135 --- 435 135 --- 436
223 <--x 136 223 <--x 136
136 --- 271 136 --- 271
136 --- 436 136 --- 437
223 <--x 137 223 <--x 137
137 --- 268 137 --- 268
137 --- 437 137 --- 438
223 <--x 138 223 <--x 138
138 --- 273 138 --- 273
138 --- 438 138 --- 439
223 <--x 139 223 <--x 139
139 --- 274 139 --- 274
139 --- 439 139 --- 440
223 <--x 140 223 <--x 140
140 --- 272 140 --- 272
140 --- 440 140 --- 441
164 --- 250 164 --- 250
164 --- 323 164 --- 323
164 --- 332 164 --- 332
@ -1171,13 +1172,13 @@ flowchart LR
165 --- 330 165 --- 330
165 --- 341 165 --- 341
165 --- 373 165 --- 373
165 --- 447 165 --- 448
166 --- 224 166 --- 224
166 --- 342 166 --- 342
166 --- 386 166 --- 386
174 --- 317 174 --- 317
174 --- 380 174 --- 380
174 --- 478 174 --- 479
176 --- 246 176 --- 246
176 --- 247 176 --- 247
176 --- 248 176 --- 248
@ -1204,10 +1205,10 @@ flowchart LR
178 --- 364 178 --- 364
178 --- 365 178 --- 365
178 --- 366 178 --- 366
178 --- 423
178 --- 424 178 --- 424
178 --- 425 178 --- 425
178 --- 426 178 --- 426
178 --- 427
179 --- 288 179 --- 288
179 --- 289 179 --- 289
179 --- 290 179 --- 290
@ -1218,10 +1219,10 @@ flowchart LR
179 --- 376 179 --- 376
179 --- 377 179 --- 377
179 --- 378 179 --- 378
179 --- 449
179 --- 450 179 --- 450
179 --- 451 179 --- 451
179 --- 452 179 --- 452
179 --- 453
180 --- 293 180 --- 293
180 --- 294 180 --- 294
180 --- 295 180 --- 295
@ -1246,7 +1247,6 @@ flowchart LR
180 --- 314 180 --- 314
180 --- 315 180 --- 315
180 --- 316 180 --- 316
180 --- 454
180 --- 455 180 --- 455
180 --- 456 180 --- 456
180 --- 457 180 --- 457
@ -1270,34 +1270,35 @@ flowchart LR
180 --- 475 180 --- 475
180 --- 476 180 --- 476
180 --- 477 180 --- 477
180 --- 478
181 --- 285 181 --- 285
181 --- 324 181 --- 324
181 --- 333 181 --- 333
181 --- 372 181 --- 372
181 --- 446 181 --- 447
182 --- 280 182 --- 280
182 --- 338 182 --- 338
182 --- 367 182 --- 367
182 --- 441 182 --- 442
185 --- 260 185 --- 260
185 --- 361 185 --- 361
185 --- 421 185 --- 422
188 --- 292 188 --- 292
188 --- 336 188 --- 336
188 --- 379 188 --- 379
188 --- 453 188 --- 454
189 --- 322 189 --- 322
189 --- 329 189 --- 329
189 --- 340 189 --- 340
189 --- 385 189 --- 385
189 --- 483 189 --- 484
191 --- 261 191 --- 261
191 --- 362 191 --- 362
191 --- 422 191 --- 423
205 --- 287 205 --- 287
205 --- 334 205 --- 334
205 --- 374 205 --- 374
205 --- 448 205 --- 449
213 --- 281 213 --- 281
213 --- 282 213 --- 282
213 --- 283 213 --- 283
@ -1307,10 +1308,10 @@ flowchart LR
213 --- 369 213 --- 369
213 --- 370 213 --- 370
213 --- 371 213 --- 371
213 --- 442
213 --- 443 213 --- 443
213 --- 444 213 --- 444
213 --- 445 213 --- 445
213 --- 446
218 --- 318 218 --- 318
218 --- 319 218 --- 319
218 --- 320 218 --- 320
@ -1320,10 +1321,10 @@ flowchart LR
218 --- 382 218 --- 382
218 --- 383 218 --- 383
218 --- 384 218 --- 384
218 --- 479
218 --- 480 218 --- 480
218 --- 481 218 --- 481
218 --- 482 218 --- 482
218 --- 483
221 --- 225 221 --- 225
221 --- 226 221 --- 226
221 --- 227 221 --- 227
@ -1394,6 +1395,7 @@ flowchart LR
222 --- 418 222 --- 418
222 --- 419 222 --- 419
222 --- 420 222 --- 420
222 --- 421
223 --- 266 223 --- 266
223 --- 267 223 --- 267
223 --- 268 223 --- 268
@ -1408,7 +1410,6 @@ flowchart LR
223 --- 277 223 --- 277
223 --- 278 223 --- 278
223 --- 279 223 --- 279
223 --- 427
223 --- 428 223 --- 428
223 --- 429 223 --- 429
223 --- 430 223 --- 430
@ -1422,59 +1423,60 @@ flowchart LR
223 --- 438 223 --- 438
223 --- 439 223 --- 439
223 --- 440 223 --- 440
223 --- 441
224 --- 342 224 --- 342
224 --- 386 224 --- 386
225 --- 356 225 --- 356
399 <--x 225
225 --- 400 225 --- 400
401 <--x 225
226 --- 344 226 --- 344
387 <--x 226
226 --- 388 226 --- 388
389 <--x 226
227 --- 348 227 --- 348
391 <--x 227
227 --- 392 227 --- 392
393 <--x 227
228 --- 355 228 --- 355
398 <--x 228
228 --- 399 228 --- 399
400 <--x 228
229 --- 346 229 --- 346
389 <--x 229
229 --- 390 229 --- 390
391 <--x 229
230 --- 351 230 --- 351
394 <--x 230
230 --- 395 230 --- 395
396 <--x 230
231 --- 359 231 --- 359
387 <--x 231 402 <--x 231
231 --- 403 231 --- 403
232 --- 358 232 --- 358
401 <--x 232
232 --- 402 232 --- 402
403 <--x 232
233 --- 343 233 --- 343
233 --- 387 233 --- 387
388 <--x 233 403 <--x 233
234 --- 357 234 --- 357
400 <--x 234
234 --- 401 234 --- 401
402 <--x 234
235 --- 353 235 --- 353
396 <--x 235
235 --- 397 235 --- 397
398 <--x 235
236 --- 352 236 --- 352
395 <--x 236
236 --- 396 236 --- 396
397 <--x 236
237 --- 354 237 --- 354
397 <--x 237
237 --- 398 237 --- 398
399 <--x 237
238 --- 345 238 --- 345
388 <--x 238
238 --- 389 238 --- 389
390 <--x 238
239 --- 347 239 --- 347
390 <--x 239
239 --- 391 239 --- 391
392 <--x 239
240 --- 349 240 --- 349
392 <--x 240
240 --- 393 240 --- 393
394 <--x 240
241 --- 350 241 --- 350
393 <--x 241
241 --- 394 241 --- 394
395 <--x 241
406 <--x 242 406 <--x 242
242 --- 407 242 --- 407
243 --- 404 243 --- 404
@ -1493,164 +1495,166 @@ flowchart LR
249 --- 411 249 --- 411
250 --- 360 250 --- 360
250 --- 412 250 --- 412
419 <--x 251 420 <--x 251
251 --- 420 251 --- 421
252 --- 413 252 --- 413
420 <--x 252 421 <--x 252
414 <--x 253 415 <--x 253
253 --- 415 253 --- 416
417 <--x 254 418 <--x 254
254 --- 418 254 --- 419
255 --- 413 413 <--x 255
415 <--x 256 255 --- 414
256 --- 416 416 <--x 256
416 <--x 257 256 --- 417
257 --- 417 417 <--x 257
418 <--x 258 257 --- 418
258 --- 419 419 <--x 258
259 --- 414 258 --- 420
414 <--x 259
259 --- 415
260 --- 361 260 --- 361
260 --- 421 260 --- 422
261 --- 362 261 --- 362
261 --- 422 261 --- 423
262 --- 363 262 --- 363
262 --- 423 262 --- 424
424 <--x 262 425 <--x 262
263 --- 364 263 --- 364
263 --- 424 263 --- 425
425 <--x 263 426 <--x 263
264 --- 366 264 --- 366
423 <--x 264 424 <--x 264
264 --- 426 264 --- 427
265 --- 365 265 --- 365
265 --- 425 265 --- 426
426 <--x 265 427 <--x 265
430 <--x 266 431 <--x 266
266 --- 431 266 --- 432
434 <--x 267 435 <--x 267
267 --- 435 267 --- 436
436 <--x 268 437 <--x 268
268 --- 437 268 --- 438
428 <--x 269 429 <--x 269
269 --- 429 269 --- 430
432 <--x 270 433 <--x 270
270 --- 433 270 --- 434
435 <--x 271 436 <--x 271
271 --- 436 271 --- 437
439 <--x 272 440 <--x 272
272 --- 440 272 --- 441
437 <--x 273 438 <--x 273
273 --- 438 273 --- 439
438 <--x 274 439 <--x 274
274 --- 439 274 --- 440
275 --- 427 275 --- 428
440 <--x 275 441 <--x 275
429 <--x 276 430 <--x 276
276 --- 430 276 --- 431
427 <--x 277 428 <--x 277
277 --- 428 277 --- 429
433 <--x 278 434 <--x 278
278 --- 434 278 --- 435
431 <--x 279 432 <--x 279
279 --- 432 279 --- 433
280 --- 367 280 --- 367
280 --- 441 280 --- 442
281 --- 369 281 --- 369
281 --- 443 443 <--x 281
444 <--x 281 281 --- 444
282 --- 368 282 --- 368
282 --- 442 282 --- 443
443 <--x 282 446 <--x 282
283 --- 370 283 --- 370
283 --- 444 444 <--x 283
445 <--x 283 283 --- 445
284 --- 371 284 --- 371
442 <--x 284 445 <--x 284
284 --- 445 284 --- 446
285 --- 372 285 --- 372
285 --- 446 285 --- 447
286 --- 373 286 --- 373
286 --- 447 286 --- 448
287 --- 374 287 --- 374
287 --- 448 287 --- 449
288 --- 376 288 --- 376
449 <--x 288 288 --- 451
288 --- 450 452 <--x 288
289 --- 375 289 --- 375
289 --- 449 289 --- 450
452 <--x 289 451 <--x 289
290 --- 377 290 --- 377
450 <--x 290 290 --- 452
290 --- 451 453 <--x 290
291 --- 378 291 --- 378
451 <--x 291 450 <--x 291
291 --- 452 291 --- 453
292 --- 379 292 --- 379
292 --- 453 292 --- 454
465 <--x 293 466 <--x 293
293 --- 466 293 --- 467
466 <--x 294 467 <--x 294
294 --- 467 294 --- 468
459 <--x 295 460 <--x 295
295 --- 460 295 --- 461
470 <--x 296 471 <--x 296
296 --- 471 296 --- 472
461 <--x 297 462 <--x 297
297 --- 462 297 --- 463
464 <--x 298 465 <--x 298
298 --- 465 298 --- 466
474 <--x 299 475 <--x 299
299 --- 475 299 --- 476
462 <--x 300 463 <--x 300
300 --- 463 300 --- 464
456 <--x 301 457 <--x 301
301 --- 457 301 --- 458
471 <--x 302 472 <--x 302
302 --- 472 302 --- 473
460 <--x 303 461 <--x 303
303 --- 461 303 --- 462
472 <--x 304 473 <--x 304
304 --- 473 304 --- 474
467 <--x 305 468 <--x 305
305 --- 468 305 --- 469
468 <--x 306 469 <--x 306
306 --- 469 306 --- 470
469 <--x 307 470 <--x 307
307 --- 470 307 --- 471
308 --- 454 308 --- 455
477 <--x 308 478 <--x 308
463 <--x 309 464 <--x 309
309 --- 464 309 --- 465
454 <--x 310 455 <--x 310
310 --- 455 310 --- 456
455 <--x 311 456 <--x 311
311 --- 456 311 --- 457
475 <--x 312 476 <--x 312
312 --- 476 312 --- 477
473 <--x 313 474 <--x 313
313 --- 474 313 --- 475
476 <--x 314 477 <--x 314
314 --- 477 314 --- 478
458 <--x 315 459 <--x 315
315 --- 459 315 --- 460
457 <--x 316 458 <--x 316
316 --- 458 316 --- 459
317 --- 380 317 --- 380
317 --- 478 317 --- 479
318 --- 384 318 --- 384
479 <--x 318 480 <--x 318
318 --- 482 318 --- 483
319 --- 381 319 --- 381
319 --- 479 319 --- 480
480 <--x 319 481 <--x 319
320 --- 382 320 --- 382
320 --- 480 320 --- 481
481 <--x 320 482 <--x 320
321 --- 383 321 --- 383
321 --- 481 321 --- 482
482 <--x 321 483 <--x 321
322 --- 385 322 --- 385
322 --- 483 322 --- 484
380 <--x 323 380 <--x 323
361 <--x 324 361 <--x 324
368 <--x 325 368 <--x 325

View File

@ -48,6 +48,99 @@ description: Operations executed car-wheel-assembly.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Array",
"value": [
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
}
]
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": 0.5,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "patternCircular3d", "name": "patternCircular3d",
@ -188,6 +281,70 @@ description: Operations executed car-wheel-assembly.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": 0.5,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "GroupBegin", "type": "GroupBegin",
"group": { "group": {

View File

@ -366,114 +366,114 @@ flowchart LR
11 ---- 74 11 ---- 74
26 --- 75 26 --- 75
26 x--> 108 26 x--> 108
26 --- 130 26 --- 139
26 --- 162 26 --- 171
27 --- 76 27 --- 76
27 x--> 108 27 x--> 108
27 --- 116 27 --- 114
27 --- 148 27 --- 146
28 --- 77 28 --- 77
28 x--> 108 28 x--> 108
28 --- 139 28 --- 115
28 --- 171 28 --- 147
29 --- 78 29 --- 78
29 x--> 108 29 x--> 108
29 --- 135 29 --- 132
29 --- 167 29 --- 164
30 --- 79 30 --- 79
30 x--> 108 30 x--> 108
30 --- 128 30 --- 124
30 --- 160 30 --- 156
31 --- 80 31 --- 80
31 x--> 108 31 x--> 108
31 --- 123 31 --- 138
31 --- 155 31 --- 170
32 --- 81 32 --- 81
32 x--> 108 32 x--> 108
32 --- 127 32 --- 129
32 --- 159 32 --- 161
33 --- 82 33 --- 82
33 x--> 108 33 x--> 108
33 --- 132 33 --- 119
33 --- 164 33 --- 151
34 --- 83 34 --- 83
34 x--> 108 34 x--> 108
34 --- 133 34 --- 123
34 --- 165 34 --- 155
35 --- 84 35 --- 84
35 x--> 108 35 x--> 108
35 --- 121 35 --- 135
35 --- 153 35 --- 167
36 --- 85 36 --- 85
36 x--> 108 36 x--> 108
36 --- 137 36 --- 125
36 --- 169 36 --- 157
37 --- 86 37 --- 86
37 x--> 108 37 x--> 108
37 --- 115 37 --- 116
37 --- 147 37 --- 148
38 --- 87 38 --- 87
38 x--> 108 38 x--> 108
38 --- 120 38 --- 131
38 --- 152 38 --- 163
39 --- 88 39 --- 88
39 x--> 108 39 x--> 108
39 --- 124 39 --- 127
39 --- 156 39 --- 159
40 --- 89 40 --- 89
40 x--> 108 40 x--> 108
40 --- 134 40 --- 134
40 --- 166 40 --- 166
41 --- 90 41 --- 90
41 x--> 108 41 x--> 108
41 --- 136 41 --- 130
41 --- 168 41 --- 162
42 --- 91 42 --- 91
42 x--> 108 42 x--> 108
42 --- 122 42 --- 136
42 --- 154 42 --- 168
43 --- 92 43 --- 92
43 x--> 108 43 x--> 108
43 --- 114 43 --- 126
43 --- 146 43 --- 158
44 --- 93 44 --- 93
44 x--> 108 44 x--> 108
44 --- 113 44 --- 113
44 --- 145 44 --- 145
45 --- 94 45 --- 94
45 x--> 108 45 x--> 108
45 --- 131 45 --- 133
45 --- 163 45 --- 165
46 --- 95 46 --- 95
46 x--> 108 46 x--> 108
46 --- 117 46 --- 137
46 --- 149 46 --- 169
47 --- 96 47 --- 96
47 x--> 108 47 x--> 108
47 --- 125 47 --- 128
47 --- 157 47 --- 160
48 --- 97 48 --- 97
48 x--> 108 48 x--> 108
48 --- 119 48 --- 118
48 --- 151 48 --- 150
49 --- 98 49 --- 98
49 x--> 108 49 x--> 108
49 --- 126 49 --- 121
49 --- 158 49 --- 153
50 --- 99 50 --- 99
50 x--> 108 50 x--> 108
50 --- 118 50 --- 120
50 --- 150 50 --- 152
51 --- 100 51 --- 100
51 x--> 108 51 x--> 108
51 --- 129 51 --- 117
51 --- 161 51 --- 149
52 --- 101 52 --- 101
52 x--> 108 52 x--> 108
52 --- 138 52 --- 122
52 --- 170 52 --- 154
61 --- 102 61 --- 102
61 x--> 110 61 x--> 109
61 --- 140 61 --- 140
61 --- 172 61 --- 172
63 --- 103 63 --- 103
@ -594,87 +594,87 @@ flowchart LR
74 --- 174 74 --- 174
74 --- 175 74 --- 175
74 --- 176 74 --- 176
75 --- 130 75 --- 139
75 --- 162 145 <--x 75
163 <--x 75 75 --- 171
76 --- 116 76 --- 114
76 --- 148 76 --- 146
149 <--x 76 147 <--x 76
77 --- 139 77 --- 115
145 <--x 77 77 --- 147
77 --- 171 148 <--x 77
78 --- 135 78 --- 132
78 --- 167 78 --- 164
168 <--x 78 165 <--x 78
79 --- 128 79 --- 124
79 --- 160 79 --- 156
161 <--x 79 157 <--x 79
80 --- 123 80 --- 138
80 --- 155 80 --- 170
156 <--x 80 171 <--x 80
81 --- 127 81 --- 129
81 --- 159 81 --- 161
160 <--x 81 162 <--x 81
82 --- 132 82 --- 119
82 --- 164 82 --- 151
165 <--x 82 152 <--x 82
83 --- 133 83 --- 123
83 --- 165 83 --- 155
166 <--x 83 156 <--x 83
84 --- 121 84 --- 135
84 --- 153 84 --- 167
154 <--x 84 168 <--x 84
85 --- 137 85 --- 125
85 --- 169 85 --- 157
170 <--x 85 158 <--x 85
86 --- 115 86 --- 116
86 --- 147 86 --- 148
148 <--x 86 149 <--x 86
87 --- 120 87 --- 131
87 --- 152 87 --- 163
153 <--x 87 164 <--x 87
88 --- 124 88 --- 127
88 --- 156 88 --- 159
157 <--x 88 160 <--x 88
89 --- 134 89 --- 134
89 --- 166 89 --- 166
167 <--x 89 167 <--x 89
90 --- 136 90 --- 130
90 --- 168 90 --- 162
169 <--x 90 163 <--x 90
91 --- 122 91 --- 136
91 --- 154 91 --- 168
155 <--x 91 169 <--x 91
92 --- 114 92 --- 126
92 --- 146 92 --- 158
147 <--x 92 159 <--x 92
93 --- 113 93 --- 113
93 --- 145 93 --- 145
146 <--x 93 146 <--x 93
94 --- 131 94 --- 133
94 --- 163 94 --- 165
164 <--x 94 166 <--x 94
95 --- 117 95 --- 137
95 --- 149 95 --- 169
150 <--x 95 170 <--x 95
96 --- 125 96 --- 128
96 --- 157 96 --- 160
158 <--x 96 161 <--x 96
97 --- 119 97 --- 118
97 --- 151 97 --- 150
152 <--x 97 151 <--x 97
98 --- 126 98 --- 121
98 --- 158 98 --- 153
159 <--x 98 154 <--x 98
99 --- 118 99 --- 120
99 --- 150 99 --- 152
151 <--x 99 153 <--x 99
100 --- 129 100 --- 117
100 --- 161 100 --- 149
162 <--x 100 150 <--x 100
101 --- 138 101 --- 122
101 --- 170 101 --- 154
171 <--x 101 155 <--x 101
102 --- 140 102 --- 140
102 --- 172 102 --- 172
103 --- 144 103 --- 144
@ -689,7 +689,7 @@ flowchart LR
106 --- 141 106 --- 141
106 --- 173 106 --- 173
174 <--x 106 174 <--x 106
140 <--x 109 140 <--x 110
141 <--x 111 141 <--x 111
142 <--x 111 142 <--x 111
143 <--x 111 143 <--x 111

View File

@ -66,6 +66,220 @@ description: Operations executed cpu-cooler.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 27.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 100.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Array",
"value": [
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
}
]
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 27.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 100.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Array",
"value": [
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
{
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
}
]
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 27.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 100.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "patternLinear3d", "name": "patternLinear3d",

View File

@ -625,6 +625,70 @@ description: Operations executed curtain-wall-anchor-plate.kcl
"labeledArgs": {}, "labeledArgs": {},
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 200.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": -70.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": -1.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "extrude", "name": "extrude",
@ -672,6 +736,70 @@ description: Operations executed curtain-wall-anchor-plate.kcl
"labeledArgs": {}, "labeledArgs": {},
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": 140.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "subtract", "name": "subtract",
@ -802,6 +930,134 @@ description: Operations executed curtain-wall-anchor-plate.kcl
}, },
"sourceRange": [] "sourceRange": []
}, },
{
"type": "StdLibCall",
"name": "rotate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"pitch": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"roll": {
"value": {
"type": "Number",
"value": 180.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"yaw": {
"value": {
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{
"type": "StdLibCall",
"name": "translate",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"x": {
"value": {
"type": "Number",
"value": 200.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"y": {
"value": {
"type": "Number",
"value": -70.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
},
"z": {
"value": {
"type": "Number",
"value": 5.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"sourceRange": []
},
{ {
"type": "StdLibCall", "type": "StdLibCall",
"name": "patternLinear3d", "name": "patternLinear3d",

File diff suppressed because it is too large Load Diff

View File

@ -191,7 +191,8 @@ flowchart LR
100["SweepEdge Adjacent"] 100["SweepEdge Adjacent"]
101["SweepEdge Adjacent"] 101["SweepEdge Adjacent"]
102["SweepEdge Adjacent"] 102["SweepEdge Adjacent"]
103["EdgeCut Chamfer<br>[2565, 2678, 0]"] 103["SweepEdge Adjacent"]
104["EdgeCut Chamfer<br>[2565, 2678, 0]"]
%% [ProgramBodyItem { index: 19 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 3 }] %% [ProgramBodyItem { index: 19 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 3 }]
1 --- 11 1 --- 11
2 <--x 3 2 <--x 3
@ -246,25 +247,25 @@ flowchart LR
78 --- 19 78 --- 19
45 <--x 20 45 <--x 20
20 --- 68 20 --- 68
20 x--> 97 20 --- 97
45 <--x 21 45 <--x 21
21 --- 65 21 --- 65
21 --- 97 21 --- 98
45 <--x 22 45 <--x 22
22 --- 64 22 --- 64
22 --- 98 22 --- 99
45 <--x 23 45 <--x 23
23 --- 66 23 --- 66
23 --- 99 23 --- 100
45 <--x 24 45 <--x 24
24 --- 63 24 --- 63
24 --- 100 24 --- 101
45 <--x 25 45 <--x 25
25 --- 62 25 --- 62
25 --- 101 25 --- 102
45 <--x 26 45 <--x 26
26 --- 67 26 --- 67
26 --- 102 26 --- 103
28 --- 57 28 --- 57
28 x--> 70 28 x--> 70
28 --- 84 28 --- 84
@ -310,6 +311,7 @@ flowchart LR
45 --- 100 45 --- 100
45 --- 101 45 --- 101
45 --- 102 45 --- 102
45 --- 103
46 --- 57 46 --- 57
46 --- 70 46 --- 70
46 --- 75 46 --- 75
@ -362,18 +364,20 @@ flowchart LR
60 --- 95 60 --- 95
61 --- 88 61 --- 88
61 --- 96 61 --- 96
100 <--x 62 101 <--x 62
62 --- 101 62 --- 102
99 <--x 63 100 <--x 63
63 --- 100 63 --- 101
64 --- 98 98 <--x 64
65 --- 97 64 --- 99
98 <--x 66 97 <--x 65
66 --- 99 65 --- 98
101 <--x 67 99 <--x 66
67 --- 102 66 --- 100
102 <--x 67
67 --- 103
68 --- 97 68 --- 97
102 <--x 68 103 <--x 68
86 <--x 73 86 <--x 73
81 <--x 74 81 <--x 74
84 <--x 75 84 <--x 75
@ -382,5 +386,5 @@ flowchart LR
87 <--x 78 87 <--x 78
88 <--x 79 88 <--x 79
85 <--x 80 85 <--x 80
81 <--x 103 81 <--x 104
``` ```

Some files were not shown because too many files have changed in this diff Show More