Compare commits

...

18 Commits

Author SHA1 Message Date
534d5431d4 Only run regex once per token 2023-09-21 16:49:34 -05:00
911c43af50 Bump phonenumber from 0.3.2+8.13.9 to 0.3.3+8.13.9 in /src-tauri (#687)
Bumps [phonenumber](https://github.com/whisperfish/rust-phonenumber) from 0.3.2+8.13.9 to 0.3.3+8.13.9.
- [Commits](https://github.com/whisperfish/rust-phonenumber/commits)

---
updated-dependencies:
- dependency-name: phonenumber
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 15:02:37 -05:00
ab4e04f6c2 Bump phonenumber from 0.3.2+8.13.9 to 0.3.3+8.13.9 in /src/wasm-lib (#685)
Bumps [phonenumber](https://github.com/whisperfish/rust-phonenumber) from 0.3.2+8.13.9 to 0.3.3+8.13.9.
- [Commits](https://github.com/whisperfish/rust-phonenumber/commits)

---
updated-dependencies:
- dependency-name: phonenumber
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 15:02:23 -05:00
94aef05f74 Bump phonenumber from 0.3.2+8.13.9 to 0.3.3+8.13.9 in /src/wasm-lib/kcl/fuzz (#686)
Bump phonenumber in /src/wasm-lib/kcl/fuzz

Bumps [phonenumber](https://github.com/whisperfish/rust-phonenumber) from 0.3.2+8.13.9 to 0.3.3+8.13.9.
- [Commits](https://github.com/whisperfish/rust-phonenumber/commits)

---
updated-dependencies:
- dependency-name: phonenumber
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 15:02:10 -05:00
d820cf2446 Tokenizer is accidentally quadratic (#689)
* Add comments and rename a function

* Typo: paran -> paren

* Use bytes, not string, for the tokenizer

* Fix typo
2023-09-21 14:18:42 -05:00
0c724c4971 Start to restructure the Engine's connection to the backend (#674)
* Start to restructure the Engine's connectio to the backend

1) Add in a tearDown stub for when the Engine is torn down. This is now
   distinct from a 'close', which will not stop connect from trying
   again. Running tearDown will mark the connection to not be retried
   and close active connections.

2) Move the retry logic out of connect and into the constructor. It will
   attempt to reconnect at the same rate as we had previously.

3) The timeout will now only close the connection, not restart it.

Signed-off-by: Paul Tagliamonte <paul@kittycad.io>

* Don't continue on dead conn & setTimeout on init only

* Clean up extra setTimeout

* Keep track of connection timeouts and clear on close

* Fix tsc by defining Timeout

Signed-off-by: Paul Tagliamonte <paul@kittycad.io>

* appease the format gods

---------

Signed-off-by: Paul Tagliamonte <paul@kittycad.io>
Co-authored-by: Adam Sunderland <adam@kittycad.io>
2023-09-21 12:07:47 -04:00
b54ac4a694 improve getNodePathFromSourceRange and therefore the ast explorer aswell (#683)
improve getNodePathFromSourceRange and therefore the ast explorer as well
2023-09-21 05:40:41 +00:00
27227092b1 app stuck on blur when engine errors (#682)
* temp fix for when engine returns error

* don't add extrued to show function
2023-09-21 04:32:47 +00:00
04e1b92a5b Add a benchmark for parsing pipes-on-pipes (#678) 2023-09-21 03:13:07 +00:00
0553cd4621 tests for big files (#675)
* shit;

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cleanup

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* u[dates;

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* still ignore the big one

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* Add big kitt SVG to benchmarks

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Adam Chalmers <adam.s.chalmers@gmail.com>
2023-09-20 19:35:37 -07:00
61a0c88af4 Add IDE dirs to .gitignore (#676) 2023-09-21 02:03:09 +00:00
d5b0544437 Bump tauri-plugin-fs-extra from 5b814f5 to 76832e6 in /src-tauri (#657)
Bumps [tauri-plugin-fs-extra](https://github.com/tauri-apps/plugins-workspace) from `5b814f5` to `76832e6`.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](5b814f56e6...76832e60bf)

---
updated-dependencies:
- dependency-name: tauri-plugin-fs-extra
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-20 18:47:38 -07:00
6cc8af5c23 make stdlib functions async (#672)
* wip

Signed-off-by: Jess Frazelle <github@jessfraz.com>

updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

closer

Signed-off-by: Jess Frazelle <github@jessfraz.com>

fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* closer

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* closer

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* compiles

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* connection

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix wasm

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* timeout

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* remove the drop

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* drop handle

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2023-09-20 18:27:08 -07:00
888104080e bump v0.9.0 (#673) 2023-09-21 10:38:40 +10:00
b6769889e3 Handle relative paths at kcl level (#506)
* handle relative paths at kcl level

* fmt

* update kittycad

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* bump

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2023-09-21 10:36:26 +10:00
a32258dac4 Engine manager can be cloned (#671) 2023-09-20 16:22:47 -07:00
18dbbad244 Use an actor to manage the Tokio engine connection (#669)
* Use an actor to manage the Tokio engine connection

This means EngineManager trait's methods take &self not &mut self, and the tokio implementation can be cloned.

* Clean up code
2023-09-20 16:59:03 -05:00
b67c16cc9d Benchmark for KCL parser (#664)
* KCL benchmarks

* CI for benchmarks

* More specific name for benchmark

* Benchmark the right directory

* Format
2023-09-20 13:15:28 -05:00
43 changed files with 1766 additions and 960 deletions

View File

@ -54,4 +54,4 @@ jobs:
- name: Run clippy
run: |
cd "${{ matrix.dir }}"
cargo clippy --all --tests -- -D warnings
cargo clippy --all --tests --benches -- -D warnings

37
.github/workflows/cargo-criterion.yml vendored Normal file
View File

@ -0,0 +1,37 @@
on:
push:
branches:
- main
paths:
- '**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-criterion.yml
pull_request:
paths:
- '**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-criterion.yml
workflow_dispatch:
permissions: read-all
name: cargo criterion
jobs:
cargocriterion:
name: cargo criterion
runs-on: ubuntu-latest-8-cores
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
cargo install cargo-criterion
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: Benchmark kcl library
shell: bash
run: |-
cd src/wasm-lib/kcl; cargo criterion

View File

@ -58,4 +58,5 @@ jobs:
cargo nextest run --workspace --no-fail-fast -P ci
env:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
RUST_MIN_STACK: 10485760000

5
.gitignore vendored
View File

@ -22,6 +22,11 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
.idea
.vscode
src/wasm-lib/.idea
src/wasm-lib/.vscode
# rust
src/wasm-lib/target
src/wasm-lib/bindings

View File

@ -1,6 +1,6 @@
{
"name": "untitled-app",
"version": "0.8.2",
"version": "0.9.0",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.9.0",
@ -10,7 +10,7 @@
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.13",
"@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "^0.0.37",
"@kittycad/lib": "^0.0.38",
"@lezer/javascript": "^1.4.7",
"@open-rpc/client-js": "^1.8.1",
"@react-hook/resize-observer": "^1.2.6",
@ -65,7 +65,7 @@
"pretest": "yarn remove-importmeta",
"test": "vitest --mode development",
"test:nowatch": "vitest run --mode development",
"test:rust": "(cd src/wasm-lib && cargo test --all && cargo clippy --all --tests)",
"test:rust": "(cd src/wasm-lib && cargo test --all && cargo clippy --all --tests --benches)",
"test:cov": "vitest run --coverage --mode development",
"simpleserver:ci": "yarn pretest && http-server ./public --cors -p 3000 &",
"simpleserver": "yarn pretest && http-server ./public --cors -p 3000",

29
src-tauri/Cargo.lock generated
View File

@ -2410,9 +2410,9 @@ dependencies = [
[[package]]
name = "phonenumber"
version = "0.3.2+8.13.9"
version = "0.3.3+8.13.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34749f64ea9d76f10cdc8a859588b57775f59177c7dd91f744d620bd62982d6f"
checksum = "635f3e6288e4f01c049d89332a031bd74f25d64b6fb94703ca966e819488cd06"
dependencies = [
"bincode",
"either",
@ -2425,6 +2425,7 @@ dependencies = [
"regex-cache",
"serde",
"serde_derive",
"strum",
"thiserror",
]
@ -3458,6 +3459,28 @@ dependencies = [
"syn 2.0.33",
]
[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"rustversion",
"syn 1.0.109",
]
[[package]]
name = "syn"
version = "1.0.109"
@ -3719,7 +3742,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs-extra"
version = "0.0.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#5b814f56e6368fdec46c4ddb04a07e0923ff995a"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#76832e60bfba44c24d6af8a5099be123886ba63d"
dependencies = [
"log",
"serde",

View File

@ -8,7 +8,7 @@
},
"package": {
"productName": "kittycad-modeling",
"version": "0.8.2"
"version": "0.9.0"
},
"tauri": {
"allowlist": {

View File

@ -50,7 +50,7 @@ export const MemoryPanel = ({
export const processMemory = (programMemory: ProgramMemory) => {
const processedMemory: any = {}
Object.keys(programMemory.root).forEach((key) => {
Object.keys(programMemory?.root || {}).forEach((key) => {
const val = programMemory.root[key]
if (typeof val.value !== 'function') {
if (val.type === 'SketchGroup') {

View File

@ -1,6 +1,7 @@
import { getNodePathFromSourceRange, getNodeFromPath } from './queryAst'
import { parser_wasm } from './abstractSyntaxTree'
import { initPromise } from './rust'
import { Identifier } from './abstractSyntaxTreeTypes'
beforeAll(() => initPromise)
@ -27,4 +28,81 @@ const sk3 = startSketchAt([0, 0])
expect([node.start, node.end]).toEqual(sourceRange)
expect(node.type).toBe('CallExpression')
})
it('gets path right for function definition params', () => {
const code = `fn cube = (pos, scale) => {
const sg = startSketchAt(pos)
|> line([0, scale], %)
|> line([scale, 0], %)
|> line([0, -scale], %)
return sg
}
const b1 = cube([0,0], 10)`
const subStr = 'pos, scale'
const subStrIndex = code.indexOf(subStr)
const sourceRange: [number, number] = [
subStrIndex,
subStrIndex + 'pos'.length,
]
const ast = parser_wasm(code)
const nodePath = getNodePathFromSourceRange(ast, sourceRange)
const node = getNodeFromPath<Identifier>(ast, nodePath).node
expect(nodePath).toEqual([
['body', ''],
[0, 'index'],
['declarations', 'VariableDeclaration'],
[0, 'index'],
['init', ''],
['params', 'FunctionExpression'],
[0, 'index'],
])
expect(node.type).toBe('Identifier')
expect(node.name).toBe('pos')
})
it('gets path right for deep within function definition body', () => {
const code = `fn cube = (pos, scale) => {
const sg = startSketchAt(pos)
|> line([0, scale], %)
|> line([scale, 0], %)
|> line([0, -scale], %)
return sg
}
const b1 = cube([0,0], 10)`
const subStr = 'scale, 0'
const subStrIndex = code.indexOf(subStr)
const sourceRange: [number, number] = [
subStrIndex,
subStrIndex + 'scale'.length,
]
const ast = parser_wasm(code)
const nodePath = getNodePathFromSourceRange(ast, sourceRange)
const node = getNodeFromPath<Identifier>(ast, nodePath).node
expect(nodePath).toEqual([
['body', ''],
[0, 'index'],
['declarations', 'VariableDeclaration'],
[0, 'index'],
['init', ''],
['body', 'FunctionExpression'],
['body', 'FunctionExpression'],
[0, 'index'],
['declarations', 'VariableDeclaration'],
[0, 'index'],
['init', ''],
['body', 'PipeExpression'],
[2, 'index'],
['arguments', 'CallExpression'],
[0, 'index'],
['elements', 'ArrayExpression'],
[0, 'index'],
])
expect(node.type).toBe('Identifier')
expect(node.name).toBe('scale')
})
})

View File

@ -321,7 +321,7 @@ export function extrudeSketch(
[0, 'index'],
]
return {
modifiedAst: addToShow(_node, name),
modifiedAst: node,
pathToNode: [...pathToNode.slice(0, -1), [showCallIndex, 'index']],
pathToExtrudeArg,
}

View File

@ -239,7 +239,29 @@ function moreNodePathFromSourceRange(
}
return path
}
console.error('not implemented')
if (_node.type === 'FunctionExpression' && isInRange) {
for (let i = 0; i < _node.params.length; i++) {
const param = _node.params[i]
if (param.start <= start && param.end >= end) {
path.push(['params', 'FunctionExpression'])
path.push([i, 'index'])
return moreNodePathFromSourceRange(param, sourceRange, path)
}
}
if (_node.body.start <= start && _node.body.end >= end) {
path.push(['body', 'FunctionExpression'])
const fnBody = _node.body.body
for (let i = 0; i < fnBody.length; i++) {
const statement = fnBody[i]
if (statement.start <= start && statement.end >= end) {
path.push(['body', 'FunctionExpression'])
path.push([i, 'index'])
return moreNodePathFromSourceRange(statement, sourceRange, path)
}
}
}
}
console.error('not implemented: ' + node.type)
return path
}

View File

@ -23,6 +23,10 @@ interface ResultCommand extends CommandInfo {
data: any
raw: WebSocketResponse
}
interface FailedCommand extends CommandInfo {
type: 'failed'
errors: Models['FailureWebSocketResponse_type']['errors']
}
interface PendingCommand extends CommandInfo {
type: 'pending'
promise: Promise<any>
@ -30,7 +34,7 @@ interface PendingCommand extends CommandInfo {
}
export interface ArtifactMap {
[key: string]: ResultCommand | PendingCommand
[key: string]: ResultCommand | PendingCommand | FailedCommand
}
export interface SourceRangeMap {
[key: string]: SourceRange
@ -41,6 +45,11 @@ interface NewTrackArgs {
mediaStream: MediaStream
}
// This looks funny, I know. This is needed because node and the browser
// disagree as to the type. In a browser it's a number, but in node it's a
// "Timeout".
type Timeout = ReturnType<typeof setTimeout>
type ClientMetrics = Models['ClientMetrics_type']
// EngineConnection encapsulates the connection(s) to the Engine
@ -52,6 +61,9 @@ export class EngineConnection {
unreliableDataChannel?: RTCDataChannel
private ready: boolean
private connecting: boolean
private dead: boolean
private failedConnTimeout: Timeout | null
readonly url: string
private readonly token?: string
@ -87,6 +99,9 @@ export class EngineConnection {
this.url = url
this.token = token
this.ready = false
this.connecting = false
this.dead = false
this.failedConnTimeout = null
this.onWebsocketOpen = onWebsocketOpen
this.onDataChannelOpen = onDataChannelOpen
this.onEngineConnectionOpen = onEngineConnectionOpen
@ -97,7 +112,10 @@ export class EngineConnection {
// TODO(paultag): This ought to be tweakable.
const pingIntervalMs = 10000
setInterval(() => {
let pingInterval = setInterval(() => {
if (this.dead) {
clearInterval(pingInterval)
}
if (this.isReady()) {
// When we're online, every 10 seconds, we'll attempt to put a 'ping'
// command through the WebSocket connection. This will help both ends
@ -106,6 +124,24 @@ export class EngineConnection {
this.send({ type: 'ping' })
}
}, pingIntervalMs)
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
let connectInterval = setInterval(() => {
if (this.dead) {
clearInterval(connectInterval)
return
}
if (this.isReady()) {
return
}
console.log('connecting via retry')
this.connect()
}, connectionTimeoutMs)
}
// isConnecting will return true when connect has been called, but the full
// WebRTC is not online.
isConnecting() {
return this.connecting
}
// isReady will return true only when the WebRTC *and* WebSocket connection
// are connected. During setup, the WebSocket connection comes online first,
@ -114,6 +150,10 @@ export class EngineConnection {
isReady() {
return this.ready
}
tearDown() {
this.dead = true
this.close()
}
// shouldTrace will return true when Sentry should be used to instrument
// the Engine.
shouldTrace() {
@ -125,8 +165,10 @@ export class EngineConnection {
// This will attempt the full handshake, and retry if the connection
// did not establish.
connect() {
// TODO(paultag): make this safe to call multiple times, and figure out
// when a connection is in progress (state: connecting or something).
console.log('connect was called')
if (this.isConnecting() || this.isReady()) {
return
}
// Information on the connect transaction
@ -358,20 +400,6 @@ export class EngineConnection {
})
})
}
// TODO(paultag): This ought to be both controllable, as well as something
// like exponential backoff to have some grace on the backend, as well as
// fix responsiveness for clients that had a weird network hiccup.
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
setTimeout(() => {
if (this.isReady()) {
return
}
console.log('engine connection timeout on connection, retrying')
this.close()
this.connect()
}, connectionTimeoutMs)
})
this.pc.addEventListener('track', (event) => {
@ -461,6 +489,7 @@ export class EngineConnection {
this.onEngineConnectionOpen(this)
this.ready = true
this.connecting = false
})
this.unreliableDataChannel.addEventListener('close', (event) => {
@ -474,6 +503,22 @@ export class EngineConnection {
})
})
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
if (this.failedConnTimeout) {
console.log('clearing timeout before set')
clearTimeout(this.failedConnTimeout)
this.failedConnTimeout = null
}
console.log('timeout set')
this.failedConnTimeout = setTimeout(() => {
if (this.isReady()) {
return
}
console.log('engine connection timeout on connection, closing')
this.close()
}, connectionTimeoutMs)
this.onConnectionStarted(this)
}
unreliableSend(message: object | string) {
@ -498,9 +543,15 @@ export class EngineConnection {
this.pc = undefined
this.unreliableDataChannel = undefined
this.webrtcStatsCollector = undefined
if (this.failedConnTimeout) {
console.log('closed timeout in close')
clearTimeout(this.failedConnTimeout)
this.failedConnTimeout = null
}
this.onClose(this)
this.ready = false
this.connecting = false
}
}
@ -617,6 +668,8 @@ export class EngineCommandManager {
message.request_id
) {
this.handleModelingCommand(message.resp, message.request_id)
} else if (!message.success && message.request_id) {
this.handleFailedModelingCommand(message)
}
}
})
@ -673,8 +726,40 @@ export class EngineCommandManager {
}
}
}
handleFailedModelingCommand({
request_id,
errors,
}: Models['FailureWebSocketResponse_type']) {
const id = request_id
if (!id) return
const command = this.artifactMap[id]
if (command && command.type === 'pending') {
const resolve = command.resolve
this.artifactMap[id] = {
type: 'failed',
range: command.range,
commandType: command.commandType,
parentId: command.parentId ? command.parentId : undefined,
errors,
}
resolve({
id,
commandType: command.commandType,
range: command.range,
errors,
})
} else {
this.artifactMap[id] = {
type: 'failed',
range: command.range,
commandType: command.commandType,
parentId: command.parentId ? command.parentId : undefined,
errors,
}
}
}
tearDown() {
this.engineConnection?.close()
this.engineConnection?.tearDown()
}
startNewSession() {
this.artifactMap = {}
@ -777,7 +862,6 @@ export class EngineCommandManager {
lastMessage = command.cmd.type
}
if (!this.engineConnection?.isReady()) {
console.log('socket not ready')
return Promise.resolve()
}
if (command.type !== 'modeling_cmd_req') return Promise.resolve()
@ -824,7 +908,6 @@ export class EngineCommandManager {
this.sourceRangeMap[id] = range
if (!this.engineConnection?.isReady()) {
console.log('socket not ready')
return Promise.resolve()
}
this.engineConnection?.send(command)
@ -890,6 +973,8 @@ export class EngineCommandManager {
}
if (command.type === 'result') {
return command.data
} else if (command.type === 'failed') {
return Promise.resolve(command.errors)
}
return command.promise
}

View File

@ -5,6 +5,9 @@ import {
EngineCommand,
} from '../lang/std/engineConnection'
import { SourceRange } from 'lang/executor'
import { Models } from '@kittycad/lib'
type WebSocketResponse = Models['OkWebSocketResponseData_type']
class MockEngineCommandManager {
constructor(mockParams: {
@ -23,7 +26,13 @@ class MockEngineCommandManager {
range: SourceRange
command: EngineCommand
}): Promise<any> {
return Promise.resolve()
const response: WebSocketResponse = {
type: 'modeling',
data: {
modeling_response: { type: 'empty' },
},
}
return Promise.resolve(JSON.stringify(response))
}
sendModelingCommandFromWasm(
id: string,

199
src/wasm-lib/Cargo.lock generated
View File

@ -63,6 +63,12 @@ dependencies = [
"libc",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
version = "0.5.0"
@ -142,6 +148,17 @@ dependencies = [
"thiserror",
]
[[package]]
name = "async-recursion"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "async-trait"
version = "0.1.73"
@ -220,6 +237,20 @@ dependencies = [
"num-traits",
]
[[package]]
name = "bigdecimal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "454bca3db10617b88b566f205ed190aedb0e0e6dd4cad61d3988a72e8c5594cb"
dependencies = [
"autocfg",
"libm",
"num-bigint",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "bincode"
version = "1.3.3"
@ -337,6 +368,12 @@ dependencies = [
"serde",
]
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.83"
@ -374,6 +411,33 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "ciborium"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
[[package]]
name = "ciborium-ll"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
dependencies = [
"ciborium-io",
"half 1.8.2",
]
[[package]]
name = "clang-sys"
version = "1.6.1"
@ -507,6 +571,42 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "criterion"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools 0.10.5",
"num-traits",
"once_cell",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools 0.10.5",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
@ -716,7 +816,7 @@ checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8"
dependencies = [
"bit_field",
"flume",
"half",
"half 2.2.1",
"lebe",
"miniz_oxide",
"rayon-core",
@ -983,6 +1083,12 @@ dependencies = [
"tracing",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "half"
version = "2.2.1"
@ -1281,12 +1387,14 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.1.30"
version = "0.1.31"
dependencies = [
"anyhow",
"async-recursion",
"async-trait",
"bson",
"clap",
"criterion",
"dashmap",
"derive-docs",
"expectorate",
@ -1315,13 +1423,14 @@ dependencies = [
[[package]]
name = "kittycad"
version = "0.2.25"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9cf962b1e81a0b4eb923a727e761b40672cbacc7f5f0b75e13579d346352bc7"
checksum = "e2623ee601ce203476229df3f9d3a14664cb43e3f7455e9ac8ed91aacaa6163d"
dependencies = [
"anyhow",
"async-trait",
"base64 0.21.4",
"bigdecimal 0.4.1",
"bytes",
"chrono",
"data-encoding",
@ -1383,6 +1492,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "libm"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
@ -1606,6 +1721,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "openapitor"
version = "0.0.9"
@ -1783,14 +1904,14 @@ dependencies = [
[[package]]
name = "phonenumber"
version = "0.3.2+8.13.9"
version = "0.3.3+8.13.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34749f64ea9d76f10cdc8a859588b57775f59177c7dd91f744d620bd62982d6f"
checksum = "635f3e6288e4f01c049d89332a031bd74f25d64b6fb94703ca966e819488cd06"
dependencies = [
"bincode",
"either",
"fnv",
"itertools 0.10.5",
"itertools 0.11.0",
"lazy_static",
"nom",
"quick-xml",
@ -1798,6 +1919,7 @@ dependencies = [
"regex-cache",
"serde",
"serde_derive",
"strum",
"thiserror",
]
@ -1839,6 +1961,34 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "plotters"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
[[package]]
name = "plotters-svg"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
dependencies = [
"plotters-backend",
]
[[package]]
name = "png"
version = "0.17.10"
@ -2313,7 +2463,8 @@ version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
dependencies = [
"bigdecimal",
"bigdecimal 0.3.1",
"bigdecimal 0.4.1",
"bytes",
"chrono",
"dyn-clone",
@ -2696,6 +2847,28 @@ dependencies = [
"syn 2.0.37",
]
[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 1.0.109",
]
[[package]]
name = "syn"
version = "1.0.109"
@ -2853,6 +3026,16 @@ dependencies = [
"time-core",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "tinyvec"
version = "1.6.0"

View File

@ -79,13 +79,6 @@ fn do_stdlib_inner(
));
}
if ast.sig.asyncness.is_some() {
errors.push(Error::new_spanned(
&ast.sig.fn_token,
"stdlib functions must not be async",
));
}
if ast.sig.unsafety.is_some() {
errors.push(Error::new_spanned(
&ast.sig.unsafety,
@ -118,6 +111,7 @@ fn do_stdlib_inner(
let fn_name = &ast.sig.ident;
let fn_name_str = fn_name.to_string().replace("inner_", "");
let fn_name_ident = format_ident!("{}", fn_name_str);
let boxed_fn_name_ident = format_ident!("boxed_{}", fn_name_str);
let _visibility = &ast.vis;
let (summary_text, description_text) = extract_doc_from_attrs(&ast.attrs);
@ -204,7 +198,10 @@ fn do_stdlib_inner(
syn::FnArg::Typed(pat) => pat.ty.as_ref().into_token_stream(),
};
let ty_string = ty.to_string().replace('&', "").replace("mut", "").replace(' ', "");
let mut ty_string = ty.to_string().replace('&', "").replace("mut", "").replace(' ', "");
if ty_string.starts_with("Args") {
ty_string = "Args".to_string();
}
let ty_string = ty_string.trim().to_string();
let ty_ident = if ty_string.starts_with("Vec<") {
let ty_string = ty_string.trim_start_matches("Vec<").trim_end_matches('>');
@ -305,6 +302,14 @@ fn do_stdlib_inner(
#description_doc_comment
#const_struct
fn #boxed_fn_name_ident(
args: crate::std::Args,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>>>,
> {
Box::pin(#fn_name_ident(args))
}
impl #docs_crate::StdLibFn for #name_ident
{
fn name(&self) -> String {
@ -348,7 +353,7 @@ fn do_stdlib_inner(
}
fn std_lib_fn(&self) -> crate::std::StdFn {
#fn_name_ident
#boxed_fn_name_ident
}
fn clone_box(&self) -> Box<dyn #docs_crate::StdLibFn> {

View File

@ -7,6 +7,18 @@ pub(crate) struct Show {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: show"]
pub(crate) const Show: Show = Show {};
fn boxed_show(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(show(args))
}
impl crate::docs::StdLibFn for Show {
fn name(&self) -> String {
"show".to_string()
@ -57,7 +69,7 @@ impl crate::docs::StdLibFn for Show {
}
fn std_lib_fn(&self) -> crate::std::StdFn {
show
boxed_show
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {

View File

@ -7,6 +7,18 @@ pub(crate) struct LineTo {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: lineTo"]
pub(crate) const LineTo: LineTo = LineTo {};
fn boxed_line_to(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(line_to(args))
}
impl crate::docs::StdLibFn for LineTo {
fn name(&self) -> String {
"lineTo".to_string()
@ -65,7 +77,7 @@ impl crate::docs::StdLibFn for LineTo {
}
fn std_lib_fn(&self) -> crate::std::StdFn {
line_to
boxed_line_to
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {

View File

@ -7,6 +7,18 @@ pub(crate) struct Min {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: min"]
pub(crate) const Min: Min = Min {};
fn boxed_min(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(min(args))
}
impl crate::docs::StdLibFn for Min {
fn name(&self) -> String {
"min".to_string()
@ -57,7 +69,7 @@ impl crate::docs::StdLibFn for Min {
}
fn std_lib_fn(&self) -> crate::std::StdFn {
min
boxed_min
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {

View File

@ -7,6 +7,18 @@ pub(crate) struct Show {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: show"]
pub(crate) const Show: Show = Show {};
fn boxed_show(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(show(args))
}
impl crate::docs::StdLibFn for Show {
fn name(&self) -> String {
"show".to_string()
@ -52,7 +64,7 @@ impl crate::docs::StdLibFn for Show {
}
fn std_lib_fn(&self) -> crate::std::StdFn {
show
boxed_show
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-lib"
description = "KittyCAD Language"
version = "0.1.30"
version = "0.1.31"
edition = "2021"
license = "MIT"
@ -9,6 +9,7 @@ license = "MIT"
[dependencies]
anyhow = { version = "1.0.75", features = ["backtrace"] }
async-recursion = "1.0.5"
async-trait = "0.1.73"
clap = { version = "4.4.3", features = ["cargo", "derive", "env", "unicode"], optional = true }
dashmap = "5.5.3"
@ -50,7 +51,12 @@ panic = "abort"
debug = true
[dev-dependencies]
criterion = "0.5.1"
expectorate = "1.0.7"
itertools = "0.11.0"
pretty_assertions = "1.4.0"
tokio = { version = "1.32.0", features = ["rt-multi-thread", "macros", "time"] }
[[bench]]
name = "compiler_benchmark"
harness = false

View File

@ -0,0 +1,33 @@
use criterion::{criterion_group, criterion_main, Criterion};
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("parse_lex_cube", |b| b.iter(|| lex_and_parse(CUBE_PROGRAM)));
c.bench_function("parse_lex_big kitt", |b| {
b.iter(|| lex_and_parse(include_str!("../../tests/executor/inputs/kittycad_svg.kcl")))
});
c.bench_function("parse_lex_pipes_on_pipes", |b| {
b.iter(|| lex_and_parse(include_str!("../../tests/executor/inputs/pipes_on_pipes.kcl")))
});
}
fn lex_and_parse(program: &str) {
let tokens = kcl_lib::tokeniser::lexer(program);
let parser = kcl_lib::parser::Parser::new(tokens);
parser.ast().unwrap();
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
const CUBE_PROGRAM: &str = r#"fn cube = (pos, scale) => {
const sg = startSketchAt(pos)
|> line([0, scale], %)
|> line([scale, 0], %)
|> line([0, -scale], %)
return sg
}
const b1 = cube([0,0], 10)
const pt1 = b1[0]
show(b1)"#;

View File

@ -0,0 +1 @@
enum-variant-size-threshold = 24

View File

@ -44,54 +44,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.75"
@ -123,6 +75,17 @@ dependencies = [
"thiserror",
]
[[package]]
name = "async-recursion"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "async-trait"
version = "0.1.73"
@ -131,7 +94,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -179,6 +142,20 @@ version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
[[package]]
name = "bigdecimal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "454bca3db10617b88b566f205ed190aedb0e0e6dd4cad61d3988a72e8c5594cb"
dependencies = [
"autocfg",
"libm",
"num-bigint",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "bincode"
version = "1.3.3"
@ -284,54 +261,6 @@ dependencies = [
"serde",
]
[[package]]
name = "clap"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"unicase",
"unicode-width",
]
[[package]]
name = "clap_derive"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.31",
]
[[package]]
name = "clap_lex"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "convert_case"
version = "0.6.0"
@ -403,16 +332,14 @@ checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
[[package]]
name = "derive-docs"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fe5c5ea065cfabc5a7c5e8ed616e369fbf108c4be01e0e5609bc9846a732664"
version = "0.1.4"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"serde",
"serde_tokenstream",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -529,7 +456,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -769,11 +696,12 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.1.24"
version = "0.1.31"
dependencies = [
"anyhow",
"async-recursion",
"async-trait",
"bson",
"clap",
"dashmap",
"derive-docs",
"futures",
@ -794,6 +722,7 @@ dependencies = [
"uuid",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
@ -806,12 +735,13 @@ dependencies = [
[[package]]
name = "kittycad"
version = "0.2.24"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd2f78e95054c83ab77059fe0237b128e2b241b4b8e9466e452d701c2599f3d3"
checksum = "e2623ee601ce203476229df3f9d3a14664cb43e3f7455e9ac8ed91aacaa6163d"
dependencies = [
"anyhow",
"base64 0.21.3",
"bigdecimal",
"bytes",
"chrono",
"data-encoding",
@ -850,6 +780,12 @@ dependencies = [
"once_cell",
]
[[package]]
name = "libm"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
@ -942,6 +878,27 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.16"
@ -1034,7 +991,7 @@ dependencies = [
"regex",
"regex-syntax 0.7.5",
"structmeta",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1045,9 +1002,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "phonenumber"
version = "0.3.2+8.13.9"
version = "0.3.3+8.13.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34749f64ea9d76f10cdc8a859588b57775f59177c7dd91f744d620bd62982d6f"
checksum = "635f3e6288e4f01c049d89332a031bd74f25d64b6fb94703ca966e819488cd06"
dependencies = [
"bincode",
"either",
@ -1060,6 +1017,7 @@ dependencies = [
"regex-cache",
"serde",
"serde_derive",
"strum",
"thiserror",
]
@ -1080,7 +1038,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1127,9 +1085,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.66"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
@ -1342,6 +1300,12 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.15"
@ -1359,10 +1323,11 @@ dependencies = [
[[package]]
name = "schemars"
version = "0.8.13"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161"
checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
dependencies = [
"bigdecimal",
"bytes",
"chrono",
"dyn-clone",
@ -1375,9 +1340,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.13"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737"
checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
dependencies = [
"proc-macro2",
"quote",
@ -1450,7 +1415,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1466,9 +1431,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.105"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [
"indexmap 2.0.0",
"itoa",
@ -1484,7 +1449,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1496,7 +1461,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1572,12 +1537,6 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structmeta"
version = "0.2.0"
@ -1587,7 +1546,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1598,7 +1557,29 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 1.0.109",
]
[[package]]
@ -1614,9 +1595,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.31"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@ -1655,7 +1636,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1728,7 +1709,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1822,7 +1803,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1851,7 +1832,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
]
[[package]]
@ -1891,7 +1872,7 @@ dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
"termcolor",
]
@ -1921,15 +1902,6 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unicase"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-bidi"
version = "0.3.13"
@ -1957,12 +1929,6 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "untrusted"
version = "0.7.1"
@ -1987,12 +1953,6 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.4.1"
@ -2046,7 +2006,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
"wasm-bindgen-shared",
]
@ -2080,7 +2040,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
"syn 2.0.37",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]

View File

@ -71,7 +71,7 @@ pub async fn modify_ast_for_sketch(
// Let's get the path info.
let resp = engine
.send_modeling_cmd_get_response(
.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::PathGetInfo { path_id: sketch_id },
@ -88,47 +88,6 @@ pub async fn modify_ast_for_sketch(
}));
};
/* // Let's try to get the children of the sketch.
let resp = engine
.send_modeling_cmd_get_response(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::EntityGetAllChildUuids { entity_id: sketch_id },
)
.await?;
let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::EntityGetAllChildUuids { data: children_info },
} = &resp
else {
return Err(KclError::Engine(KclErrorDetails {
message: format!("Get child info response was not as expected: {:?}", resp),
source_ranges: vec![SourceRange::default()],
}));
};
println!("children_info: {:#?}", children_info);
// Let's try to get the parent id.
let resp = engine
.send_modeling_cmd_get_response(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::EntityGetParentId { entity_id: sketch_id },
)
.await?;
let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::EntityGetParentId { data: parent_info },
} = &resp
else {
return Err(KclError::Engine(KclErrorDetails {
message: format!("Get parent id response was not as expected: {:?}", resp),
source_ranges: vec![SourceRange::default()],
}));
};
println!("parent_info: {:#?}", parent_info);*/
// Now let's get the control points for all the segments.
// TODO: We should probably await all these at once so we aren't going one by one.
// But I guess this is fine for now.
@ -136,7 +95,7 @@ pub async fn modify_ast_for_sketch(
let mut control_points = Vec::new();
for segment in &path_info.segments {
if let Some(command_id) = &segment.command_id {
let h = engine.send_modeling_cmd_get_response(
let h = engine.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::CurveGetControlPoints { curve_id: *command_id },

View File

@ -571,11 +571,12 @@ impl BinaryPart {
}
}
pub fn get_result(
#[async_recursion::async_recursion(?Send)]
pub async fn get_result(
&self,
memory: &mut ProgramMemory,
pipe_info: &mut PipeInfo,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
// stop the execution of the pipe.
@ -590,11 +591,13 @@ impl BinaryPart {
Ok(value.clone())
}
BinaryPart::BinaryExpression(binary_expression) => {
binary_expression.get_result(memory, &mut new_pipe_info, engine)
binary_expression.get_result(memory, &mut new_pipe_info, engine).await
}
BinaryPart::CallExpression(call_expression) => {
call_expression.execute(memory, &mut new_pipe_info, engine).await
}
BinaryPart::CallExpression(call_expression) => call_expression.execute(memory, &mut new_pipe_info, engine),
BinaryPart::UnaryExpression(unary_expression) => {
unary_expression.get_result(memory, &mut new_pipe_info, engine)
unary_expression.get_result(memory, &mut new_pipe_info, engine).await
}
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(memory),
}
@ -810,11 +813,12 @@ impl CallExpression {
)
}
pub fn execute(
#[async_recursion::async_recursion(?Send)]
pub async fn execute(
&self,
memory: &mut ProgramMemory,
pipe_info: &mut PipeInfo,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
let fn_name = self.callee.name.clone();
@ -828,7 +832,7 @@ impl CallExpression {
value.clone()
}
Value::BinaryExpression(binary_expression) => {
binary_expression.get_result(memory, pipe_info, engine)?
binary_expression.get_result(memory, pipe_info, engine).await?
}
Value::CallExpression(call_expression) => {
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
@ -836,11 +840,15 @@ impl CallExpression {
// THIS IS IMPORTANT.
let mut new_pipe_info = pipe_info.clone();
new_pipe_info.is_in_pipe = false;
call_expression.execute(memory, &mut new_pipe_info, engine)?
call_expression.execute(memory, &mut new_pipe_info, engine).await?
}
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, engine)?,
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, engine)?,
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine)?,
Value::UnaryExpression(unary_expression) => {
unary_expression.get_result(memory, pipe_info, engine).await?
}
Value::ObjectExpression(object_expression) => {
object_expression.execute(memory, pipe_info, engine).await?
}
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine).await?,
Value::PipeExpression(pipe_expression) => {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("PipeExpression not implemented here: {:?}", pipe_expression),
@ -871,31 +879,28 @@ impl CallExpression {
match &self.function {
Function::StdLib { func } => {
/* let source_range: SourceRange = self.into();
println!(
"Calling stdlib function: {}, source_range: {:?}, args: {:?}",
fn_name, source_range, fn_args
);*/
// Attempt to call the function.
let mut args = crate::std::Args::new(fn_args, self.into(), engine);
let result = func.std_lib_fn()(&mut args)?;
let args = crate::std::Args::new(fn_args, self.into(), engine.clone());
let result = func.std_lib_fn()(args).await?;
if pipe_info.is_in_pipe {
pipe_info.index += 1;
pipe_info.previous_results.push(result);
execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine)
execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine).await
} else {
Ok(result)
}
}
Function::InMemory => {
let mem = memory.clone();
let func = mem.get(&fn_name, self.into())?;
let result = func.call_fn(&fn_args, &mem, engine)?.ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails {
message: format!("Result of function {} is undefined", fn_name),
source_ranges: vec![self.into()],
})
})?;
let func = memory.get(&fn_name, self.into())?;
let result = func
.call_fn(fn_args, memory.clone(), engine.clone())
.await?
.ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails {
message: format!("Result of function {} is undefined", fn_name),
source_ranges: vec![self.into()],
})
})?;
let result = result.get_value()?;
@ -903,7 +908,7 @@ impl CallExpression {
pipe_info.index += 1;
pipe_info.previous_results.push(result);
execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine)
execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine).await
} else {
Ok(result)
}
@ -1424,11 +1429,12 @@ impl ArrayExpression {
None
}
pub fn execute(
#[async_recursion::async_recursion(?Send)]
pub async fn execute(
&self,
memory: &mut ProgramMemory,
pipe_info: &mut PipeInfo,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
let mut results = Vec::with_capacity(self.elements.len());
@ -1440,7 +1446,7 @@ impl ArrayExpression {
value.clone()
}
Value::BinaryExpression(binary_expression) => {
binary_expression.get_result(memory, pipe_info, engine)?
binary_expression.get_result(memory, pipe_info, engine).await?
}
Value::CallExpression(call_expression) => {
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
@ -1448,12 +1454,16 @@ impl ArrayExpression {
// THIS IS IMPORTANT.
let mut new_pipe_info = pipe_info.clone();
new_pipe_info.is_in_pipe = false;
call_expression.execute(memory, &mut new_pipe_info, engine)?
call_expression.execute(memory, &mut new_pipe_info, engine).await?
}
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, engine)?,
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, engine)?,
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine)?,
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine)?,
Value::UnaryExpression(unary_expression) => {
unary_expression.get_result(memory, pipe_info, engine).await?
}
Value::ObjectExpression(object_expression) => {
object_expression.execute(memory, pipe_info, engine).await?
}
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine).await?,
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine).await?,
Value::PipeSubstitution(pipe_substitution) => {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
@ -1569,11 +1579,12 @@ impl ObjectExpression {
None
}
pub fn execute(
#[async_recursion::async_recursion(?Send)]
pub async fn execute(
&self,
memory: &mut ProgramMemory,
pipe_info: &mut PipeInfo,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
let mut object = Map::new();
for property in &self.properties {
@ -1584,7 +1595,7 @@ impl ObjectExpression {
value.clone()
}
Value::BinaryExpression(binary_expression) => {
binary_expression.get_result(memory, pipe_info, engine)?
binary_expression.get_result(memory, pipe_info, engine).await?
}
Value::CallExpression(call_expression) => {
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
@ -1592,12 +1603,16 @@ impl ObjectExpression {
// THIS IS IMPORTANT.
let mut new_pipe_info = pipe_info.clone();
new_pipe_info.is_in_pipe = false;
call_expression.execute(memory, &mut new_pipe_info, engine)?
call_expression.execute(memory, &mut new_pipe_info, engine).await?
}
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, engine)?,
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, engine)?,
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine)?,
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine)?,
Value::UnaryExpression(unary_expression) => {
unary_expression.get_result(memory, pipe_info, engine).await?
}
Value::ObjectExpression(object_expression) => {
object_expression.execute(memory, pipe_info, engine).await?
}
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine).await?,
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine).await?,
Value::PipeSubstitution(pipe_substitution) => {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
@ -2005,11 +2020,12 @@ impl BinaryExpression {
None
}
pub fn get_result(
#[async_recursion::async_recursion(?Send)]
pub async fn get_result(
&self,
memory: &mut ProgramMemory,
pipe_info: &mut PipeInfo,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
// stop the execution of the pipe.
@ -2019,11 +2035,13 @@ impl BinaryExpression {
let left_json_value = self
.left
.get_result(memory, &mut new_pipe_info, engine)?
.get_result(memory, &mut new_pipe_info, engine)
.await?
.get_json_value()?;
let right_json_value = self
.right
.get_result(memory, &mut new_pipe_info, engine)?
.get_result(memory, &mut new_pipe_info, engine)
.await?
.get_json_value()?;
// First check if we are doing string concatenation.
@ -2173,11 +2191,11 @@ impl UnaryExpression {
format!("{}{}", &self.operator, self.argument.recast(options, 0))
}
pub fn get_result(
pub async fn get_result(
&self,
memory: &mut ProgramMemory,
pipe_info: &mut PipeInfo,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
// stop the execution of the pipe.
@ -2188,7 +2206,8 @@ impl UnaryExpression {
let num = parse_json_number_as_f64(
&self
.argument
.get_result(memory, &mut new_pipe_info, engine)?
.get_result(memory, &mut new_pipe_info, engine)
.await?
.get_json_value()?,
self.into(),
)?;
@ -2310,16 +2329,16 @@ impl PipeExpression {
None
}
pub fn get_result(
pub async fn get_result(
&self,
memory: &mut ProgramMemory,
pipe_info: &mut PipeInfo,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
// Reset the previous results.
pipe_info.previous_results = vec![];
pipe_info.index = 0;
execute_pipe_body(memory, &self.body, pipe_info, self.into(), engine)
execute_pipe_body(memory, &self.body, pipe_info, self.into(), engine).await
}
/// Rename all identifiers that have the old name to the new given name.
@ -2330,12 +2349,13 @@ impl PipeExpression {
}
}
fn execute_pipe_body(
#[async_recursion::async_recursion(?Send)]
async fn execute_pipe_body(
memory: &mut ProgramMemory,
body: &[Value],
pipe_info: &mut PipeInfo,
source_range: SourceRange,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<MemoryItem, KclError> {
if pipe_info.index == body.len() {
pipe_info.is_in_pipe = false;
@ -2360,15 +2380,15 @@ fn execute_pipe_body(
match expression {
Value::BinaryExpression(binary_expression) => {
let result = binary_expression.get_result(memory, pipe_info, engine)?;
let result = binary_expression.get_result(memory, pipe_info, engine).await?;
pipe_info.previous_results.push(result);
pipe_info.index += 1;
execute_pipe_body(memory, body, pipe_info, source_range, engine)
execute_pipe_body(memory, body, pipe_info, source_range, engine).await
}
Value::CallExpression(call_expression) => {
pipe_info.is_in_pipe = true;
pipe_info.body = body.to_vec();
call_expression.execute(memory, pipe_info, engine)
call_expression.execute(memory, pipe_info, engine).await
}
_ => {
// Return an error this should not happen.

View File

@ -3,10 +3,11 @@
use std::sync::Arc;
use anyhow::Result;
use anyhow::{anyhow, Result};
use dashmap::DashMap;
use futures::{SinkExt, StreamExt};
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest, WebSocketResponse};
use tokio::sync::{mpsc, oneshot};
use tokio_tungstenite::tungstenite::Message as WsMsg;
use crate::{
@ -14,18 +15,13 @@ use crate::{
errors::{KclError, KclErrorDetails},
};
#[derive(Debug)]
type WebSocketTcpWrite = futures::stream::SplitSink<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>, WsMsg>;
#[derive(Debug, Clone)]
#[allow(dead_code)] // for the TcpReadHandle
pub struct EngineConnection {
tcp_write: futures::stream::SplitSink<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>, WsMsg>,
tcp_read_handle: tokio::task::JoinHandle<Result<()>>,
engine_req_tx: mpsc::Sender<ToEngineReq>,
responses: Arc<DashMap<uuid::Uuid, WebSocketResponse>>,
}
impl Drop for EngineConnection {
fn drop(&mut self) {
// Drop the read handle.
self.tcp_read_handle.abort();
}
tcp_read_handle: Arc<TcpReadHandle>,
}
pub struct TcpRead {
@ -46,16 +42,63 @@ impl TcpRead {
}
}
#[derive(Debug)]
pub struct TcpReadHandle {
handle: Arc<tokio::task::JoinHandle<Result<()>>>,
}
impl Drop for TcpReadHandle {
fn drop(&mut self) {
// Drop the read handle.
self.handle.abort();
}
}
/// Requests to send to the engine, and a way to await a response.
struct ToEngineReq {
/// The request to send
req: WebSocketRequest,
/// If this resolves to Ok, the request was sent.
/// If this resolves to Err, the request could not be sent.
/// If this has not yet resolved, the request has not been sent yet.
request_sent: oneshot::Sender<Result<()>>,
}
impl EngineConnection {
/// Start waiting for incoming engine requests, and send each one over the WebSocket to the engine.
async fn start_write_actor(mut tcp_write: WebSocketTcpWrite, mut engine_req_rx: mpsc::Receiver<ToEngineReq>) {
while let Some(req) = engine_req_rx.recv().await {
let ToEngineReq { req, request_sent } = req;
let res = Self::inner_send_to_engine(req, &mut tcp_write).await;
let _ = request_sent.send(res);
}
}
/// Send the given `request` to the engine via the WebSocket connection `tcp_write`.
async fn inner_send_to_engine(request: WebSocketRequest, tcp_write: &mut WebSocketTcpWrite) -> Result<()> {
let msg = serde_json::to_string(&request).map_err(|e| anyhow!("could not serialize json: {e}"))?;
tcp_write
.send(WsMsg::Text(msg))
.await
.map_err(|e| anyhow!("could not send json over websocket: {e}"))?;
Ok(())
}
pub async fn new(ws: reqwest::Upgraded) -> Result<EngineConnection> {
let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
ws,
tokio_tungstenite::tungstenite::protocol::Role::Client,
None,
Some(tokio_tungstenite::tungstenite::protocol::WebSocketConfig {
write_buffer_size: 1024 * 128,
max_write_buffer_size: 1024 * 256,
..Default::default()
}),
)
.await;
let (tcp_write, tcp_read) = ws_stream.split();
let (engine_req_tx, engine_req_rx) = mpsc::channel(10);
tokio::task::spawn(Self::start_write_actor(tcp_write, engine_req_rx));
let mut tcp_read = TcpRead { stream: tcp_read };
@ -80,42 +123,34 @@ impl EngineConnection {
});
Ok(EngineConnection {
tcp_write,
tcp_read_handle,
engine_req_tx,
tcp_read_handle: Arc::new(TcpReadHandle {
handle: Arc::new(tcp_read_handle),
}),
responses,
})
}
pub async fn tcp_send(&mut self, msg: WebSocketRequest) -> Result<()> {
let msg = serde_json::to_string(&msg)?;
self.tcp_write.send(WsMsg::Text(msg)).await?;
Ok(())
}
}
#[async_trait::async_trait(?Send)]
impl EngineManager for EngineConnection {
/// Send a modeling command.
/// Do not wait for the response message.
fn send_modeling_cmd(
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
) -> Result<(), KclError> {
futures::executor::block_on(self.send_modeling_cmd_get_response(id, source_range, cmd))?;
Ok(())
}
/// Send a modeling command and wait for the response message.
async fn send_modeling_cmd_get_response(
&mut self,
async fn send_modeling_cmd(
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
) -> Result<OkWebSocketResponseData, KclError> {
self.tcp_send(WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id })
let (tx, rx) = oneshot::channel();
// Send the request to the engine, via the actor.
self.engine_req_tx
.send(ToEngineReq {
req: WebSocketRequest::ModelingCmdReq {
cmd: cmd.clone(),
cmd_id: id,
},
request_sent: tx,
})
.await
.map_err(|e| {
KclError::Engine(KclErrorDetails {
@ -124,18 +159,40 @@ impl EngineManager for EngineConnection {
})
})?;
// Wait for the request to be sent.
rx.await
.map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("could not send request to the engine actor: {e}"),
source_ranges: vec![source_range],
})
})?
.map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("could not send request to the engine: {e}"),
source_ranges: vec![source_range],
})
})?;
// Wait for the response.
loop {
if let Some(resp) = self.responses.get(&id) {
if let Some(data) = &resp.resp {
return Ok(data.clone());
let current_time = std::time::Instant::now();
while current_time.elapsed().as_secs() < 60 {
// We pop off the responses to cleanup our mappings.
if let Some((_, resp)) = self.responses.remove(&id) {
return if let Some(data) = &resp.resp {
Ok(data.clone())
} else {
return Err(KclError::Engine(KclErrorDetails {
Err(KclError::Engine(KclErrorDetails {
message: format!("Modeling command failed: {:?}", resp.errors),
source_ranges: vec![source_range],
}));
}
}))
};
}
}
Err(KclError::Engine(KclErrorDetails {
message: format!("Modeling command timed out `{}`: {:?}", id, cmd),
source_ranges: vec![source_range],
}))
}
}

View File

@ -6,7 +6,7 @@ use kittycad::types::OkWebSocketResponseData;
use crate::errors::KclError;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct EngineConnection {}
impl EngineConnection {
@ -17,21 +17,14 @@ impl EngineConnection {
#[async_trait::async_trait(?Send)]
impl crate::engine::EngineManager for EngineConnection {
fn send_modeling_cmd(
&mut self,
_id: uuid::Uuid,
_source_range: crate::executor::SourceRange,
_cmd: kittycad::types::ModelingCmd,
) -> Result<(), KclError> {
Ok(())
}
async fn send_modeling_cmd_get_response(
&mut self,
async fn send_modeling_cmd(
&self,
_id: uuid::Uuid,
_source_range: crate::executor::SourceRange,
_cmd: kittycad::types::ModelingCmd,
) -> Result<OkWebSocketResponseData, KclError> {
todo!()
Ok(OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {},
})
}
}

View File

@ -1,5 +1,6 @@
//! Functions for setting up our WebSocket and WebRTC connections for communications with the
//! engine.
use std::sync::Arc;
use anyhow::Result;
use kittycad::types::WebSocketRequest;
@ -23,44 +24,21 @@ extern "C" {
#[derive(Debug, Clone)]
pub struct EngineConnection {
manager: EngineCommandManager,
manager: Arc<EngineCommandManager>,
}
impl EngineConnection {
pub async fn new(manager: EngineCommandManager) -> Result<EngineConnection, JsValue> {
Ok(EngineConnection { manager })
Ok(EngineConnection {
manager: Arc::new(manager),
})
}
}
#[async_trait::async_trait(?Send)]
impl crate::engine::EngineManager for EngineConnection {
fn send_modeling_cmd(
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
) -> Result<(), KclError> {
let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("Failed to serialize source range: {:?}", e),
source_ranges: vec![source_range],
})
})?;
let ws_msg = WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id };
let cmd_str = serde_json::to_string(&ws_msg).map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("Failed to serialize modeling command: {:?}", e),
source_ranges: vec![source_range],
})
})?;
let _ = self
.manager
.sendModelingCommandFromWasm(id.to_string(), source_range_str, cmd_str);
Ok(())
}
async fn send_modeling_cmd_get_response(
&mut self,
async fn send_modeling_cmd(
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,

View File

@ -32,19 +32,10 @@ use anyhow::Result;
pub use conn_mock::EngineConnection;
#[async_trait::async_trait(?Send)]
pub trait EngineManager {
/// Send a modeling command.
/// Do not wait for the response message.
fn send_modeling_cmd(
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
) -> Result<(), crate::errors::KclError>;
pub trait EngineManager: Clone {
/// Send a modeling command and wait for the response message.
async fn send_modeling_cmd_get_response(
&mut self,
async fn send_modeling_cmd(
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,

View File

@ -104,7 +104,7 @@ pub enum MemoryItem {
SketchGroup(Box<SketchGroup>),
ExtrudeGroup(Box<ExtrudeGroup>),
#[ts(skip)]
ExtrudeTransform(ExtrudeTransform),
ExtrudeTransform(Box<ExtrudeTransform>),
#[ts(skip)]
Function {
#[serde(skip)]
@ -134,13 +134,28 @@ pub struct ExtrudeTransform {
pub meta: Vec<Metadata>,
}
pub type MemoryFunction = fn(
s: &[MemoryItem],
memory: &ProgramMemory,
expression: &FunctionExpression,
metadata: &[Metadata],
engine: &mut EngineConnection,
) -> Result<Option<ProgramReturn>, KclError>;
pub type MemoryFunction =
fn(
s: Vec<MemoryItem>,
memory: ProgramMemory,
expression: Box<FunctionExpression>,
metadata: Vec<Metadata>,
engine: EngineConnection,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Option<ProgramReturn>, KclError>>>>;
fn force_memory_function<
F: Fn(
Vec<MemoryItem>,
ProgramMemory,
Box<FunctionExpression>,
Vec<Metadata>,
EngineConnection,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Option<ProgramReturn>, KclError>>>>,
>(
f: F,
) -> F {
f
}
impl From<MemoryItem> for Vec<SourceRange> {
fn from(item: MemoryItem) -> Self {
@ -168,24 +183,24 @@ impl MemoryItem {
}
}
pub fn call_fn(
pub async fn call_fn(
&self,
args: &[MemoryItem],
memory: &ProgramMemory,
engine: &mut EngineConnection,
args: Vec<MemoryItem>,
memory: ProgramMemory,
engine: EngineConnection,
) -> Result<Option<ProgramReturn>, KclError> {
if let MemoryItem::Function { func, expression, meta } = self {
if let MemoryItem::Function { func, expression, meta } = &self {
if let Some(func) = func {
func(args, memory, expression, meta, engine)
func(args, memory, expression.clone(), meta.clone(), engine).await
} else {
Err(KclError::Semantic(KclErrorDetails {
message: format!("Not a function: {:?}", self),
message: format!("Not a function: {:?}", expression),
source_ranges: vec![],
}))
}
} else {
Err(KclError::Semantic(KclErrorDetails {
message: format!("not a function: {:?}", self),
message: "not a in memory function".to_string(),
source_ranges: vec![],
}))
}
@ -579,11 +594,11 @@ impl Default for PipeInfo {
}
/// Execute a AST's program.
pub fn execute(
pub async fn execute(
program: crate::ast::types::Program,
memory: &mut ProgramMemory,
options: BodyType,
engine: &mut EngineConnection,
engine: &EngineConnection,
) -> Result<ProgramMemory, KclError> {
let mut pipe_info = PipeInfo::default();
@ -602,7 +617,7 @@ pub fn execute(
args.push(memory_item.clone());
}
Value::CallExpression(call_expr) => {
let result = call_expr.execute(memory, &mut pipe_info, engine)?;
let result = call_expr.execute(memory, &mut pipe_info, engine).await?;
args.push(result);
}
// We do nothing for the rest.
@ -620,7 +635,7 @@ pub fn execute(
memory.return_ = Some(ProgramReturn::Arguments(call_expr.arguments.clone()));
} else if let Some(func) = memory.clone().root.get(&fn_name) {
let result = func.call_fn(&args, memory, engine)?;
let result = func.call_fn(args.clone(), memory.clone(), engine.clone()).await?;
memory.return_ = result;
} else {
@ -646,22 +661,27 @@ pub fn execute(
memory.add(&var_name, value.clone(), source_range)?;
}
Value::BinaryExpression(binary_expression) => {
let result = binary_expression.get_result(memory, &mut pipe_info, engine)?;
let result = binary_expression.get_result(memory, &mut pipe_info, engine).await?;
memory.add(&var_name, result, source_range)?;
}
Value::FunctionExpression(function_expression) => {
memory.add(
&var_name,
MemoryItem::Function{
expression: function_expression.clone(),
meta: vec![metadata],
func: Some(|args: &[MemoryItem], memory: &ProgramMemory, function_expression: &FunctionExpression, _metadata: &[Metadata], engine: &mut EngineConnection| -> Result<Option<ProgramReturn>, KclError> {
let mem_func = force_memory_function(
|args: Vec<MemoryItem>,
memory: ProgramMemory,
function_expression: Box<FunctionExpression>,
_metadata: Vec<Metadata>,
engine: EngineConnection| {
Box::pin(async move {
let mut fn_memory = memory.clone();
if args.len() != function_expression.params.len() {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("Expected {} arguments, got {}", function_expression.params.len(), args.len()),
source_ranges: vec![function_expression.into()],
message: format!(
"Expected {} arguments, got {}",
function_expression.params.len(),
args.len()
),
source_ranges: vec![(&function_expression).into()],
}));
}
@ -674,20 +694,34 @@ pub fn execute(
)?;
}
let result = execute(function_expression.body.clone(), &mut fn_memory, BodyType::Block, engine)?;
let result = execute(
function_expression.body.clone(),
&mut fn_memory,
BodyType::Block,
&engine,
)
.await?;
Ok(result.return_)
})
},
);
memory.add(
&var_name,
MemoryItem::Function {
expression: function_expression.clone(),
meta: vec![metadata],
func: Some(mem_func),
},
source_range,
)?;
}
Value::CallExpression(call_expression) => {
let result = call_expression.execute(memory, &mut pipe_info, engine)?;
let result = call_expression.execute(memory, &mut pipe_info, engine).await?;
memory.add(&var_name, result, source_range)?;
}
Value::PipeExpression(pipe_expression) => {
let result = pipe_expression.get_result(memory, &mut pipe_info, engine)?;
let result = pipe_expression.get_result(memory, &mut pipe_info, engine).await?;
memory.add(&var_name, result, source_range)?;
}
Value::PipeSubstitution(pipe_substitution) => {
@ -700,11 +734,11 @@ pub fn execute(
}));
}
Value::ArrayExpression(array_expression) => {
let result = array_expression.execute(memory, &mut pipe_info, engine)?;
let result = array_expression.execute(memory, &mut pipe_info, engine).await?;
memory.add(&var_name, result, source_range)?;
}
Value::ObjectExpression(object_expression) => {
let result = object_expression.execute(memory, &mut pipe_info, engine)?;
let result = object_expression.execute(memory, &mut pipe_info, engine).await?;
memory.add(&var_name, result, source_range)?;
}
Value::MemberExpression(member_expression) => {
@ -712,7 +746,7 @@ pub fn execute(
memory.add(&var_name, result, source_range)?;
}
Value::UnaryExpression(unary_expression) => {
let result = unary_expression.get_result(memory, &mut pipe_info, engine)?;
let result = unary_expression.get_result(memory, &mut pipe_info, engine).await?;
memory.add(&var_name, result, source_range)?;
}
}
@ -720,11 +754,11 @@ pub fn execute(
}
BodyItem::ReturnStatement(return_statement) => match &return_statement.argument {
Value::BinaryExpression(bin_expr) => {
let result = bin_expr.get_result(memory, &mut pipe_info, engine)?;
let result = bin_expr.get_result(memory, &mut pipe_info, engine).await?;
memory.return_ = Some(ProgramReturn::Value(result));
}
Value::UnaryExpression(unary_expr) => {
let result = unary_expr.get_result(memory, &mut pipe_info, engine)?;
let result = unary_expr.get_result(memory, &mut pipe_info, engine).await?;
memory.return_ = Some(ProgramReturn::Value(result));
}
Value::Identifier(identifier) => {
@ -735,15 +769,15 @@ pub fn execute(
memory.return_ = Some(ProgramReturn::Value(literal.into()));
}
Value::ArrayExpression(array_expr) => {
let result = array_expr.execute(memory, &mut pipe_info, engine)?;
let result = array_expr.execute(memory, &mut pipe_info, engine).await?;
memory.return_ = Some(ProgramReturn::Value(result));
}
Value::ObjectExpression(obj_expr) => {
let result = obj_expr.execute(memory, &mut pipe_info, engine)?;
let result = obj_expr.execute(memory, &mut pipe_info, engine).await?;
memory.return_ = Some(ProgramReturn::Value(result));
}
Value::CallExpression(call_expr) => {
let result = call_expr.execute(memory, &mut pipe_info, engine)?;
let result = call_expr.execute(memory, &mut pipe_info, engine).await?;
memory.return_ = Some(ProgramReturn::Value(result));
}
Value::MemberExpression(member_expr) => {
@ -751,7 +785,7 @@ pub fn execute(
memory.return_ = Some(ProgramReturn::Value(result));
}
Value::PipeExpression(pipe_expr) => {
let result = pipe_expr.get_result(memory, &mut pipe_info, engine)?;
let result = pipe_expr.get_result(memory, &mut pipe_info, engine).await?;
memory.return_ = Some(ProgramReturn::Value(result));
}
Value::PipeSubstitution(_) => {}
@ -774,8 +808,8 @@ mod tests {
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast()?;
let mut mem: ProgramMemory = Default::default();
let mut engine = EngineConnection::new().await?;
let memory = execute(program, &mut mem, BodyType::Root, &mut engine)?;
let engine = EngineConnection::new().await?;
let memory = execute(program, &mut mem, BodyType::Root, &engine).await?;
Ok(memory)
}

View File

@ -11,10 +11,10 @@ use crate::{
};
/// Extrudes by a given amount.
pub fn extrude(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn extrude(args: Args) -> Result<MemoryItem, KclError> {
let (length, sketch_group) = args.get_number_sketch_group()?;
let result = inner_extrude(length, sketch_group, args)?;
let result = inner_extrude(length, sketch_group, args).await?;
Ok(MemoryItem::ExtrudeGroup(result))
}
@ -23,7 +23,7 @@ pub fn extrude(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "extrude"
}]
fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<Box<ExtrudeGroup>, KclError> {
async fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: Args) -> Result<Box<ExtrudeGroup>, KclError> {
let id = uuid::Uuid::new_v4();
let cmd = kittycad::types::ModelingCmd::Extrude {
@ -31,7 +31,7 @@ fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: &mut Args) -
distance: length,
cap: true,
};
args.send_modeling_cmd(id, cmd)?;
args.send_modeling_cmd(id, cmd).await?;
Ok(Box::new(ExtrudeGroup {
id,
@ -46,7 +46,7 @@ fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: &mut Args) -
}
/// Returns the extrude wall transform.
pub fn get_extrude_wall_transform(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn get_extrude_wall_transform(args: Args) -> Result<MemoryItem, KclError> {
let (surface_name, extrude_group) = args.get_path_name_extrude_group()?;
let result = inner_get_extrude_wall_transform(&surface_name, *extrude_group, args)?;
Ok(MemoryItem::ExtrudeTransform(result))
@ -59,8 +59,8 @@ pub fn get_extrude_wall_transform(args: &mut Args) -> Result<MemoryItem, KclErro
fn inner_get_extrude_wall_transform(
surface_name: &str,
extrude_group: ExtrudeGroup,
args: &mut Args,
) -> Result<ExtrudeTransform, KclError> {
args: Args,
) -> Result<Box<ExtrudeTransform>, KclError> {
let surface = extrude_group.get_path_by_name(surface_name).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
@ -71,9 +71,9 @@ fn inner_get_extrude_wall_transform(
})
})?;
Ok(ExtrudeTransform {
Ok(Box::new(ExtrudeTransform {
position: surface.get_position(),
rotation: surface.get_rotation(),
meta: extrude_group.meta,
})
}))
}

View File

@ -11,7 +11,7 @@ use crate::{
};
/// Computes the cosine of a number (in radians).
pub fn cos(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn cos(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_cos(num)?;
@ -27,7 +27,7 @@ fn inner_cos(num: f64) -> Result<f64, KclError> {
}
/// Computes the sine of a number (in radians).
pub fn sin(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn sin(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_sin(num)?;
@ -43,7 +43,7 @@ fn inner_sin(num: f64) -> Result<f64, KclError> {
}
/// Computes the tangent of a number (in radians).
pub fn tan(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn tan(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_tan(num)?;
@ -59,7 +59,7 @@ fn inner_tan(num: f64) -> Result<f64, KclError> {
}
/// Return the value of `pi`. Archimedes constant (π).
pub fn pi(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn pi(args: Args) -> Result<MemoryItem, KclError> {
let result = inner_pi()?;
args.make_user_val_from_f64(result)
@ -74,7 +74,7 @@ fn inner_pi() -> Result<f64, KclError> {
}
/// Computes the square root of a number.
pub fn sqrt(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn sqrt(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_sqrt(num)?;
@ -90,7 +90,7 @@ fn inner_sqrt(num: f64) -> Result<f64, KclError> {
}
/// Computes the absolute value of a number.
pub fn abs(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn abs(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_abs(num)?;
@ -106,7 +106,7 @@ fn inner_abs(num: f64) -> Result<f64, KclError> {
}
/// Computes the largest integer less than or equal to a number.
pub fn floor(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn floor(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_floor(num)?;
@ -122,7 +122,7 @@ fn inner_floor(num: f64) -> Result<f64, KclError> {
}
/// Computes the smallest integer greater than or equal to a number.
pub fn ceil(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn ceil(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_ceil(num)?;
@ -138,7 +138,7 @@ fn inner_ceil(num: f64) -> Result<f64, KclError> {
}
/// Computes the minimum of the given arguments.
pub fn min(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn min(args: Args) -> Result<MemoryItem, KclError> {
let nums = args.get_number_array()?;
let result = inner_min(nums);
@ -161,7 +161,7 @@ fn inner_min(args: Vec<f64>) -> f64 {
}
/// Computes the maximum of the given arguments.
pub fn max(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn max(args: Args) -> Result<MemoryItem, KclError> {
let nums = args.get_number_array()?;
let result = inner_max(nums);
@ -184,7 +184,7 @@ fn inner_max(args: Vec<f64>) -> f64 {
}
/// Computes the number to a power.
pub fn pow(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn pow(args: Args) -> Result<MemoryItem, KclError> {
let nums = args.get_number_array()?;
if nums.len() > 2 {
return Err(KclError::Type(KclErrorDetails {
@ -214,7 +214,7 @@ fn inner_pow(num: f64, pow: f64) -> Result<f64, KclError> {
}
/// Computes the arccosine of a number (in radians).
pub fn acos(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn acos(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_acos(num)?;
@ -230,7 +230,7 @@ fn inner_acos(num: f64) -> Result<f64, KclError> {
}
/// Computes the arcsine of a number (in radians).
pub fn asin(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn asin(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_asin(num)?;
@ -246,7 +246,7 @@ fn inner_asin(num: f64) -> Result<f64, KclError> {
}
/// Computes the arctangent of a number (in radians).
pub fn atan(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn atan(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_atan(num)?;
@ -266,7 +266,7 @@ fn inner_atan(num: f64) -> Result<f64, KclError> {
/// The result might not be correctly rounded owing to implementation
/// details; `log2()` can produce more accurate results for base 2,
/// and `log10()` can produce more accurate results for base 10.
pub fn log(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn log(args: Args) -> Result<MemoryItem, KclError> {
let nums = args.get_number_array()?;
if nums.len() > 2 {
return Err(KclError::Type(KclErrorDetails {
@ -299,7 +299,7 @@ fn inner_log(num: f64, base: f64) -> Result<f64, KclError> {
}
/// Computes the base 2 logarithm of the number.
pub fn log2(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn log2(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_log2(num)?;
@ -315,7 +315,7 @@ fn inner_log2(num: f64) -> Result<f64, KclError> {
}
/// Computes the base 10 logarithm of the number.
pub fn log10(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn log10(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_log10(num)?;
@ -331,7 +331,7 @@ fn inner_log10(num: f64) -> Result<f64, KclError> {
}
/// Computes the natural logarithm of the number.
pub fn ln(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn ln(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?;
let result = inner_ln(num)?;
@ -347,7 +347,7 @@ fn inner_ln(num: f64) -> Result<f64, KclError> {
}
/// Return the value of Eulers number `e`.
pub fn e(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn e(args: Args) -> Result<MemoryItem, KclError> {
let result = inner_e()?;
args.make_user_val_from_f64(result)
@ -362,7 +362,7 @@ fn inner_e() -> Result<f64, KclError> {
}
/// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
pub fn tau(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn tau(args: Args) -> Result<MemoryItem, KclError> {
let result = inner_tau()?;
args.make_user_val_from_f64(result)

View File

@ -10,6 +10,7 @@ use std::collections::HashMap;
use anyhow::Result;
use derive_docs::stdlib;
use kittycad::types::OkWebSocketResponseData;
use parse_display::{Display, FromStr};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@ -21,7 +22,7 @@ use crate::{
executor::{ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SourceRange},
};
pub type StdFn = fn(&mut Args) -> Result<MemoryItem, KclError>;
pub type StdFn = fn(Args) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<MemoryItem, KclError>>>>;
pub type FnMap = HashMap<String, StdFn>;
pub struct StdLib {
@ -102,15 +103,15 @@ impl Default for StdLib {
}
}
#[derive(Debug)]
pub struct Args<'a> {
#[derive(Debug, Clone)]
pub struct Args {
pub args: Vec<MemoryItem>,
pub source_range: SourceRange,
engine: &'a mut EngineConnection,
engine: EngineConnection,
}
impl<'a> Args<'a> {
pub fn new(args: Vec<MemoryItem>, source_range: SourceRange, engine: &'a mut EngineConnection) -> Self {
impl Args {
pub fn new(args: Vec<MemoryItem>, source_range: SourceRange, engine: EngineConnection) -> Self {
Self {
args,
source_range,
@ -118,8 +119,12 @@ impl<'a> Args<'a> {
}
}
pub fn send_modeling_cmd(&mut self, id: uuid::Uuid, cmd: kittycad::types::ModelingCmd) -> Result<(), KclError> {
self.engine.send_modeling_cmd(id, self.source_range, cmd)
pub async fn send_modeling_cmd(
&self,
id: uuid::Uuid,
cmd: kittycad::types::ModelingCmd,
) -> Result<OkWebSocketResponseData, KclError> {
self.engine.send_modeling_cmd(id, self.source_range, cmd).await
}
fn make_user_val_from_json(&self, j: serde_json::Value) -> Result<MemoryItem, KclError> {
@ -443,7 +448,7 @@ impl<'a> Args<'a> {
/// Render a model.
// This never actually gets called so this is fine.
pub fn show(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn show<'a>(args: Args) -> Result<MemoryItem, KclError> {
let sketch_group = args.get_sketch_group()?;
inner_show(sketch_group);
@ -457,7 +462,7 @@ pub fn show(args: &mut Args) -> Result<MemoryItem, KclError> {
fn inner_show(_sketch: Box<SketchGroup>) {}
/// Returns the length of the given leg.
pub fn leg_length(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn leg_length(args: Args) -> Result<MemoryItem, KclError> {
let (hypotenuse, leg) = args.get_hypotenuse_leg()?;
let result = inner_leg_length(hypotenuse, leg);
args.make_user_val_from_f64(result)
@ -472,7 +477,7 @@ fn inner_leg_length(hypotenuse: f64, leg: f64) -> f64 {
}
/// Returns the angle of the given leg for x.
pub fn leg_angle_x(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn leg_angle_x(args: Args) -> Result<MemoryItem, KclError> {
let (hypotenuse, leg) = args.get_hypotenuse_leg()?;
let result = inner_leg_angle_x(hypotenuse, leg);
args.make_user_val_from_f64(result)
@ -487,7 +492,7 @@ fn inner_leg_angle_x(hypotenuse: f64, leg: f64) -> f64 {
}
/// Returns the angle of the given leg for y.
pub fn leg_angle_y(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn leg_angle_y(args: Args) -> Result<MemoryItem, KclError> {
let (hypotenuse, leg) = args.get_hypotenuse_leg()?;
let result = inner_leg_angle_y(hypotenuse, leg);
args.make_user_val_from_f64(result)

View File

@ -11,9 +11,9 @@ use crate::{
};
/// Returns the segment end of x.
pub fn segment_end_x(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn segment_end_x(args: Args) -> Result<MemoryItem, KclError> {
let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?;
let result = inner_segment_end_x(&segment_name, sketch_group, args)?;
let result = inner_segment_end_x(&segment_name, sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -22,7 +22,7 @@ pub fn segment_end_x(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "segEndX",
}]
fn inner_segment_end_x(segment_name: &str, sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<f64, KclError> {
fn inner_segment_end_x(segment_name: &str, sketch_group: Box<SketchGroup>, args: Args) -> Result<f64, KclError> {
let line = sketch_group.get_base_by_name_or_start(segment_name).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
@ -37,9 +37,9 @@ fn inner_segment_end_x(segment_name: &str, sketch_group: Box<SketchGroup>, args:
}
/// Returns the segment end of y.
pub fn segment_end_y(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn segment_end_y(args: Args) -> Result<MemoryItem, KclError> {
let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?;
let result = inner_segment_end_y(&segment_name, sketch_group, args)?;
let result = inner_segment_end_y(&segment_name, sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -48,7 +48,7 @@ pub fn segment_end_y(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "segEndY",
}]
fn inner_segment_end_y(segment_name: &str, sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<f64, KclError> {
fn inner_segment_end_y(segment_name: &str, sketch_group: Box<SketchGroup>, args: Args) -> Result<f64, KclError> {
let line = sketch_group.get_base_by_name_or_start(segment_name).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
@ -63,9 +63,9 @@ fn inner_segment_end_y(segment_name: &str, sketch_group: Box<SketchGroup>, args:
}
/// Returns the last segment of x.
pub fn last_segment_x(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn last_segment_x(args: Args) -> Result<MemoryItem, KclError> {
let sketch_group = args.get_sketch_group()?;
let result = inner_last_segment_x(sketch_group, args)?;
let result = inner_last_segment_x(sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -74,7 +74,7 @@ pub fn last_segment_x(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "lastSegX",
}]
fn inner_last_segment_x(sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<f64, KclError> {
fn inner_last_segment_x(sketch_group: Box<SketchGroup>, args: Args) -> Result<f64, KclError> {
let last_line = sketch_group
.value
.last()
@ -93,9 +93,9 @@ fn inner_last_segment_x(sketch_group: Box<SketchGroup>, args: &mut Args) -> Resu
}
/// Returns the last segment of y.
pub fn last_segment_y(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn last_segment_y(args: Args) -> Result<MemoryItem, KclError> {
let sketch_group = args.get_sketch_group()?;
let result = inner_last_segment_y(sketch_group, args)?;
let result = inner_last_segment_y(sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -104,7 +104,7 @@ pub fn last_segment_y(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "lastSegY",
}]
fn inner_last_segment_y(sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<f64, KclError> {
fn inner_last_segment_y(sketch_group: Box<SketchGroup>, args: Args) -> Result<f64, KclError> {
let last_line = sketch_group
.value
.last()
@ -123,9 +123,9 @@ fn inner_last_segment_y(sketch_group: Box<SketchGroup>, args: &mut Args) -> Resu
}
/// Returns the length of the segment.
pub fn segment_length(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn segment_length(args: Args) -> Result<MemoryItem, KclError> {
let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?;
let result = inner_segment_length(&segment_name, sketch_group, args)?;
let result = inner_segment_length(&segment_name, sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -133,7 +133,7 @@ pub fn segment_length(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "segLen",
}]
fn inner_segment_length(segment_name: &str, sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<f64, KclError> {
fn inner_segment_length(segment_name: &str, sketch_group: Box<SketchGroup>, args: Args) -> Result<f64, KclError> {
let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
@ -151,10 +151,10 @@ fn inner_segment_length(segment_name: &str, sketch_group: Box<SketchGroup>, args
}
/// Returns the angle of the segment.
pub fn segment_angle(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn segment_angle(args: Args) -> Result<MemoryItem, KclError> {
let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?;
let result = inner_segment_angle(&segment_name, sketch_group, args)?;
let result = inner_segment_angle(&segment_name, sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -162,7 +162,7 @@ pub fn segment_angle(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "segAng",
}]
fn inner_segment_angle(segment_name: &str, sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<f64, KclError> {
fn inner_segment_angle(segment_name: &str, sketch_group: Box<SketchGroup>, args: Args) -> Result<f64, KclError> {
let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
@ -180,9 +180,9 @@ fn inner_segment_angle(segment_name: &str, sketch_group: Box<SketchGroup>, args:
}
/// Returns the angle to match the given length for x.
pub fn angle_to_match_length_x(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angle_to_match_length_x(args: Args) -> Result<MemoryItem, KclError> {
let (segment_name, to, sketch_group) = args.get_segment_name_to_number_sketch_group()?;
let result = inner_angle_to_match_length_x(&segment_name, to, sketch_group, args)?;
let result = inner_angle_to_match_length_x(&segment_name, to, sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -194,7 +194,7 @@ fn inner_angle_to_match_length_x(
segment_name: &str,
to: f64,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<f64, KclError> {
let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| {
KclError::Type(KclErrorDetails {
@ -235,9 +235,9 @@ fn inner_angle_to_match_length_x(
}
/// Returns the angle to match the given length for y.
pub fn angle_to_match_length_y(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angle_to_match_length_y(args: Args) -> Result<MemoryItem, KclError> {
let (segment_name, to, sketch_group) = args.get_segment_name_to_number_sketch_group()?;
let result = inner_angle_to_match_length_y(&segment_name, to, sketch_group, args)?;
let result = inner_angle_to_match_length_y(&segment_name, to, sketch_group, args.clone())?;
args.make_user_val_from_f64(result)
}
@ -249,7 +249,7 @@ fn inner_angle_to_match_length_y(
segment_name: &str,
to: f64,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<f64, KclError> {
let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| {
KclError::Type(KclErrorDetails {

View File

@ -33,10 +33,10 @@ pub enum LineToData {
}
/// Draw a line to a point.
pub fn line_to(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn line_to(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (LineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_line_to(data, sketch_group, args)?;
let new_sketch_group = inner_line_to(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -44,10 +44,10 @@ pub fn line_to(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "lineTo",
}]
fn inner_line_to(
async fn inner_line_to(
data: LineToData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
let to = match data {
@ -67,9 +67,11 @@ fn inner_line_to(
y: to[1],
z: 0.0,
},
relative: false,
},
},
)?;
)
.await?;
let current_path = Path::ToPoint {
base: BasePath {
@ -110,10 +112,10 @@ pub enum AxisLineToData {
}
/// Draw a line to a point on the x-axis.
pub fn x_line_to(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn x_line_to(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AxisLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_x_line_to(data, sketch_group, args)?;
let new_sketch_group = inner_x_line_to(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -121,10 +123,10 @@ pub fn x_line_to(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "xLineTo",
}]
fn inner_x_line_to(
async fn inner_x_line_to(
data: AxisLineToData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
@ -133,16 +135,16 @@ fn inner_x_line_to(
AxisLineToData::Point(data) => LineToData::Point([data, from.y]),
};
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args)?;
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?;
Ok(new_sketch_group)
}
/// Draw a line to a point on the y-axis.
pub fn y_line_to(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn y_line_to(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AxisLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_y_line_to(data, sketch_group, args)?;
let new_sketch_group = inner_y_line_to(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -150,10 +152,10 @@ pub fn y_line_to(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "yLineTo",
}]
fn inner_y_line_to(
async fn inner_y_line_to(
data: AxisLineToData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
@ -162,7 +164,7 @@ fn inner_y_line_to(
AxisLineToData::Point(data) => LineToData::Point([from.x, data]),
};
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args)?;
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?;
Ok(new_sketch_group)
}
@ -183,10 +185,10 @@ pub enum LineData {
}
/// Draw a line.
pub fn line(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn line(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (LineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_line(data, sketch_group, args)?;
let new_sketch_group = inner_line(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -194,13 +196,14 @@ pub fn line(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "line",
}]
fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<Box<SketchGroup>, KclError> {
async fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: Args) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
let inner_args = match &data {
LineData::PointWithTag { to, .. } => *to,
LineData::Point(to) => *to,
};
let delta = inner_args;
let to = [from.x + inner_args[0], from.y + inner_args[1]];
let id = uuid::Uuid::new_v4();
@ -211,13 +214,15 @@ fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: &mut Args) -
path: sketch_group.id,
segment: kittycad::types::PathSegment::Line {
end: Point3D {
x: to[0],
y: to[1],
x: delta[0],
y: delta[1],
z: 0.0,
},
relative: true,
},
},
)?;
)
.await?;
let current_path = Path::ToPoint {
base: BasePath {
@ -258,10 +263,10 @@ pub enum AxisLineData {
}
/// Draw a line on the x-axis.
pub fn x_line(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn x_line(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AxisLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_x_line(data, sketch_group, args)?;
let new_sketch_group = inner_x_line(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -269,25 +274,25 @@ pub fn x_line(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "xLine",
}]
fn inner_x_line(
async fn inner_x_line(
data: AxisLineData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let line_data = match data {
AxisLineData::LengthWithTag { length, tag } => LineData::PointWithTag { to: [length, 0.0], tag },
AxisLineData::Length(length) => LineData::Point([length, 0.0]),
};
let new_sketch_group = inner_line(line_data, sketch_group, args)?;
let new_sketch_group = inner_line(line_data, sketch_group, args).await?;
Ok(new_sketch_group)
}
/// Draw a line on the y-axis.
pub fn y_line(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn y_line(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AxisLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_y_line(data, sketch_group, args)?;
let new_sketch_group = inner_y_line(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -295,17 +300,17 @@ pub fn y_line(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "yLine",
}]
fn inner_y_line(
async fn inner_y_line(
data: AxisLineData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let line_data = match data {
AxisLineData::LengthWithTag { length, tag } => LineData::PointWithTag { to: [0.0, length], tag },
AxisLineData::Length(length) => LineData::Point([0.0, length]),
};
let new_sketch_group = inner_line(line_data, sketch_group, args)?;
let new_sketch_group = inner_line(line_data, sketch_group, args).await?;
Ok(new_sketch_group)
}
@ -328,10 +333,10 @@ pub enum AngledLineData {
}
/// Draw an angled line.
pub fn angled_line(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angled_line(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_angled_line(data, sketch_group, args)?;
let new_sketch_group = inner_angled_line(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -339,20 +344,25 @@ pub fn angled_line(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "angledLine",
}]
fn inner_angled_line(
async fn inner_angled_line(
data: AngledLineData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
let (angle, length) = match &data {
AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length),
AngledLineData::AngleAndLength(angle_and_length) => (angle_and_length[0], angle_and_length[1]),
};
let to: [f64; 2] = [
from.x + length * f64::cos(angle.to_radians()),
from.y + length * f64::sin(angle.to_radians()),
//double check me on this one - mike
let delta: [f64; 2] = [
length * f64::cos(angle.to_radians()),
length * f64::sin(angle.to_radians()),
];
let relative = true;
let to: [f64; 2] = [from.x + delta[0], from.y + delta[1]];
let id = uuid::Uuid::new_v4();
@ -378,13 +388,15 @@ fn inner_angled_line(
path: sketch_group.id,
segment: kittycad::types::PathSegment::Line {
end: Point3D {
x: to[0],
y: to[1],
x: delta[0],
y: delta[1],
z: 0.0,
},
relative,
},
},
)?;
)
.await?;
let mut new_sketch_group = sketch_group.clone();
new_sketch_group.value.push(current_path);
@ -392,10 +404,10 @@ fn inner_angled_line(
}
/// Draw an angled line of a given x length.
pub fn angled_line_of_x_length(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angled_line_of_x_length(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, args)?;
let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -403,10 +415,10 @@ pub fn angled_line_of_x_length(args: &mut Args) -> Result<MemoryItem, KclError>
#[stdlib {
name = "angledLineOfXLength",
}]
fn inner_angled_line_of_x_length(
async fn inner_angled_line_of_x_length(
data: AngledLineData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let (angle, length) = match &data {
AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length),
@ -423,7 +435,8 @@ fn inner_angled_line_of_x_length(
},
sketch_group,
args,
)?;
)
.await?;
Ok(new_sketch_group)
}
@ -447,10 +460,10 @@ pub enum AngledLineToData {
}
/// Draw an angled line to a given x coordinate.
pub fn angled_line_to_x(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angled_line_to_x(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AngledLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_angled_line_to_x(data, sketch_group, args)?;
let new_sketch_group = inner_angled_line_to_x(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -458,10 +471,10 @@ pub fn angled_line_to_x(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "angledLineToX",
}]
fn inner_angled_line_to_x(
async fn inner_angled_line_to_x(
data: AngledLineToData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
let (angle, x_to) = match &data {
@ -481,15 +494,16 @@ fn inner_angled_line_to_x(
},
sketch_group,
args,
)?;
)
.await?;
Ok(new_sketch_group)
}
/// Draw an angled line of a given y length.
pub fn angled_line_of_y_length(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angled_line_of_y_length(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, args)?;
let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -498,10 +512,10 @@ pub fn angled_line_of_y_length(args: &mut Args) -> Result<MemoryItem, KclError>
#[stdlib {
name = "angledLineOfYLength",
}]
fn inner_angled_line_of_y_length(
async fn inner_angled_line_of_y_length(
data: AngledLineData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let (angle, length) = match &data {
AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length),
@ -518,16 +532,17 @@ fn inner_angled_line_of_y_length(
},
sketch_group,
args,
)?;
)
.await?;
Ok(new_sketch_group)
}
/// Draw an angled line to a given y coordinate.
pub fn angled_line_to_y(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angled_line_to_y(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AngledLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_angled_line_to_y(data, sketch_group, args)?;
let new_sketch_group = inner_angled_line_to_y(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -535,10 +550,10 @@ pub fn angled_line_to_y(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "angledLineToY",
}]
fn inner_angled_line_to_y(
async fn inner_angled_line_to_y(
data: AngledLineToData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
let (angle, y_to) = match &data {
@ -558,7 +573,8 @@ fn inner_angled_line_to_y(
},
sketch_group,
args,
)?;
)
.await?;
Ok(new_sketch_group)
}
@ -579,9 +595,9 @@ pub struct AngeledLineThatIntersectsData {
}
/// Draw an angled line that intersects with a given line.
pub fn angled_line_that_intersects(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (AngeledLineThatIntersectsData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, args)?;
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -589,10 +605,10 @@ pub fn angled_line_that_intersects(args: &mut Args) -> Result<MemoryItem, KclErr
#[stdlib {
name = "angledLineThatIntersects",
}]
fn inner_angled_line_that_intersects(
async fn inner_angled_line_that_intersects(
data: AngeledLineThatIntersectsData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let intersect_path = sketch_group
.get_path_by_name(&data.intersect_tag)
@ -621,15 +637,15 @@ fn inner_angled_line_that_intersects(
LineToData::Point(to.into())
};
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args)?;
let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?;
Ok(new_sketch_group)
}
/// Start a sketch at a given point.
pub fn start_sketch_at(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn start_sketch_at(args: Args) -> Result<MemoryItem, KclError> {
let data: LineData = args.get_data()?;
let sketch_group = inner_start_sketch_at(data, args)?;
let sketch_group = inner_start_sketch_at(data, args).await?;
Ok(MemoryItem::SketchGroup(sketch_group))
}
@ -637,7 +653,7 @@ pub fn start_sketch_at(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "startSketchAt",
}]
fn inner_start_sketch_at(data: LineData, args: &mut Args) -> Result<Box<SketchGroup>, KclError> {
async fn inner_start_sketch_at(data: LineData, args: Args) -> Result<Box<SketchGroup>, KclError> {
let to = match &data {
LineData::PointWithTag { to, .. } => *to,
LineData::Point(to) => *to,
@ -646,7 +662,7 @@ fn inner_start_sketch_at(data: LineData, args: &mut Args) -> Result<Box<SketchGr
let id = uuid::Uuid::new_v4();
let path_id = uuid::Uuid::new_v4();
args.send_modeling_cmd(path_id, ModelingCmd::StartPath {})?;
args.send_modeling_cmd(path_id, ModelingCmd::StartPath {}).await?;
args.send_modeling_cmd(
id,
ModelingCmd::MovePathPen {
@ -657,7 +673,8 @@ fn inner_start_sketch_at(data: LineData, args: &mut Args) -> Result<Box<SketchGr
z: 0.0,
},
},
)?;
)
.await?;
let current_path = BasePath {
from: to,
@ -685,10 +702,10 @@ fn inner_start_sketch_at(data: LineData, args: &mut Args) -> Result<Box<SketchGr
}
/// Close the current sketch.
pub fn close(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn close(args: Args) -> Result<MemoryItem, KclError> {
let sketch_group = args.get_sketch_group()?;
let new_sketch_group = inner_close(sketch_group, args)?;
let new_sketch_group = inner_close(sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -697,7 +714,7 @@ pub fn close(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "close",
}]
fn inner_close(sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<Box<SketchGroup>, KclError> {
async fn inner_close(sketch_group: Box<SketchGroup>, args: Args) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
let to: Point2d = sketch_group.start.from.into();
@ -708,7 +725,8 @@ fn inner_close(sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<Box<Sk
ModelingCmd::ClosePath {
path_id: sketch_group.id,
},
)?;
)
.await?;
let mut new_sketch_group = sketch_group.clone();
new_sketch_group.value.push(Path::ToPoint {
@ -775,10 +793,10 @@ pub enum ArcData {
}
/// Draw an arc.
pub fn arc(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn arc(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (ArcData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_arc(data, sketch_group, args)?;
let new_sketch_group = inner_arc(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -786,7 +804,7 @@ pub fn arc(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "arc",
}]
fn inner_arc(data: ArcData, sketch_group: Box<SketchGroup>, args: &mut Args) -> Result<Box<SketchGroup>, KclError> {
async fn inner_arc(data: ArcData, sketch_group: Box<SketchGroup>, args: Args) -> Result<Box<SketchGroup>, KclError> {
let from: Point2d = sketch_group.get_coords_from_paths()?;
let (center, angle_start, angle_end, radius, end) = match &data {
@ -832,9 +850,15 @@ fn inner_arc(data: ArcData, sketch_group: Box<SketchGroup>, args: &mut Args) ->
angle_end: angle_end.degrees(),
center: center.into(),
radius,
relative: false,
},
},
)?;
)
.await?;
// TODO: Dont do this (move path pen) - mike
// lets review what the needs are here and see if any existing arc endpoints can accomplish this
// Move the path pen to the end of the arc.
// Since that is where we want to draw the next path.
// TODO: the engine should automatically move the pen to the end of the arc.
@ -849,7 +873,8 @@ fn inner_arc(data: ArcData, sketch_group: Box<SketchGroup>, args: &mut Args) ->
z: 0.0,
},
},
)?;
)
.await?;
let current_path = Path::ToPoint {
base: BasePath {
@ -902,10 +927,10 @@ pub enum BezierData {
}
/// Draw a bezier curve.
pub fn bezier_curve(args: &mut Args) -> Result<MemoryItem, KclError> {
pub async fn bezier_curve(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (BezierData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_bezier_curve(data, sketch_group, args)?;
let new_sketch_group = inner_bezier_curve(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
@ -913,10 +938,10 @@ pub fn bezier_curve(args: &mut Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "bezierCurve",
}]
fn inner_bezier_curve(
async fn inner_bezier_curve(
data: BezierData,
sketch_group: Box<SketchGroup>,
args: &mut Args,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from = sketch_group.get_coords_from_paths()?;
@ -927,6 +952,8 @@ fn inner_bezier_curve(
BezierData::Points { to, control1, control2 } => (to, control1, control2),
};
let relative = true;
let delta = to;
let to = [from.x + to[0], from.y + to[1]];
let id = uuid::Uuid::new_v4();
@ -937,23 +964,25 @@ fn inner_bezier_curve(
path: sketch_group.id,
segment: kittycad::types::PathSegment::Bezier {
control1: Point3D {
x: from.x + control1[0],
y: from.y + control1[1],
x: control1[0],
y: control1[1],
z: 0.0,
},
control2: Point3D {
x: from.x + control2[0],
y: from.y + control2[1],
x: control2[0],
y: control2[1],
z: 0.0,
},
end: Point3D {
x: to[0],
y: to[1],
x: delta[0],
y: delta[1],
z: 0.0,
},
relative,
},
},
)?;
)
.await?;
let current_path = Path::ToPoint {
base: BasePath {

View File

@ -3,7 +3,7 @@ use std::str::FromStr;
use anyhow::Result;
use lazy_static::lazy_static;
use parse_display::{Display, FromStr};
use regex::Regex;
use regex::bytes::Regex;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tower_lsp::lsp_types::SemanticTokenType;
@ -44,6 +44,7 @@ pub enum TokenType {
Function,
}
/// Most KCL tokens correspond to LSP semantic tokens (but not all).
impl TryFrom<TokenType> for SemanticTokenType {
type Error = anyhow::Error;
fn try_from(token_type: TokenType) -> Result<Self> {
@ -70,7 +71,7 @@ impl TryFrom<TokenType> for SemanticTokenType {
impl TokenType {
// This is for the lsp server.
pub fn to_semantic_token_types() -> Result<Vec<SemanticTokenType>> {
pub fn all_semantic_token_types() -> Result<Vec<SemanticTokenType>> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
@ -119,7 +120,9 @@ impl TokenType {
pub struct Token {
#[serde(rename = "type")]
pub token_type: TokenType,
/// Offset in the source code where this token begins.
pub start: usize,
/// Offset in the source code where this token ends.
pub end: usize,
pub value: String,
}
@ -159,218 +162,95 @@ lazy_static! {
static ref BLOCKCOMMENT: Regex = Regex::new(r"^/\*[\s\S]*?\*/").unwrap();
}
fn is_number(character: &str) -> bool {
NUMBER.is_match(character)
}
fn is_whitespace(character: &str) -> bool {
WHITESPACE.is_match(character)
}
fn is_word(character: &str) -> bool {
WORD.is_match(character)
}
fn is_keyword(character: &str) -> bool {
KEYWORD.is_match(character)
}
fn is_string(character: &str) -> bool {
fn is_string(character: &[u8]) -> bool {
match STRING.find(character) {
Some(m) => m.start() == 0,
None => false,
}
}
fn is_operator(character: &str) -> bool {
OPERATOR.is_match(character)
}
fn is_block_start(character: &str) -> bool {
BLOCK_START.is_match(character)
}
fn is_block_end(character: &str) -> bool {
BLOCK_END.is_match(character)
}
fn is_paran_start(character: &str) -> bool {
PARAN_START.is_match(character)
}
fn is_paran_end(character: &str) -> bool {
PARAN_END.is_match(character)
}
fn is_array_start(character: &str) -> bool {
ARRAY_START.is_match(character)
}
fn is_array_end(character: &str) -> bool {
ARRAY_END.is_match(character)
}
fn is_comma(character: &str) -> bool {
COMMA.is_match(character)
}
fn is_colon(character: &str) -> bool {
COLON.is_match(character)
}
fn is_double_period(character: &str) -> bool {
DOUBLE_PERIOD.is_match(character)
}
fn is_period(character: &str) -> bool {
PERIOD.is_match(character)
}
fn is_line_comment(character: &str) -> bool {
LINECOMMENT.is_match(character)
}
fn is_block_comment(character: &str) -> bool {
BLOCKCOMMENT.is_match(character)
fn match_first(s: &[u8], regex: &Regex) -> Option<String> {
regex
.find(s)
.map(|the_match| String::from_utf8_lossy(the_match.as_bytes()).into())
}
fn match_first(s: &str, regex: &Regex) -> Option<String> {
regex.find(s).map(|the_match| the_match.as_str().to_string())
}
fn make_token(token_type: TokenType, value: &str, start: usize) -> Token {
fn make_token(token_type: TokenType, value: String, start: usize) -> Token {
Token {
token_type,
value: value.to_string(),
start,
end: start + value.len(),
value,
start,
}
}
fn return_token_at_index(s: &str, start_index: usize) -> Option<Token> {
let str_from_index = &s.chars().skip(start_index).collect::<String>();
fn return_token_at_index(str_from_index: &[u8], start_index: usize) -> Option<Token> {
if is_string(str_from_index) {
return Some(make_token(
TokenType::String,
&match_first(str_from_index, &STRING)?,
match_first(str_from_index, &STRING)?,
start_index,
));
}
let is_line_comment_bool = is_line_comment(str_from_index);
if is_line_comment_bool || is_block_comment(str_from_index) {
return Some(make_token(
if is_line_comment_bool {
TokenType::LineComment
} else {
TokenType::BlockComment
},
&match_first(
str_from_index,
if is_line_comment_bool {
&LINECOMMENT
} else {
&BLOCKCOMMENT
},
)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &LINECOMMENT) {
return Some(make_token(TokenType::LineComment, val, start_index));
}
if is_paran_end(str_from_index) {
return Some(make_token(
TokenType::Brace,
&match_first(str_from_index, &PARAN_END)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &BLOCKCOMMENT) {
return Some(make_token(TokenType::BlockComment, val, start_index));
}
if is_paran_start(str_from_index) {
return Some(make_token(
TokenType::Brace,
&match_first(str_from_index, &PARAN_START)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &PARAN_END) {
return Some(make_token(TokenType::Brace, val, start_index));
}
if is_block_start(str_from_index) {
return Some(make_token(
TokenType::Brace,
&match_first(str_from_index, &BLOCK_START)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &PARAN_START) {
return Some(make_token(TokenType::Brace, val, start_index));
}
if is_block_end(str_from_index) {
return Some(make_token(
TokenType::Brace,
&match_first(str_from_index, &BLOCK_END)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &BLOCK_START) {
return Some(make_token(TokenType::Brace, val, start_index));
}
if is_array_start(str_from_index) {
return Some(make_token(
TokenType::Brace,
&match_first(str_from_index, &ARRAY_START)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &BLOCK_END) {
return Some(make_token(TokenType::Brace, val, start_index));
}
if is_array_end(str_from_index) {
return Some(make_token(
TokenType::Brace,
&match_first(str_from_index, &ARRAY_END)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &ARRAY_START) {
return Some(make_token(TokenType::Brace, val, start_index));
}
if is_comma(str_from_index) {
return Some(make_token(
TokenType::Comma,
&match_first(str_from_index, &COMMA)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &ARRAY_END) {
return Some(make_token(TokenType::Brace, val, start_index));
}
if is_operator(str_from_index) {
return Some(make_token(
TokenType::Operator,
&match_first(str_from_index, &OPERATOR)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &COMMA) {
return Some(make_token(TokenType::Comma, val, start_index));
}
if is_number(str_from_index) {
return Some(make_token(
TokenType::Number,
&match_first(str_from_index, &NUMBER)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &OPERATOR) {
return Some(make_token(TokenType::Operator, val, start_index));
}
if is_keyword(str_from_index) {
return Some(make_token(
TokenType::Keyword,
&match_first(str_from_index, &KEYWORD)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &NUMBER) {
return Some(make_token(TokenType::Number, val, start_index));
}
if is_word(str_from_index) {
return Some(make_token(
TokenType::Word,
&match_first(str_from_index, &WORD)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &KEYWORD) {
return Some(make_token(TokenType::Keyword, val, start_index));
}
if is_colon(str_from_index) {
return Some(make_token(
TokenType::Colon,
&match_first(str_from_index, &COLON)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &WORD) {
return Some(make_token(TokenType::Word, val, start_index));
}
if is_double_period(str_from_index) {
return Some(make_token(
TokenType::DoublePeriod,
&match_first(str_from_index, &DOUBLE_PERIOD)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &COLON) {
return Some(make_token(TokenType::Colon, val, start_index));
}
if is_period(str_from_index) {
return Some(make_token(
TokenType::Period,
&match_first(str_from_index, &PERIOD)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &DOUBLE_PERIOD) {
return Some(make_token(TokenType::DoublePeriod, val, start_index));
}
if is_whitespace(str_from_index) {
return Some(make_token(
TokenType::Whitespace,
&match_first(str_from_index, &WHITESPACE)?,
start_index,
));
if let Some(val) = match_first(str_from_index, &PERIOD) {
return Some(make_token(TokenType::Period, val, start_index));
}
if let Some(val) = match_first(str_from_index, &WHITESPACE) {
return Some(make_token(TokenType::Whitespace, val, start_index));
}
None
}
fn recursively_tokenise(s: &str, current_index: usize, previous_tokens: Vec<Token>) -> Vec<Token> {
fn recursively_tokenise(s: &[u8], current_index: usize, previous_tokens: Vec<Token>) -> Vec<Token> {
if current_index >= s.len() {
return previous_tokens;
}
let token = return_token_at_index(s, current_index);
let token = return_token_at_index(&s[current_index..], current_index);
let Some(token) = token else {
return recursively_tokenise(s, current_index + 1, previous_tokens);
};
@ -381,7 +261,7 @@ fn recursively_tokenise(s: &str, current_index: usize, previous_tokens: Vec<Toke
}
pub fn lexer(s: &str) -> Vec<Token> {
recursively_tokenise(s, 0, Vec::new())
recursively_tokenise(s.as_bytes(), 0, Vec::new())
}
#[cfg(test)]
@ -390,201 +270,243 @@ mod tests {
use super::*;
fn is_paren_end(character: &[u8]) -> bool {
PARAN_END.is_match(character)
}
fn is_number(character: &[u8]) -> bool {
NUMBER.is_match(character)
}
fn is_whitespace(character: &[u8]) -> bool {
WHITESPACE.is_match(character)
}
fn is_word(character: &[u8]) -> bool {
WORD.is_match(character)
}
fn is_string(character: &[u8]) -> bool {
match STRING.find(character) {
Some(m) => m.start() == 0,
None => false,
}
}
fn is_operator(character: &[u8]) -> bool {
OPERATOR.is_match(character)
}
fn is_block_start(character: &[u8]) -> bool {
BLOCK_START.is_match(character)
}
fn is_block_end(character: &[u8]) -> bool {
BLOCK_END.is_match(character)
}
fn is_paren_start(character: &[u8]) -> bool {
PARAN_START.is_match(character)
}
fn is_comma(character: &[u8]) -> bool {
COMMA.is_match(character)
}
fn is_line_comment(character: &[u8]) -> bool {
LINECOMMENT.is_match(character)
}
fn is_block_comment(character: &[u8]) -> bool {
BLOCKCOMMENT.is_match(character)
}
#[test]
fn is_number_test() {
assert!(is_number("1"));
assert!(is_number("1 abc"));
assert!(is_number("1.1"));
assert!(is_number("1.1 abc"));
assert!(!is_number("a"));
assert!(is_number("1".as_bytes()));
assert!(is_number("1 abc".as_bytes()));
assert!(is_number("1.1".as_bytes()));
assert!(is_number("1.1 abc".as_bytes()));
assert!(!is_number("a".as_bytes()));
assert!(is_number("1"));
assert!(is_number(".1"));
assert!(is_number("5?"));
assert!(is_number("5 + 6"));
assert!(is_number("5 + a"));
assert!(is_number("5.5"));
assert!(is_number("1".as_bytes()));
assert!(is_number(".1".as_bytes()));
assert!(is_number("5?".as_bytes()));
assert!(is_number("5 + 6".as_bytes()));
assert!(is_number("5 + a".as_bytes()));
assert!(is_number("5.5".as_bytes()));
assert!(!is_number("1abc"));
assert!(!is_number("a"));
assert!(!is_number("?"));
assert!(!is_number("?5"));
assert!(!is_number("1abc".as_bytes()));
assert!(!is_number("a".as_bytes()));
assert!(!is_number("?".as_bytes()));
assert!(!is_number("?5".as_bytes()));
}
#[test]
fn is_whitespace_test() {
assert!(is_whitespace(" "));
assert!(is_whitespace(" "));
assert!(is_whitespace(" a"));
assert!(is_whitespace("a "));
assert!(is_whitespace(" ".as_bytes()));
assert!(is_whitespace(" ".as_bytes()));
assert!(is_whitespace(" a".as_bytes()));
assert!(is_whitespace("a ".as_bytes()));
assert!(!is_whitespace("a"));
assert!(!is_whitespace("?"));
assert!(!is_whitespace("a".as_bytes()));
assert!(!is_whitespace("?".as_bytes()));
}
#[test]
fn is_word_test() {
assert!(is_word("a"));
assert!(is_word("a "));
assert!(is_word("a5"));
assert!(is_word("a5a"));
assert!(is_word("a".as_bytes()));
assert!(is_word("a ".as_bytes()));
assert!(is_word("a5".as_bytes()));
assert!(is_word("a5a".as_bytes()));
assert!(!is_word("5"));
assert!(!is_word("5a"));
assert!(!is_word("5a5"));
assert!(!is_word("5".as_bytes()));
assert!(!is_word("5a".as_bytes()));
assert!(!is_word("5a5".as_bytes()));
}
#[test]
fn is_string_test() {
assert!(is_string("\"\""));
assert!(is_string("\"a\""));
assert!(is_string("\"a\" "));
assert!(is_string("\"a\"5"));
assert!(is_string("'a'5"));
assert!(is_string("\"with escaped \\\" backslash\""));
assert!(is_string("\"\"".as_bytes()));
assert!(is_string("\"a\"".as_bytes()));
assert!(is_string("\"a\" ".as_bytes()));
assert!(is_string("\"a\"5".as_bytes()));
assert!(is_string("'a'5".as_bytes()));
assert!(is_string("\"with escaped \\\" backslash\"".as_bytes()));
assert!(!is_string("\""));
assert!(!is_string("\"a"));
assert!(!is_string("a\""));
assert!(!is_string(" \"a\""));
assert!(!is_string("5\"a\""));
assert!(!is_string("a + 'str'"));
assert!(is_string("'c'"));
assert!(!is_string("\"".as_bytes()));
assert!(!is_string("\"a".as_bytes()));
assert!(!is_string("a\"".as_bytes()));
assert!(!is_string(" \"a\"".as_bytes()));
assert!(!is_string("5\"a\"".as_bytes()));
assert!(!is_string("a + 'str'".as_bytes()));
assert!(is_string("'c'".as_bytes()));
}
#[test]
fn is_operator_test() {
assert!(is_operator("+"));
assert!(is_operator("+ "));
assert!(is_operator("-"));
assert!(is_operator("<="));
assert!(is_operator("<= "));
assert!(is_operator(">="));
assert!(is_operator(">= "));
assert!(is_operator("> "));
assert!(is_operator("< "));
assert!(is_operator("| "));
assert!(is_operator("|> "));
assert!(is_operator("^ "));
assert!(is_operator("% "));
assert!(is_operator("+* "));
assert!(is_operator("+".as_bytes()));
assert!(is_operator("+ ".as_bytes()));
assert!(is_operator("-".as_bytes()));
assert!(is_operator("<=".as_bytes()));
assert!(is_operator("<= ".as_bytes()));
assert!(is_operator(">=".as_bytes()));
assert!(is_operator(">= ".as_bytes()));
assert!(is_operator("> ".as_bytes()));
assert!(is_operator("< ".as_bytes()));
assert!(is_operator("| ".as_bytes()));
assert!(is_operator("|> ".as_bytes()));
assert!(is_operator("^ ".as_bytes()));
assert!(is_operator("% ".as_bytes()));
assert!(is_operator("+* ".as_bytes()));
assert!(!is_operator("5 + 5"));
assert!(!is_operator("a"));
assert!(!is_operator("a+"));
assert!(!is_operator("a+5"));
assert!(!is_operator("5a+5"));
assert!(!is_operator(", newVar"));
assert!(!is_operator(","));
assert!(!is_operator("5 + 5".as_bytes()));
assert!(!is_operator("a".as_bytes()));
assert!(!is_operator("a+".as_bytes()));
assert!(!is_operator("a+5".as_bytes()));
assert!(!is_operator("5a+5".as_bytes()));
assert!(!is_operator(", newVar".as_bytes()));
assert!(!is_operator(",".as_bytes()));
}
#[test]
fn is_block_start_test() {
assert!(is_block_start("{"));
assert!(is_block_start("{ "));
assert!(is_block_start("{5"));
assert!(is_block_start("{a"));
assert!(is_block_start("{5 "));
assert!(is_block_start("{".as_bytes()));
assert!(is_block_start("{ ".as_bytes()));
assert!(is_block_start("{5".as_bytes()));
assert!(is_block_start("{a".as_bytes()));
assert!(is_block_start("{5 ".as_bytes()));
assert!(!is_block_start("5"));
assert!(!is_block_start("5 + 5"));
assert!(!is_block_start("5{ + 5"));
assert!(!is_block_start("a{ + 5"));
assert!(!is_block_start(" { + 5"));
assert!(!is_block_start("5".as_bytes()));
assert!(!is_block_start("5 + 5".as_bytes()));
assert!(!is_block_start("5{ + 5".as_bytes()));
assert!(!is_block_start("a{ + 5".as_bytes()));
assert!(!is_block_start(" { + 5".as_bytes()));
}
#[test]
fn is_block_end_test() {
assert!(is_block_end("}"));
assert!(is_block_end("} "));
assert!(is_block_end("}5"));
assert!(is_block_end("}5 "));
assert!(is_block_end("}".as_bytes()));
assert!(is_block_end("} ".as_bytes()));
assert!(is_block_end("}5".as_bytes()));
assert!(is_block_end("}5 ".as_bytes()));
assert!(!is_block_end("5"));
assert!(!is_block_end("5 + 5"));
assert!(!is_block_end("5} + 5"));
assert!(!is_block_end(" } + 5"));
assert!(!is_block_end("5".as_bytes()));
assert!(!is_block_end("5 + 5".as_bytes()));
assert!(!is_block_end("5} + 5".as_bytes()));
assert!(!is_block_end(" } + 5".as_bytes()));
}
#[test]
fn is_paran_start_test() {
assert!(is_paran_start("("));
assert!(is_paran_start("( "));
assert!(is_paran_start("(5"));
assert!(is_paran_start("(5 "));
assert!(is_paran_start("(5 + 5"));
assert!(is_paran_start("(5 + 5)"));
assert!(is_paran_start("(5 + 5) "));
fn is_paren_start_test() {
assert!(is_paren_start("(".as_bytes()));
assert!(is_paren_start("( ".as_bytes()));
assert!(is_paren_start("(5".as_bytes()));
assert!(is_paren_start("(5 ".as_bytes()));
assert!(is_paren_start("(5 + 5".as_bytes()));
assert!(is_paren_start("(5 + 5)".as_bytes()));
assert!(is_paren_start("(5 + 5) ".as_bytes()));
assert!(!is_paran_start("5"));
assert!(!is_paran_start("5 + 5"));
assert!(!is_paran_start("5( + 5)"));
assert!(!is_paran_start(" ( + 5)"));
assert!(!is_paren_start("5".as_bytes()));
assert!(!is_paren_start("5 + 5".as_bytes()));
assert!(!is_paren_start("5( + 5)".as_bytes()));
assert!(!is_paren_start(" ( + 5)".as_bytes()));
}
#[test]
fn is_paran_end_test() {
assert!(is_paran_end(")"));
assert!(is_paran_end(") "));
assert!(is_paran_end(")5"));
assert!(is_paran_end(")5 "));
fn is_paren_end_test() {
assert!(is_paren_end(")".as_bytes()));
assert!(is_paren_end(") ".as_bytes()));
assert!(is_paren_end(")5".as_bytes()));
assert!(is_paren_end(")5 ".as_bytes()));
assert!(!is_paran_end("5"));
assert!(!is_paran_end("5 + 5"));
assert!(!is_paran_end("5) + 5"));
assert!(!is_paran_end(" ) + 5"));
assert!(!is_paren_end("5".as_bytes()));
assert!(!is_paren_end("5 + 5".as_bytes()));
assert!(!is_paren_end("5) + 5".as_bytes()));
assert!(!is_paren_end(" ) + 5".as_bytes()));
}
#[test]
fn is_comma_test() {
assert!(is_comma(","));
assert!(is_comma(", "));
assert!(is_comma(",5"));
assert!(is_comma(",5 "));
assert!(is_comma(",".as_bytes()));
assert!(is_comma(", ".as_bytes()));
assert!(is_comma(",5".as_bytes()));
assert!(is_comma(",5 ".as_bytes()));
assert!(!is_comma("5"));
assert!(!is_comma("5 + 5"));
assert!(!is_comma("5, + 5"));
assert!(!is_comma(" , + 5"));
assert!(!is_comma("5".as_bytes()));
assert!(!is_comma("5 + 5".as_bytes()));
assert!(!is_comma("5, + 5".as_bytes()));
assert!(!is_comma(" , + 5".as_bytes()));
}
#[test]
fn is_line_comment_test() {
assert!(is_line_comment("//"));
assert!(is_line_comment("// "));
assert!(is_line_comment("//5"));
assert!(is_line_comment("//5 "));
assert!(is_line_comment("//".as_bytes()));
assert!(is_line_comment("// ".as_bytes()));
assert!(is_line_comment("//5".as_bytes()));
assert!(is_line_comment("//5 ".as_bytes()));
assert!(!is_line_comment("5"));
assert!(!is_line_comment("5 + 5"));
assert!(!is_line_comment("5// + 5"));
assert!(!is_line_comment(" // + 5"));
assert!(!is_line_comment("5".as_bytes()));
assert!(!is_line_comment("5 + 5".as_bytes()));
assert!(!is_line_comment("5// + 5".as_bytes()));
assert!(!is_line_comment(" // + 5".as_bytes()));
}
#[test]
fn is_block_comment_test() {
assert!(is_block_comment("/* */"));
assert!(is_block_comment("/***/"));
assert!(is_block_comment("/*5*/"));
assert!(is_block_comment("/*5 */"));
assert!(is_block_comment("/* */".as_bytes()));
assert!(is_block_comment("/***/".as_bytes()));
assert!(is_block_comment("/*5*/".as_bytes()));
assert!(is_block_comment("/*5 */".as_bytes()));
assert!(!is_block_comment("/*"));
assert!(!is_block_comment("5"));
assert!(!is_block_comment("5 + 5"));
assert!(!is_block_comment("5/* + 5"));
assert!(!is_block_comment(" /* + 5"));
assert!(!is_block_comment("/*".as_bytes()));
assert!(!is_block_comment("5".as_bytes()));
assert!(!is_block_comment("5 + 5".as_bytes()));
assert!(!is_block_comment("5/* + 5".as_bytes()));
assert!(!is_block_comment(" /* + 5".as_bytes()));
assert!(!is_block_comment(
r#" /* and
here
*/
"#
.as_bytes()
));
}
#[test]
fn make_token_test() {
assert_eq!(
make_token(TokenType::Keyword, "const", 56),
make_token(TokenType::Keyword, "const".to_owned(), 56),
Token {
token_type: TokenType::Keyword,
value: "const".to_string(),
@ -597,7 +519,7 @@ mod tests {
#[test]
fn return_token_at_index_test() {
assert_eq!(
return_token_at_index("const", 0),
return_token_at_index("const".as_bytes(), 0),
Some(Token {
token_type: TokenType::Keyword,
value: "const".to_string(),
@ -606,7 +528,7 @@ mod tests {
})
);
assert_eq!(
return_token_at_index(" 4554", 2),
return_token_at_index("4554".as_bytes(), 2),
Some(Token {
token_type: TokenType::Number,
value: "4554".to_string(),
@ -717,7 +639,7 @@ mod tests {
// We have this as a test so we can ensure it never panics with an unwrap in the server.
#[test]
fn test_token_type_to_semantic_token_type() {
let semantic_types = TokenType::to_semantic_token_types().unwrap();
let semantic_types = TokenType::all_semantic_token_types().unwrap();
assert!(!semantic_types.is_empty());
}

View File

@ -21,11 +21,12 @@ pub async fn execute_wasm(
let program: kcl_lib::ast::types::Program = serde_json::from_str(program_str).map_err(|e| e.to_string())?;
let mut mem: kcl_lib::executor::ProgramMemory = serde_json::from_str(memory_str).map_err(|e| e.to_string())?;
let mut engine = kcl_lib::engine::EngineConnection::new(manager)
let engine = kcl_lib::engine::EngineConnection::new(manager)
.await
.map_err(|e| format!("{:?}", e))?;
let memory = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &mut engine)
let memory = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &engine)
.await
.map_err(String::from)?;
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
// gloo-serialize crate instead.
@ -148,7 +149,7 @@ pub async fn lsp_run(config: ServerConfig) -> Result<(), JsValue> {
let stdlib_signatures = get_signatures_from_stdlib(&stdlib).map_err(|e| e.to_string())?;
// We can unwrap here because we know the tokeniser is valid, since
// we have a test for it.
let token_types = kcl_lib::tokeniser::TokenType::to_semantic_token_types().unwrap();
let token_types = kcl_lib::tokeniser::TokenType::all_semantic_token_types().unwrap();
let (service, socket) = LspService::new(|client| Backend {
client,

View File

@ -0,0 +1,310 @@
const svg = startSketchAt([0, 0])
|> lineTo([2.52, -26.04], %) // MoveAbsolute
|> lineTo([2.52, -25.2], %) // VerticalLineAbsolute
|> lineTo([0.84, -25.2], %) // HorizontalLineAbsolute
|> lineTo([0.84, -24.36], %) // VerticalLineAbsolute
|> lineTo([0, -24.36], %) // HorizontalLineAbsolute
|> lineTo([0, -6.72], %) // VerticalLineAbsolute
|> lineTo([0.84, -6.72], %) // HorizontalLineAbsolute
|> lineTo([0.84, -5.88], %) // VerticalLineAbsolute
|> lineTo([1.68, -5.88], %) // HorizontalLineAbsolute
|> lineTo([1.68, -5.04], %) // VerticalLineAbsolute
|> lineTo([2.52, -5.04], %) // HorizontalLineAbsolute
|> lineTo([2.52, -4.2], %) // VerticalLineAbsolute
|> lineTo([3.36, -4.2], %) // HorizontalLineAbsolute
|> lineTo([3.36, -3.36], %) // VerticalLineAbsolute
|> lineTo([17.64, -3.36], %) // HorizontalLineAbsolute
|> lineTo([17.64, -4.2], %) // VerticalLineAbsolute
|> lineTo([18.48, -4.2], %) // HorizontalLineRelative
|> lineTo([18.48, -5.04], %) // VerticalLineHorizonal
|> lineTo([19.32, -5.04], %) // HorizontalLineRelative
|> lineTo([19.32, -5.88], %) // VerticalLineHorizonal
|> lineTo([20.16, -5.88], %) // HorizontalLineRelative
|> lineTo([20.16, -6.72], %) // VerticalLineAbsolute
|> lineTo([21, -6.72], %) // HorizontalLineAbsolute
|> lineTo([21, -24.36], %) // VerticalLineHorizonal
|> lineTo([20.16, -24.36], %) // HorizontalLineRelative
|> lineTo([20.16, -25.2], %) // VerticalLineHorizonal
|> lineTo([18.48, -25.2], %) // HorizontalLineRelative
|> lineTo([18.48, -26.04], %) // VerticalLineHorizonal
|> lineTo([15.96, -26.04], %) // HorizontalLineRelative
|> lineTo([15.96, -26.88], %) // VerticalLineHorizonal
|> lineTo([16.8, -26.88], %) // HorizontalLineRelative
|> lineTo([16.8, -28.56], %) // VerticalLineHorizonal
|> lineTo([11.76, -28.56], %) // HorizontalLineAbsolute
|> lineTo([11.76, -26.88], %) // VerticalLineAbsolute
|> lineTo([12.6, -26.88], %) // HorizontalLineAbsolute
|> lineTo([12.6, -26.04], %) // VerticalLineAbsolute
|> lineTo([8.4, -26.04], %) // HorizontalLineAbsolute
|> lineTo([8.4, -26.88], %) // VerticalLineHorizonal
|> lineTo([9.24, -26.88], %) // HorizontalLineRelative
|> lineTo([9.24, -28.56], %) // VerticalLineHorizonal
|> lineTo([4.2, -28.56], %) // HorizontalLineAbsolute
|> lineTo([4.2, -26.88], %) // VerticalLineHorizonal
|> lineTo([5.04, -26.88], %) // HorizontalLineRelative
|> lineTo([5.04, -26.04], %) // VerticalLineHorizonal
|> lineTo([0.839996, -20.58], %) // MoveRelative
|> lineTo([0.839996, -24.36], %) // VerticalLineHorizonal
|> lineTo([2.52, -24.36], %) // HorizontalLineAbsolute
|> lineTo([2.52, -25.2], %) // VerticalLineHorizonal
|> lineTo([18.48, -25.2], %) // HorizontalLineRelative
|> lineTo([18.48, -24.36], %) // VerticalLineHorizonal
|> lineTo([20.16, -24.36], %) // HorizontalLineRelative
|> lineTo([20.16, -20.58], %) // VerticalLineAbsolute
// StopAbsolute
|> lineTo([7.56, -24.36], %) // MoveAbsolute
|> lineTo([7.56, -22.68], %) // VerticalLineHorizonal
|> lineTo([13.44, -22.68], %) // HorizontalLineRelative
|> lineTo([13.44, -24.36], %) // VerticalLineHorizonal
|> lineTo([1.68, -22.68], %) // MoveRelative
|> lineTo([1.68, -21.84], %) // VerticalLineHorizonal
|> lineTo([5.88, -21.84], %) // HorizontalLineRelative
|> lineTo([5.88, -22.68], %) // VerticalLineHorizonal
|> lineTo([3.36, -24.36], %) // MoveRelative
|> lineTo([3.36, -23.52], %) // VerticalLineHorizonal
|> lineTo([5.88, -23.52], %) // HorizontalLineRelative
|> lineTo([5.88, -24.36], %) // VerticalLineHorizonal
|> lineTo([15.12, -22.68], %) // MoveRelative
|> lineTo([15.12, -21.84], %) // VerticalLineHorizonal
|> lineTo([15.959999999999999, -21.84], %) // HorizontalLineRelative
|> lineTo([15.959999999999999, -22.68], %) // VerticalLineHorizonal
|> lineTo([16.8, -22.68], %) // MoveRelative
|> lineTo([16.8, -21.84], %) // VerticalLineHorizonal
|> lineTo([17.64, -21.84], %) // HorizontalLineRelative
|> lineTo([17.64, -22.68], %) // VerticalLineHorizonal
|> lineTo([18.48, -22.68], %) // MoveRelative
|> lineTo([18.48, -21.84], %) // VerticalLineHorizonal
|> lineTo([19.32, -21.84], %) // HorizontalLineRelative
|> lineTo([19.32, -22.68], %) // VerticalLineHorizonal
|> lineTo([15.12, -24.36], %) // MoveRelative
|> lineTo([15.12, -23.52], %) // VerticalLineHorizonal
|> lineTo([17.64, -23.52], %) // HorizontalLineRelative
|> lineTo([17.64, -24.36], %) // VerticalLineHorizonal
|> lineTo([18.48, -5.88], %) // MoveAbsolute
|> lineTo([18.48, -5.04], %) // VerticalLineAbsolute
|> lineTo([17.64, -5.04], %) // HorizontalLineAbsolute
|> lineTo([17.64, -4.2], %) // VerticalLineAbsolute
|> lineTo([3.36, -4.2], %) // HorizontalLineAbsolute
|> lineTo([3.36, -5.04], %) // VerticalLineAbsolute
|> lineTo([2.52, -5.04], %) // HorizontalLineAbsolute
|> lineTo([2.52, -5.88], %) // VerticalLineAbsolute
|> lineTo([1.68, -5.88], %) // HorizontalLineAbsolute
|> lineTo([1.68, -6.72], %) // VerticalLineAbsolute
|> lineTo([0.839996, -6.72], %) // HorizontalLineAbsolute
|> lineTo([0.839996, -8.4], %) // VerticalLineAbsolute
|> lineTo([20.16, -8.4], %) // HorizontalLineAbsolute
|> lineTo([20.16, -6.72], %) // VerticalLineAbsolute
|> lineTo([19.32, -6.72], %) // HorizontalLineAbsolute
|> lineTo([19.32, -5.88], %) // VerticalLineAbsolute
|> lineTo([20.16, -7.56], %) // MoveAbsolute
|> lineTo([0.839996, -7.56], %) // HorizontalLineAbsolute
|> lineTo([0.839996, -19.32], %) // VerticalLineAbsolute
|> lineTo([20.16, -19.32], %) // HorizontalLineAbsolute
|> lineTo([3.36, -10.08], %) // MoveAbsolute
|> lineTo([3.36, -9.24001], %) // VerticalLineAbsolute
|> lineTo([17.64, -9.24001], %) // HorizontalLineAbsolute
|> lineTo([17.64, -10.08], %) // VerticalLineAbsolute
|> lineTo([18.48, -10.08], %) // HorizontalLineRelative
|> lineTo([18.48, -16.8], %) // VerticalLineHorizonal
|> lineTo([17.64, -16.8], %) // HorizontalLineRelative
|> lineTo([17.64, -17.64], %) // VerticalLineHorizonal
|> lineTo([3.36, -17.64], %) // HorizontalLineAbsolute
|> lineTo([3.36, -16.8], %) // VerticalLineAbsolute
|> lineTo([2.52, -16.8], %) // HorizontalLineAbsolute
|> lineTo([2.52, -10.080000000000002], %) // VerticalLineHorizonal
|> lineTo([13.44, -10.92], %) // MoveRelative
|> lineTo([13.44, -10.08], %) // VerticalLineHorizonal
|> lineTo([15.12, -10.08], %) // HorizontalLineRelative
|> lineTo([15.12, -13.44], %) // VerticalLineHorizonal
|> lineTo([14.28, -13.44], %) // HorizontalLineRelative
|> lineTo([9.24, -13.44], %) // MoveRelative
|> lineTo([11.76, -13.44], %) // HorizontalLineRelative
|> lineTo([11.76, -14.28], %) // VerticalLineHorizonal
|> lineTo([10.92, -14.28], %) // HorizontalLineRelative here
|> lineTo([10.92, -15.959999999999999], %) // VerticalLineHorizonal
|> lineTo([13.44, -15.959999999999999], %) // HorizontalLineRelative
|> lineTo([13.44, -15.12], %) // VerticalLineHorizonal
|> lineTo([14.28, -15.12], %) // HorizontalLineRelative
|> lineTo([14.28, -15.959999999999999], %) // VerticalLineHorizonal
|> lineTo([13.44, -15.959999999999999], %) // HorizontalLineAbsolute
|> lineTo([13.44, -16.8], %) // VerticalLineAbsolute
|> lineTo([7.56, -16.8], %) // HorizontalLineAbsolute
|> lineTo([7.56, -15.96], %) // VerticalLineAbsolute
|> lineTo([6.72, -15.96], %) // HorizontalLineAbsolute
|> lineTo([6.72, -15.120000000000001], %) // VerticalLineHorizonal
|> lineTo([7.56, -15.120000000000001], %) // HorizontalLineRelative
|> lineTo([7.56, -15.96], %) // VerticalLineHorizonal
|> lineTo([10.08, -15.96], %) // HorizontalLineRelative
|> lineTo([10.08, -14.28], %) // VerticalLineAbsolute
|> lineTo([9.24, -14.28], %) // HorizontalLineAbsolute
|> lineTo([7.56, -12.6], %) // MoveAbsolute
|> lineTo([7.56, -11.76], %) // VerticalLineAbsolute
|> lineTo([5.04, -11.76], %) // HorizontalLineAbsolute
|> lineTo([5.04, -12.6], %) // VerticalLineAbsolute
|> lineTo([4.2, -12.6], %) // HorizontalLineAbsolute
|> lineTo([4.2, -11.76], %) // VerticalLineHorizonal
|> lineTo([5.04, -11.76], %) // HorizontalLineRelative
|> lineTo([5.04, -10.92], %) // VerticalLineHorizonal
|> lineTo([7.5600000000000005, -10.92], %) // HorizontalLineRelative
|> lineTo([7.5600000000000005, -11.76], %) // VerticalLineHorizonal
|> lineTo([8.4, -11.76], %) // HorizontalLineAbsolute
|> lineTo([8.4, -12.6], %) // VerticalLineHorizonal
|> lineTo([3.36, -5.88], %) // MoveAbsolute
|> lineTo([3.36, -5.04], %) // VerticalLineAbsolute
|> lineTo([4.2, -5.04], %) // HorizontalLineAbsolute
|> lineTo([4.2, -3.36], %) // VerticalLineAbsolute
|> lineTo([5.04, -3.36], %) // HorizontalLineAbsolute
|> lineTo([5.04, -1.68], %) // VerticalLineAbsolute
|> lineTo([5.88, -1.68], %) // HorizontalLineAbsolute
|> lineTo([5.88, -0.83999599], %) // VerticalLineAbsolute
|> lineTo([6.72, -0.83999599], %) // HorizontalLineAbsolute
|> lineTo([6.72, -1.68], %) // VerticalLineAbsolute
|> lineTo([7.56, -1.68], %) // HorizontalLineAbsolute
|> lineTo([7.56, -3.36], %) // VerticalLineAbsolute
|> lineTo([8.4, -3.36], %) // HorizontalLineAbsolute
|> lineTo([8.4, -5.04], %) // VerticalLineHorizonal
|> lineTo([9.24, -5.04], %) // HorizontalLineRelative
|> lineTo([9.24, -5.88], %) // VerticalLineHorizonal
|> lineTo([17.64, -5.04], %) // MoveAbsolute
|> lineTo([17.64, -5.88], %) // VerticalLineAbsolute
|> lineTo([11.76, -5.88], %) // HorizontalLineAbsolute
|> lineTo([11.76, -5.04], %) // VerticalLineAbsolute
|> lineTo([12.6, -5.04], %) // HorizontalLineAbsolute
|> lineTo([12.6, -3.36], %) // VerticalLineAbsolute
|> lineTo([13.44, -3.36], %) // HorizontalLineRelative
|> lineTo([13.44, -1.68], %) // VerticalLineAbsolute
|> lineTo([14.28, -1.68], %) // HorizontalLineRelative
|> lineTo([14.28, -0.83999599], %) // VerticalLineAbsolute
|> lineTo([15.12, -0.83999599], %) // HorizontalLineRelative
|> lineTo([15.12, -1.68], %) // VerticalLineAbsolute
|> lineTo([15.959999999999999, -1.68], %) // HorizontalLineRelative
|> lineTo([15.959999999999999, -3.36], %) // VerticalLineHorizonal
|> lineTo([16.8, -3.36], %) // HorizontalLineRelative
|> lineTo([16.8, -5.04], %) // VerticalLineHorizonal
|> lineTo([13.44, -1.68], %) // MoveAbsolute
|> lineTo([13.44, -0], %) // VerticalLineAbsolute
|> lineTo([15.959999999999999, -0], %) // HorizontalLineRelative
|> lineTo([15.959999999999999, -1.68], %) // VerticalLineHorizonal
|> lineTo([16.8, -1.68], %) // HorizontalLineRelative
|> lineTo([16.8, -3.36], %) // VerticalLineHorizonal
|> lineTo([17.64, -3.36], %) // HorizontalLineRelative
|> lineTo([17.64, -4.62], %) // VerticalLineAbsolute
|> lineTo([16.8, -4.62], %) // HorizontalLineAbsolute
|> lineTo([16.8, -3.36], %) // VerticalLineAbsolute
|> lineTo([15.96, -3.36], %) // HorizontalLineAbsolute
|> lineTo([15.96, -1.68], %) // VerticalLineAbsolute
|> lineTo([15.12, -1.68], %) // HorizontalLineAbsolute
|> lineTo([15.12, -0.83999999], %) // VerticalLineAbsolute
|> lineTo([14.28, -0.83999999], %) // HorizontalLineAbsolute
|> lineTo([14.28, -1.68], %) // VerticalLineAbsolute
|> lineTo([13.44, -1.68], %) // HorizontalLineAbsolute
|> lineTo([13.44, -3.36], %) // VerticalLineAbsolute
|> lineTo([12.6, -3.36], %) // HorizontalLineAbsolute
|> lineTo([12.6, -4.62], %) // VerticalLineAbsolute
|> lineTo([11.76, -4.62], %) // HorizontalLineAbsolute
|> lineTo([11.76, -3.36], %) // VerticalLineAbsolute
|> lineTo([12.6, -3.36], %) // HorizontalLineAbsolute
|> lineTo([12.6, -1.68], %) // VerticalLineAbsolute
|> lineTo([5.04, -1.68], %) // MoveAbsolute
|> lineTo([5.04, -0], %) // VerticalLineAbsolute
|> lineTo([7.56, -0], %) // HorizontalLineAbsolute
|> lineTo([7.56, -1.68], %) // VerticalLineAbsolute
|> lineTo([8.4, -1.68], %) // HorizontalLineAbsolute
|> lineTo([8.4, -3.36], %) // VerticalLineAbsolute
|> lineTo([9.24, -3.36], %) // HorizontalLineAbsolute
|> lineTo([9.24, -4.62], %) // VerticalLineAbsolute
|> lineTo([8.4, -4.62], %) // HorizontalLineAbsolute
|> lineTo([8.4, -3.36], %) // VerticalLineAbsolute
|> lineTo([7.56, -3.36], %) // HorizontalLineAbsolute
|> lineTo([7.56, -1.68], %) // VerticalLineAbsolute
|> lineTo([6.72, -1.68], %) // HorizontalLineAbsolute
|> lineTo([6.72, -0.83999999], %) // VerticalLineAbsolute
|> lineTo([5.88, -0.83999999], %) // HorizontalLineAbsolute
|> lineTo([5.88, -1.68], %) // VerticalLineAbsolute
|> lineTo([5.04, -1.68], %) // HorizontalLineAbsolute
|> lineTo([5.04, -3.36], %) // VerticalLineAbsolute
|> lineTo([4.2, -3.36], %) // HorizontalLineAbsolute
|> lineTo([4.2, -4.62], %) // VerticalLineAbsolute
|> lineTo([3.36, -4.62], %) // HorizontalLineAbsolute
|> lineTo([3.36, -3.36], %) // VerticalLineAbsolute
|> lineTo([4.2, -3.36], %) // HorizontalLineAbsolute
|> lineTo([4.2, -1.68], %) // VerticalLineAbsolute
|> lineTo([13.44, -5.88], %) // MoveAbsolute
|> lineTo([13.44, -5.04], %) // VerticalLineAbsolute
|> lineTo([14.28, -5.04], %) // HorizontalLineRelative
|> lineTo([14.28, -4.2], %) // VerticalLineAbsolute
|> lineTo([15.12, -4.2], %) // HorizontalLineRelative
|> lineTo([15.12, -5.04], %) // VerticalLineHorizonal
|> lineTo([15.959999999999999, -5.04], %) // HorizontalLineRelative
|> lineTo([15.959999999999999, -5.88], %) // VerticalLineHorizonal
|> lineTo([5.88, -5.04], %) // MoveAbsolute
|> lineTo([5.88, -4.2], %) // VerticalLineAbsolute
|> lineTo([6.72, -4.2], %) // HorizontalLineAbsolute
|> lineTo([6.72, -5.04], %) // VerticalLineAbsolute
|> lineTo([7.56, -5.04], %) // HorizontalLineAbsolute
|> lineTo([7.56, -5.88], %) // VerticalLineAbsolute
|> lineTo([5.04, -5.88], %) // HorizontalLineAbsolute
|> lineTo([5.04, -5.04], %) // VerticalLineAbsolute
|> lineTo([17.64, -5.88], %) // MoveAbsolute
|> lineTo([17.64, -5.04], %) // VerticalLineAbsolute
|> lineTo([16.8, -5.04], %) // HorizontalLineAbsolute
|> lineTo([16.8, -4.2], %) // VerticalLineAbsolute
|> lineTo([17.64, -4.2], %) // HorizontalLineRelative
|> lineTo([17.64, -5.04], %) // VerticalLineHorizonal
|> lineTo([18.48, -5.04], %) // HorizontalLineRelative
|> lineTo([18.48, -5.88], %) // VerticalLineHorizonal
|> lineTo([3.36, -5.04], %) // MoveAbsolute
|> lineTo([3.36, -5.88], %) // VerticalLineAbsolute
|> lineTo([2.52, -5.88], %) // HorizontalLineAbsolute
|> lineTo([2.52, -5.04], %) // VerticalLineAbsolute
|> lineTo([3.36, -5.04], %) // HorizontalLineAbsolute
|> lineTo([3.36, -4.2], %) // VerticalLineAbsolute
|> lineTo([4.2, -4.2], %) // HorizontalLineAbsolute
|> lineTo([4.2, -5.04], %) // VerticalLineHorizonal
|> lineTo([8.4, -4.2], %) // MoveRelative
|> lineTo([9.24, -4.2], %) // HorizontalLineRelative
|> lineTo([9.24, -5.04], %) // VerticalLineHorizonal
|> lineTo([10.08, -5.04], %) // HorizontalLineRelative
|> lineTo([10.08, -5.88], %) // VerticalLineAbsolute
|> lineTo([9.24, -5.88], %) // HorizontalLineAbsolute
|> lineTo([9.24, -5.04], %) // VerticalLineAbsolute
|> lineTo([8.4, -5.04], %) // HorizontalLineAbsolute
|> lineTo([11.76, -4.2], %) // MoveAbsolute
|> lineTo([12.6, -4.2], %) // HorizontalLineAbsolute
|> lineTo([12.6, -5.04], %) // VerticalLineAbsolute
|> lineTo([11.76, -5.04], %) // HorizontalLineAbsolute
|> lineTo([11.76, -5.88], %) // VerticalLineAbsolute
|> lineTo([10.92, -5.88], %) // HorizontalLineAbsolute
|> lineTo([10.92, -5.04], %) // VerticalLineAbsolute
|> lineTo([11.76, -5.04], %) // HorizontalLineRelative
|> lineTo([14.28, -10.92], %) // MoveRelative
|> lineTo([13.44, -10.92], %) // HorizontalLineRelative
|> lineTo([13.44, -13.44], %) // VerticalLineHorizonal
|> lineTo([14.28, -13.44], %) // HorizontalLineRelative
|> close(%);
show(svg);

View File

@ -15,6 +15,7 @@ async fn execute_and_snapshot(code: &str) -> Result<image::DynamicImage> {
// For file conversions we need this to be long.
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
@ -35,12 +36,12 @@ async fn execute_and_snapshot(code: &str) -> Result<image::DynamicImage> {
let parser = kcl_lib::parser::Parser::new(tokens);
let program = parser.ast()?;
let mut mem: kcl_lib::executor::ProgramMemory = Default::default();
let mut engine = kcl_lib::engine::EngineConnection::new(ws).await?;
let _ = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &mut engine)?;
let engine = kcl_lib::engine::EngineConnection::new(ws).await?;
let _ = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &engine).await?;
// Send a snapshot request to the engine.
let resp = engine
.send_modeling_cmd_get_response(
.send_modeling_cmd(
uuid::Uuid::new_v4(),
kcl_lib::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
@ -174,6 +175,14 @@ async fn serial_test_execute_pipes_on_pipes() {
twenty_twenty::assert_image("tests/executor/outputs/pipes_on_pipes.png", &result, 1.0);
}
#[tokio::test(flavor = "multi_thread")]
async fn serial_test_execute_kittycad_svg() {
let code = include_str!("inputs/kittycad_svg.kcl");
let result = execute_and_snapshot(code).await.unwrap();
twenty_twenty::assert_image("tests/executor/outputs/kittycad_svg.png", &result, 1.0);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_member_expression_sketch_group() {
let code = r#"fn cube = (pos, scale) => {

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -37,13 +37,9 @@ async fn setup(code: &str, name: &str) -> Result<(EngineConnection, Program, uui
let parser = kcl_lib::parser::Parser::new(tokens);
let program = parser.ast()?;
let mut mem: kcl_lib::executor::ProgramMemory = Default::default();
let mut engine = kcl_lib::engine::EngineConnection::new(ws).await?;
let memory = kcl_lib::executor::execute(
program.clone(),
&mut mem,
kcl_lib::executor::BodyType::Root,
&mut engine,
)?;
let engine = kcl_lib::engine::EngineConnection::new(ws).await?;
let memory =
kcl_lib::executor::execute(program.clone(), &mut mem, kcl_lib::executor::BodyType::Root, &engine).await?;
// We need to get the sketch ID.
// Get the sketch group ID from memory.
@ -53,38 +49,44 @@ async fn setup(code: &str, name: &str) -> Result<(EngineConnection, Program, uui
let sketch_id = sketch_group.id;
let plane_id = uuid::Uuid::new_v4();
engine.send_modeling_cmd(
plane_id,
SourceRange::default(),
ModelingCmd::MakePlane {
clobber: false,
origin: Point3D { x: 0.0, y: 0.0, z: 0.0 },
size: 60.0,
x_axis: Point3D { x: 1.0, y: 0.0, z: 0.0 },
y_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 },
},
)?;
engine
.send_modeling_cmd(
plane_id,
SourceRange::default(),
ModelingCmd::MakePlane {
clobber: false,
origin: Point3D { x: 0.0, y: 0.0, z: 0.0 },
size: 60.0,
x_axis: Point3D { x: 1.0, y: 0.0, z: 0.0 },
y_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 },
},
)
.await?;
// Enter sketch mode.
// We can't get control points without being in sketch mode.
// You can however get path info without sketch mode.
engine.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::SketchModeEnable {
animated: false,
ortho: true,
plane_id,
},
)?;
engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::SketchModeEnable {
animated: false,
ortho: true,
plane_id,
},
)
.await?;
// Enter edit mode.
// We can't get control points of an existing sketch without being in edit mode.
engine.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::EditModeEnter { target: sketch_id },
)?;
engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
ModelingCmd::EditModeEnter { target: sketch_id },
)
.await?;
Ok((engine, program, sketch_id))
}

View File

@ -1530,10 +1530,10 @@
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
"@kittycad/lib@^0.0.37":
version "0.0.37"
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.37.tgz#ec4f6c4fb5d06402a19339f3374036b6582d2265"
integrity sha512-P8p9FeLV79/0Lfd0RioBta1drzhmpROnU4YV38+zsAA4LhibQCTjeekRkxVvHztGumPxz9pPsAeeLJyuz2RWKQ==
"@kittycad/lib@^0.0.38":
version "0.0.38"
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.38.tgz#50474266f679990bd414c30f884f2d42a0d5dba9"
integrity sha512-Lv9P7jqVRoGgOnCsRCsG8OwZH5n3scxXYrElR+5/Rsd6/KIarLB4bSBngJrXebOnmTw5md0OPeY+b3ZDbZFDeg==
dependencies:
node-fetch "3.3.2"
openapi-types "^12.0.0"