Compare commits
9 Commits
pierremtb/
...
v0.29.0
Author | SHA1 | Date | |
---|---|---|---|
5ae1aecd74 | |||
68ae7e98f9 | |||
56771d561a | |||
f09411817c | |||
bed7ae3b8b | |||
c43510732c | |||
51f0b669a4 | |||
3cbedcd3e7 | |||
5d2fa43150 |
4
.github/workflows/e2e-tests.yml
vendored
4
.github/workflows/e2e-tests.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
|||||||
- name: Download Wasm Cache
|
- name: Download Wasm Cache
|
||||||
id: download-wasm
|
id: download-wasm
|
||||||
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
||||||
uses: dawidd6/action-download-artifact@v6
|
uses: dawidd6/action-download-artifact@v7
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||||
@ -255,7 +255,7 @@ jobs:
|
|||||||
- name: Download Wasm Cache
|
- name: Download Wasm Cache
|
||||||
id: download-wasm
|
id: download-wasm
|
||||||
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
||||||
uses: dawidd6/action-download-artifact@v6
|
uses: dawidd6/action-download-artifact@v7
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
19916
docs/kcl/std.json
19916
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
@ -1,161 +0,0 @@
|
|||||||
---
|
|
||||||
title: "BinaryOperator"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Add two numbers.
|
|
||||||
|
|
||||||
**enum:** `+`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Subtract two numbers.
|
|
||||||
|
|
||||||
**enum:** `-`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Multiply two numbers.
|
|
||||||
|
|
||||||
**enum:** `*`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Divide two numbers.
|
|
||||||
|
|
||||||
**enum:** `/`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Modulo two numbers.
|
|
||||||
|
|
||||||
**enum:** `%`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Raise a number to a power.
|
|
||||||
|
|
||||||
**enum:** `^`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Are two numbers equal?
|
|
||||||
|
|
||||||
**enum:** `==`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Are two numbers not equal?
|
|
||||||
|
|
||||||
**enum:** `!=`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left greater than right
|
|
||||||
|
|
||||||
**enum:** `>`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left greater than or equal to right
|
|
||||||
|
|
||||||
**enum:** `>=`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left less than right
|
|
||||||
|
|
||||||
**enum:** `<`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left less than or equal to right
|
|
||||||
|
|
||||||
**enum:** `<=`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,160 +0,0 @@
|
|||||||
---
|
|
||||||
title: "BinaryPart"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `Literal`| | No |
|
|
||||||
| `value` |[`LiteralValue`](/docs/kcl/types/LiteralValue)| | No |
|
|
||||||
| `raw` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
|
|
||||||
| `name` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `BinaryExpression`| | No |
|
|
||||||
| `operator` |[`BinaryOperator`](/docs/kcl/types/BinaryOperator)| | No |
|
|
||||||
| `left` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| | No |
|
|
||||||
| `right` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `CallExpression`| | No |
|
|
||||||
| `callee` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
|
|
||||||
| `arguments` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `UnaryExpression`| | No |
|
|
||||||
| `operator` |[`UnaryOperator`](/docs/kcl/types/UnaryOperator)| | No |
|
|
||||||
| `argument` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `MemberExpression`| | No |
|
|
||||||
| `object` |[`MemberObject`](/docs/kcl/types/MemberObject)| | No |
|
|
||||||
| `property` |[`LiteralIdentifier`](/docs/kcl/types/LiteralIdentifier)| | No |
|
|
||||||
| `computed` |`boolean`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `IfExpression`| | No |
|
|
||||||
| `cond` |[`Expr`](/docs/kcl/types/Expr)| | No |
|
|
||||||
| `then_val` |[`Program`](/docs/kcl/types/Program)| | No |
|
|
||||||
| `else_ifs` |`[` [`ElseIf`](/docs/kcl/types/ElseIf) `]`| | No |
|
|
||||||
| `final_else` |[`Program`](/docs/kcl/types/Program)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
|||||||
---
|
|
||||||
title: "BodyItem"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ImportStatement`| | No |
|
|
||||||
| `items` |`[` [`ImportItem`](/docs/kcl/types/ImportItem) `]`| | No |
|
|
||||||
| `path` |`string`| | No |
|
|
||||||
| `raw_path` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ExpressionStatement`| | No |
|
|
||||||
| `expression` |[`Expr`](/docs/kcl/types/Expr)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `VariableDeclaration`| | No |
|
|
||||||
| `declarations` |`[` [`VariableDeclarator`](/docs/kcl/types/VariableDeclarator) `]`| | No |
|
|
||||||
| `visibility` |[`ItemVisibility`](/docs/kcl/types/ItemVisibility)| | No |
|
|
||||||
| `kind` |[`VariableKind`](/docs/kcl/types/VariableKind)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ReturnStatement`| | No |
|
|
||||||
| `argument` |[`Expr`](/docs/kcl/types/Expr)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
title: "CommentStyle"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Like // foo
|
|
||||||
|
|
||||||
**enum:** `line`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Like /* foo */
|
|
||||||
|
|
||||||
**enum:** `block`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ElseIf"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `cond` |[`Expr`](/docs/kcl/types/Expr)| | No |
|
|
||||||
| `then_val` |[`Program`](/docs/kcl/types/Program)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
title: "EnvironmentRef"
|
|
||||||
excerpt: "An index pointing to an environment."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
An index pointing to an environment.
|
|
||||||
|
|
||||||
**Type:** `integer` (`uint`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,317 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Expr"
|
|
||||||
excerpt: "An expression can be evaluated to yield a single KCL value."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
An expression can be evaluated to yield a single KCL value.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `Literal`| | No |
|
|
||||||
| `value` |[`LiteralValue`](/docs/kcl/types/LiteralValue)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `raw` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
|
|
||||||
| `name` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No |
|
|
||||||
| `value` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `BinaryExpression`| | No |
|
|
||||||
| `operator` |[`BinaryOperator`](/docs/kcl/types/BinaryOperator)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `left` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `right` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`FunctionExpression`](/docs/kcl/types/FunctionExpression)| | No |
|
|
||||||
| `params` |`[` [`Parameter`](/docs/kcl/types/Parameter) `]`| | No |
|
|
||||||
| `body` |[`Program`](/docs/kcl/types/Program)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `CallExpression`| | No |
|
|
||||||
| `callee` |[`Identifier`](/docs/kcl/types/Identifier)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `arguments` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `PipeExpression`| | No |
|
|
||||||
| `body` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
|
|
||||||
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `PipeSubstitution`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ArrayExpression`| | No |
|
|
||||||
| `elements` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
|
|
||||||
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ArrayRangeExpression`| | No |
|
|
||||||
| `startElement` |[`Expr`](/docs/kcl/types/Expr)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `endElement` |[`Expr`](/docs/kcl/types/Expr)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `endInclusive` |`boolean`| Is the `end_element` included in the range? | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ObjectExpression`| | No |
|
|
||||||
| `properties` |`[` [`ObjectProperty`](/docs/kcl/types/ObjectProperty) `]`| | No |
|
|
||||||
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `MemberExpression`| | No |
|
|
||||||
| `object` |[`MemberObject`](/docs/kcl/types/MemberObject)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `property` |[`LiteralIdentifier`](/docs/kcl/types/LiteralIdentifier)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `computed` |`boolean`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `UnaryExpression`| | No |
|
|
||||||
| `operator` |[`UnaryOperator`](/docs/kcl/types/UnaryOperator)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `argument` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `IfExpression`| | No |
|
|
||||||
| `cond` |[`Expr`](/docs/kcl/types/Expr)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `then_val` |[`Program`](/docs/kcl/types/Program)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `else_ifs` |`[` [`ElseIf`](/docs/kcl/types/ElseIf) `]`| | No |
|
|
||||||
| `final_else` |[`Program`](/docs/kcl/types/Program)| An expression can be evaluated to yield a single KCL value. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `None`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "FunctionExpression"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `params` |`[` [`Parameter`](/docs/kcl/types/Parameter) `]`| | No |
|
|
||||||
| `body` |[`Program`](/docs/kcl/types/Program)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Identifier"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `name` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ImportItem"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `name` |[`Identifier`](/docs/kcl/types/Identifier)| Name of the item to import. | No |
|
|
||||||
| `alias` |[`Identifier`](/docs/kcl/types/Identifier)| Rename the item using an identifier after "as". | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ItemVisibility"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**enum:** `default`, `export`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -317,7 +317,6 @@ Data for an imported geometry.
|
|||||||
| Property | Type | Description | Required |
|
| Property | Type | Description | Required |
|
||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `type` |enum: `Function`| | No |
|
| `type` |enum: `Function`| | No |
|
||||||
| `expression` |[`FunctionExpression`](/docs/kcl/types/FunctionExpression)| Any KCL value. | No |
|
|
||||||
| `memory` |[`ProgramMemory`](/docs/kcl/types/ProgramMemory)| Any KCL value. | No |
|
| `memory` |[`ProgramMemory`](/docs/kcl/types/ProgramMemory)| Any KCL value. | No |
|
||||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||||
|
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
---
|
|
||||||
title: "LiteralIdentifier"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
|
|
||||||
| `name` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `Literal`| | No |
|
|
||||||
| `value` |[`LiteralValue`](/docs/kcl/types/LiteralValue)| | No |
|
|
||||||
| `raw` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
title: "LiteralValue"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts any of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `number` (`double`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `string`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `boolean`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
|||||||
---
|
|
||||||
title: "MemberObject"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `MemberExpression`| | No |
|
|
||||||
| `object` |[`MemberObject`](/docs/kcl/types/MemberObject)| | No |
|
|
||||||
| `property` |[`LiteralIdentifier`](/docs/kcl/types/LiteralIdentifier)| | No |
|
|
||||||
| `computed` |`boolean`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
|
|
||||||
| `name` |`string`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
title: "NonCodeMeta"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `nonCodeNodes` |`object`| | No |
|
|
||||||
| `startNodes` |`[` [`NonCodeNode`](/docs/kcl/types/NonCodeNode) `]`| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "NonCodeNode"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `value` |[`NonCodeValue`](/docs/kcl/types/NonCodeValue)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
|||||||
---
|
|
||||||
title: "NonCodeValue"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
An inline comment. Here are examples: `1 + 1 // This is an inline comment`. `1 + 1 /* Here's another */`.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `inlineComment`| | No |
|
|
||||||
| `value` |`string`| | No |
|
|
||||||
| `style` |[`CommentStyle`](/docs/kcl/types/CommentStyle)| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
A block comment. An example of this is the following: ```python,no_run /* This is a block comment */ 1 + 1 ``` Now this is important. The block comment is attached to the next line. This is always the case. Also the block comment doesn't have a new line above it. If it did it would be a `NewLineBlockComment`.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `blockComment`| | No |
|
|
||||||
| `value` |`string`| | No |
|
|
||||||
| `style` |[`CommentStyle`](/docs/kcl/types/CommentStyle)| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
A block comment that has a new line above it. The user explicitly added a new line above the block comment.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `newLineBlockComment`| | No |
|
|
||||||
| `value` |`string`| | No |
|
|
||||||
| `style` |[`CommentStyle`](/docs/kcl/types/CommentStyle)| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `newLine`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ObjectProperty"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `key` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
|
|
||||||
| `value` |[`Expr`](/docs/kcl/types/Expr)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Parameter"
|
|
||||||
excerpt: "Parameter of a KCL function."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
Parameter of a KCL function.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `identifier` |[`Identifier`](/docs/kcl/types/Identifier)| The parameter's label or name. | No |
|
|
||||||
| `optional` |`boolean`| Is the parameter optional? | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Program"
|
|
||||||
excerpt: "A KCL program top level, or function body."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
A KCL program top level, or function body.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `body` |`[` [`BodyItem`](/docs/kcl/types/BodyItem) `]`| | No |
|
|
||||||
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| A KCL program top level, or function body. | No |
|
|
||||||
| `shebang` |[`Shebang`](/docs/kcl/types/Shebang)| | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Shebang"
|
|
||||||
excerpt: "A shebang. This is a special type of comment that is at the top of the file. It looks like this: ```python,no_run #!/usr/bin/env python ```"
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
A shebang. This is a special type of comment that is at the top of the file. It looks like this: ```python,no_run #!/usr/bin/env python ```
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `content` |`string`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Uint"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `integer` (`uint32`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
title: "UnaryOperator"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Negate a number.
|
|
||||||
|
|
||||||
**enum:** `-`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Negate a boolean.
|
|
||||||
|
|
||||||
**enum:** `!`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "VariableDeclarator"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `id` |[`Identifier`](/docs/kcl/types/Identifier)| The identifier of the variable. | No |
|
|
||||||
| `init` |[`Expr`](/docs/kcl/types/Expr)| The value of the variable. | No |
|
|
||||||
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
title: "VariableKind"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Declare a named constant.
|
|
||||||
|
|
||||||
**enum:** `const`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Declare a function.
|
|
||||||
|
|
||||||
**enum:** `fn`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -45,7 +45,6 @@ test.describe('integrations tests', () => {
|
|||||||
{
|
{
|
||||||
title: 'test-sample',
|
title: 'test-sample',
|
||||||
fileCount: 1,
|
fileCount: 1,
|
||||||
folderCount: 1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
sortBy: 'last-modified-desc',
|
sortBy: 'last-modified-desc',
|
||||||
@ -233,7 +232,6 @@ test.describe('when using the file tree to', () => {
|
|||||||
{
|
{
|
||||||
title: projectName,
|
title: projectName,
|
||||||
fileCount: 2,
|
fileCount: 2,
|
||||||
folderCount: 2, // TODO: This is a pre-existing bug, there are no folders within the project
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
sortBy: 'last-modified-desc',
|
sortBy: 'last-modified-desc',
|
||||||
|
@ -4,7 +4,6 @@ import { expect } from '@playwright/test'
|
|||||||
interface ProjectCardState {
|
interface ProjectCardState {
|
||||||
title: string
|
title: string
|
||||||
fileCount: number
|
fileCount: number
|
||||||
folderCount: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HomePageState {
|
interface HomePageState {
|
||||||
@ -61,15 +60,13 @@ export class HomePageFixture {
|
|||||||
const projectCards = await this.projectCard.all()
|
const projectCards = await this.projectCard.all()
|
||||||
const projectCardStates: Array<ProjectCardState> = []
|
const projectCardStates: Array<ProjectCardState> = []
|
||||||
for (const projectCard of projectCards) {
|
for (const projectCard of projectCards) {
|
||||||
const [title, fileCount, folderCount] = await Promise.all([
|
const [title, fileCount] = await Promise.all([
|
||||||
(await projectCard.locator(this.projectCardTitle).textContent()) || '',
|
(await projectCard.locator(this.projectCardTitle).textContent()) || '',
|
||||||
Number(await projectCard.locator(this.projectCardFile).textContent()),
|
Number(await projectCard.locator(this.projectCardFile).textContent()),
|
||||||
Number(await projectCard.locator(this.projectCardFolder).textContent()),
|
|
||||||
])
|
])
|
||||||
projectCardStates.push({
|
projectCardStates.push({
|
||||||
title: title,
|
title: title,
|
||||||
fileCount,
|
fileCount,
|
||||||
folderCount,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return projectCardStates
|
return projectCardStates
|
||||||
|
@ -82,7 +82,7 @@ import { getVarNameModal } from 'hooks/useToolbarGuards'
|
|||||||
import { err, reportRejection, trap } from 'lib/trap'
|
import { err, reportRejection, trap } from 'lib/trap'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { modelingMachineEvent } from 'editor/manager'
|
import { modelingMachineEvent } from 'editor/manager'
|
||||||
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'
|
import { hasValidEdgeTreatmentSelection } from 'lang/modifyAst/addFillet'
|
||||||
import {
|
import {
|
||||||
ExportIntent,
|
ExportIntent,
|
||||||
EngineConnectionStateType,
|
EngineConnectionStateType,
|
||||||
@ -576,8 +576,10 @@ export const ModelingMachineProvider = ({
|
|||||||
if (selectionRanges.graphSelections.length <= 0) return false
|
if (selectionRanges.graphSelections.length <= 0) return false
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
'has valid fillet selection': ({ context: { selectionRanges } }) => {
|
'has valid edge treatment selection': ({
|
||||||
return hasValidFilletSelection({
|
context: { selectionRanges },
|
||||||
|
}) => {
|
||||||
|
return hasValidEdgeTreatmentSelection({
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
ast: kclManager.ast,
|
ast: kclManager.ast,
|
||||||
code: codeManager.code,
|
code: codeManager.code,
|
||||||
|
@ -10,10 +10,14 @@ import {
|
|||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
} from '../wasm'
|
} from '../wasm'
|
||||||
import {
|
import {
|
||||||
|
EdgeTreatmentType,
|
||||||
getPathToExtrudeForSegmentSelection,
|
getPathToExtrudeForSegmentSelection,
|
||||||
hasValidFilletSelection,
|
hasValidEdgeTreatmentSelection,
|
||||||
isTagUsedInFillet,
|
isTagUsedInEdgeTreatment,
|
||||||
modifyAstWithFilletAndTag,
|
modifyAstWithEdgeTreatmentAndTag,
|
||||||
|
FilletParameters,
|
||||||
|
ChamferParameters,
|
||||||
|
EdgeTreatmentParameters,
|
||||||
} from './addFillet'
|
} from './addFillet'
|
||||||
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
||||||
import { createLiteral } from 'lang/modifyAst'
|
import { createLiteral } from 'lang/modifyAst'
|
||||||
@ -21,7 +25,6 @@ import { err } from 'lib/trap'
|
|||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { VITE_KC_DEV_TOKEN } from 'env'
|
import { VITE_KC_DEV_TOKEN } from 'env'
|
||||||
import { KclCommandValue } from 'lib/commandTypes'
|
|
||||||
import { isOverlap } from 'lib/utils'
|
import { isOverlap } from 'lib/utils'
|
||||||
import { codeRefFromRange } from 'lang/std/artifactGraph'
|
import { codeRefFromRange } from 'lang/std/artifactGraph'
|
||||||
|
|
||||||
@ -253,10 +256,10 @@ extrude003 = extrude(-15, sketch003)`
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const runModifyAstCloneWithFilletAndTag = async (
|
const runModifyAstCloneWithEdgeTreatmentAndTag = async (
|
||||||
code: string,
|
code: string,
|
||||||
selectionSnippets: Array<string>,
|
selectionSnippets: Array<string>,
|
||||||
radiusValue: number,
|
parameters: EdgeTreatmentParameters,
|
||||||
expectedCode: string
|
expectedCode: string
|
||||||
) => {
|
) => {
|
||||||
// ast
|
// ast
|
||||||
@ -274,13 +277,6 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
// radius
|
|
||||||
const radius: KclCommandValue = {
|
|
||||||
valueAst: createLiteral(radiusValue),
|
|
||||||
valueText: radiusValue.toString(),
|
|
||||||
valueCalculated: radiusValue.toString(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// executeAst
|
// executeAst
|
||||||
await kclManager.executeAst({ ast })
|
await kclManager.executeAst({ ast })
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
@ -299,8 +295,8 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
otherSelections: [],
|
otherSelections: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply fillet to selection
|
// apply edge treatment to seleciton
|
||||||
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
const result = modifyAstWithEdgeTreatmentAndTag(ast, selection, parameters)
|
||||||
if (err(result)) {
|
if (err(result)) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -310,9 +306,42 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
|
|
||||||
expect(newCode).toContain(expectedCode)
|
expect(newCode).toContain(expectedCode)
|
||||||
}
|
}
|
||||||
describe('Testing applyFilletToSelection', () => {
|
const createFilletParameters = (radiusValue: number): FilletParameters => ({
|
||||||
it('should add a fillet to a specific segment', async () => {
|
type: EdgeTreatmentType.Fillet,
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
radius: {
|
||||||
|
valueAst: createLiteral(radiusValue),
|
||||||
|
valueText: radiusValue.toString(),
|
||||||
|
valueCalculated: radiusValue.toString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const createChamferParameters = (lengthValue: number): ChamferParameters => ({
|
||||||
|
type: EdgeTreatmentType.Chamfer,
|
||||||
|
length: {
|
||||||
|
valueAst: createLiteral(lengthValue),
|
||||||
|
valueText: lengthValue.toString(),
|
||||||
|
valueCalculated: lengthValue.toString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Iterate tests over all edge treatment types
|
||||||
|
Object.values(EdgeTreatmentType).forEach(
|
||||||
|
(edgeTreatmentType: EdgeTreatmentType) => {
|
||||||
|
// create parameters based on the edge treatment type
|
||||||
|
let parameterName: string
|
||||||
|
let parameters: EdgeTreatmentParameters
|
||||||
|
if (edgeTreatmentType === EdgeTreatmentType.Fillet) {
|
||||||
|
parameterName = 'radius'
|
||||||
|
parameters = createFilletParameters(3)
|
||||||
|
} else if (edgeTreatmentType === EdgeTreatmentType.Chamfer) {
|
||||||
|
parameterName = 'length'
|
||||||
|
parameters = createChamferParameters(3)
|
||||||
|
} else {
|
||||||
|
// Handle future edge treatments
|
||||||
|
return new Error(`Unsupported edge treatment type: ${edgeTreatmentType}`)
|
||||||
|
}
|
||||||
|
// run tests
|
||||||
|
describe(`Testing modifyAstCloneWithEdgeTreatmentAndTag with ${edgeTreatmentType}s`, () => {
|
||||||
|
it(`should add a ${edgeTreatmentType} to a specific segment`, async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -320,9 +349,8 @@ describe('Testing applyFilletToSelection', () => {
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([0, -20], %)']
|
const segmentSnippets = ['line([0, -20], %)']
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -330,17 +358,17 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to the sketch pipe', async () => {
|
it(`should add a ${edgeTreatmentType} to the sketch pipe`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -348,9 +376,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(-15, %)`
|
|> extrude(-15, %)`
|
||||||
const segmentSnippets = ['line([0, -20], %)']
|
const segmentSnippets = ['line([0, -20], %)']
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -358,17 +385,17 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(-15, %)
|
|> extrude(-15, %)
|
||||||
|> fillet({ radius = 3, tags = [seg01] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to an already tagged segment', async () => {
|
it(`should add a ${edgeTreatmentType} to an already tagged segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -376,9 +403,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %, $seg01)
|
|> line([0, -20], %, $seg01)
|
||||||
@ -386,17 +412,17 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet with existing tag on other segment', async () => {
|
it(`should add a ${edgeTreatmentType} with existing tag on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -404,9 +430,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([-20, 0], %)']
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -414,17 +439,17 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg02] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet with existing fillet on other segment', async () => {
|
it(`should add a ${edgeTreatmentType} with existing fillet on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -433,9 +458,8 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 5, tags = [seg01] }, %)`
|
|> fillet({ radius = 5, tags = [seg01] }, %)`
|
||||||
const segmentSnippets = ['line([-20, 0], %)']
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -444,27 +468,27 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 5, tags = [seg01] }, %)
|
|> fillet({ radius = 5, tags = [seg01] }, %)
|
||||||
|> fillet({ radius = 3, tags = [seg02] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to two segments of a single extrusion', async () => {
|
it(`should add a ${edgeTreatmentType} with existing chamfer on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
|> line([-20, 0], %)
|
|> line([-20, 0], %)
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)
|
||||||
const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)']
|
|> chamfer({ length: 5, tags: [seg01] }, %)`
|
||||||
const radiusValue = 3
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -472,17 +496,45 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01, seg02] }, %)`
|
|> chamfer({ length: 5, tags: [seg01] }, %)
|
||||||
|
|> ${edgeTreatmentType}({ ${parameterName}: 3, tags: [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add fillets to two bodies', async () => {
|
it(`should add a ${edgeTreatmentType} to two segments of a single extrusion`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)`
|
||||||
|
const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)']
|
||||||
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %, $seg01)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %, $seg02)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)
|
||||||
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01, seg02] }, %)`
|
||||||
|
|
||||||
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
|
code,
|
||||||
|
segmentSnippets,
|
||||||
|
parameters,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it(`should add ${edgeTreatmentType}s to two bodies`, async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -498,13 +550,12 @@ sketch002 = startSketchOn('XY')
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude002 = extrude(-25, sketch002)` // <--- body 2
|
extrude002 = extrude(-25, sketch002)` // <--- body 2
|
||||||
const segmentSnippets = [
|
const segmentSnippets = [
|
||||||
'line([20, 0], %)',
|
'line([20, 0], %)',
|
||||||
'line([-20, 0], %)',
|
'line([-20, 0], %)',
|
||||||
'line([0, -15], %)',
|
'line([0, -15], %)',
|
||||||
]
|
]
|
||||||
const radiusValue = 3
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
|> line([0, -20], %)
|
|> line([0, -20], %)
|
||||||
@ -512,7 +563,7 @@ extrude002 = extrude(-25, sketch002)` // <--- body 2
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01, seg02] }, %)
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01, seg02] }, %)
|
||||||
sketch002 = startSketchOn('XY')
|
sketch002 = startSketchOn('XY')
|
||||||
|> startProfileAt([30, 10], %)
|
|> startProfileAt([30, 10], %)
|
||||||
|> line([15, 0], %)
|
|> line([15, 0], %)
|
||||||
@ -521,18 +572,20 @@ sketch002 = startSketchOn('XY')
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude002 = extrude(-25, sketch002)
|
extrude002 = extrude(-25, sketch002)
|
||||||
|> fillet({ radius = 3, tags = [seg03] }, %)` // <-- able to add a new one
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg03] }, %)` // <-- able to add a new one
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
describe('Testing isTagUsedInFillet', () => {
|
describe('Testing isTagUsedInEdgeTreatment', () => {
|
||||||
const code = `sketch001 = startSketchOn('XZ')
|
const code = `sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([7.72, 4.13], %)
|
|> startProfileAt([7.72, 4.13], %)
|
||||||
|> line([7.11, 3.48], %, $seg01)
|
|> line([7.11, 3.48], %, $seg01)
|
||||||
@ -565,7 +618,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
||||||
})
|
})
|
||||||
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
||||||
@ -584,7 +637,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
||||||
})
|
})
|
||||||
it('should correctly identify no edges', () => {
|
it('should correctly identify no edges', () => {
|
||||||
@ -603,7 +656,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual([])
|
expect(edges).toEqual([])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -638,7 +691,7 @@ describe('Testing button states', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// state
|
// state
|
||||||
const buttonState = hasValidFilletSelection({
|
const buttonState = hasValidEdgeTreatmentSelection({
|
||||||
ast,
|
ast,
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
code,
|
code,
|
||||||
|
@ -44,32 +44,49 @@ import {
|
|||||||
} from 'lib/singletons'
|
} from 'lib/singletons'
|
||||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||||
|
|
||||||
// Apply Fillet To Selection
|
// Edge Treatment Types
|
||||||
|
export enum EdgeTreatmentType {
|
||||||
|
Chamfer = 'chamfer',
|
||||||
|
Fillet = 'fillet',
|
||||||
|
}
|
||||||
|
|
||||||
export function applyFilletToSelection(
|
export interface ChamferParameters {
|
||||||
|
type: EdgeTreatmentType.Chamfer
|
||||||
|
length: KclCommandValue
|
||||||
|
}
|
||||||
|
export interface FilletParameters {
|
||||||
|
type: EdgeTreatmentType.Fillet
|
||||||
|
radius: KclCommandValue
|
||||||
|
}
|
||||||
|
export type EdgeTreatmentParameters = ChamferParameters | FilletParameters
|
||||||
|
|
||||||
|
// Apply Edge Treatment (Fillet or Chamfer) To Selection
|
||||||
|
export function applyEdgeTreatmentToSelection(
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
selection: Selections,
|
selection: Selections,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): void | Error {
|
): void | Error {
|
||||||
// 1. clone and modify with fillet and tag
|
// 1. clone and modify with edge treatment and tag
|
||||||
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
const result = modifyAstWithEdgeTreatmentAndTag(ast, selection, parameters)
|
||||||
if (err(result)) return result
|
if (err(result)) return result
|
||||||
const { modifiedAst, pathToFilletNode } = result
|
const { modifiedAst, pathToEdgeTreatmentNode } = result
|
||||||
|
|
||||||
// 2. update ast
|
// 2. update ast
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
updateAstAndFocus(modifiedAst, pathToFilletNode)
|
updateAstAndFocus(modifiedAst, pathToEdgeTreatmentNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function modifyAstWithFilletAndTag(
|
export function modifyAstWithEdgeTreatmentAndTag(
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
selections: Selections,
|
selections: Selections,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): { modifiedAst: Node<Program>; pathToFilletNode: Array<PathToNode> } | Error {
|
):
|
||||||
|
| { modifiedAst: Node<Program>; pathToEdgeTreatmentNode: Array<PathToNode> }
|
||||||
|
| Error {
|
||||||
let clonedAst = structuredClone(ast)
|
let clonedAst = structuredClone(ast)
|
||||||
const clonedAstForGetExtrude = structuredClone(ast)
|
const clonedAstForGetExtrude = structuredClone(ast)
|
||||||
|
|
||||||
const astResult = insertRadiusIntoAst(clonedAst, radius)
|
const astResult = insertParametersIntoAst(clonedAst, parameters)
|
||||||
if (err(astResult)) return astResult
|
if (err(astResult)) return astResult
|
||||||
|
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
@ -119,21 +136,26 @@ export function modifyAstWithFilletAndTag(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Apply fillet(s) for each extrude node (body)
|
// Step 2: Apply edge treatments for each extrude node (body)
|
||||||
let pathToFilletNodes: Array<PathToNode> = []
|
let pathToEdgeTreatmentNodes: Array<PathToNode> = []
|
||||||
for (const [pathToExtrudeNode, tagInfos] of extrudeToTagsMap.entries()) {
|
for (const [pathToExtrudeNode, tagInfos] of extrudeToTagsMap.entries()) {
|
||||||
// Create a fillet expression with multiple tags
|
// Create an edge treatment expression with multiple tags
|
||||||
const radiusValue =
|
|
||||||
'variableName' in radius ? radius.variableIdentifierAst : radius.valueAst
|
|
||||||
|
|
||||||
|
// edge treatment parameter
|
||||||
|
const parameterResult = getParameterNameAndValue(parameters)
|
||||||
|
if (err(parameterResult)) return parameterResult
|
||||||
|
const { parameterName, parameterValue } = parameterResult
|
||||||
|
|
||||||
|
// tag calls
|
||||||
const tagCalls = tagInfos.map(({ tag, artifact }) => {
|
const tagCalls = tagInfos.map(({ tag, artifact }) => {
|
||||||
return getEdgeTagCall(tag, artifact)
|
return getEdgeTagCall(tag, artifact)
|
||||||
})
|
})
|
||||||
const firstTag = tagCalls[0] // can be Identifier or CallExpression (for opposite and adjacent edges)
|
const firstTag = tagCalls[0] // can be Identifier or CallExpression (for opposite and adjacent edges)
|
||||||
|
|
||||||
const filletCall = createCallExpressionStdLib('fillet', [
|
// edge treatment call
|
||||||
|
const edgeTreatmentCall = createCallExpressionStdLib(parameters.type, [
|
||||||
createObjectExpression({
|
createObjectExpression({
|
||||||
radius: radiusValue,
|
[parameterName]: parameterValue,
|
||||||
tags: createArrayExpression(tagCalls),
|
tags: createArrayExpression(tagCalls),
|
||||||
}),
|
}),
|
||||||
createPipeSubstitution(),
|
createPipeSubstitution(),
|
||||||
@ -147,64 +169,89 @@ export function modifyAstWithFilletAndTag(
|
|||||||
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
||||||
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
||||||
|
|
||||||
// Modify the extrude expression to include this fillet expression
|
// Modify the extrude expression to include this edge treatment expression
|
||||||
// CallExpression - no fillet
|
// CallExpression - no edge treatment
|
||||||
// PipeExpression - fillet exists or extrude in sketch pipe
|
// PipeExpression - edge treatment exists or body in sketch pipe
|
||||||
|
|
||||||
let pathToFilletNode: PathToNode = []
|
let pathToEdgeTreatmentNode: PathToNode
|
||||||
|
|
||||||
if (extrudeDeclarator.init.type === 'CallExpression') {
|
if (extrudeDeclarator.init.type === 'CallExpression') {
|
||||||
// 1. case when no fillet exists
|
// 1. case when no edge treatment exists
|
||||||
|
|
||||||
// modify ast with new fillet call by mutating the extrude node
|
// modify ast with new edge treatment call by mutating the extrude node
|
||||||
extrudeDeclarator.init = createPipeExpression([
|
extrudeDeclarator.init = createPipeExpression([
|
||||||
extrudeDeclarator.init,
|
extrudeDeclarator.init,
|
||||||
filletCall,
|
edgeTreatmentCall,
|
||||||
])
|
])
|
||||||
|
|
||||||
// get path to the fillet node
|
// get path to the edge treatment node
|
||||||
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
pathToEdgeTreatmentNode = getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode,
|
pathToExtrudeNode,
|
||||||
extrudeDeclarator,
|
extrudeDeclarator,
|
||||||
firstTag
|
firstTag,
|
||||||
|
parameters
|
||||||
)
|
)
|
||||||
pathToFilletNodes.push(pathToFilletNode)
|
pathToEdgeTreatmentNodes.push(pathToEdgeTreatmentNode)
|
||||||
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
||||||
// 2. case when fillet exists or extrude in sketch pipe
|
// 2. case when edge treatment exists or extrude in sketch pipe
|
||||||
|
|
||||||
// mutate the extrude node with the new fillet call
|
// mutate the extrude node with the new edge treatment call
|
||||||
extrudeDeclarator.init.body.push(filletCall)
|
extrudeDeclarator.init.body.push(edgeTreatmentCall)
|
||||||
|
|
||||||
// get path to the fillet node
|
// get path to the edge treatment node
|
||||||
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
pathToEdgeTreatmentNode = getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode,
|
pathToExtrudeNode,
|
||||||
extrudeDeclarator,
|
extrudeDeclarator,
|
||||||
firstTag
|
firstTag,
|
||||||
|
parameters
|
||||||
)
|
)
|
||||||
pathToFilletNodes.push(pathToFilletNode)
|
pathToEdgeTreatmentNodes.push(pathToEdgeTreatmentNode)
|
||||||
} else {
|
} else {
|
||||||
return new Error('Unsupported extrude type.')
|
return new Error('Unsupported extrude type.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { modifiedAst: clonedAst, pathToFilletNode: pathToFilletNodes }
|
return {
|
||||||
|
modifiedAst: clonedAst,
|
||||||
|
pathToEdgeTreatmentNode: pathToEdgeTreatmentNodes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertRadiusIntoAst(
|
function insertParametersIntoAst(
|
||||||
ast: Program,
|
ast: Program,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): { ast: Program } | Error {
|
): { ast: Program } | Error {
|
||||||
try {
|
try {
|
||||||
// Validate and update AST
|
const newAst = structuredClone(ast)
|
||||||
|
|
||||||
|
// handle radius parameter
|
||||||
if (
|
if (
|
||||||
'variableName' in radius &&
|
parameters.type === EdgeTreatmentType.Fillet &&
|
||||||
radius.variableName &&
|
'variableName' in parameters.radius &&
|
||||||
radius.insertIndex !== undefined
|
parameters.radius.variableName &&
|
||||||
|
parameters.radius.insertIndex !== undefined
|
||||||
) {
|
) {
|
||||||
const newAst = structuredClone(ast)
|
newAst.body.splice(
|
||||||
newAst.body.splice(radius.insertIndex, 0, radius.variableDeclarationAst)
|
parameters.radius.insertIndex,
|
||||||
return { ast: newAst }
|
0,
|
||||||
|
parameters.radius.variableDeclarationAst
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return { ast }
|
// handle length parameter
|
||||||
|
if (
|
||||||
|
parameters.type === EdgeTreatmentType.Chamfer &&
|
||||||
|
'variableName' in parameters.length &&
|
||||||
|
parameters.length.variableName &&
|
||||||
|
parameters.length.insertIndex !== undefined
|
||||||
|
) {
|
||||||
|
newAst.body.splice(
|
||||||
|
parameters.length.insertIndex,
|
||||||
|
0,
|
||||||
|
parameters.length.variableDeclarationAst
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle upcoming parameters here (for blend, bevel, etc.)
|
||||||
|
return { ast: newAst }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new Error(`Failed to handle AST: ${(error as Error).message}`)
|
return new Error(`Failed to handle AST: ${(error as Error).message}`)
|
||||||
}
|
}
|
||||||
@ -248,10 +295,10 @@ export function getPathToExtrudeForSegmentSelection(
|
|||||||
|
|
||||||
async function updateAstAndFocus(
|
async function updateAstAndFocus(
|
||||||
modifiedAst: Node<Program>,
|
modifiedAst: Node<Program>,
|
||||||
pathToFilletNode: Array<PathToNode>
|
pathToEdgeTreatmentNode: Array<PathToNode>
|
||||||
) {
|
) {
|
||||||
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
||||||
focusPath: pathToFilletNode,
|
focusPath: pathToEdgeTreatmentNode,
|
||||||
})
|
})
|
||||||
|
|
||||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||||
@ -340,27 +387,38 @@ function locateExtrudeDeclarator(
|
|||||||
return { extrudeDeclarator }
|
return { extrudeDeclarator }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPathToNodeOfFilletLiteral(
|
function getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode: PathToNode,
|
pathToExtrudeNode: PathToNode,
|
||||||
extrudeDeclarator: VariableDeclarator,
|
extrudeDeclarator: VariableDeclarator,
|
||||||
tag: Identifier | CallExpression
|
tag: Identifier | CallExpression,
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
): PathToNode {
|
): PathToNode {
|
||||||
let pathToFilletObj: PathToNode = []
|
let pathToEdgeTreatmentObj: PathToNode = []
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
|
|
||||||
traverse(extrudeDeclarator.init, {
|
traverse(extrudeDeclarator.init, {
|
||||||
enter(node, path) {
|
enter(node, path) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = true
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === parameters.type
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
if (!hasTag(node, tag)) return false
|
if (!hasTag(node, tag)) return false
|
||||||
pathToFilletObj = getPathToRadiusLiteral(node, path)
|
pathToEdgeTreatmentObj = getPathToEdgeTreatmentParameterLiteral(
|
||||||
|
node,
|
||||||
|
path,
|
||||||
|
parameters
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node) {
|
leave(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === parameters.type
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -375,7 +433,7 @@ function getPathToNodeOfFilletLiteral(
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
...pathToExtrudeNode.slice(0, indexOfPipeExpression),
|
...pathToExtrudeNode.slice(0, indexOfPipeExpression),
|
||||||
...pathToFilletObj,
|
...pathToEdgeTreatmentObj,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,23 +466,62 @@ function hasTag(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPathToRadiusLiteral(node: ObjectExpression, path: any): PathToNode {
|
function getPathToEdgeTreatmentParameterLiteral(
|
||||||
let pathToFilletObj = path
|
node: ObjectExpression,
|
||||||
|
path: any,
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
|
): PathToNode {
|
||||||
|
let pathToEdgeTreatmentObj = path
|
||||||
|
const parameterResult = getParameterNameAndValue(parameters)
|
||||||
|
if (err(parameterResult)) return pathToEdgeTreatmentObj
|
||||||
|
const { parameterName } = parameterResult
|
||||||
|
|
||||||
node.properties.forEach((prop, index) => {
|
node.properties.forEach((prop, index) => {
|
||||||
if (prop.key.name === 'radius') {
|
if (prop.key.name === parameterName) {
|
||||||
pathToFilletObj.push(
|
pathToEdgeTreatmentObj.push(
|
||||||
['properties', 'ObjectExpression'],
|
['properties', 'ObjectExpression'],
|
||||||
[index, 'index'],
|
[index, 'index'],
|
||||||
['value', 'Property']
|
['value', 'Property']
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return pathToFilletObj
|
return pathToEdgeTreatmentObj
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParameterNameAndValue(
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
|
): { parameterName: string; parameterValue: Expr } | Error {
|
||||||
|
if (parameters.type === EdgeTreatmentType.Fillet) {
|
||||||
|
const parameterValue =
|
||||||
|
'variableName' in parameters.radius
|
||||||
|
? parameters.radius.variableIdentifierAst
|
||||||
|
: parameters.radius.valueAst
|
||||||
|
return { parameterName: 'radius', parameterValue }
|
||||||
|
} else if (parameters.type === EdgeTreatmentType.Chamfer) {
|
||||||
|
const parameterValue =
|
||||||
|
'variableName' in parameters.length
|
||||||
|
? parameters.length.variableIdentifierAst
|
||||||
|
: parameters.length.valueAst
|
||||||
|
return { parameterName: 'length', parameterValue }
|
||||||
|
} else {
|
||||||
|
return new Error('Unsupported edge treatment type}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type Guards
|
||||||
|
function isEdgeTreatmentType(name: string): name is EdgeTreatmentType {
|
||||||
|
return name === EdgeTreatmentType.Chamfer || name === EdgeTreatmentType.Fillet
|
||||||
|
}
|
||||||
|
function isEdgeType(name: string): name is EdgeTypes {
|
||||||
|
return (
|
||||||
|
name === 'getNextAdjacentEdge' ||
|
||||||
|
name === 'getPreviousAdjacentEdge' ||
|
||||||
|
name === 'getOppositeEdge'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button states
|
// Button states
|
||||||
|
export const hasValidEdgeTreatmentSelection = ({
|
||||||
export const hasValidFilletSelection = ({
|
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
ast,
|
ast,
|
||||||
code,
|
code,
|
||||||
@ -433,11 +530,14 @@ export const hasValidFilletSelection = ({
|
|||||||
ast: Node<Program>
|
ast: Node<Program>
|
||||||
code: string
|
code: string
|
||||||
}) => {
|
}) => {
|
||||||
// check if there is anything filletable in the scene
|
// check if there is anything valid for the edge treatment in the scene
|
||||||
let extrudeExists = false
|
let extrudeExists = false
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'extrude') {
|
if (
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
(node.callee.name === 'extrude' || node.callee.name === 'revolve')
|
||||||
|
) {
|
||||||
extrudeExists = true
|
extrudeExists = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -494,32 +594,39 @@ export const hasValidFilletSelection = ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// check if tag is used in fillet
|
// check if tag is used in edge treatment
|
||||||
if (tagExists && selection.artifact) {
|
if (tagExists && selection.artifact) {
|
||||||
// create tag call
|
// create tag call
|
||||||
let tagCall: Expr = getEdgeTagCall(tag, selection.artifact)
|
let tagCall: Expr = getEdgeTagCall(tag, selection.artifact)
|
||||||
|
|
||||||
// check if tag is used in fillet
|
// check if tag is used in edge treatment
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
let tagUsedInFillet = false
|
let tagUsedInEdgeTreatment = false
|
||||||
|
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = true
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
if (hasTag(node, tagCall)) {
|
if (hasTag(node, tagCall)) {
|
||||||
tagUsedInFillet = true
|
tagUsedInEdgeTreatment = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node) {
|
leave(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (tagUsedInFillet) {
|
if (tagUsedInEdgeTreatment) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -533,7 +640,7 @@ type EdgeTypes =
|
|||||||
| 'getPreviousAdjacentEdge'
|
| 'getPreviousAdjacentEdge'
|
||||||
| 'getOppositeEdge'
|
| 'getOppositeEdge'
|
||||||
|
|
||||||
export const isTagUsedInFillet = ({
|
export const isTagUsedInEdgeTreatment = ({
|
||||||
ast,
|
ast,
|
||||||
callExp,
|
callExp,
|
||||||
}: {
|
}: {
|
||||||
@ -543,16 +650,21 @@ export const isTagUsedInFillet = ({
|
|||||||
const tag = getTagFromCallExpression(callExp)
|
const tag = getTagFromCallExpression(callExp)
|
||||||
if (err(tag)) return []
|
if (err(tag)) return []
|
||||||
|
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
let inObj = false
|
let inObj = false
|
||||||
let inTagHelper: EdgeTypes | '' = ''
|
let inTagHelper: EdgeTypes | '' = ''
|
||||||
const edges: Array<EdgeTypes> = []
|
const edges: Array<EdgeTypes> = []
|
||||||
|
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter: (node) => {
|
enter: (node) => {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
// Check if we are entering an edge treatment call
|
||||||
inFillet = true
|
if (
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
node.properties.forEach((prop) => {
|
node.properties.forEach((prop) => {
|
||||||
if (
|
if (
|
||||||
prop.key.name === 'tags' &&
|
prop.key.name === 'tags' &&
|
||||||
@ -564,17 +676,15 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
(node.callee.name === 'getOppositeEdge' ||
|
isEdgeType(node.callee.name)
|
||||||
node.callee.name === 'getNextAdjacentEdge' ||
|
|
||||||
node.callee.name === 'getPreviousAdjacentEdge')
|
|
||||||
) {
|
) {
|
||||||
inTagHelper = node.callee.name
|
inTagHelper = node.callee.name
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
!inTagHelper &&
|
!inTagHelper &&
|
||||||
node.type === 'Identifier' &&
|
node.type === 'Identifier' &&
|
||||||
node.name === tag
|
node.name === tag
|
||||||
@ -583,7 +693,7 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
inTagHelper &&
|
inTagHelper &&
|
||||||
node.type === 'Identifier' &&
|
node.type === 'Identifier' &&
|
||||||
node.name === tag
|
node.name === tag
|
||||||
@ -592,10 +702,13 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave: (node) => {
|
leave: (node) => {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
node.properties.forEach((prop) => {
|
node.properties.forEach((prop) => {
|
||||||
if (
|
if (
|
||||||
prop.key.name === 'tags' &&
|
prop.key.name === 'tags' &&
|
||||||
@ -607,11 +720,9 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
(node.callee.name === 'getOppositeEdge' ||
|
isEdgeType(node.callee.name)
|
||||||
node.callee.name === 'getNextAdjacentEdge' ||
|
|
||||||
node.callee.name === 'getPreviousAdjacentEdge')
|
|
||||||
) {
|
) {
|
||||||
inTagHelper = ''
|
inTagHelper = ''
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,21 @@ describe('desktop utilities', () => {
|
|||||||
'project-without-kcl-files',
|
'project-without-kcl-files',
|
||||||
'another-valid-project',
|
'another-valid-project',
|
||||||
],
|
],
|
||||||
'/test/projects/valid-project': ['file1.kcl', 'file2.stp'],
|
'/test/projects/valid-project': [
|
||||||
|
'file1.kcl',
|
||||||
|
'file2.stp',
|
||||||
|
'file3.kcl',
|
||||||
|
'directory1',
|
||||||
|
],
|
||||||
|
'/test/projects/valid-project/directory1': [],
|
||||||
'/test/projects/project-without-kcl-files': ['file3.glb'],
|
'/test/projects/project-without-kcl-files': ['file3.glb'],
|
||||||
'/test/projects/another-valid-project': ['file4.kcl'],
|
'/test/projects/another-valid-project': [
|
||||||
|
'file4.kcl',
|
||||||
|
'directory2',
|
||||||
|
'directory3',
|
||||||
|
],
|
||||||
|
'/test/projects/another-valid-project/directory2': [],
|
||||||
|
'/test/projects/another-valid-project/directory3': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -119,6 +131,15 @@ describe('desktop utilities', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('correctly counts directories and files', async () => {
|
||||||
|
const projects = await listProjects(mockConfig)
|
||||||
|
// Verify that directories and files are counted correctly
|
||||||
|
expect(projects[0].directory_count).toEqual(1)
|
||||||
|
expect(projects[0].kcl_file_count).toEqual(2)
|
||||||
|
expect(projects[1].directory_count).toEqual(2)
|
||||||
|
expect(projects[1].kcl_file_count).toEqual(1)
|
||||||
|
})
|
||||||
|
|
||||||
it('handles empty project directory', async () => {
|
it('handles empty project directory', async () => {
|
||||||
// Adjust mockFileSystem to simulate empty directory
|
// Adjust mockFileSystem to simulate empty directory
|
||||||
mockFileSystem['/test/projects'] = []
|
mockFileSystem['/test/projects'] = []
|
||||||
|
@ -307,7 +307,10 @@ const directoryCount = (file: FileEntry) => {
|
|||||||
let count = 0
|
let count = 0
|
||||||
if (file.children) {
|
if (file.children) {
|
||||||
for (let entry of file.children) {
|
for (let entry of file.children) {
|
||||||
count += 1
|
// We only want to count FileEntries with children, e.g. folders
|
||||||
|
if (entry.children !== null) {
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
directoryCount(entry)
|
directoryCount(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,11 @@ import {
|
|||||||
extrudeSketch,
|
extrudeSketch,
|
||||||
revolveSketch,
|
revolveSketch,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
import { applyFilletToSelection } from 'lang/modifyAst/addFillet'
|
import {
|
||||||
|
applyEdgeTreatmentToSelection,
|
||||||
|
EdgeTreatmentType,
|
||||||
|
FilletParameters,
|
||||||
|
} from 'lang/modifyAst/addFillet'
|
||||||
import { getNodeFromPath } from '../lang/queryAst'
|
import { getNodeFromPath } from '../lang/queryAst'
|
||||||
import {
|
import {
|
||||||
applyConstraintEqualAngle,
|
applyConstraintEqualAngle,
|
||||||
@ -383,7 +387,7 @@ export const modelingMachine = setup({
|
|||||||
guards: {
|
guards: {
|
||||||
'Selection is on face': () => false,
|
'Selection is on face': () => false,
|
||||||
'has valid sweep selection': () => false,
|
'has valid sweep selection': () => false,
|
||||||
'has valid fillet selection': () => false,
|
'has valid edge treatment selection': () => false,
|
||||||
'Has exportable geometry': () => false,
|
'Has exportable geometry': () => false,
|
||||||
'has valid selection for deletion': () => false,
|
'has valid selection for deletion': () => false,
|
||||||
'has made first point': ({ context }) => {
|
'has made first point': ({ context }) => {
|
||||||
@ -739,14 +743,19 @@ export const modelingMachine = setup({
|
|||||||
// Extract inputs
|
// Extract inputs
|
||||||
const ast = kclManager.ast
|
const ast = kclManager.ast
|
||||||
const { selection, radius } = event.data
|
const { selection, radius } = event.data
|
||||||
|
const parameters: FilletParameters = {
|
||||||
|
type: EdgeTreatmentType.Fillet,
|
||||||
|
radius,
|
||||||
|
}
|
||||||
|
|
||||||
// Apply fillet to selection
|
// Apply fillet to selection
|
||||||
const applyFilletToSelectionResult = applyFilletToSelection(
|
const applyEdgeTreatmentToSelectionResult = applyEdgeTreatmentToSelection(
|
||||||
ast,
|
ast,
|
||||||
selection,
|
selection,
|
||||||
radius
|
parameters
|
||||||
)
|
)
|
||||||
if (err(applyFilletToSelectionResult)) return applyFilletToSelectionResult
|
if (err(applyEdgeTreatmentToSelectionResult))
|
||||||
|
return applyEdgeTreatmentToSelectionResult
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||||
@ -1563,7 +1572,7 @@ export const modelingMachine = setup({
|
|||||||
|
|
||||||
Fillet: {
|
Fillet: {
|
||||||
target: 'idle',
|
target: 'idle',
|
||||||
guard: 'has valid fillet selection', // TODO: fix selections
|
guard: 'has valid edge treatment selection',
|
||||||
actions: ['AST fillet'],
|
actions: ['AST fillet'],
|
||||||
reenter: false,
|
reenter: false,
|
||||||
},
|
},
|
||||||
|
16
src/wasm-lib/Cargo.lock
generated
16
src/wasm-lib/Cargo.lock
generated
@ -443,9 +443,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.20"
|
version = "4.5.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -453,9 +453,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.20"
|
version = "4.5.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -3065,9 +3065,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.13"
|
version = "0.23.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
|
checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
@ -3101,9 +3101,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
|
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
|
@ -16,7 +16,7 @@ async-recursion = "1.1.1"
|
|||||||
async-trait = "0.1.83"
|
async-trait = "0.1.83"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
clap = { version = "4.5.20", default-features = false, optional = true, features = ["std", "derive"] }
|
clap = { version = "4.5.21", default-features = false, optional = true, features = ["std", "derive"] }
|
||||||
convert_case = "0.6.0"
|
convert_case = "0.6.0"
|
||||||
dashmap = "6.1.0"
|
dashmap = "6.1.0"
|
||||||
databake = { version = "0.1.8", features = ["derive"] }
|
databake = { version = "0.1.8", features = ["derive"] }
|
||||||
|
@ -8,17 +8,16 @@ use kittycad_modeling_cmds as kcmc;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{
|
ast::types::{
|
||||||
ArrayExpression, CallExpression, ConstraintLevel, FormatOptions, Literal, PipeExpression, PipeSubstitution,
|
ArrayExpression, CallExpression, ConstraintLevel, FormatOptions, Literal, Node, PipeExpression,
|
||||||
VariableDeclarator,
|
PipeSubstitution, VariableDeclarator,
|
||||||
},
|
},
|
||||||
engine::EngineManager,
|
engine::EngineManager,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{Point2d, SourceRange},
|
executor::Point2d,
|
||||||
|
source_range::{ModuleId, SourceRange},
|
||||||
Program,
|
Program,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::types::{ModuleId, Node};
|
|
||||||
|
|
||||||
type Point3d = kcmc::shared::Point3d<f64>;
|
type Point3d = kcmc::shared::Point3d<f64>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -27,8 +27,9 @@ pub use crate::ast::types::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
docs::StdLibFn,
|
docs::StdLibFn,
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
executor::{ExecState, ExecutorContext, KclValue, Metadata, SourceRange, TagIdentifier},
|
executor::{ExecState, ExecutorContext, KclValue, Metadata, TagIdentifier},
|
||||||
parser::PIPE_OPERATOR,
|
parser::PIPE_OPERATOR,
|
||||||
|
source_range::{ModuleId, SourceRange},
|
||||||
std::kcl_stdlib::KclStdLibFn,
|
std::kcl_stdlib::KclStdLibFn,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ pub struct Node<T> {
|
|||||||
impl<T> Node<T> {
|
impl<T> Node<T> {
|
||||||
pub fn metadata(&self) -> Metadata {
|
pub fn metadata(&self) -> Metadata {
|
||||||
Metadata {
|
Metadata {
|
||||||
source_range: SourceRange([self.start, self.end, self.module_id.0 as usize]),
|
source_range: SourceRange::new(self.start, self.end, self.module_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ impl<T> Node<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_source_range(&self) -> SourceRange {
|
pub fn as_source_range(&self) -> SourceRange {
|
||||||
SourceRange([self.start, self.end, self.module_id.as_usize()])
|
SourceRange::new(self.start, self.end, self.module_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_source_ranges(&self) -> Vec<SourceRange> {
|
pub fn as_source_ranges(&self) -> Vec<SourceRange> {
|
||||||
@ -150,21 +151,21 @@ impl<T: fmt::Display> fmt::Display for Node<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<Node<T>> for crate::executor::SourceRange {
|
impl<T> From<Node<T>> for SourceRange {
|
||||||
fn from(v: Node<T>) -> Self {
|
fn from(v: Node<T>) -> Self {
|
||||||
Self([v.start, v.end, v.module_id.as_usize()])
|
Self::new(v.start, v.end, v.module_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<&Node<T>> for crate::executor::SourceRange {
|
impl<T> From<&Node<T>> for SourceRange {
|
||||||
fn from(v: &Node<T>) -> Self {
|
fn from(v: &Node<T>) -> Self {
|
||||||
Self([v.start, v.end, v.module_id.as_usize()])
|
Self::new(v.start, v.end, v.module_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<&BoxNode<T>> for crate::executor::SourceRange {
|
impl<T> From<&BoxNode<T>> for SourceRange {
|
||||||
fn from(v: &BoxNode<T>) -> Self {
|
fn from(v: &BoxNode<T>) -> Self {
|
||||||
Self([v.start, v.end, v.module_id.as_usize()])
|
Self::new(v.start, v.end, v.module_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +541,6 @@ impl Program {
|
|||||||
/// #!/usr/bin/env python
|
/// #!/usr/bin/env python
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema, Bake)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema, Bake)]
|
||||||
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
|
|
||||||
#[databake(path = kcl_lib::ast::types)]
|
#[databake(path = kcl_lib::ast::types)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
pub struct Shebang {
|
pub struct Shebang {
|
||||||
@ -553,29 +553,6 @@ impl Shebang {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identifier of a source file. Uses a u32 to keep the size small.
|
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema, Bake)]
|
|
||||||
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
|
|
||||||
#[databake(path = kcl_lib::ast::types)]
|
|
||||||
#[ts(export)]
|
|
||||||
pub struct ModuleId(pub u32);
|
|
||||||
|
|
||||||
impl ModuleId {
|
|
||||||
pub fn from_usize(id: usize) -> Self {
|
|
||||||
Self(u32::try_from(id).expect("module ID should fit in a u32"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_usize(&self) -> usize {
|
|
||||||
usize::try_from(self.0).expect("module ID should fit in a usize")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Top-level file is the one being executed.
|
|
||||||
/// Represented by module ID of 0, i.e. the default value.
|
|
||||||
pub fn is_top_level(&self) -> bool {
|
|
||||||
*self == Self::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
|
||||||
#[databake(path = kcl_lib::ast::types)]
|
#[databake(path = kcl_lib::ast::types)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
@ -609,13 +586,13 @@ impl BodyItem {
|
|||||||
|
|
||||||
impl From<BodyItem> for SourceRange {
|
impl From<BodyItem> for SourceRange {
|
||||||
fn from(item: BodyItem) -> Self {
|
fn from(item: BodyItem) -> Self {
|
||||||
Self([item.start(), item.end(), item.module_id().as_usize()])
|
Self::new(item.start(), item.end(), item.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&BodyItem> for SourceRange {
|
impl From<&BodyItem> for SourceRange {
|
||||||
fn from(item: &BodyItem) -> Self {
|
fn from(item: &BodyItem) -> Self {
|
||||||
Self([item.start(), item.end(), item.module_id().as_usize()])
|
Self::new(item.start(), item.end(), item.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,6 +608,7 @@ pub enum Expr {
|
|||||||
BinaryExpression(BoxNode<BinaryExpression>),
|
BinaryExpression(BoxNode<BinaryExpression>),
|
||||||
FunctionExpression(BoxNode<FunctionExpression>),
|
FunctionExpression(BoxNode<FunctionExpression>),
|
||||||
CallExpression(BoxNode<CallExpression>),
|
CallExpression(BoxNode<CallExpression>),
|
||||||
|
CallExpressionKw(BoxNode<CallExpressionKw>),
|
||||||
PipeExpression(BoxNode<PipeExpression>),
|
PipeExpression(BoxNode<PipeExpression>),
|
||||||
PipeSubstitution(BoxNode<PipeSubstitution>),
|
PipeSubstitution(BoxNode<PipeSubstitution>),
|
||||||
ArrayExpression(BoxNode<ArrayExpression>),
|
ArrayExpression(BoxNode<ArrayExpression>),
|
||||||
@ -674,6 +652,7 @@ impl Expr {
|
|||||||
Expr::Literal(_literal) => None,
|
Expr::Literal(_literal) => None,
|
||||||
Expr::FunctionExpression(_func_exp) => None,
|
Expr::FunctionExpression(_func_exp) => None,
|
||||||
Expr::CallExpression(_call_exp) => None,
|
Expr::CallExpression(_call_exp) => None,
|
||||||
|
Expr::CallExpressionKw(_call_exp) => None,
|
||||||
Expr::Identifier(_ident) => None,
|
Expr::Identifier(_ident) => None,
|
||||||
Expr::TagDeclarator(_tag) => None,
|
Expr::TagDeclarator(_tag) => None,
|
||||||
Expr::PipeExpression(pipe_exp) => Some(&pipe_exp.non_code_meta),
|
Expr::PipeExpression(pipe_exp) => Some(&pipe_exp.non_code_meta),
|
||||||
@ -699,6 +678,7 @@ impl Expr {
|
|||||||
Expr::Literal(_) => {}
|
Expr::Literal(_) => {}
|
||||||
Expr::FunctionExpression(ref mut func_exp) => func_exp.replace_value(source_range, new_value),
|
Expr::FunctionExpression(ref mut func_exp) => func_exp.replace_value(source_range, new_value),
|
||||||
Expr::CallExpression(ref mut call_exp) => call_exp.replace_value(source_range, new_value),
|
Expr::CallExpression(ref mut call_exp) => call_exp.replace_value(source_range, new_value),
|
||||||
|
Expr::CallExpressionKw(ref mut call_exp) => call_exp.replace_value(source_range, new_value),
|
||||||
Expr::Identifier(_) => {}
|
Expr::Identifier(_) => {}
|
||||||
Expr::TagDeclarator(_) => {}
|
Expr::TagDeclarator(_) => {}
|
||||||
Expr::PipeExpression(ref mut pipe_exp) => pipe_exp.replace_value(source_range, new_value),
|
Expr::PipeExpression(ref mut pipe_exp) => pipe_exp.replace_value(source_range, new_value),
|
||||||
@ -717,6 +697,7 @@ impl Expr {
|
|||||||
Expr::BinaryExpression(binary_expression) => binary_expression.start,
|
Expr::BinaryExpression(binary_expression) => binary_expression.start,
|
||||||
Expr::FunctionExpression(function_expression) => function_expression.start,
|
Expr::FunctionExpression(function_expression) => function_expression.start,
|
||||||
Expr::CallExpression(call_expression) => call_expression.start,
|
Expr::CallExpression(call_expression) => call_expression.start,
|
||||||
|
Expr::CallExpressionKw(call_expression) => call_expression.start,
|
||||||
Expr::PipeExpression(pipe_expression) => pipe_expression.start,
|
Expr::PipeExpression(pipe_expression) => pipe_expression.start,
|
||||||
Expr::PipeSubstitution(pipe_substitution) => pipe_substitution.start,
|
Expr::PipeSubstitution(pipe_substitution) => pipe_substitution.start,
|
||||||
Expr::ArrayExpression(array_expression) => array_expression.start,
|
Expr::ArrayExpression(array_expression) => array_expression.start,
|
||||||
@ -737,6 +718,7 @@ impl Expr {
|
|||||||
Expr::BinaryExpression(binary_expression) => binary_expression.end,
|
Expr::BinaryExpression(binary_expression) => binary_expression.end,
|
||||||
Expr::FunctionExpression(function_expression) => function_expression.end,
|
Expr::FunctionExpression(function_expression) => function_expression.end,
|
||||||
Expr::CallExpression(call_expression) => call_expression.end,
|
Expr::CallExpression(call_expression) => call_expression.end,
|
||||||
|
Expr::CallExpressionKw(call_expression) => call_expression.end,
|
||||||
Expr::PipeExpression(pipe_expression) => pipe_expression.end,
|
Expr::PipeExpression(pipe_expression) => pipe_expression.end,
|
||||||
Expr::PipeSubstitution(pipe_substitution) => pipe_substitution.end,
|
Expr::PipeSubstitution(pipe_substitution) => pipe_substitution.end,
|
||||||
Expr::ArrayExpression(array_expression) => array_expression.end,
|
Expr::ArrayExpression(array_expression) => array_expression.end,
|
||||||
@ -758,6 +740,7 @@ impl Expr {
|
|||||||
function_expression.get_hover_value_for_position(pos, code)
|
function_expression.get_hover_value_for_position(pos, code)
|
||||||
}
|
}
|
||||||
Expr::CallExpression(call_expression) => call_expression.get_hover_value_for_position(pos, code),
|
Expr::CallExpression(call_expression) => call_expression.get_hover_value_for_position(pos, code),
|
||||||
|
Expr::CallExpressionKw(call_expression) => call_expression.get_hover_value_for_position(pos, code),
|
||||||
Expr::PipeExpression(pipe_expression) => pipe_expression.get_hover_value_for_position(pos, code),
|
Expr::PipeExpression(pipe_expression) => pipe_expression.get_hover_value_for_position(pos, code),
|
||||||
Expr::ArrayExpression(array_expression) => array_expression.get_hover_value_for_position(pos, code),
|
Expr::ArrayExpression(array_expression) => array_expression.get_hover_value_for_position(pos, code),
|
||||||
Expr::ArrayRangeExpression(array_range) => array_range.get_hover_value_for_position(pos, code),
|
Expr::ArrayRangeExpression(array_range) => array_range.get_hover_value_for_position(pos, code),
|
||||||
@ -786,6 +769,7 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
Expr::FunctionExpression(_function_identifier) => {}
|
Expr::FunctionExpression(_function_identifier) => {}
|
||||||
Expr::CallExpression(ref mut call_expression) => call_expression.rename_identifiers(old_name, new_name),
|
Expr::CallExpression(ref mut call_expression) => call_expression.rename_identifiers(old_name, new_name),
|
||||||
|
Expr::CallExpressionKw(ref mut call_expression) => call_expression.rename_identifiers(old_name, new_name),
|
||||||
Expr::PipeExpression(ref mut pipe_expression) => pipe_expression.rename_identifiers(old_name, new_name),
|
Expr::PipeExpression(ref mut pipe_expression) => pipe_expression.rename_identifiers(old_name, new_name),
|
||||||
Expr::PipeSubstitution(_) => {}
|
Expr::PipeSubstitution(_) => {}
|
||||||
Expr::ArrayExpression(ref mut array_expression) => array_expression.rename_identifiers(old_name, new_name),
|
Expr::ArrayExpression(ref mut array_expression) => array_expression.rename_identifiers(old_name, new_name),
|
||||||
@ -812,6 +796,7 @@ impl Expr {
|
|||||||
|
|
||||||
Expr::FunctionExpression(function_identifier) => function_identifier.get_constraint_level(),
|
Expr::FunctionExpression(function_identifier) => function_identifier.get_constraint_level(),
|
||||||
Expr::CallExpression(call_expression) => call_expression.get_constraint_level(),
|
Expr::CallExpression(call_expression) => call_expression.get_constraint_level(),
|
||||||
|
Expr::CallExpressionKw(call_expression) => call_expression.get_constraint_level(),
|
||||||
Expr::PipeExpression(pipe_expression) => pipe_expression.get_constraint_level(),
|
Expr::PipeExpression(pipe_expression) => pipe_expression.get_constraint_level(),
|
||||||
Expr::PipeSubstitution(pipe_substitution) => ConstraintLevel::Ignore {
|
Expr::PipeSubstitution(pipe_substitution) => ConstraintLevel::Ignore {
|
||||||
source_ranges: vec![pipe_substitution.into()],
|
source_ranges: vec![pipe_substitution.into()],
|
||||||
@ -829,13 +814,13 @@ impl Expr {
|
|||||||
|
|
||||||
impl From<Expr> for SourceRange {
|
impl From<Expr> for SourceRange {
|
||||||
fn from(value: Expr) -> Self {
|
fn from(value: Expr) -> Self {
|
||||||
Self([value.start(), value.end(), value.module_id().as_usize()])
|
Self::new(value.start(), value.end(), value.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Expr> for SourceRange {
|
impl From<&Expr> for SourceRange {
|
||||||
fn from(value: &Expr) -> Self {
|
fn from(value: &Expr) -> Self {
|
||||||
Self([value.start(), value.end(), value.module_id().as_usize()])
|
Self::new(value.start(), value.end(), value.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,6 +833,7 @@ pub enum BinaryPart {
|
|||||||
Identifier(BoxNode<Identifier>),
|
Identifier(BoxNode<Identifier>),
|
||||||
BinaryExpression(BoxNode<BinaryExpression>),
|
BinaryExpression(BoxNode<BinaryExpression>),
|
||||||
CallExpression(BoxNode<CallExpression>),
|
CallExpression(BoxNode<CallExpression>),
|
||||||
|
CallExpressionKw(BoxNode<CallExpressionKw>),
|
||||||
UnaryExpression(BoxNode<UnaryExpression>),
|
UnaryExpression(BoxNode<UnaryExpression>),
|
||||||
MemberExpression(BoxNode<MemberExpression>),
|
MemberExpression(BoxNode<MemberExpression>),
|
||||||
IfExpression(BoxNode<IfExpression>),
|
IfExpression(BoxNode<IfExpression>),
|
||||||
@ -855,13 +841,13 @@ pub enum BinaryPart {
|
|||||||
|
|
||||||
impl From<BinaryPart> for SourceRange {
|
impl From<BinaryPart> for SourceRange {
|
||||||
fn from(value: BinaryPart) -> Self {
|
fn from(value: BinaryPart) -> Self {
|
||||||
Self([value.start(), value.end(), value.module_id().as_usize()])
|
Self::new(value.start(), value.end(), value.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&BinaryPart> for SourceRange {
|
impl From<&BinaryPart> for SourceRange {
|
||||||
fn from(value: &BinaryPart) -> Self {
|
fn from(value: &BinaryPart) -> Self {
|
||||||
Self([value.start(), value.end(), value.module_id().as_usize()])
|
Self::new(value.start(), value.end(), value.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,6 +859,7 @@ impl BinaryPart {
|
|||||||
BinaryPart::Identifier(identifier) => identifier.get_constraint_level(),
|
BinaryPart::Identifier(identifier) => identifier.get_constraint_level(),
|
||||||
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_constraint_level(),
|
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_constraint_level(),
|
||||||
BinaryPart::CallExpression(call_expression) => call_expression.get_constraint_level(),
|
BinaryPart::CallExpression(call_expression) => call_expression.get_constraint_level(),
|
||||||
|
BinaryPart::CallExpressionKw(call_expression) => call_expression.get_constraint_level(),
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_constraint_level(),
|
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_constraint_level(),
|
||||||
BinaryPart::MemberExpression(member_expression) => member_expression.get_constraint_level(),
|
BinaryPart::MemberExpression(member_expression) => member_expression.get_constraint_level(),
|
||||||
BinaryPart::IfExpression(e) => e.get_constraint_level(),
|
BinaryPart::IfExpression(e) => e.get_constraint_level(),
|
||||||
@ -889,6 +876,9 @@ impl BinaryPart {
|
|||||||
BinaryPart::CallExpression(ref mut call_expression) => {
|
BinaryPart::CallExpression(ref mut call_expression) => {
|
||||||
call_expression.replace_value(source_range, new_value)
|
call_expression.replace_value(source_range, new_value)
|
||||||
}
|
}
|
||||||
|
BinaryPart::CallExpressionKw(ref mut call_expression) => {
|
||||||
|
call_expression.replace_value(source_range, new_value)
|
||||||
|
}
|
||||||
BinaryPart::UnaryExpression(ref mut unary_expression) => {
|
BinaryPart::UnaryExpression(ref mut unary_expression) => {
|
||||||
unary_expression.replace_value(source_range, new_value)
|
unary_expression.replace_value(source_range, new_value)
|
||||||
}
|
}
|
||||||
@ -903,6 +893,7 @@ impl BinaryPart {
|
|||||||
BinaryPart::Identifier(identifier) => identifier.start,
|
BinaryPart::Identifier(identifier) => identifier.start,
|
||||||
BinaryPart::BinaryExpression(binary_expression) => binary_expression.start,
|
BinaryPart::BinaryExpression(binary_expression) => binary_expression.start,
|
||||||
BinaryPart::CallExpression(call_expression) => call_expression.start,
|
BinaryPart::CallExpression(call_expression) => call_expression.start,
|
||||||
|
BinaryPart::CallExpressionKw(call_expression) => call_expression.start,
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.start,
|
BinaryPart::UnaryExpression(unary_expression) => unary_expression.start,
|
||||||
BinaryPart::MemberExpression(member_expression) => member_expression.start,
|
BinaryPart::MemberExpression(member_expression) => member_expression.start,
|
||||||
BinaryPart::IfExpression(e) => e.start,
|
BinaryPart::IfExpression(e) => e.start,
|
||||||
@ -915,6 +906,7 @@ impl BinaryPart {
|
|||||||
BinaryPart::Identifier(identifier) => identifier.end,
|
BinaryPart::Identifier(identifier) => identifier.end,
|
||||||
BinaryPart::BinaryExpression(binary_expression) => binary_expression.end,
|
BinaryPart::BinaryExpression(binary_expression) => binary_expression.end,
|
||||||
BinaryPart::CallExpression(call_expression) => call_expression.end,
|
BinaryPart::CallExpression(call_expression) => call_expression.end,
|
||||||
|
BinaryPart::CallExpressionKw(call_expression) => call_expression.end,
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.end,
|
BinaryPart::UnaryExpression(unary_expression) => unary_expression.end,
|
||||||
BinaryPart::MemberExpression(member_expression) => member_expression.end,
|
BinaryPart::MemberExpression(member_expression) => member_expression.end,
|
||||||
BinaryPart::IfExpression(e) => e.end,
|
BinaryPart::IfExpression(e) => e.end,
|
||||||
@ -930,6 +922,7 @@ impl BinaryPart {
|
|||||||
binary_expression.get_hover_value_for_position(pos, code)
|
binary_expression.get_hover_value_for_position(pos, code)
|
||||||
}
|
}
|
||||||
BinaryPart::CallExpression(call_expression) => call_expression.get_hover_value_for_position(pos, code),
|
BinaryPart::CallExpression(call_expression) => call_expression.get_hover_value_for_position(pos, code),
|
||||||
|
BinaryPart::CallExpressionKw(call_expression) => call_expression.get_hover_value_for_position(pos, code),
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_hover_value_for_position(pos, code),
|
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_hover_value_for_position(pos, code),
|
||||||
BinaryPart::IfExpression(e) => e.get_hover_value_for_position(pos, code),
|
BinaryPart::IfExpression(e) => e.get_hover_value_for_position(pos, code),
|
||||||
BinaryPart::MemberExpression(member_expression) => {
|
BinaryPart::MemberExpression(member_expression) => {
|
||||||
@ -949,6 +942,9 @@ impl BinaryPart {
|
|||||||
BinaryPart::CallExpression(ref mut call_expression) => {
|
BinaryPart::CallExpression(ref mut call_expression) => {
|
||||||
call_expression.rename_identifiers(old_name, new_name)
|
call_expression.rename_identifiers(old_name, new_name)
|
||||||
}
|
}
|
||||||
|
BinaryPart::CallExpressionKw(ref mut call_expression) => {
|
||||||
|
call_expression.rename_identifiers(old_name, new_name)
|
||||||
|
}
|
||||||
BinaryPart::UnaryExpression(ref mut unary_expression) => {
|
BinaryPart::UnaryExpression(ref mut unary_expression) => {
|
||||||
unary_expression.rename_identifiers(old_name, new_name)
|
unary_expression.rename_identifiers(old_name, new_name)
|
||||||
}
|
}
|
||||||
@ -1270,12 +1266,42 @@ pub struct CallExpression {
|
|||||||
pub digest: Option<Digest>,
|
pub digest: Option<Digest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
|
||||||
|
#[databake(path = kcl_lib::ast::types)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub struct CallExpressionKw {
|
||||||
|
pub callee: Node<Identifier>,
|
||||||
|
pub unlabeled: Option<Expr>,
|
||||||
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub arguments: Vec<LabeledArg>,
|
||||||
|
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
#[ts(optional)]
|
||||||
|
pub digest: Option<Digest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
|
||||||
|
#[databake(path = kcl_lib::ast::types)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub struct LabeledArg {
|
||||||
|
pub label: Identifier,
|
||||||
|
pub arg: Expr,
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Node<CallExpression>> for Expr {
|
impl From<Node<CallExpression>> for Expr {
|
||||||
fn from(call_expression: Node<CallExpression>) -> Self {
|
fn from(call_expression: Node<CallExpression>) -> Self {
|
||||||
Expr::CallExpression(Box::new(call_expression))
|
Expr::CallExpression(Box::new(call_expression))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Node<CallExpressionKw>> for Expr {
|
||||||
|
fn from(call_expression: Node<CallExpressionKw>) -> Self {
|
||||||
|
Expr::CallExpressionKw(Box::new(call_expression))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Node<CallExpression> {
|
impl Node<CallExpression> {
|
||||||
/// Return the constraint level for this call expression.
|
/// Return the constraint level for this call expression.
|
||||||
pub fn get_constraint_level(&self) -> ConstraintLevel {
|
pub fn get_constraint_level(&self) -> ConstraintLevel {
|
||||||
@ -1295,6 +1321,25 @@ impl Node<CallExpression> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Node<CallExpressionKw> {
|
||||||
|
/// Return the constraint level for this call expression.
|
||||||
|
pub fn get_constraint_level(&self) -> ConstraintLevel {
|
||||||
|
if self.arguments.is_empty() {
|
||||||
|
return ConstraintLevel::Ignore {
|
||||||
|
source_ranges: vec![self.into()],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the arguments and get the constraint level for each one.
|
||||||
|
let mut constraint_levels = ConstraintLevels::new();
|
||||||
|
for arg in &self.arguments {
|
||||||
|
constraint_levels.push(arg.arg.get_constraint_level());
|
||||||
|
}
|
||||||
|
|
||||||
|
constraint_levels.get_constraint_level(self.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CallExpression {
|
impl CallExpression {
|
||||||
pub fn new(name: &str, arguments: Vec<Expr>) -> Result<Node<Self>, KclError> {
|
pub fn new(name: &str, arguments: Vec<Expr>) -> Result<Node<Self>, KclError> {
|
||||||
Ok(Node::no_src(Self {
|
Ok(Node::no_src(Self {
|
||||||
@ -1351,6 +1396,68 @@ impl CallExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CallExpressionKw {
|
||||||
|
pub fn new(name: &str, unlabeled: Option<Expr>, arguments: Vec<LabeledArg>) -> Result<Node<Self>, KclError> {
|
||||||
|
Ok(Node::no_src(Self {
|
||||||
|
callee: Identifier::new(name),
|
||||||
|
unlabeled,
|
||||||
|
arguments,
|
||||||
|
digest: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over all arguments (labeled or not)
|
||||||
|
pub fn iter_arguments(&self) -> impl Iterator<Item = &Expr> {
|
||||||
|
self.unlabeled.iter().chain(self.arguments.iter().map(|arg| &arg.arg))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is at least one argument the '%' i.e. the substitution operator?
|
||||||
|
pub fn has_substitution_arg(&self) -> bool {
|
||||||
|
self.arguments
|
||||||
|
.iter()
|
||||||
|
.any(|arg| matches!(arg.arg, Expr::PipeSubstitution(_)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Expr) {
|
||||||
|
for arg in &mut self.arguments {
|
||||||
|
arg.arg.replace_value(source_range, new_value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a hover value that includes the given character position.
|
||||||
|
pub fn get_hover_value_for_position(&self, pos: usize, code: &str) -> Option<Hover> {
|
||||||
|
let callee_source_range: SourceRange = self.callee.clone().into();
|
||||||
|
if callee_source_range.contains(pos) {
|
||||||
|
return Some(Hover::Function {
|
||||||
|
name: self.callee.name.clone(),
|
||||||
|
range: callee_source_range.to_lsp_range(code),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, arg) in self.iter_arguments().enumerate() {
|
||||||
|
let source_range: SourceRange = arg.into();
|
||||||
|
if source_range.contains(pos) {
|
||||||
|
return Some(Hover::Signature {
|
||||||
|
name: self.callee.name.clone(),
|
||||||
|
parameter_index: index as u32,
|
||||||
|
range: source_range.to_lsp_range(code),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rename all identifiers that have the old name to the new given name.
|
||||||
|
fn rename_identifiers(&mut self, old_name: &str, new_name: &str) {
|
||||||
|
self.callee.rename(old_name, new_name);
|
||||||
|
|
||||||
|
for arg in &mut self.arguments {
|
||||||
|
arg.arg.rename_identifiers(old_name, new_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A function declaration.
|
/// A function declaration.
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, ts_rs::TS, JsonSchema)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
@ -2199,13 +2306,13 @@ impl MemberObject {
|
|||||||
|
|
||||||
impl From<MemberObject> for SourceRange {
|
impl From<MemberObject> for SourceRange {
|
||||||
fn from(obj: MemberObject) -> Self {
|
fn from(obj: MemberObject) -> Self {
|
||||||
Self([obj.start(), obj.end(), obj.module_id().as_usize()])
|
Self::new(obj.start(), obj.end(), obj.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&MemberObject> for SourceRange {
|
impl From<&MemberObject> for SourceRange {
|
||||||
fn from(obj: &MemberObject) -> Self {
|
fn from(obj: &MemberObject) -> Self {
|
||||||
Self([obj.start(), obj.end(), obj.module_id().as_usize()])
|
Self::new(obj.start(), obj.end(), obj.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2236,13 +2343,13 @@ impl LiteralIdentifier {
|
|||||||
|
|
||||||
impl From<LiteralIdentifier> for SourceRange {
|
impl From<LiteralIdentifier> for SourceRange {
|
||||||
fn from(id: LiteralIdentifier) -> Self {
|
fn from(id: LiteralIdentifier) -> Self {
|
||||||
Self([id.start(), id.end(), id.module_id().as_usize()])
|
Self::new(id.start(), id.end(), id.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&LiteralIdentifier> for SourceRange {
|
impl From<&LiteralIdentifier> for SourceRange {
|
||||||
fn from(id: &LiteralIdentifier) -> Self {
|
fn from(id: &LiteralIdentifier) -> Self {
|
||||||
Self([id.start(), id.end(), id.module_id().as_usize()])
|
Self::new(id.start(), id.end(), id.module_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2828,7 +2935,6 @@ pub enum Hover {
|
|||||||
|
|
||||||
/// Format options.
|
/// Format options.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
|
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct FormatOptions {
|
pub struct FormatOptions {
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
use crate::executor::SourceRange;
|
|
||||||
|
|
||||||
use super::BoxNode;
|
|
||||||
use super::ConstraintLevel;
|
|
||||||
use super::Hover;
|
|
||||||
use super::Node;
|
|
||||||
use super::NodeList;
|
|
||||||
use super::{Digest, Expr};
|
|
||||||
use databake::*;
|
use databake::*;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{BoxNode, ConstraintLevel, Digest, Expr, Hover, Node, NodeList};
|
||||||
|
use crate::SourceRange;
|
||||||
|
|
||||||
// TODO: This should be its own type, similar to Program,
|
// TODO: This should be its own type, similar to Program,
|
||||||
// but guaranteed to have an Expression as its final item.
|
// but guaranteed to have an Expression as its final item.
|
||||||
// https://github.com/KittyCAD/modeling-app/issues/4015
|
// https://github.com/KittyCAD/modeling-app/issues/4015
|
||||||
@ -50,7 +45,7 @@ impl Node<IfExpression> {
|
|||||||
impl Node<ElseIf> {
|
impl Node<ElseIf> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn source_ranges(&self) -> Vec<SourceRange> {
|
fn source_ranges(&self) -> Vec<SourceRange> {
|
||||||
vec![SourceRange([self.start, self.end, self.module_id.as_usize()])]
|
vec![SourceRange::new(self.start, self.end, self.module_id)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use sha2::{Digest as DigestTrait, Sha256};
|
use sha2::{Digest as DigestTrait, Sha256};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryPart, BodyItem, CallExpression, ElseIf, Expr,
|
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryPart, BodyItem, CallExpression, CallExpressionKw,
|
||||||
ExpressionStatement, FnArgType, FunctionExpression, Identifier, IfExpression, ImportItem, ImportStatement, Literal,
|
ElseIf, Expr, ExpressionStatement, FnArgType, FunctionExpression, Identifier, IfExpression, ImportItem,
|
||||||
LiteralIdentifier, MemberExpression, MemberObject, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression,
|
ImportStatement, Literal, LiteralIdentifier, MemberExpression, MemberObject, NonCodeMeta, NonCodeNode,
|
||||||
ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement, TagDeclarator,
|
NonCodeValue, ObjectExpression, ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program,
|
||||||
UnaryExpression, VariableDeclaration, VariableDeclarator,
|
ReturnStatement, TagDeclarator, UnaryExpression, VariableDeclaration, VariableDeclarator,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Position-independent digest of the AST node.
|
/// Position-independent digest of the AST node.
|
||||||
@ -93,6 +93,7 @@ impl Expr {
|
|||||||
Expr::BinaryExpression(be) => be.compute_digest(),
|
Expr::BinaryExpression(be) => be.compute_digest(),
|
||||||
Expr::FunctionExpression(fe) => fe.compute_digest(),
|
Expr::FunctionExpression(fe) => fe.compute_digest(),
|
||||||
Expr::CallExpression(ce) => ce.compute_digest(),
|
Expr::CallExpression(ce) => ce.compute_digest(),
|
||||||
|
Expr::CallExpressionKw(ce) => ce.compute_digest(),
|
||||||
Expr::PipeExpression(pe) => pe.compute_digest(),
|
Expr::PipeExpression(pe) => pe.compute_digest(),
|
||||||
Expr::PipeSubstitution(ps) => ps.compute_digest(),
|
Expr::PipeSubstitution(ps) => ps.compute_digest(),
|
||||||
Expr::ArrayExpression(ae) => ae.compute_digest(),
|
Expr::ArrayExpression(ae) => ae.compute_digest(),
|
||||||
@ -117,6 +118,7 @@ impl BinaryPart {
|
|||||||
BinaryPart::Identifier(id) => id.compute_digest(),
|
BinaryPart::Identifier(id) => id.compute_digest(),
|
||||||
BinaryPart::BinaryExpression(be) => be.compute_digest(),
|
BinaryPart::BinaryExpression(be) => be.compute_digest(),
|
||||||
BinaryPart::CallExpression(ce) => ce.compute_digest(),
|
BinaryPart::CallExpression(ce) => ce.compute_digest(),
|
||||||
|
BinaryPart::CallExpressionKw(ce) => ce.compute_digest(),
|
||||||
BinaryPart::UnaryExpression(ue) => ue.compute_digest(),
|
BinaryPart::UnaryExpression(ue) => ue.compute_digest(),
|
||||||
BinaryPart::MemberExpression(me) => me.compute_digest(),
|
BinaryPart::MemberExpression(me) => me.compute_digest(),
|
||||||
BinaryPart::IfExpression(e) => e.compute_digest(),
|
BinaryPart::IfExpression(e) => e.compute_digest(),
|
||||||
@ -372,6 +374,22 @@ impl CallExpression {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CallExpressionKw {
|
||||||
|
compute_digest!(|slf, hasher| {
|
||||||
|
hasher.update(slf.callee.compute_digest());
|
||||||
|
if let Some(ref mut unlabeled) = slf.unlabeled {
|
||||||
|
hasher.update(unlabeled.compute_digest());
|
||||||
|
} else {
|
||||||
|
hasher.update("no_unlabeled");
|
||||||
|
}
|
||||||
|
hasher.update(slf.arguments.len().to_ne_bytes());
|
||||||
|
for argument in slf.arguments.iter_mut() {
|
||||||
|
hasher.update(argument.label.compute_digest());
|
||||||
|
hasher.update(argument.arg.compute_digest());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
impl IfExpression {
|
impl IfExpression {
|
||||||
compute_digest!(|slf, hasher| {
|
compute_digest!(|slf, hasher| {
|
||||||
hasher.update(slf.cond.compute_digest());
|
hasher.update(slf.cond.compute_digest());
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use async_recursion::async_recursion;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, CallExpression, Expr,
|
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, CallExpression,
|
||||||
IfExpression, KclNone, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, ObjectExpression,
|
CallExpressionKw, Expr, IfExpression, KclNone, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject,
|
||||||
TagDeclarator, UnaryExpression, UnaryOperator,
|
Node, ObjectExpression, TagDeclarator, UnaryExpression, UnaryOperator,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{BodyType, ExecState, ExecutorContext, KclValue, Metadata, StatementKind, TagEngineInfo, TagIdentifier},
|
||||||
BodyType, ExecState, ExecutorContext, KclValue, Metadata, SourceRange, StatementKind, TagEngineInfo,
|
source_range::SourceRange,
|
||||||
TagIdentifier,
|
|
||||||
},
|
|
||||||
std::{args::Arg, FunctionKind},
|
std::{args::Arg, FunctionKind},
|
||||||
};
|
};
|
||||||
use async_recursion::async_recursion;
|
|
||||||
|
|
||||||
const FLOAT_TO_INT_MAX_DELTA: f64 = 0.01;
|
const FLOAT_TO_INT_MAX_DELTA: f64 = 0.01;
|
||||||
|
|
||||||
@ -28,6 +27,7 @@ impl BinaryPart {
|
|||||||
}
|
}
|
||||||
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
|
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
|
||||||
BinaryPart::CallExpression(call_expression) => call_expression.execute(exec_state, ctx).await,
|
BinaryPart::CallExpression(call_expression) => call_expression.execute(exec_state, ctx).await,
|
||||||
|
BinaryPart::CallExpressionKw(call_expression) => call_expression.execute(exec_state, ctx).await,
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, ctx).await,
|
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, ctx).await,
|
||||||
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state),
|
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state),
|
||||||
BinaryPart::IfExpression(e) => e.get_result(exec_state, ctx).await,
|
BinaryPart::IfExpression(e) => e.get_result(exec_state, ctx).await,
|
||||||
@ -333,6 +333,7 @@ async fn inner_execute_pipe_body(
|
|||||||
| Expr::BinaryExpression(_)
|
| Expr::BinaryExpression(_)
|
||||||
| Expr::FunctionExpression(_)
|
| Expr::FunctionExpression(_)
|
||||||
| Expr::CallExpression(_)
|
| Expr::CallExpression(_)
|
||||||
|
| Expr::CallExpressionKw(_)
|
||||||
| Expr::PipeExpression(_)
|
| Expr::PipeExpression(_)
|
||||||
| Expr::PipeSubstitution(_)
|
| Expr::PipeSubstitution(_)
|
||||||
| Expr::ArrayExpression(_)
|
| Expr::ArrayExpression(_)
|
||||||
@ -356,6 +357,12 @@ async fn inner_execute_pipe_body(
|
|||||||
Ok(final_output)
|
Ok(final_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Node<CallExpressionKw> {
|
||||||
|
pub async fn execute(&self, _exec_state: &mut ExecState, _ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Node<CallExpression> {
|
impl Node<CallExpression> {
|
||||||
#[async_recursion]
|
#[async_recursion]
|
||||||
pub async fn execute(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
pub async fn execute(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||||
|
@ -3,9 +3,8 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value as JValue;
|
use serde_json::Value as JValue;
|
||||||
|
|
||||||
use crate::ast::types::{Expr, Literal};
|
|
||||||
|
|
||||||
use super::Node;
|
use super::Node;
|
||||||
|
use crate::ast::types::{Expr, Literal};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
|
||||||
#[databake(path = kcl_lib::ast::types)]
|
#[databake(path = kcl_lib::ast::types)]
|
||||||
|
@ -4,9 +4,8 @@ use databake::*;
|
|||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{ast::types::ConstraintLevel, executor::KclValue};
|
|
||||||
|
|
||||||
use super::Node;
|
use super::Node;
|
||||||
|
use crate::{ast::types::ConstraintLevel, executor::KclValue};
|
||||||
|
|
||||||
const KCL_NONE_ID: &str = "KCL_NONE_ID";
|
const KCL_NONE_ID: &str = "KCL_NONE_ID";
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::{BinaryPart, BodyItem, Expr, LiteralIdentifier, MemberObject, ModuleId};
|
use super::{BinaryPart, BodyItem, Expr, LiteralIdentifier, MemberObject};
|
||||||
|
use crate::source_range::ModuleId;
|
||||||
|
|
||||||
impl BodyItem {
|
impl BodyItem {
|
||||||
pub fn module_id(&self) -> ModuleId {
|
pub fn module_id(&self) -> ModuleId {
|
||||||
@ -20,6 +21,7 @@ impl Expr {
|
|||||||
Expr::BinaryExpression(binary_expression) => binary_expression.module_id,
|
Expr::BinaryExpression(binary_expression) => binary_expression.module_id,
|
||||||
Expr::FunctionExpression(function_expression) => function_expression.module_id,
|
Expr::FunctionExpression(function_expression) => function_expression.module_id,
|
||||||
Expr::CallExpression(call_expression) => call_expression.module_id,
|
Expr::CallExpression(call_expression) => call_expression.module_id,
|
||||||
|
Expr::CallExpressionKw(call_expression) => call_expression.module_id,
|
||||||
Expr::PipeExpression(pipe_expression) => pipe_expression.module_id,
|
Expr::PipeExpression(pipe_expression) => pipe_expression.module_id,
|
||||||
Expr::PipeSubstitution(pipe_substitution) => pipe_substitution.module_id,
|
Expr::PipeSubstitution(pipe_substitution) => pipe_substitution.module_id,
|
||||||
Expr::ArrayExpression(array_expression) => array_expression.module_id,
|
Expr::ArrayExpression(array_expression) => array_expression.module_id,
|
||||||
@ -40,6 +42,7 @@ impl BinaryPart {
|
|||||||
BinaryPart::Identifier(identifier) => identifier.module_id,
|
BinaryPart::Identifier(identifier) => identifier.module_id,
|
||||||
BinaryPart::BinaryExpression(binary_expression) => binary_expression.module_id,
|
BinaryPart::BinaryExpression(binary_expression) => binary_expression.module_id,
|
||||||
BinaryPart::CallExpression(call_expression) => call_expression.module_id,
|
BinaryPart::CallExpression(call_expression) => call_expression.module_id,
|
||||||
|
BinaryPart::CallExpressionKw(call_expression) => call_expression.module_id,
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.module_id,
|
BinaryPart::UnaryExpression(unary_expression) => unary_expression.module_id,
|
||||||
BinaryPart::MemberExpression(member_expression) => member_expression.module_id,
|
BinaryPart::MemberExpression(member_expression) => member_expression.module_id,
|
||||||
BinaryPart::IfExpression(e) => e.module_id,
|
BinaryPart::IfExpression(e) => e.module_id,
|
||||||
|
@ -18,14 +18,14 @@ use kittycad_modeling_cmds as kcmc;
|
|||||||
use tokio::sync::{mpsc, oneshot, RwLock};
|
use tokio::sync::{mpsc, oneshot, RwLock};
|
||||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
|
use tokio_tungstenite::tungstenite::Message as WsMsg;
|
||||||
|
|
||||||
|
use super::ExecutionKind;
|
||||||
use crate::{
|
use crate::{
|
||||||
engine::EngineManager,
|
engine::EngineManager,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{DefaultPlanes, IdGenerator},
|
executor::{DefaultPlanes, IdGenerator},
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ExecutionKind;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum SocketHealth {
|
enum SocketHealth {
|
||||||
Active,
|
Active,
|
||||||
@ -41,8 +41,8 @@ pub struct EngineConnection {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
tcp_read_handle: Arc<TcpReadHandle>,
|
tcp_read_handle: Arc<TcpReadHandle>,
|
||||||
socket_health: Arc<Mutex<SocketHealth>>,
|
socket_health: Arc<Mutex<SocketHealth>>,
|
||||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch: Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>>,
|
||||||
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||||
|
|
||||||
/// The default planes for the scene.
|
/// The default planes for the scene.
|
||||||
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
|
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
|
||||||
@ -311,11 +311,11 @@ impl EngineConnection {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EngineManager for EngineConnection {
|
impl EngineManager for EngineConnection {
|
||||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch.clone()
|
self.batch.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch_end.clone()
|
self.batch_end.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +334,7 @@ impl EngineManager for EngineConnection {
|
|||||||
async fn default_planes(
|
async fn default_planes(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, KclError> {
|
) -> Result<DefaultPlanes, KclError> {
|
||||||
{
|
{
|
||||||
let opt = self.default_planes.read().await.as_ref().cloned();
|
let opt = self.default_planes.read().await.as_ref().cloned();
|
||||||
@ -352,7 +352,7 @@ impl EngineManager for EngineConnection {
|
|||||||
async fn clear_scene_post_hook(
|
async fn clear_scene_post_hook(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<(), KclError> {
|
) -> Result<(), KclError> {
|
||||||
// Remake the default planes, since they would have been removed after the scene was cleared.
|
// Remake the default planes, since they would have been removed after the scene was cleared.
|
||||||
let new_planes = self.new_default_planes(id_generator, source_range).await?;
|
let new_planes = self.new_default_planes(id_generator, source_range).await?;
|
||||||
@ -364,9 +364,9 @@ impl EngineManager for EngineConnection {
|
|||||||
async fn inner_send_modeling_cmd(
|
async fn inner_send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: WebSocketRequest,
|
cmd: WebSocketRequest,
|
||||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
_id_to_source_range: std::collections::HashMap<uuid::Uuid, SourceRange>,
|
||||||
) -> Result<WebSocketResponse, KclError> {
|
) -> Result<WebSocketResponse, KclError> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
|
@ -17,17 +17,17 @@ use kcmc::{
|
|||||||
};
|
};
|
||||||
use kittycad_modeling_cmds::{self as kcmc};
|
use kittycad_modeling_cmds::{self as kcmc};
|
||||||
|
|
||||||
|
use super::ExecutionKind;
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
executor::{DefaultPlanes, IdGenerator},
|
executor::{DefaultPlanes, IdGenerator},
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ExecutionKind;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EngineConnection {
|
pub struct EngineConnection {
|
||||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch: Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>>,
|
||||||
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||||
execution_kind: Arc<Mutex<ExecutionKind>>,
|
execution_kind: Arc<Mutex<ExecutionKind>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,11 +43,11 @@ impl EngineConnection {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl crate::engine::EngineManager for EngineConnection {
|
impl crate::engine::EngineManager for EngineConnection {
|
||||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch.clone()
|
self.batch.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch_end.clone()
|
self.batch_end.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn default_planes(
|
async fn default_planes(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
_source_range: crate::executor::SourceRange,
|
_source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, KclError> {
|
) -> Result<DefaultPlanes, KclError> {
|
||||||
Ok(DefaultPlanes::default())
|
Ok(DefaultPlanes::default())
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn clear_scene_post_hook(
|
async fn clear_scene_post_hook(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
_source_range: crate::executor::SourceRange,
|
_source_range: SourceRange,
|
||||||
) -> Result<(), KclError> {
|
) -> Result<(), KclError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -82,9 +82,9 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn inner_send_modeling_cmd(
|
async fn inner_send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
_source_range: crate::executor::SourceRange,
|
_source_range: SourceRange,
|
||||||
cmd: WebSocketRequest,
|
cmd: WebSocketRequest,
|
||||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
_id_to_source_range: std::collections::HashMap<uuid::Uuid, SourceRange>,
|
||||||
) -> Result<WebSocketResponse, KclError> {
|
) -> Result<WebSocketResponse, KclError> {
|
||||||
match cmd {
|
match cmd {
|
||||||
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch {
|
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch {
|
||||||
|
@ -12,6 +12,7 @@ use crate::{
|
|||||||
engine::ExecutionKind,
|
engine::ExecutionKind,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{DefaultPlanes, IdGenerator},
|
executor::{DefaultPlanes, IdGenerator},
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[wasm_bindgen(module = "/../../lang/std/engineConnection.ts")]
|
#[wasm_bindgen(module = "/../../lang/std/engineConnection.ts")]
|
||||||
@ -41,8 +42,8 @@ extern "C" {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EngineConnection {
|
pub struct EngineConnection {
|
||||||
manager: Arc<EngineCommandManager>,
|
manager: Arc<EngineCommandManager>,
|
||||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch: Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>>,
|
||||||
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||||
execution_kind: Arc<Mutex<ExecutionKind>>,
|
execution_kind: Arc<Mutex<ExecutionKind>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,11 +64,11 @@ impl EngineConnection {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl crate::engine::EngineManager for EngineConnection {
|
impl crate::engine::EngineManager for EngineConnection {
|
||||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch.clone()
|
self.batch.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch_end.clone()
|
self.batch_end.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn default_planes(
|
async fn default_planes(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, KclError> {
|
) -> Result<DefaultPlanes, KclError> {
|
||||||
// Get the default planes.
|
// Get the default planes.
|
||||||
let promise = self.manager.get_default_planes().map_err(|e| {
|
let promise = self.manager.get_default_planes().map_err(|e| {
|
||||||
@ -128,7 +129,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn clear_scene_post_hook(
|
async fn clear_scene_post_hook(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<(), KclError> {
|
) -> Result<(), KclError> {
|
||||||
self.manager.clear_default_planes().map_err(|e| {
|
self.manager.clear_default_planes().map_err(|e| {
|
||||||
KclError::Engine(KclErrorDetails {
|
KclError::Engine(KclErrorDetails {
|
||||||
@ -158,9 +159,9 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn inner_send_modeling_cmd(
|
async fn inner_send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: WebSocketRequest,
|
cmd: WebSocketRequest,
|
||||||
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
id_to_source_range: std::collections::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 {
|
KclError::Engine(KclErrorDetails {
|
||||||
|
@ -33,6 +33,7 @@ use uuid::Uuid;
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{DefaultPlanes, IdGenerator, Point3d},
|
executor::{DefaultPlanes, IdGenerator, Point3d},
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
@ -61,10 +62,10 @@ impl ExecutionKind {
|
|||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||||
/// Get the batch of commands to be sent to the engine.
|
/// Get the batch of commands to be sent to the engine.
|
||||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>;
|
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>>;
|
||||||
|
|
||||||
/// Get the batch of end commands to be sent to the engine.
|
/// Get the batch of end commands to be sent to the engine.
|
||||||
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>;
|
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>;
|
||||||
|
|
||||||
/// Get the current execution kind.
|
/// Get the current execution kind.
|
||||||
fn execution_kind(&self) -> ExecutionKind;
|
fn execution_kind(&self) -> ExecutionKind;
|
||||||
@ -77,7 +78,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
async fn default_planes(
|
async fn default_planes(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
_source_range: crate::executor::SourceRange,
|
_source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, crate::errors::KclError>;
|
) -> Result<DefaultPlanes, crate::errors::KclError>;
|
||||||
|
|
||||||
/// Helpers to be called after clearing a scene.
|
/// Helpers to be called after clearing a scene.
|
||||||
@ -85,22 +86,22 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
async fn clear_scene_post_hook(
|
async fn clear_scene_post_hook(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<(), crate::errors::KclError>;
|
) -> Result<(), crate::errors::KclError>;
|
||||||
|
|
||||||
/// Send a modeling command and wait for the response message.
|
/// Send a modeling command and wait for the response message.
|
||||||
async fn inner_send_modeling_cmd(
|
async fn inner_send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: WebSocketRequest,
|
cmd: WebSocketRequest,
|
||||||
id_to_source_range: HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
|
||||||
) -> Result<kcmc::websocket::WebSocketResponse, crate::errors::KclError>;
|
) -> Result<kcmc::websocket::WebSocketResponse, crate::errors::KclError>;
|
||||||
|
|
||||||
async fn clear_scene(
|
async fn clear_scene(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<(), crate::errors::KclError> {
|
) -> Result<(), crate::errors::KclError> {
|
||||||
self.batch_modeling_cmd(
|
self.batch_modeling_cmd(
|
||||||
uuid::Uuid::new_v4(),
|
uuid::Uuid::new_v4(),
|
||||||
@ -123,7 +124,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
async fn batch_modeling_cmd(
|
async fn batch_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: &ModelingCmd,
|
cmd: &ModelingCmd,
|
||||||
) -> Result<(), crate::errors::KclError> {
|
) -> Result<(), crate::errors::KclError> {
|
||||||
let execution_kind = self.execution_kind();
|
let execution_kind = self.execution_kind();
|
||||||
@ -147,7 +148,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
async fn batch_end_cmd(
|
async fn batch_end_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: &ModelingCmd,
|
cmd: &ModelingCmd,
|
||||||
) -> Result<(), crate::errors::KclError> {
|
) -> Result<(), crate::errors::KclError> {
|
||||||
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
|
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
|
||||||
@ -166,7 +167,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
async fn send_modeling_cmd(
|
async fn send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: ModelingCmd,
|
cmd: ModelingCmd,
|
||||||
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
||||||
self.batch_modeling_cmd(id, source_range, &cmd).await?;
|
self.batch_modeling_cmd(id, source_range, &cmd).await?;
|
||||||
@ -181,7 +182,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
// Whether or not to flush the end commands as well.
|
// Whether or not to flush the end commands as well.
|
||||||
// We only do this at the very end of the file.
|
// We only do this at the very end of the file.
|
||||||
batch_end: bool,
|
batch_end: bool,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
||||||
let all_requests = if batch_end {
|
let all_requests = if batch_end {
|
||||||
let mut requests = self.batch().lock().unwrap().clone();
|
let mut requests = self.batch().lock().unwrap().clone();
|
||||||
@ -303,7 +304,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
x_axis: Point3d,
|
x_axis: Point3d,
|
||||||
y_axis: Point3d,
|
y_axis: Point3d,
|
||||||
color: Option<Color>,
|
color: Option<Color>,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<uuid::Uuid, KclError> {
|
) -> Result<uuid::Uuid, KclError> {
|
||||||
// Create new default planes.
|
// Create new default planes.
|
||||||
let default_size = 100.0;
|
let default_size = 100.0;
|
||||||
@ -339,7 +340,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
async fn new_default_planes(
|
async fn new_default_planes(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, KclError> {
|
) -> Result<DefaultPlanes, KclError> {
|
||||||
let plane_settings: HashMap<PlaneName, (Uuid, Point3d, Point3d, Option<Color>)> = HashMap::from([
|
let plane_settings: HashMap<PlaneName, (Uuid, Point3d, Point3d, Option<Color>)> = HashMap::from([
|
||||||
(
|
(
|
||||||
@ -450,7 +451,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
fn parse_websocket_response(
|
fn parse_websocket_response(
|
||||||
&self,
|
&self,
|
||||||
response: WebSocketResponse,
|
response: WebSocketResponse,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
||||||
match response {
|
match response {
|
||||||
WebSocketResponse::Success(success) => Ok(success.resp),
|
WebSocketResponse::Success(success) => Ok(success.resp),
|
||||||
@ -469,7 +470,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
|||||||
// The last response we are looking for.
|
// The last response we are looking for.
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
// The mapping of source ranges to command IDs.
|
// The mapping of source ranges to command IDs.
|
||||||
id_to_source_range: HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
|
||||||
// The response from the engine.
|
// The response from the engine.
|
||||||
responses: HashMap<uuid::Uuid, BatchResponse>,
|
responses: HashMap<uuid::Uuid, BatchResponse>,
|
||||||
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
|
||||||
|
@ -2,7 +2,10 @@ use serde::{Deserialize, Serialize};
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
|
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
|
||||||
|
|
||||||
use crate::{ast::types::ModuleId, executor::SourceRange, lsp::IntoDiagnostic};
|
use crate::{
|
||||||
|
lsp::IntoDiagnostic,
|
||||||
|
source_range::{ModuleId, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
/// How did the KCL execution fail
|
/// How did the KCL execution fail
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
@ -19,20 +19,18 @@ use kittycad_modeling_cmds::length_unit::LengthUnit;
|
|||||||
use parse_display::{Display, FromStr};
|
use parse_display::{Display, FromStr};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
|
|
||||||
|
|
||||||
type Point2D = kcmc::shared::Point2d<f64>;
|
type Point2D = kcmc::shared::Point2d<f64>;
|
||||||
type Point3D = kcmc::shared::Point3d<f64>;
|
type Point3D = kcmc::shared::Point3d<f64>;
|
||||||
|
|
||||||
pub use crate::kcl_value::KclValue;
|
pub use crate::kcl_value::KclValue;
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{
|
ast::types::{BodyItem, Expr, FunctionExpression, ItemVisibility, KclNone, Node, NodeRef, TagDeclarator, TagNode},
|
||||||
BodyItem, Expr, FunctionExpression, ItemVisibility, KclNone, ModuleId, Node, NodeRef, TagDeclarator, TagNode,
|
|
||||||
},
|
|
||||||
engine::{EngineManager, ExecutionKind},
|
engine::{EngineManager, ExecutionKind},
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
fs::{FileManager, FileSystem},
|
fs::{FileManager, FileSystem},
|
||||||
settings::types::UnitLength,
|
settings::types::UnitLength,
|
||||||
|
source_range::{ModuleId, SourceRange},
|
||||||
std::{args::Arg, StdLib},
|
std::{args::Arg, StdLib},
|
||||||
ExecError, Program,
|
ExecError, Program,
|
||||||
};
|
};
|
||||||
@ -993,7 +991,6 @@ pub enum BodyType {
|
|||||||
/// Info about a module. Right now, this is pretty minimal. We hope to cache
|
/// Info about a module. Right now, this is pretty minimal. We hope to cache
|
||||||
/// modules here in the future.
|
/// modules here in the future.
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
|
||||||
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
|
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
pub struct ModuleInfo {
|
pub struct ModuleInfo {
|
||||||
/// The ID of the module.
|
/// The ID of the module.
|
||||||
@ -1002,101 +999,6 @@ pub struct ModuleInfo {
|
|||||||
path: std::path::PathBuf,
|
path: std::path::PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema, Hash, Eq)]
|
|
||||||
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
|
|
||||||
#[ts(export)]
|
|
||||||
pub struct SourceRange(#[ts(type = "[number, number]")] pub [usize; 3]);
|
|
||||||
|
|
||||||
impl From<[usize; 3]> for SourceRange {
|
|
||||||
fn from(value: [usize; 3]) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&SourceRange> for miette::SourceSpan {
|
|
||||||
fn from(source_range: &SourceRange) -> Self {
|
|
||||||
let length = source_range.end() - source_range.start();
|
|
||||||
let start = miette::SourceOffset::from(source_range.start());
|
|
||||||
Self::new(start, length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SourceRange> for miette::SourceSpan {
|
|
||||||
fn from(source_range: SourceRange) -> Self {
|
|
||||||
Self::from(&source_range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SourceRange {
|
|
||||||
/// Create a new source range.
|
|
||||||
pub fn new(start: usize, end: usize, module_id: ModuleId) -> Self {
|
|
||||||
Self([start, end, module_id.as_usize()])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A source range that doesn't correspond to any source code.
|
|
||||||
pub fn synthetic() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the start of the range.
|
|
||||||
pub fn start(&self) -> usize {
|
|
||||||
self.0[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the end of the range.
|
|
||||||
pub fn end(&self) -> usize {
|
|
||||||
self.0[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the module ID of the range.
|
|
||||||
pub fn module_id(&self) -> ModuleId {
|
|
||||||
ModuleId::from_usize(self.0[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the range contains a position.
|
|
||||||
pub fn contains(&self, pos: usize) -> bool {
|
|
||||||
pos >= self.start() && pos <= self.end()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start_to_lsp_position(&self, code: &str) -> LspPosition {
|
|
||||||
// Calculate the line and column of the error from the source range.
|
|
||||||
// Lines are zero indexed in vscode so we need to subtract 1.
|
|
||||||
let mut line = code.get(..self.start()).unwrap_or_default().lines().count();
|
|
||||||
if line > 0 {
|
|
||||||
line = line.saturating_sub(1);
|
|
||||||
}
|
|
||||||
let column = code[..self.start()].lines().last().map(|l| l.len()).unwrap_or_default();
|
|
||||||
|
|
||||||
LspPosition {
|
|
||||||
line: line as u32,
|
|
||||||
character: column as u32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn end_to_lsp_position(&self, code: &str) -> LspPosition {
|
|
||||||
let lines = code.get(..self.end()).unwrap_or_default().lines();
|
|
||||||
if lines.clone().count() == 0 {
|
|
||||||
return LspPosition { line: 0, character: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the line and column of the error from the source range.
|
|
||||||
// Lines are zero indexed in vscode so we need to subtract 1.
|
|
||||||
let line = lines.clone().count() - 1;
|
|
||||||
let column = lines.last().map(|l| l.len()).unwrap_or_default();
|
|
||||||
|
|
||||||
LspPosition {
|
|
||||||
line: line as u32,
|
|
||||||
character: column as u32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_lsp_range(&self, code: &str) -> LspRange {
|
|
||||||
let start = self.start_to_lsp_position(code);
|
|
||||||
let end = self.end_to_lsp_position(code);
|
|
||||||
LspRange { start, end }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone, Copy, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone, Copy, ts_rs::TS, JsonSchema)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
pub struct Point2d {
|
pub struct Point2d {
|
||||||
@ -2109,7 +2011,7 @@ impl ExecutorContext {
|
|||||||
// True here tells the engine to flush all the end commands as well like fillets
|
// True here tells the engine to flush all the end commands as well like fillets
|
||||||
// and chamfers where the engine would otherwise eat the ID of the segments.
|
// and chamfers where the engine would otherwise eat the ID of the segments.
|
||||||
true,
|
true,
|
||||||
SourceRange([program.end, program.end, program.module_id.as_usize()]),
|
SourceRange::new(program.end, program.end, program.module_id),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
@ -2145,6 +2047,7 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::CallExpression(call_expression) => call_expression.execute(exec_state, self).await?,
|
Expr::CallExpression(call_expression) => call_expression.execute(exec_state, self).await?,
|
||||||
|
Expr::CallExpressionKw(call_expression) => call_expression.execute(exec_state, self).await?,
|
||||||
Expr::PipeExpression(pipe_expression) => pipe_expression.get_result(exec_state, self).await?,
|
Expr::PipeExpression(pipe_expression) => pipe_expression.get_result(exec_state, self).await?,
|
||||||
Expr::PipeSubstitution(pipe_substitution) => match statement_kind {
|
Expr::PipeSubstitution(pipe_substitution) => match statement_kind {
|
||||||
StatementKind::Declaration { name } => {
|
StatementKind::Declaration { name } => {
|
||||||
@ -2714,7 +2617,10 @@ const answer = returnX()"#;
|
|||||||
err,
|
err,
|
||||||
KclError::UndefinedValue(KclErrorDetails {
|
KclError::UndefinedValue(KclErrorDetails {
|
||||||
message: "memory item key `x` is not defined".to_owned(),
|
message: "memory item key `x` is not defined".to_owned(),
|
||||||
source_ranges: vec![SourceRange([64, 65, 0]), SourceRange([97, 106, 0])],
|
source_ranges: vec![
|
||||||
|
SourceRange::new(64, 65, ModuleId::default()),
|
||||||
|
SourceRange::new(97, 106, ModuleId::default())
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2749,7 +2655,7 @@ let shape = layer() |> patternTransform(10, transform, %)
|
|||||||
err,
|
err,
|
||||||
KclError::UndefinedValue(KclErrorDetails {
|
KclError::UndefinedValue(KclErrorDetails {
|
||||||
message: "memory item key `x` is not defined".to_owned(),
|
message: "memory item key `x` is not defined".to_owned(),
|
||||||
source_ranges: vec![SourceRange([80, 81, 0])],
|
source_ranges: vec![SourceRange::new(80, 81, ModuleId::default())],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2845,7 +2751,7 @@ let notNull = !myNull
|
|||||||
parse_execute(code1).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code1).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
||||||
source_ranges: vec![SourceRange([56, 63, 0])],
|
source_ranges: vec![SourceRange::new(56, 63, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2854,7 +2760,7 @@ let notNull = !myNull
|
|||||||
parse_execute(code2).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code2).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
||||||
source_ranges: vec![SourceRange([14, 16, 0])],
|
source_ranges: vec![SourceRange::new(14, 16, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2865,7 +2771,7 @@ let notEmptyString = !""
|
|||||||
parse_execute(code3).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code3).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
message: "Cannot apply unary operator ! to non-boolean value: string (text)".to_owned(),
|
message: "Cannot apply unary operator ! to non-boolean value: string (text)".to_owned(),
|
||||||
source_ranges: vec![SourceRange([22, 25, 0])],
|
source_ranges: vec![SourceRange::new(22, 25, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2877,7 +2783,7 @@ let notMember = !obj.a
|
|||||||
parse_execute(code4).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code4).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
||||||
source_ranges: vec![SourceRange([36, 42, 0])],
|
source_ranges: vec![SourceRange::new(36, 42, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2888,7 +2794,7 @@ let notArray = !a";
|
|||||||
parse_execute(code5).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code5).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
message: "Cannot apply unary operator ! to non-boolean value: array (list)".to_owned(),
|
message: "Cannot apply unary operator ! to non-boolean value: array (list)".to_owned(),
|
||||||
source_ranges: vec![SourceRange([27, 29, 0])],
|
source_ranges: vec![SourceRange::new(27, 29, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2899,7 +2805,7 @@ let notObject = !x";
|
|||||||
parse_execute(code6).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code6).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
message: "Cannot apply unary operator ! to non-boolean value: object".to_owned(),
|
message: "Cannot apply unary operator ! to non-boolean value: object".to_owned(),
|
||||||
source_ranges: vec![SourceRange([28, 30, 0])],
|
source_ranges: vec![SourceRange::new(28, 30, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2952,7 +2858,7 @@ let notTagIdentifier = !myTag";
|
|||||||
parse_execute(code10).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code10).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Syntax(KclErrorDetails {
|
KclError::Syntax(KclErrorDetails {
|
||||||
message: "Unexpected token: !".to_owned(),
|
message: "Unexpected token: !".to_owned(),
|
||||||
source_ranges: vec![SourceRange([14, 15, 0])],
|
source_ranges: vec![SourceRange::new(14, 15, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2965,7 +2871,7 @@ let notPipeSub = 1 |> identity(!%))";
|
|||||||
parse_execute(code11).await.unwrap_err().downcast::<KclError>().unwrap(),
|
parse_execute(code11).await.unwrap_err().downcast::<KclError>().unwrap(),
|
||||||
KclError::Syntax(KclErrorDetails {
|
KclError::Syntax(KclErrorDetails {
|
||||||
message: "Unexpected token: |>".to_owned(),
|
message: "Unexpected token: |>".to_owned(),
|
||||||
source_ranges: vec![SourceRange([54, 56, 0])],
|
source_ranges: vec![SourceRange::new(54, 56, ModuleId::default())],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3009,10 +2915,10 @@ test([0, 0])
|
|||||||
"#;
|
"#;
|
||||||
let result = parse_execute(ast).await;
|
let result = parse_execute(ast).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert!(result
|
||||||
result.unwrap_err().to_string(),
|
.unwrap_err()
|
||||||
r#"undefined value: KclErrorDetails { source_ranges: [SourceRange([10, 34, 0])], message: "Result of user-defined function test is undefined" }"#.to_owned()
|
.to_string()
|
||||||
);
|
.contains("Result of user-defined function test is undefined"),);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -3128,7 +3034,7 @@ let w = f() + f()
|
|||||||
vec![req_param("x")],
|
vec![req_param("x")],
|
||||||
vec![],
|
vec![],
|
||||||
Err(KclError::Semantic(KclErrorDetails {
|
Err(KclError::Semantic(KclErrorDetails {
|
||||||
source_ranges: vec![SourceRange([0, 0, 0])],
|
source_ranges: vec![SourceRange::default()],
|
||||||
message: "Expected 1 arguments, got 0".to_owned(),
|
message: "Expected 1 arguments, got 0".to_owned(),
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
@ -3146,7 +3052,7 @@ let w = f() + f()
|
|||||||
vec![req_param("x"), opt_param("y")],
|
vec![req_param("x"), opt_param("y")],
|
||||||
vec![],
|
vec![],
|
||||||
Err(KclError::Semantic(KclErrorDetails {
|
Err(KclError::Semantic(KclErrorDetails {
|
||||||
source_ranges: vec![SourceRange([0, 0, 0])],
|
source_ranges: vec![SourceRange::default()],
|
||||||
message: "Expected 1-2 arguments, got 0".to_owned(),
|
message: "Expected 1-2 arguments, got 0".to_owned(),
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
@ -3173,7 +3079,7 @@ let w = f() + f()
|
|||||||
vec![req_param("x"), opt_param("y")],
|
vec![req_param("x"), opt_param("y")],
|
||||||
vec![mem(1), mem(2), mem(3)],
|
vec![mem(1), mem(2), mem(3)],
|
||||||
Err(KclError::Semantic(KclErrorDetails {
|
Err(KclError::Semantic(KclErrorDetails {
|
||||||
source_ranges: vec![SourceRange([0, 0, 0])],
|
source_ranges: vec![SourceRange::default()],
|
||||||
message: "Expected 1-2 arguments, got 3".to_owned(),
|
message: "Expected 1-2 arguments, got 3".to_owned(),
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
|
@ -5,6 +5,7 @@ use anyhow::Result;
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
fs::FileSystem,
|
fs::FileSystem,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -27,7 +28,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn read<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn read<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<Vec<u8>, KclError> {
|
) -> Result<Vec<u8>, KclError> {
|
||||||
tokio::fs::read(&path).await.map_err(|e| {
|
tokio::fs::read(&path).await.map_err(|e| {
|
||||||
KclError::Engine(KclErrorDetails {
|
KclError::Engine(KclErrorDetails {
|
||||||
@ -40,7 +41,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn read_to_string<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn read_to_string<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<String, KclError> {
|
) -> Result<String, KclError> {
|
||||||
tokio::fs::read_to_string(&path).await.map_err(|e| {
|
tokio::fs::read_to_string(&path).await.map_err(|e| {
|
||||||
KclError::Engine(KclErrorDetails {
|
KclError::Engine(KclErrorDetails {
|
||||||
@ -53,7 +54,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn exists<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn exists<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<bool, crate::errors::KclError> {
|
) -> Result<bool, crate::errors::KclError> {
|
||||||
tokio::fs::metadata(&path).await.map(|_| true).or_else(|e| {
|
tokio::fs::metadata(&path).await.map(|_| true).or_else(|e| {
|
||||||
if e.kind() == std::io::ErrorKind::NotFound {
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
@ -70,7 +71,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn get_all_files<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn get_all_files<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<Vec<std::path::PathBuf>, crate::errors::KclError> {
|
) -> Result<Vec<std::path::PathBuf>, crate::errors::KclError> {
|
||||||
let mut files = vec![];
|
let mut files = vec![];
|
||||||
let mut stack = vec![path.as_ref().to_path_buf()];
|
let mut stack = vec![path.as_ref().to_path_buf()];
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
//! Functions for interacting with files on a machine.
|
//! Functions for interacting with files on a machine.
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::SourceRange;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod local;
|
pub mod local;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -9,7 +13,6 @@ pub use local::FileManager;
|
|||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub mod wasm;
|
pub mod wasm;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub use wasm::FileManager;
|
pub use wasm::FileManager;
|
||||||
@ -20,27 +23,27 @@ pub trait FileSystem: Clone {
|
|||||||
async fn read<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn read<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<Vec<u8>, crate::errors::KclError>;
|
) -> Result<Vec<u8>, crate::errors::KclError>;
|
||||||
|
|
||||||
/// Read a file from the local file system.
|
/// Read a file from the local file system.
|
||||||
async fn read_to_string<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn read_to_string<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<String, crate::errors::KclError>;
|
) -> Result<String, crate::errors::KclError>;
|
||||||
|
|
||||||
/// Check if a file exists on the local file system.
|
/// Check if a file exists on the local file system.
|
||||||
async fn exists<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn exists<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<bool, crate::errors::KclError>;
|
) -> Result<bool, crate::errors::KclError>;
|
||||||
|
|
||||||
/// Get all the files in a directory recursively.
|
/// Get all the files in a directory recursively.
|
||||||
async fn get_all_files<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn get_all_files<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<Vec<std::path::PathBuf>, crate::errors::KclError>;
|
) -> Result<Vec<std::path::PathBuf>, crate::errors::KclError>;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
fs::FileSystem,
|
fs::FileSystem,
|
||||||
wasm::JsFuture,
|
wasm::JsFuture,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[wasm_bindgen(module = "/../../lang/std/fileSystemManager.ts")]
|
#[wasm_bindgen(module = "/../../lang/std/fileSystemManager.ts")]
|
||||||
@ -43,7 +44,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn read<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn read<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<Vec<u8>, KclError> {
|
) -> Result<Vec<u8>, KclError> {
|
||||||
let promise = self
|
let promise = self
|
||||||
.manager
|
.manager
|
||||||
@ -81,7 +82,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn read_to_string<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn read_to_string<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<String, KclError> {
|
) -> 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| {
|
||||||
@ -97,7 +98,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn exists<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn exists<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<bool, crate::errors::KclError> {
|
) -> Result<bool, crate::errors::KclError> {
|
||||||
let promise = self
|
let promise = self
|
||||||
.manager
|
.manager
|
||||||
@ -139,7 +140,7 @@ impl FileSystem for FileManager {
|
|||||||
async fn get_all_files<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
async fn get_all_files<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<Vec<std::path::PathBuf>, crate::errors::KclError> {
|
) -> Result<Vec<std::path::PathBuf>, crate::errors::KclError> {
|
||||||
let promise = self
|
let promise = self
|
||||||
.manager
|
.manager
|
||||||
|
@ -74,6 +74,7 @@ pub enum KclValue {
|
|||||||
Function {
|
Function {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
func: Option<MemoryFunction>,
|
func: Option<MemoryFunction>,
|
||||||
|
#[schemars(skip)]
|
||||||
expression: crate::ast::types::BoxNode<FunctionExpression>,
|
expression: crate::ast::types::BoxNode<FunctionExpression>,
|
||||||
memory: Box<ProgramMemory>,
|
memory: Box<ProgramMemory>,
|
||||||
#[serde(rename = "__meta")]
|
#[serde(rename = "__meta")]
|
||||||
@ -122,7 +123,7 @@ impl From<Vec<Box<Solid>>> for KclValue {
|
|||||||
impl From<KclValue> for Vec<SourceRange> {
|
impl From<KclValue> for Vec<SourceRange> {
|
||||||
fn from(item: KclValue) -> Self {
|
fn from(item: KclValue) -> Self {
|
||||||
match item {
|
match item {
|
||||||
KclValue::TagDeclarator(t) => vec![SourceRange([t.start, t.end, t.module_id.0 as usize])],
|
KclValue::TagDeclarator(t) => vec![SourceRange::new(t.start, t.end, t.module_id)],
|
||||||
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
|
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
|
||||||
KclValue::Solid(e) => to_vec_sr(&e.meta),
|
KclValue::Solid(e) => to_vec_sr(&e.meta),
|
||||||
KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
|
KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
|
||||||
@ -151,7 +152,7 @@ fn to_vec_sr(meta: &[Metadata]) -> Vec<SourceRange> {
|
|||||||
impl From<&KclValue> for Vec<SourceRange> {
|
impl From<&KclValue> for Vec<SourceRange> {
|
||||||
fn from(item: &KclValue) -> Self {
|
fn from(item: &KclValue) -> Self {
|
||||||
match item {
|
match item {
|
||||||
KclValue::TagDeclarator(t) => vec![SourceRange([t.start, t.end, t.module_id.0 as usize])],
|
KclValue::TagDeclarator(t) => vec![SourceRange::new(t.start, t.end, t.module_id)],
|
||||||
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
|
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
|
||||||
KclValue::Solid(e) => to_vec_sr(&e.meta),
|
KclValue::Solid(e) => to_vec_sr(&e.meta),
|
||||||
KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
|
KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
|
||||||
|
@ -72,6 +72,7 @@ mod parser;
|
|||||||
mod settings;
|
mod settings;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod simulation_tests;
|
mod simulation_tests;
|
||||||
|
mod source_range;
|
||||||
mod std;
|
mod std;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub mod test_server;
|
pub mod test_server;
|
||||||
@ -82,16 +83,17 @@ mod walk;
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
mod wasm;
|
mod wasm;
|
||||||
|
|
||||||
pub use ast::modify::modify_ast_for_sketch;
|
pub use ast::{modify::modify_ast_for_sketch, types::FormatOptions};
|
||||||
pub use ast::types::{FormatOptions, ModuleId};
|
|
||||||
pub use coredump::CoreDump;
|
pub use coredump::CoreDump;
|
||||||
pub use engine::{EngineManager, ExecutionKind};
|
pub use engine::{EngineManager, ExecutionKind};
|
||||||
pub use errors::{ConnectionError, ExecError, KclError};
|
pub use errors::{ConnectionError, ExecError, KclError};
|
||||||
pub use executor::{ExecState, ExecutorContext, ExecutorSettings, SourceRange};
|
pub use executor::{ExecState, ExecutorContext, ExecutorSettings};
|
||||||
pub use lsp::copilot::Backend as CopilotLspBackend;
|
pub use lsp::{
|
||||||
pub use lsp::kcl::Backend as KclLspBackend;
|
copilot::Backend as CopilotLspBackend,
|
||||||
pub use lsp::kcl::Server as KclLspServerSubCommand;
|
kcl::{Backend as KclLspBackend, Server as KclLspServerSubCommand},
|
||||||
|
};
|
||||||
pub use settings::types::{project::ProjectConfiguration, Configuration, UnitLength};
|
pub use settings::types::{project::ProjectConfiguration, Configuration, UnitLength};
|
||||||
|
pub use source_range::{ModuleId, SourceRange};
|
||||||
|
|
||||||
// Rather than make executor public and make lots of it pub(crate), just re-export into a new module.
|
// Rather than make executor public and make lots of it pub(crate), just re-export into a new module.
|
||||||
// Ideally we wouldn't export these things at all, they should only be used for testing.
|
// Ideally we wouldn't export these things at all, they should only be used for testing.
|
||||||
@ -101,9 +103,11 @@ pub mod exec {
|
|||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub mod wasm_engine {
|
pub mod wasm_engine {
|
||||||
pub use crate::coredump::wasm::{CoreDumpManager, CoreDumper};
|
pub use crate::{
|
||||||
pub use crate::engine::conn_wasm::{EngineCommandManager, EngineConnection};
|
coredump::wasm::{CoreDumpManager, CoreDumper},
|
||||||
pub use crate::fs::wasm::FileSystemManager;
|
engine::conn_wasm::{EngineCommandManager, EngineConnection},
|
||||||
|
fs::wasm::FileSystemManager,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -115,9 +119,10 @@ pub mod std_utils {
|
|||||||
pub use crate::std::utils::{get_tangential_arc_to_info, is_points_ccw_wasm, TangentialArcInfoInput};
|
pub use crate::std::utils::{get_tangential_arc_to_info, is_points_ccw_wasm, TangentialArcInfoInput};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::log::{log, logln};
|
use crate::log::{log, logln};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
|
@ -3,9 +3,9 @@ use convert_case::Casing;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{ObjectProperty, VariableDeclarator},
|
ast::types::{ObjectProperty, VariableDeclarator},
|
||||||
executor::SourceRange,
|
|
||||||
lint::rule::{def_finding, Discovered, Finding},
|
lint::rule::{def_finding, Discovered, Finding},
|
||||||
walk::Node,
|
walk::Node,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
def_finding!(
|
def_finding!(
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{BinaryPart, Expr, LiteralValue, ObjectExpression, UnaryOperator},
|
ast::types::{BinaryPart, Expr, LiteralValue, ObjectExpression, UnaryOperator},
|
||||||
executor::SourceRange,
|
|
||||||
lint::rule::{def_finding, Discovered, Finding},
|
lint::rule::{def_finding, Discovered, Finding},
|
||||||
walk::Node,
|
walk::Node,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
def_finding!(
|
def_finding!(
|
||||||
Z0003,
|
Z0003,
|
||||||
|
@ -5,10 +5,10 @@ use anyhow::Result;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{CallExpression, NodeRef},
|
ast::types::{CallExpression, NodeRef},
|
||||||
docs::StdLibFn,
|
docs::StdLibFn,
|
||||||
executor::SourceRange,
|
|
||||||
lint::rule::{def_finding, Discovered, Finding},
|
lint::rule::{def_finding, Discovered, Finding},
|
||||||
std::{FunctionKind, StdLib},
|
std::{FunctionKind, StdLib},
|
||||||
walk::Node,
|
walk::Node,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
def_finding!(
|
def_finding!(
|
||||||
|
@ -3,7 +3,7 @@ use schemars::JsonSchema;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
|
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
|
||||||
|
|
||||||
use crate::{executor::SourceRange, lsp::IntoDiagnostic, walk::Node};
|
use crate::{lsp::IntoDiagnostic, walk::Node, SourceRange};
|
||||||
|
|
||||||
/// Check the provided AST for any found rule violations.
|
/// Check the provided AST for any found rule violations.
|
||||||
///
|
///
|
||||||
@ -30,16 +30,16 @@ where
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Discovered {
|
pub struct Discovered {
|
||||||
/// Zoo Lint Finding information.
|
/// Zoo Lint Finding information.
|
||||||
pub finding: Finding,
|
pub(super) finding: Finding,
|
||||||
|
|
||||||
/// Further information about the specific finding.
|
/// Further information about the specific finding.
|
||||||
pub description: String,
|
pub(super) description: String,
|
||||||
|
|
||||||
/// Source code location.
|
/// Source code location.
|
||||||
pub pos: SourceRange,
|
pub(super) pos: SourceRange,
|
||||||
|
|
||||||
/// Is this discovered issue overridden by the programmer?
|
/// Is this discovered issue overridden by the programmer?
|
||||||
pub overridden: bool,
|
pub(super) overridden: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "pyo3")]
|
#[cfg(feature = "pyo3")]
|
||||||
@ -56,8 +56,8 @@ impl Discovered {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn pos(&self) -> SourceRange {
|
pub fn pos(&self) -> (usize, usize) {
|
||||||
self.pos
|
(self.pos.start(), self.pos.end())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
use std::env;
|
||||||
|
|
||||||
#[cfg(feature = "dhat-heap")]
|
#[cfg(feature = "dhat-heap")]
|
||||||
use dhat::{HeapStats, Profiler};
|
use dhat::{HeapStats, Profiler};
|
||||||
use std::env;
|
|
||||||
use web_time::Instant;
|
use web_time::Instant;
|
||||||
|
|
||||||
const LOG_ENV_VAR: &str = "ZOO_LOG";
|
const LOG_ENV_VAR: &str = "ZOO_LOG";
|
||||||
|
@ -27,10 +27,12 @@ use tower_lsp::{
|
|||||||
|
|
||||||
use crate::lsp::{
|
use crate::lsp::{
|
||||||
backend::Backend as _,
|
backend::Backend as _,
|
||||||
copilot::cache::CopilotCache,
|
copilot::{
|
||||||
copilot::types::{
|
cache::CopilotCache,
|
||||||
CopilotAcceptCompletionParams, CopilotCompletionResponse, CopilotCompletionTelemetry, CopilotEditorInfo,
|
types::{
|
||||||
CopilotLspCompletionParams, CopilotRejectCompletionParams, DocParams,
|
CopilotAcceptCompletionParams, CopilotCompletionResponse, CopilotCompletionTelemetry, CopilotEditorInfo,
|
||||||
|
CopilotLspCompletionParams, CopilotRejectCompletionParams, DocParams,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,11 +41,11 @@ use tower_lsp::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{Expr, ModuleId, Node, VariableKind},
|
ast::types::{Expr, Node, VariableKind},
|
||||||
lsp::{backend::Backend as _, util::IntoDiagnostic},
|
lsp::{backend::Backend as _, util::IntoDiagnostic},
|
||||||
parser::PIPE_OPERATOR,
|
parser::PIPE_OPERATOR,
|
||||||
token::TokenType,
|
token::TokenType,
|
||||||
ExecState, Program, SourceRange,
|
ExecState, ModuleId, Program, SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use parser_impl::ParseContext;
|
use parser_impl::ParseContext;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{ModuleId, Node, Program},
|
ast::types::{Node, Program},
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::SourceRange,
|
source_range::{ModuleId, SourceRange},
|
||||||
token::{Token, TokenType},
|
token::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{BinaryExpression, BinaryOperator, BinaryPart, Node},
|
ast::types::{BinaryExpression, BinaryOperator, BinaryPart, Node},
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::SourceRange,
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses a list of tokens (in infix order, i.e. as the user typed them)
|
/// Parses a list of tokens (in infix order, i.e. as the user typed them)
|
||||||
@ -66,7 +66,7 @@ fn source_range(tokens: &[BinaryExpressionToken]) -> Vec<SourceRange> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
match (sources.first(), sources.last()) {
|
match (sources.first(), sources.last()) {
|
||||||
(Some((start, _, module_id)), Some((_, end, _))) => vec![SourceRange([*start, *end, module_id.as_usize()])],
|
(Some((start, _, module_id)), Some((_, end, _))) => vec![SourceRange::new(*start, *end, *module_id)],
|
||||||
_ => Vec::new(),
|
_ => Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ impl From<BinaryOperator> for BinaryExpressionToken {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast::types::{Literal, ModuleId};
|
use crate::{ast::types::Literal, source_range::ModuleId};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_and_evaluate() {
|
fn parse_and_evaluate() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, str::FromStr};
|
use std::{cell::RefCell, collections::HashMap, str::FromStr};
|
||||||
|
|
||||||
use winnow::{
|
use winnow::{
|
||||||
combinator::{alt, delimited, opt, peek, preceded, repeat, separated, terminated},
|
combinator::{alt, delimited, opt, peek, preceded, repeat, separated, separated_pair, terminated},
|
||||||
dispatch,
|
dispatch,
|
||||||
error::{ErrMode, StrContext, StrContextValue},
|
error::{ErrMode, StrContext, StrContextValue},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -12,20 +12,20 @@ use self::error::ParseError;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{
|
ast::types::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, BoxNode,
|
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, BoxNode,
|
||||||
CallExpression, CommentStyle, ElseIf, Expr, ExpressionStatement, FnArgPrimitive, FnArgType, FunctionExpression,
|
CallExpression, CallExpressionKw, CommentStyle, ElseIf, Expr, ExpressionStatement, FnArgPrimitive, FnArgType,
|
||||||
Identifier, IfExpression, ImportItem, ImportStatement, ItemVisibility, Literal, LiteralIdentifier,
|
FunctionExpression, Identifier, IfExpression, ImportItem, ImportStatement, ItemVisibility, LabeledArg, Literal,
|
||||||
LiteralValue, MemberExpression, MemberObject, Node, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression,
|
LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, NonCodeMeta, NonCodeNode, NonCodeValue,
|
||||||
ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement, Shebang, TagDeclarator,
|
ObjectExpression, ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement,
|
||||||
UnaryExpression, UnaryOperator, VariableDeclaration, VariableDeclarator, VariableKind,
|
Shebang, TagDeclarator, UnaryExpression, UnaryOperator, VariableDeclaration, VariableDeclarator, VariableKind,
|
||||||
},
|
},
|
||||||
docs::StdLibFn,
|
docs::StdLibFn,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::SourceRange,
|
|
||||||
parser::{
|
parser::{
|
||||||
math::BinaryExpressionToken, parser_impl::error::ContextError, PIPE_OPERATOR, PIPE_SUBSTITUTION_OPERATOR,
|
math::BinaryExpressionToken, parser_impl::error::ContextError, PIPE_OPERATOR, PIPE_SUBSTITUTION_OPERATOR,
|
||||||
},
|
},
|
||||||
token::{Token, TokenType},
|
token::{Token, TokenType},
|
||||||
unparser::ExprContext,
|
unparser::ExprContext,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) mod error;
|
pub(crate) mod error;
|
||||||
@ -478,6 +478,7 @@ fn operand(i: TokenSlice) -> PResult<BinaryPart> {
|
|||||||
Expr::Identifier(x) => BinaryPart::Identifier(x),
|
Expr::Identifier(x) => BinaryPart::Identifier(x),
|
||||||
Expr::BinaryExpression(x) => BinaryPart::BinaryExpression(x),
|
Expr::BinaryExpression(x) => BinaryPart::BinaryExpression(x),
|
||||||
Expr::CallExpression(x) => BinaryPart::CallExpression(x),
|
Expr::CallExpression(x) => BinaryPart::CallExpression(x),
|
||||||
|
Expr::CallExpressionKw(x) => BinaryPart::CallExpressionKw(x),
|
||||||
Expr::MemberExpression(x) => BinaryPart::MemberExpression(x),
|
Expr::MemberExpression(x) => BinaryPart::MemberExpression(x),
|
||||||
Expr::IfExpression(x) => BinaryPart::IfExpression(x),
|
Expr::IfExpression(x) => BinaryPart::IfExpression(x),
|
||||||
};
|
};
|
||||||
@ -1511,6 +1512,7 @@ fn expr_allowed_in_pipe_expr(i: TokenSlice) -> PResult<Expr> {
|
|||||||
tag.map(Box::new).map(Expr::TagDeclarator),
|
tag.map(Box::new).map(Expr::TagDeclarator),
|
||||||
literal.map(Expr::Literal),
|
literal.map(Expr::Literal),
|
||||||
fn_call.map(Box::new).map(Expr::CallExpression),
|
fn_call.map(Box::new).map(Expr::CallExpression),
|
||||||
|
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
|
||||||
identifier.map(Box::new).map(Expr::Identifier),
|
identifier.map(Box::new).map(Expr::Identifier),
|
||||||
array,
|
array,
|
||||||
object.map(Box::new).map(Expr::ObjectExpression),
|
object.map(Box::new).map(Expr::ObjectExpression),
|
||||||
@ -1603,7 +1605,7 @@ fn declaration(i: TokenSlice) -> PResult<BoxNode<VariableDeclaration>> {
|
|||||||
let ctxt_end = val.as_ref().map(|e| e.end()).unwrap_or(t.end);
|
let ctxt_end = val.as_ref().map(|e| e.end()).unwrap_or(t.end);
|
||||||
ParseContext::warn(ParseError::with_suggestion(
|
ParseContext::warn(ParseError::with_suggestion(
|
||||||
t.as_source_range(),
|
t.as_source_range(),
|
||||||
Some(SourceRange([id.start, ctxt_end, module_id.as_usize()])),
|
Some(SourceRange::new(id.start, ctxt_end, module_id)),
|
||||||
"Unnecessary `=` in function declaration",
|
"Unnecessary `=` in function declaration",
|
||||||
Some(""),
|
Some(""),
|
||||||
));
|
));
|
||||||
@ -1620,7 +1622,7 @@ fn declaration(i: TokenSlice) -> PResult<BoxNode<VariableDeclaration>> {
|
|||||||
// Check the 'if' direction:
|
// Check the 'if' direction:
|
||||||
if matches!(val, Expr::FunctionExpression(_)) {
|
if matches!(val, Expr::FunctionExpression(_)) {
|
||||||
return Err(KclError::Syntax(KclErrorDetails {
|
return Err(KclError::Syntax(KclErrorDetails {
|
||||||
source_ranges: vec![SourceRange([start, dec_end, module_id.as_usize()])],
|
source_ranges: vec![SourceRange::new(start, dec_end, module_id)],
|
||||||
message: format!("Expected a `fn` variable kind, found: `{}`", kind),
|
message: format!("Expected a `fn` variable kind, found: `{}`", kind),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -2028,6 +2030,23 @@ fn arguments(i: TokenSlice) -> PResult<Vec<Expr>> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn labeled_argument(i: TokenSlice) -> PResult<LabeledArg> {
|
||||||
|
separated_pair(identifier, (one_of(TokenType::Colon), opt(whitespace)), expression)
|
||||||
|
.map(|(label, arg)| LabeledArg {
|
||||||
|
label: label.inner,
|
||||||
|
arg,
|
||||||
|
})
|
||||||
|
.parse_next(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arguments are passed into a function,
|
||||||
|
/// preceded by the name of the parameter (the label).
|
||||||
|
fn labeled_arguments(i: TokenSlice) -> PResult<Vec<LabeledArg>> {
|
||||||
|
separated(0.., labeled_argument, comma_sep)
|
||||||
|
.context(expected("function arguments"))
|
||||||
|
.parse_next(i)
|
||||||
|
}
|
||||||
|
|
||||||
/// A type of a function argument.
|
/// A type of a function argument.
|
||||||
/// This can be:
|
/// This can be:
|
||||||
/// - a primitive type, e.g. 'number' or 'string' or 'bool'
|
/// - a primitive type, e.g. 'number' or 'string' or 'bool'
|
||||||
@ -2147,7 +2166,7 @@ fn binding_name(i: TokenSlice) -> PResult<Node<Identifier>> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typecheck_all(std_fn: Box<dyn StdLibFn>, args: &[Expr]) -> PResult<()> {
|
fn typecheck_all(std_fn: Box<dyn StdLibFn>, args: &[&Expr]) -> PResult<()> {
|
||||||
// Type check the arguments.
|
// Type check the arguments.
|
||||||
for (i, spec_arg) in std_fn.args(false).iter().enumerate() {
|
for (i, spec_arg) in std_fn.args(false).iter().enumerate() {
|
||||||
let Some(arg) = &args.get(i) else {
|
let Some(arg) = &args.get(i) else {
|
||||||
@ -2205,7 +2224,8 @@ fn fn_call(i: TokenSlice) -> PResult<Node<CallExpression>> {
|
|||||||
let _ = terminated(open_paren, opt(whitespace)).parse_next(i)?;
|
let _ = terminated(open_paren, opt(whitespace)).parse_next(i)?;
|
||||||
let args = arguments(i)?;
|
let args = arguments(i)?;
|
||||||
if let Some(std_fn) = crate::std::get_stdlib_fn(&fn_name.name) {
|
if let Some(std_fn) = crate::std::get_stdlib_fn(&fn_name.name) {
|
||||||
typecheck_all(std_fn, &args)?;
|
let just_args: Vec<_> = args.iter().collect();
|
||||||
|
typecheck_all(std_fn, &just_args)?;
|
||||||
}
|
}
|
||||||
let end = preceded(opt(whitespace), close_paren).parse_next(i)?.end;
|
let end = preceded(opt(whitespace), close_paren).parse_next(i)?.end;
|
||||||
|
|
||||||
@ -2237,13 +2257,40 @@ fn fn_call(i: TokenSlice) -> PResult<Node<CallExpression>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fn_call_kw(i: TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
||||||
|
let fn_name = identifier(i)?;
|
||||||
|
opt(whitespace).parse_next(i)?;
|
||||||
|
let _ = open_paren.parse_next(i)?;
|
||||||
|
ignore_whitespace(i);
|
||||||
|
|
||||||
|
let initial_unlabeled_arg = opt((expression, comma, opt(whitespace)).map(|(arg, _, _)| arg)).parse_next(i)?;
|
||||||
|
let args = labeled_arguments(i)?;
|
||||||
|
ignore_whitespace(i);
|
||||||
|
let end = close_paren.parse_next(i)?.end;
|
||||||
|
|
||||||
|
Ok(Node {
|
||||||
|
start: fn_name.start,
|
||||||
|
end,
|
||||||
|
module_id: fn_name.module_id,
|
||||||
|
inner: CallExpressionKw {
|
||||||
|
callee: fn_name,
|
||||||
|
unlabeled: initial_unlabeled_arg,
|
||||||
|
arguments: args,
|
||||||
|
digest: None,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast::types::{BodyItem, Expr, ModuleId, VariableKind};
|
use crate::{
|
||||||
|
ast::types::{BodyItem, Expr, VariableKind},
|
||||||
|
ModuleId,
|
||||||
|
};
|
||||||
|
|
||||||
fn assert_reserved(word: &str) {
|
fn assert_reserved(word: &str) {
|
||||||
// Try to use it as a variable name.
|
// Try to use it as a variable name.
|
||||||
@ -2301,7 +2348,10 @@ mod tests {
|
|||||||
let tokens = crate::token::lexer("|", ModuleId::default()).unwrap();
|
let tokens = crate::token::lexer("|", ModuleId::default()).unwrap();
|
||||||
let err: super::error::ErrorKind = program.parse(&tokens).unwrap_err().into();
|
let err: super::error::ErrorKind = program.parse(&tokens).unwrap_err().into();
|
||||||
let err = err.unwrap_parse_error();
|
let err = err.unwrap_parse_error();
|
||||||
assert_eq!(vec![err.source_range], vec![SourceRange([0, 1, 0])]);
|
assert_eq!(
|
||||||
|
vec![err.source_range],
|
||||||
|
vec![SourceRange::new(0, 1, ModuleId::default())]
|
||||||
|
);
|
||||||
assert_eq!(err.message, "Unexpected token: |");
|
assert_eq!(err.message, "Unexpected token: |");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2925,7 +2975,10 @@ const mySk1 = startSketchAt([0, 0])"#;
|
|||||||
let err = function_decl.parse(&tokens).unwrap_err().into_inner();
|
let err = function_decl.parse(&tokens).unwrap_err().into_inner();
|
||||||
let cause = err.cause.unwrap();
|
let cause = err.cause.unwrap();
|
||||||
// This is the token `let`
|
// This is the token `let`
|
||||||
assert_eq!(cause.source_ranges(), vec![SourceRange([1, 4, 2])]);
|
assert_eq!(
|
||||||
|
cause.source_ranges(),
|
||||||
|
vec![SourceRange::new(1, 4, ModuleId::from_usize(2))]
|
||||||
|
);
|
||||||
assert_eq!(cause.message(), "Cannot assign a variable to a reserved keyword: let");
|
assert_eq!(cause.message(), "Cannot assign a variable to a reserved keyword: let");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3245,7 +3298,8 @@ const mySk1 = startSketchAt([0, 0])"#;
|
|||||||
let result = crate::parser::top_level_parse(p);
|
let result = crate::parser::top_level_parse(p);
|
||||||
let err = &result.unwrap_errs()[0];
|
let err = &result.unwrap_errs()[0];
|
||||||
assert_eq!(err.message, msg);
|
assert_eq!(err.message, msg);
|
||||||
assert_eq!(&err.source_range.0[..2], &src);
|
assert_eq!(err.source_range.start(), src[0]);
|
||||||
|
assert_eq!(err.source_range.end(), src[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
@ -3368,7 +3422,8 @@ const secondExtrude = startSketchOn('XY')
|
|||||||
// TODO: Better errors when program cannot tokenize.
|
// TODO: Better errors when program cannot tokenize.
|
||||||
// https://github.com/KittyCAD/modeling-app/issues/696
|
// https://github.com/KittyCAD/modeling-app/issues/696
|
||||||
assert_eq!(details.message, "found unknown token 'ޜ'");
|
assert_eq!(details.message, "found unknown token 'ޜ'");
|
||||||
assert_eq!(&details.source_ranges[0].0[..2], &[1, 2]);
|
assert_eq!(details.source_ranges[0].start(), 1);
|
||||||
|
assert_eq!(details.source_ranges[0].end(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -3759,6 +3814,25 @@ let myBox = box([0,0], -3, -16, -10)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn arg_labels() {
|
||||||
|
let input = r#"length: 3"#;
|
||||||
|
let module_id = ModuleId::default();
|
||||||
|
let tokens = crate::token::lexer(input, module_id).unwrap();
|
||||||
|
let mut sl: &[Token] = &tokens;
|
||||||
|
super::labeled_arguments(&mut sl).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn kw_fn() {
|
||||||
|
for input in ["val = foo(x, y: z)", "val = foo(y: z)"] {
|
||||||
|
let module_id = ModuleId::default();
|
||||||
|
let tokens = crate::token::lexer(input, module_id).unwrap();
|
||||||
|
let sl = &tokens;
|
||||||
|
super::program.parse(sl).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_tag_named_std_lib() {
|
fn test_parse_tag_named_std_lib() {
|
||||||
let some_program_string = r#"startSketchOn('XY')
|
let some_program_string = r#"startSketchOn('XY')
|
||||||
@ -3826,6 +3900,7 @@ int(42.3)"#;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod snapshot_math_tests {
|
mod snapshot_math_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::ModuleId;
|
||||||
|
|
||||||
// This macro generates a test function with the given function name.
|
// This macro generates a test function with the given function name.
|
||||||
// The macro takes a KCL program, ensures it tokenizes and parses, then compares
|
// The macro takes a KCL program, ensures it tokenizes and parses, then compares
|
||||||
@ -3834,7 +3909,7 @@ mod snapshot_math_tests {
|
|||||||
($func_name:ident, $test_kcl_program:expr) => {
|
($func_name:ident, $test_kcl_program:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func_name() {
|
fn $func_name() {
|
||||||
let module_id = crate::ast::types::ModuleId::default();
|
let module_id = ModuleId::default();
|
||||||
let tokens = crate::token::lexer($test_kcl_program, module_id).unwrap();
|
let tokens = crate::token::lexer($test_kcl_program, module_id).unwrap();
|
||||||
ParseContext::init();
|
ParseContext::init();
|
||||||
|
|
||||||
@ -3864,6 +3939,7 @@ mod snapshot_math_tests {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod snapshot_tests {
|
mod snapshot_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::ModuleId;
|
||||||
|
|
||||||
// This macro generates a test function with the given function name.
|
// This macro generates a test function with the given function name.
|
||||||
// The macro takes a KCL program, ensures it tokenizes and parses, then compares
|
// The macro takes a KCL program, ensures it tokenizes and parses, then compares
|
||||||
@ -3872,7 +3948,7 @@ mod snapshot_tests {
|
|||||||
($func_name:ident, $test_kcl_program:expr) => {
|
($func_name:ident, $test_kcl_program:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func_name() {
|
fn $func_name() {
|
||||||
let module_id = crate::ast::types::ModuleId::default();
|
let module_id = ModuleId::default();
|
||||||
let tokens = crate::token::lexer($test_kcl_program, module_id).unwrap();
|
let tokens = crate::token::lexer($test_kcl_program, module_id).unwrap();
|
||||||
print_tokens(&tokens);
|
print_tokens(&tokens);
|
||||||
ParseContext::init();
|
ParseContext::init();
|
||||||
@ -4082,6 +4158,8 @@ const my14 = 4 ^ 2 - 3 ^ 2 * 2
|
|||||||
r#"x = 3
|
r#"x = 3
|
||||||
obj = { x, y: 4}"#
|
obj = { x, y: 4}"#
|
||||||
);
|
);
|
||||||
|
snapshot_test!(kw_function_unnamed_first, r#"val = foo(x, y: z)"#);
|
||||||
|
snapshot_test!(kw_function_all_named, r#"val = foo(x: a, y: b)"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -2,8 +2,8 @@ use winnow::{error::StrContext, stream::Stream};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::SourceRange,
|
|
||||||
token::Token,
|
token::Token,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Accumulate context while backtracking errors
|
/// Accumulate context while backtracking errors
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
source: kcl/src/parser/parser_impl.rs
|
||||||
|
expression: actual
|
||||||
|
snapshot_kind: text
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"declarations": [
|
||||||
|
{
|
||||||
|
"end": 21,
|
||||||
|
"id": {
|
||||||
|
"end": 3,
|
||||||
|
"name": "val",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"type": "LabeledArg",
|
||||||
|
"label": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"name": "x"
|
||||||
|
},
|
||||||
|
"arg": {
|
||||||
|
"end": 14,
|
||||||
|
"name": "a",
|
||||||
|
"start": 13,
|
||||||
|
"type": "Identifier",
|
||||||
|
"type": "Identifier"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "LabeledArg",
|
||||||
|
"label": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"name": "y"
|
||||||
|
},
|
||||||
|
"arg": {
|
||||||
|
"end": 20,
|
||||||
|
"name": "b",
|
||||||
|
"start": 19,
|
||||||
|
"type": "Identifier",
|
||||||
|
"type": "Identifier"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"callee": {
|
||||||
|
"end": 9,
|
||||||
|
"name": "foo",
|
||||||
|
"start": 6,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"end": 21,
|
||||||
|
"start": 6,
|
||||||
|
"type": "CallExpressionKw",
|
||||||
|
"type": "CallExpressionKw",
|
||||||
|
"unlabeled": null
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclarator"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"end": 21,
|
||||||
|
"kind": "const",
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"type": "VariableDeclaration"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"end": 21,
|
||||||
|
"start": 0
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
source: kcl/src/parser/parser_impl.rs
|
||||||
|
expression: actual
|
||||||
|
snapshot_kind: text
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"declarations": [
|
||||||
|
{
|
||||||
|
"end": 18,
|
||||||
|
"id": {
|
||||||
|
"end": 3,
|
||||||
|
"name": "val",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"type": "LabeledArg",
|
||||||
|
"label": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"name": "y"
|
||||||
|
},
|
||||||
|
"arg": {
|
||||||
|
"end": 17,
|
||||||
|
"name": "z",
|
||||||
|
"start": 16,
|
||||||
|
"type": "Identifier",
|
||||||
|
"type": "Identifier"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"callee": {
|
||||||
|
"end": 9,
|
||||||
|
"name": "foo",
|
||||||
|
"start": 6,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"end": 18,
|
||||||
|
"start": 6,
|
||||||
|
"type": "CallExpressionKw",
|
||||||
|
"type": "CallExpressionKw",
|
||||||
|
"unlabeled": {
|
||||||
|
"end": 11,
|
||||||
|
"name": "x",
|
||||||
|
"start": 10,
|
||||||
|
"type": "Identifier",
|
||||||
|
"type": "Identifier"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclarator"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"end": 18,
|
||||||
|
"kind": "const",
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"type": "VariableDeclaration"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"end": 18,
|
||||||
|
"start": 0
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
use insta::rounded_redaction;
|
use insta::rounded_redaction;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{ModuleId, Node, Program},
|
ast::types::{Node, Program},
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
|
source_range::ModuleId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Deserialize the data from a snapshot.
|
/// Deserialize the data from a snapshot.
|
||||||
|
129
src/wasm-lib/kcl/src/source_range.rs
Normal file
129
src/wasm-lib/kcl/src/source_range.rs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
use databake::*;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
|
||||||
|
|
||||||
|
/// Identifier of a source file. Uses a u32 to keep the size small.
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema, Bake)]
|
||||||
|
#[databake(path = kcl_lib::ast::types)]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct ModuleId(u32);
|
||||||
|
|
||||||
|
impl ModuleId {
|
||||||
|
pub fn from_usize(id: usize) -> Self {
|
||||||
|
Self(u32::try_from(id).expect("module ID should fit in a u32"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_usize(&self) -> usize {
|
||||||
|
usize::try_from(self.0).expect("module ID should fit in a usize")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Top-level file is the one being executed.
|
||||||
|
/// Represented by module ID of 0, i.e. the default value.
|
||||||
|
pub fn is_top_level(&self) -> bool {
|
||||||
|
*self == Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema, Hash, Eq)]
|
||||||
|
#[ts(export, as = "TsSourceRange")]
|
||||||
|
pub struct SourceRange([usize; 3]);
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema, Hash, Eq)]
|
||||||
|
struct TsSourceRange(#[ts(type = "[number, number]")] [usize; 2]);
|
||||||
|
|
||||||
|
impl From<[usize; 3]> for SourceRange {
|
||||||
|
fn from(value: [usize; 3]) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SourceRange> for TsSourceRange {
|
||||||
|
fn from(value: SourceRange) -> Self {
|
||||||
|
Self([value.start(), value.end()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&SourceRange> for miette::SourceSpan {
|
||||||
|
fn from(source_range: &SourceRange) -> Self {
|
||||||
|
let length = source_range.end() - source_range.start();
|
||||||
|
let start = miette::SourceOffset::from(source_range.start());
|
||||||
|
Self::new(start, length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SourceRange> for miette::SourceSpan {
|
||||||
|
fn from(source_range: SourceRange) -> Self {
|
||||||
|
Self::from(&source_range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceRange {
|
||||||
|
/// Create a new source range.
|
||||||
|
pub fn new(start: usize, end: usize, module_id: ModuleId) -> Self {
|
||||||
|
Self([start, end, module_id.as_usize()])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A source range that doesn't correspond to any source code.
|
||||||
|
pub fn synthetic() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the start of the range.
|
||||||
|
pub fn start(&self) -> usize {
|
||||||
|
self.0[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the end of the range.
|
||||||
|
pub fn end(&self) -> usize {
|
||||||
|
self.0[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the module ID of the range.
|
||||||
|
pub fn module_id(&self) -> ModuleId {
|
||||||
|
ModuleId::from_usize(self.0[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the range contains a position.
|
||||||
|
pub fn contains(&self, pos: usize) -> bool {
|
||||||
|
pos >= self.start() && pos <= self.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_to_lsp_position(&self, code: &str) -> LspPosition {
|
||||||
|
// Calculate the line and column of the error from the source range.
|
||||||
|
// Lines are zero indexed in vscode so we need to subtract 1.
|
||||||
|
let mut line = code.get(..self.start()).unwrap_or_default().lines().count();
|
||||||
|
if line > 0 {
|
||||||
|
line = line.saturating_sub(1);
|
||||||
|
}
|
||||||
|
let column = code[..self.start()].lines().last().map(|l| l.len()).unwrap_or_default();
|
||||||
|
|
||||||
|
LspPosition {
|
||||||
|
line: line as u32,
|
||||||
|
character: column as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_to_lsp_position(&self, code: &str) -> LspPosition {
|
||||||
|
let lines = code.get(..self.end()).unwrap_or_default().lines();
|
||||||
|
if lines.clone().count() == 0 {
|
||||||
|
return LspPosition { line: 0, character: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the line and column of the error from the source range.
|
||||||
|
// Lines are zero indexed in vscode so we need to subtract 1.
|
||||||
|
let line = lines.clone().count() - 1;
|
||||||
|
let column = lines.last().map(|l| l.len()).unwrap_or_default();
|
||||||
|
|
||||||
|
LspPosition {
|
||||||
|
line: line as u32,
|
||||||
|
character: column as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_lsp_range(&self, code: &str) -> LspRange {
|
||||||
|
let start = self.start_to_lsp_position(code);
|
||||||
|
let end = self.end_to_lsp_position(code);
|
||||||
|
LspRange { start, end }
|
||||||
|
}
|
||||||
|
}
|
@ -4,19 +4,20 @@ use anyhow::Result;
|
|||||||
use kcmc::{websocket::OkWebSocketResponseData, ModelingCmd};
|
use kcmc::{websocket::OkWebSocketResponseData, ModelingCmd};
|
||||||
use kittycad_modeling_cmds as kcmc;
|
use kittycad_modeling_cmds as kcmc;
|
||||||
|
|
||||||
|
use super::shapes::PolygonType;
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::TagNode,
|
ast::types::TagNode,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{
|
||||||
ExecState, ExecutorContext, ExtrudeSurface, KclValue, Metadata, Sketch, SketchSet, SketchSurface, Solid,
|
ExecState, ExecutorContext, ExtrudeSurface, KclValue, Metadata, Sketch, SketchSet, SketchSurface, Solid,
|
||||||
SolidSet, SourceRange, TagIdentifier,
|
SolidSet, TagIdentifier,
|
||||||
},
|
},
|
||||||
kcl_value::KclObjectFields,
|
kcl_value::KclObjectFields,
|
||||||
|
source_range::SourceRange,
|
||||||
std::{shapes::SketchOrSurface, sketch::FaceTag, FnAsArg},
|
std::{shapes::SketchOrSurface, sketch::FaceTag, FnAsArg},
|
||||||
|
ModuleId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::shapes::PolygonType;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Arg {
|
pub struct Arg {
|
||||||
/// The evaluated argument.
|
/// The evaluated argument.
|
||||||
@ -1221,7 +1222,6 @@ impl<'a> FromKclValue<'a> for crate::executor::GeoMeta {
|
|||||||
let obj = arg.as_object()?;
|
let obj = arg.as_object()?;
|
||||||
let_field_of!(obj, id);
|
let_field_of!(obj, id);
|
||||||
let_field_of!(obj, source_range "sourceRange");
|
let_field_of!(obj, source_range "sourceRange");
|
||||||
let source_range = SourceRange(source_range);
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
id,
|
id,
|
||||||
metadata: Metadata { source_range },
|
metadata: Metadata { source_range },
|
||||||
@ -1314,9 +1314,22 @@ impl_from_kcl_for_vec!(super::fillet::EdgeReference);
|
|||||||
impl_from_kcl_for_vec!(ExtrudeSurface);
|
impl_from_kcl_for_vec!(ExtrudeSurface);
|
||||||
impl_from_kcl_for_vec!(Sketch);
|
impl_from_kcl_for_vec!(Sketch);
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for crate::executor::SourceRange {
|
impl<'a> FromKclValue<'a> for SourceRange {
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
FromKclValue::from_kcl_val(arg).map(crate::executor::SourceRange)
|
let KclValue::Array { value, meta: _ } = arg else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
if value.len() != 3 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let v0 = value.first()?;
|
||||||
|
let v1 = value.get(1)?;
|
||||||
|
let v2 = value.get(2)?;
|
||||||
|
Some(SourceRange::new(
|
||||||
|
v0.as_usize()?,
|
||||||
|
v1.as_usize()?,
|
||||||
|
ModuleId::from_usize(v2.as_usize()?),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,8 +6,9 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{ExecState, KclValue, SourceRange},
|
executor::{ExecState, KclValue},
|
||||||
function_param::FunctionParam,
|
function_param::FunctionParam,
|
||||||
|
source_range::SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Apply a function to each element of an array.
|
/// Apply a function to each element of an array.
|
||||||
|
@ -16,18 +16,16 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::args::Arg;
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{ExecState, Geometries, Geometry, KclValue, Point2d, Point3d, Sketch, SketchSet, Solid, SolidSet},
|
||||||
ExecState, Geometries, Geometry, KclValue, Point2d, Point3d, Sketch, SketchSet, Solid, SolidSet, SourceRange,
|
|
||||||
},
|
|
||||||
function_param::FunctionParam,
|
function_param::FunctionParam,
|
||||||
kcl_value::KclObjectFields,
|
kcl_value::KclObjectFields,
|
||||||
std::Args,
|
std::Args,
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::args::Arg;
|
|
||||||
|
|
||||||
const MUST_HAVE_ONE_INSTANCE: &str = "There must be at least 1 instance of your geometry";
|
const MUST_HAVE_ONE_INSTANCE: &str = "There must be at least 1 instance of your geometry";
|
||||||
|
|
||||||
/// Data for a linear pattern on a 2D sketch.
|
/// Data for a linear pattern on a 2D sketch.
|
||||||
|
@ -12,8 +12,8 @@ use parse_display::{Display, FromStr};
|
|||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::ast::types::TagNode;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
ast::types::TagNode,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{
|
||||||
BasePath, ExecState, Face, GeoMeta, KclValue, Path, Plane, Point2d, Point3d, Sketch, SketchSet, SketchSurface,
|
BasePath, ExecState, Face, GeoMeta, KclValue, Path, Plane, Point2d, Point3d, Sketch, SketchSet, SketchSurface,
|
||||||
@ -2250,7 +2250,10 @@ mod tests {
|
|||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::{executor::TagIdentifier, std::sketch::calculate_circle_center, std::sketch::PlaneData};
|
use crate::{
|
||||||
|
executor::TagIdentifier,
|
||||||
|
std::sketch::{calculate_circle_center, PlaneData},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deserialize_plane_data() {
|
fn test_deserialize_plane_data() {
|
||||||
|
@ -4,7 +4,8 @@ use kittycad_modeling_cmds::shared::Angle;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{Point2d, SourceRange},
|
executor::Point2d,
|
||||||
|
source_range::SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Get the angle between these points
|
/// Get the angle between these points
|
||||||
@ -234,7 +235,7 @@ mod tests {
|
|||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::{get_x_component, get_y_component, Angle};
|
use super::{get_x_component, get_y_component, Angle};
|
||||||
use crate::executor::SourceRange;
|
use crate::SourceRange;
|
||||||
|
|
||||||
static EACH_QUAD: [(i32, [i32; 2]); 12] = [
|
static EACH_QUAD: [(i32, [i32; 2]); 12] = [
|
||||||
(-315, [1, 1]),
|
(-315, [1, 1]),
|
||||||
@ -354,7 +355,7 @@ mod tests {
|
|||||||
super::Point2d { x: -1.0, y: 1.0 },
|
super::Point2d { x: -1.0, y: 1.0 },
|
||||||
super::Point2d { x: -1.0, y: 0.0 },
|
super::Point2d { x: -1.0, y: 0.0 },
|
||||||
1.0,
|
1.0,
|
||||||
SourceRange(Default::default()),
|
SourceRange::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(angle_start.to_degrees().round(), 0.0);
|
assert_eq!(angle_start.to_degrees().round(), 0.0);
|
||||||
@ -365,7 +366,7 @@ mod tests {
|
|||||||
super::Point2d { x: -2.0, y: 0.0 },
|
super::Point2d { x: -2.0, y: 0.0 },
|
||||||
super::Point2d { x: -1.0, y: 0.0 },
|
super::Point2d { x: -1.0, y: 0.0 },
|
||||||
1.0,
|
1.0,
|
||||||
SourceRange(Default::default()),
|
SourceRange::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(angle_start.to_degrees().round(), 0.0);
|
assert_eq!(angle_start.to_degrees().round(), 0.0);
|
||||||
@ -376,7 +377,7 @@ mod tests {
|
|||||||
super::Point2d { x: -20.0, y: 0.0 },
|
super::Point2d { x: -20.0, y: 0.0 },
|
||||||
super::Point2d { x: -10.0, y: 0.0 },
|
super::Point2d { x: -10.0, y: 0.0 },
|
||||||
10.0,
|
10.0,
|
||||||
SourceRange(Default::default()),
|
SourceRange::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(angle_start.to_degrees().round(), 0.0);
|
assert_eq!(angle_start.to_degrees().round(), 0.0);
|
||||||
@ -387,7 +388,7 @@ mod tests {
|
|||||||
super::Point2d { x: 5.0, y: 5.0 },
|
super::Point2d { x: 5.0, y: 5.0 },
|
||||||
super::Point2d { x: 10.0, y: -10.0 },
|
super::Point2d { x: 10.0, y: -10.0 },
|
||||||
10.0,
|
10.0,
|
||||||
SourceRange(Default::default()),
|
SourceRange::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
|
@ -8,9 +8,9 @@ use tower_lsp::lsp_types::SemanticTokenType;
|
|||||||
use winnow::{error::ParseError, stream::ContainsToken};
|
use winnow::{error::ParseError, stream::ContainsToken};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{ItemVisibility, ModuleId, VariableKind},
|
ast::types::{ItemVisibility, VariableKind},
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
executor::SourceRange,
|
source_range::{ModuleId, SourceRange},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod tokeniser;
|
mod tokeniser;
|
||||||
@ -22,7 +22,6 @@ pub(crate) use tokeniser::RESERVED_WORDS;
|
|||||||
|
|
||||||
/// The types of tokens.
|
/// The types of tokens.
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize, JsonSchema, FromStr, Display)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize, JsonSchema, FromStr, Display)]
|
||||||
#[cfg_attr(feature = "pyo3", pyo3::pyclass(eq, eq_int))]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[display(style = "camelCase")]
|
#[display(style = "camelCase")]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
@ -66,6 +65,8 @@ pub enum TokenType {
|
|||||||
Unknown,
|
Unknown,
|
||||||
/// The ? symbol, used for optional values.
|
/// The ? symbol, used for optional values.
|
||||||
QuestionMark,
|
QuestionMark,
|
||||||
|
/// The @ symbol.
|
||||||
|
At,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Most KCL tokens correspond to LSP semantic tokens (but not all).
|
/// Most KCL tokens correspond to LSP semantic tokens (but not all).
|
||||||
@ -92,6 +93,7 @@ impl TryFrom<TokenType> for SemanticTokenType {
|
|||||||
| TokenType::DoublePeriod
|
| TokenType::DoublePeriod
|
||||||
| TokenType::Hash
|
| TokenType::Hash
|
||||||
| TokenType::Dollar
|
| TokenType::Dollar
|
||||||
|
| TokenType::At
|
||||||
| TokenType::Unknown => {
|
| TokenType::Unknown => {
|
||||||
anyhow::bail!("unsupported token type: {:?}", token_type)
|
anyhow::bail!("unsupported token type: {:?}", token_type)
|
||||||
}
|
}
|
||||||
@ -156,7 +158,6 @@ impl TokenType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)]
|
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)]
|
||||||
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
|
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub token_type: TokenType,
|
pub token_type: TokenType,
|
||||||
@ -204,7 +205,7 @@ impl Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_source_range(&self) -> SourceRange {
|
pub fn as_source_range(&self) -> SourceRange {
|
||||||
SourceRange([self.start, self.end, self.module_id.as_usize()])
|
SourceRange::new(self.start, self.end, self.module_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_source_ranges(&self) -> Vec<SourceRange> {
|
pub fn as_source_ranges(&self) -> Vec<SourceRange> {
|
||||||
@ -238,13 +239,13 @@ impl Token {
|
|||||||
|
|
||||||
impl From<Token> for SourceRange {
|
impl From<Token> for SourceRange {
|
||||||
fn from(token: Token) -> Self {
|
fn from(token: Token) -> Self {
|
||||||
Self([token.start, token.end, token.module_id.as_usize()])
|
Self::new(token.start, token.end, token.module_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Token> for SourceRange {
|
impl From<&Token> for SourceRange {
|
||||||
fn from(token: &Token) -> Self {
|
fn from(token: &Token) -> Self {
|
||||||
Self([token.start, token.end, token.module_id.as_usize()])
|
Self::new(token.start, token.end, token.module_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +265,7 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
|
|||||||
// the end of input (input.len()) on eof errors.
|
// the end of input (input.len()) on eof errors.
|
||||||
|
|
||||||
return KclError::Lexical(crate::errors::KclErrorDetails {
|
return KclError::Lexical(crate::errors::KclErrorDetails {
|
||||||
source_ranges: vec![SourceRange([offset, offset, module_id.as_usize()])],
|
source_ranges: vec![SourceRange::new(offset, offset, module_id)],
|
||||||
message: "unexpected EOF while parsing".to_string(),
|
message: "unexpected EOF while parsing".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -275,7 +276,7 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
|
|||||||
// 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 {
|
KclError::Lexical(crate::errors::KclErrorDetails {
|
||||||
source_ranges: vec![SourceRange([offset, offset + 1, module_id.as_usize()])],
|
source_ranges: vec![SourceRange::new(offset, offset + 1, module_id)],
|
||||||
message: format!("found unknown token '{}'", bad_token),
|
message: format!("found unknown token '{}'", bad_token),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ use winnow::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::ModuleId,
|
source_range::ModuleId,
|
||||||
token::{Token, TokenType},
|
token::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,6 +92,7 @@ pub fn token(i: &mut Input<'_>) -> PResult<Token> {
|
|||||||
'}' | ')' | ']' => brace_end,
|
'}' | ')' | ']' => brace_end,
|
||||||
',' => comma,
|
',' => comma,
|
||||||
'?' => question_mark,
|
'?' => question_mark,
|
||||||
|
'@' => at,
|
||||||
'0'..='9' => number,
|
'0'..='9' => number,
|
||||||
':' => colon,
|
':' => colon,
|
||||||
'.' => alt((number, double_period, period)),
|
'.' => alt((number, double_period, period)),
|
||||||
@ -268,6 +269,16 @@ fn question_mark(i: &mut Input<'_>) -> PResult<Token> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn at(i: &mut Input<'_>) -> PResult<Token> {
|
||||||
|
let (value, range) = '@'.with_span().parse_next(i)?;
|
||||||
|
Ok(Token::from_range(
|
||||||
|
range,
|
||||||
|
i.state.module_id,
|
||||||
|
TokenType::At,
|
||||||
|
value.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn colon(i: &mut Input<'_>) -> PResult<Token> {
|
fn colon(i: &mut Input<'_>) -> PResult<Token> {
|
||||||
let (value, range) = ':'.with_span().parse_next(i)?;
|
let (value, range) = ':'.with_span().parse_next(i)?;
|
||||||
Ok(Token::from_range(
|
Ok(Token::from_range(
|
||||||
|
@ -3,9 +3,10 @@ use std::fmt::Write;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{
|
ast::types::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression,
|
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression,
|
||||||
Expr, FnArgType, FormatOptions, FunctionExpression, IfExpression, ImportStatement, ItemVisibility, Literal,
|
CallExpressionKw, Expr, FnArgType, FormatOptions, FunctionExpression, IfExpression, ImportStatement,
|
||||||
LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, NonCodeValue, ObjectExpression,
|
ItemVisibility, LabeledArg, Literal, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node,
|
||||||
Parameter, PipeExpression, Program, TagDeclarator, UnaryExpression, VariableDeclaration, VariableKind,
|
NonCodeValue, ObjectExpression, Parameter, PipeExpression, Program, TagDeclarator, UnaryExpression,
|
||||||
|
VariableDeclaration, VariableKind,
|
||||||
},
|
},
|
||||||
parser::PIPE_OPERATOR,
|
parser::PIPE_OPERATOR,
|
||||||
};
|
};
|
||||||
@ -166,6 +167,7 @@ impl Expr {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
Expr::CallExpression(call_exp) => call_exp.recast(options, indentation_level, ctxt),
|
Expr::CallExpression(call_exp) => call_exp.recast(options, indentation_level, ctxt),
|
||||||
|
Expr::CallExpressionKw(call_exp) => call_exp.recast(options, indentation_level, ctxt),
|
||||||
Expr::Identifier(ident) => ident.name.to_string(),
|
Expr::Identifier(ident) => ident.name.to_string(),
|
||||||
Expr::TagDeclarator(tag) => tag.recast(),
|
Expr::TagDeclarator(tag) => tag.recast(),
|
||||||
Expr::PipeExpression(pipe_exp) => pipe_exp.recast(options, indentation_level),
|
Expr::PipeExpression(pipe_exp) => pipe_exp.recast(options, indentation_level),
|
||||||
@ -188,6 +190,9 @@ impl BinaryPart {
|
|||||||
BinaryPart::CallExpression(call_expression) => {
|
BinaryPart::CallExpression(call_expression) => {
|
||||||
call_expression.recast(options, indentation_level, ExprContext::Other)
|
call_expression.recast(options, indentation_level, ExprContext::Other)
|
||||||
}
|
}
|
||||||
|
BinaryPart::CallExpressionKw(call_expression) => {
|
||||||
|
call_expression.recast(options, indentation_level, ExprContext::Other)
|
||||||
|
}
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.recast(options),
|
BinaryPart::UnaryExpression(unary_expression) => unary_expression.recast(options),
|
||||||
BinaryPart::MemberExpression(member_expression) => member_expression.recast(),
|
BinaryPart::MemberExpression(member_expression) => member_expression.recast(),
|
||||||
BinaryPart::IfExpression(e) => e.recast(options, indentation_level, ExprContext::Other),
|
BinaryPart::IfExpression(e) => e.recast(options, indentation_level, ExprContext::Other),
|
||||||
@ -214,6 +219,37 @@ impl CallExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CallExpressionKw {
|
||||||
|
fn recast(&self, options: &FormatOptions, indentation_level: usize, ctxt: ExprContext) -> String {
|
||||||
|
let indent = if ctxt == ExprContext::Pipe {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
options.get_indentation(indentation_level)
|
||||||
|
};
|
||||||
|
let name = &self.callee.name;
|
||||||
|
let mut arg_list = if let Some(first_arg) = &self.unlabeled {
|
||||||
|
vec![first_arg.recast(options, indentation_level, ctxt)]
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
arg_list.extend(
|
||||||
|
self.arguments
|
||||||
|
.iter()
|
||||||
|
.map(|arg| arg.recast(options, indentation_level, ctxt)),
|
||||||
|
);
|
||||||
|
let args = arg_list.join(", ");
|
||||||
|
format!("{indent}{name}({args})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LabeledArg {
|
||||||
|
fn recast(&self, options: &FormatOptions, indentation_level: usize, ctxt: ExprContext) -> String {
|
||||||
|
let label = &self.label.name;
|
||||||
|
let arg = self.arg.recast(options, indentation_level, ctxt);
|
||||||
|
format!("{label}: {arg}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl VariableDeclaration {
|
impl VariableDeclaration {
|
||||||
pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
|
pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
|
||||||
let indentation = options.get_indentation(indentation_level);
|
let indentation = options.get_indentation(indentation_level);
|
||||||
@ -345,6 +381,7 @@ fn expr_is_trivial(expr: &Expr) -> bool {
|
|||||||
Expr::BinaryExpression(_)
|
Expr::BinaryExpression(_)
|
||||||
| Expr::FunctionExpression(_)
|
| Expr::FunctionExpression(_)
|
||||||
| Expr::CallExpression(_)
|
| Expr::CallExpression(_)
|
||||||
|
| Expr::CallExpressionKw(_)
|
||||||
| Expr::PipeExpression(_)
|
| Expr::PipeExpression(_)
|
||||||
| Expr::ArrayExpression(_)
|
| Expr::ArrayExpression(_)
|
||||||
| Expr::ArrayRangeExpression(_)
|
| Expr::ArrayRangeExpression(_)
|
||||||
@ -504,6 +541,7 @@ impl UnaryExpression {
|
|||||||
| BinaryPart::Identifier(_)
|
| BinaryPart::Identifier(_)
|
||||||
| BinaryPart::MemberExpression(_)
|
| BinaryPart::MemberExpression(_)
|
||||||
| BinaryPart::IfExpression(_)
|
| BinaryPart::IfExpression(_)
|
||||||
|
| BinaryPart::CallExpressionKw(_)
|
||||||
| BinaryPart::CallExpression(_) => {
|
| BinaryPart::CallExpression(_) => {
|
||||||
format!("{}{}", &self.operator, self.argument.recast(options, 0))
|
format!("{}{}", &self.operator, self.argument.recast(options, 0))
|
||||||
}
|
}
|
||||||
@ -645,7 +683,7 @@ mod tests {
|
|||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast::types::{FormatOptions, ModuleId};
|
use crate::{ast::types::FormatOptions, source_range::ModuleId};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_recast_if_else_if_same() {
|
fn test_recast_if_else_if_same() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{self, NodeRef},
|
ast::types::{self, NodeRef},
|
||||||
executor::SourceRange,
|
source_range::SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The "Node" type wraps all the AST elements we're able to find in a KCL
|
/// The "Node" type wraps all the AST elements we're able to find in a KCL
|
||||||
@ -22,6 +22,7 @@ pub enum Node<'a> {
|
|||||||
BinaryExpression(NodeRef<'a, types::BinaryExpression>),
|
BinaryExpression(NodeRef<'a, types::BinaryExpression>),
|
||||||
FunctionExpression(NodeRef<'a, types::FunctionExpression>),
|
FunctionExpression(NodeRef<'a, types::FunctionExpression>),
|
||||||
CallExpression(NodeRef<'a, types::CallExpression>),
|
CallExpression(NodeRef<'a, types::CallExpression>),
|
||||||
|
CallExpressionKw(NodeRef<'a, types::CallExpressionKw>),
|
||||||
PipeExpression(NodeRef<'a, types::PipeExpression>),
|
PipeExpression(NodeRef<'a, types::PipeExpression>),
|
||||||
PipeSubstitution(NodeRef<'a, types::PipeSubstitution>),
|
PipeSubstitution(NodeRef<'a, types::PipeSubstitution>),
|
||||||
ArrayExpression(NodeRef<'a, types::ArrayExpression>),
|
ArrayExpression(NodeRef<'a, types::ArrayExpression>),
|
||||||
@ -54,6 +55,7 @@ impl From<&Node<'_>> for SourceRange {
|
|||||||
Node::BinaryExpression(n) => SourceRange::from(*n),
|
Node::BinaryExpression(n) => SourceRange::from(*n),
|
||||||
Node::FunctionExpression(n) => SourceRange::from(*n),
|
Node::FunctionExpression(n) => SourceRange::from(*n),
|
||||||
Node::CallExpression(n) => SourceRange::from(*n),
|
Node::CallExpression(n) => SourceRange::from(*n),
|
||||||
|
Node::CallExpressionKw(n) => SourceRange::from(*n),
|
||||||
Node::PipeExpression(n) => SourceRange::from(*n),
|
Node::PipeExpression(n) => SourceRange::from(*n),
|
||||||
Node::PipeSubstitution(n) => SourceRange::from(*n),
|
Node::PipeSubstitution(n) => SourceRange::from(*n),
|
||||||
Node::ArrayExpression(n) => SourceRange::from(*n),
|
Node::ArrayExpression(n) => SourceRange::from(*n),
|
||||||
@ -63,9 +65,9 @@ impl From<&Node<'_>> for SourceRange {
|
|||||||
Node::UnaryExpression(n) => SourceRange::from(*n),
|
Node::UnaryExpression(n) => SourceRange::from(*n),
|
||||||
Node::Parameter(p) => SourceRange::from(&p.identifier),
|
Node::Parameter(p) => SourceRange::from(&p.identifier),
|
||||||
Node::ObjectProperty(n) => SourceRange::from(*n),
|
Node::ObjectProperty(n) => SourceRange::from(*n),
|
||||||
Node::MemberObject(m) => SourceRange([m.start(), m.end(), m.module_id().as_usize()]),
|
Node::MemberObject(m) => SourceRange::new(m.start(), m.end(), m.module_id()),
|
||||||
Node::IfExpression(n) => SourceRange::from(*n),
|
Node::IfExpression(n) => SourceRange::from(*n),
|
||||||
Node::LiteralIdentifier(l) => SourceRange([l.start(), l.end(), l.module_id().as_usize()]),
|
Node::LiteralIdentifier(l) => SourceRange::new(l.start(), l.end(), l.module_id()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,6 +104,7 @@ impl_from!(Node, Identifier);
|
|||||||
impl_from!(Node, BinaryExpression);
|
impl_from!(Node, BinaryExpression);
|
||||||
impl_from!(Node, FunctionExpression);
|
impl_from!(Node, FunctionExpression);
|
||||||
impl_from!(Node, CallExpression);
|
impl_from!(Node, CallExpression);
|
||||||
|
impl_from!(Node, CallExpressionKw);
|
||||||
impl_from!(Node, PipeExpression);
|
impl_from!(Node, PipeExpression);
|
||||||
impl_from!(Node, PipeSubstitution);
|
impl_from!(Node, PipeSubstitution);
|
||||||
impl_from!(Node, ArrayExpression);
|
impl_from!(Node, ArrayExpression);
|
||||||
|
@ -103,6 +103,7 @@ where
|
|||||||
BinaryPart::Identifier(id) => f.walk(id.as_ref().into()),
|
BinaryPart::Identifier(id) => f.walk(id.as_ref().into()),
|
||||||
BinaryPart::BinaryExpression(be) => f.walk(be.as_ref().into()),
|
BinaryPart::BinaryExpression(be) => f.walk(be.as_ref().into()),
|
||||||
BinaryPart::CallExpression(ce) => f.walk(ce.as_ref().into()),
|
BinaryPart::CallExpression(ce) => f.walk(ce.as_ref().into()),
|
||||||
|
BinaryPart::CallExpressionKw(ce) => f.walk(ce.as_ref().into()),
|
||||||
BinaryPart::UnaryExpression(ue) => walk_unary_expression(ue, f),
|
BinaryPart::UnaryExpression(ue) => walk_unary_expression(ue, f),
|
||||||
BinaryPart::MemberExpression(me) => walk_member_expression(me, f),
|
BinaryPart::MemberExpression(me) => walk_member_expression(me, f),
|
||||||
BinaryPart::IfExpression(e) => walk_if_expression(e, f),
|
BinaryPart::IfExpression(e) => walk_if_expression(e, f),
|
||||||
@ -159,6 +160,26 @@ where
|
|||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
Expr::CallExpressionKw(ce) => {
|
||||||
|
if !f.walk(ce.as_ref().into())? {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.walk((&ce.callee).into())? {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
if let Some(ref e) = ce.unlabeled {
|
||||||
|
if !walk_value::<WalkT>(e, f)? {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for e in &ce.arguments {
|
||||||
|
if !walk_value::<WalkT>(&e.arg, f)? {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
Expr::PipeExpression(pe) => {
|
Expr::PipeExpression(pe) => {
|
||||||
if !f.walk(pe.as_ref().into())? {
|
if !f.walk(pe.as_ref().into())? {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
Reference in New Issue
Block a user