Compare commits

...

64 Commits

Author SHA1 Message Date
58659652c1 Cut release v0.12.0 (#1069) 2023-11-13 21:11:38 -05:00
251971238d Fit resolutions to less than 2k x 2k (#1065)
* Fit resolutions to less than 2k x 2k

* Integer resolutions

* Scale mouse clicks

* Move stream maxResolution logic to getDimensions
2023-11-13 19:32:07 -05:00
381d0b3bc8 Add a console.error when ICE fails (#1067)
This is purely cosmetic right now, but I want to try and make it easier
to tell when the browser is unable to communicate with the ICE server
by writing it to the console.

I want to add some Sentry logging in the future, but for now, when we
see a stream failing to start, we can at least see what I suspect is the
most common trigger in the console.

Signed-off-by: Paul R. Tagliamonte <paul@kittycad.io>
2023-11-14 06:13:15 +11:00
fa7943d06a Bump clap from 4.4.7 to 4.4.8 in /src/wasm-lib (#1062)
Bumps [clap](https://github.com/clap-rs/clap) from 4.4.7 to 4.4.8.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.4.7...v4.4.8)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-13 13:08:16 -06:00
7a384251d4 Bump @babel/preset-env from 7.22.9 to 7.23.3 (#1058)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.22.9 to 7.23.3.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.3/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-13 05:13:28 -05:00
8e07ea32a6 Bump tailwindcss from 3.3.3 to 3.3.5 (#1059)
Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss) from 3.3.3 to 3.3.5.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/compare/v3.3.3...v3.3.5)

---
updated-dependencies:
- dependency-name: tailwindcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-13 05:13:16 -05:00
23adf9d905 Disable eslint rule react-hooks/exhaustive-deps (#1055)
Disable react-hooks/exhaustive-deps
Workaround for #1014
2023-11-11 16:27:12 -05:00
9f0ac5f6fd Macro for parsing KCL at Rust compile-time (#1049)
Macro for parsing KCL at Rust compile-time

This adds a new `parse_kcl!` macro which takes a string as input. It parses the string into KCL source code _at compile-time_. Invalid KCL will make your Rust project fail to compile.

Fixes https://github.com/KittyCAD/modeling-app/issues/1018
2023-11-10 10:36:21 -06:00
08dbd2e9c3 Bump web-sys from 0.3.64 to 0.3.65 in /src/wasm-lib (#1052)
Bumps [web-sys](https://github.com/rustwasm/wasm-bindgen) from 0.3.64 to 0.3.65.
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

---
updated-dependencies:
- dependency-name: web-sys
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 06:49:33 -05:00
2e2ba5adbd Bump tauri-plugin-fs-extra from 6865299 to 61e8625 in /src-tauri (#1054)
Bumps [tauri-plugin-fs-extra](https://github.com/tauri-apps/plugins-workspace) from `6865299` to `61e8625`.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](6865299149...61e862597e)

---
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-11-10 06:49:12 -05:00
a21dbf1055 Bump tokio from 1.33.0 to 1.34.0 in /src-tauri (#1053)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.33.0 to 1.34.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.33.0...tokio-1.34.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 05:24:59 -05:00
5ecb176467 Bump tokio from 1.33.0 to 1.34.0 in /src/wasm-lib (#1051)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.33.0 to 1.34.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.33.0...tokio-1.34.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 05:24:40 -05:00
66135636ec Bump wasm-bindgen-futures from 0.4.37 to 0.4.38 in /src/wasm-lib (#1050)
Bumps [wasm-bindgen-futures](https://github.com/rustwasm/wasm-bindgen) from 0.4.37 to 0.4.38.
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

---
updated-dependencies:
- dependency-name: wasm-bindgen-futures
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 05:24:10 -05:00
685a16545c Bump @vitejs/plugin-react from 4.0.4 to 4.1.1 (#1035)
Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 4.0.4 to 4.1.1.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/v4.1.1/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 05:20:45 -05:00
9adb15ee93 Bump @headlessui/react from 1.7.16 to 1.7.17 (#1037)
Bumps [@headlessui/react](https://github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-react) from 1.7.16 to 1.7.17.
- [Release notes](https://github.com/tailwindlabs/headlessui/releases)
- [Changelog](https://github.com/tailwindlabs/headlessui/blob/main/packages/@headlessui-react/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/headlessui/commits/@headlessui/react@v1.7.17/packages/@headlessui-react)

---
updated-dependencies:
- dependency-name: "@headlessui/react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 05:20:02 -05:00
a8c4c97d79 Bump fuse.js from 6.6.2 to 7.0.0 (#1036)
Bumps [fuse.js](https://github.com/krisk/Fuse) from 6.6.2 to 7.0.0.
- [Release notes](https://github.com/krisk/Fuse/releases)
- [Changelog](https://github.com/krisk/Fuse/blob/main/CHANGELOG.md)
- [Commits](https://github.com/krisk/Fuse/compare/v6.6.2...v7.0.0)

---
updated-dependencies:
- dependency-name: fuse.js
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 05:19:46 -05:00
39e8e1f259 Bump eslint-plugin-css-modules from 2.11.0 to 2.12.0 (#1034)
Bumps [eslint-plugin-css-modules](https://github.com/atfzl/eslint-plugin-css-modules) from 2.11.0 to 2.12.0.
- [Release notes](https://github.com/atfzl/eslint-plugin-css-modules/releases)
- [Commits](https://github.com/atfzl/eslint-plugin-css-modules/compare/v2.11.0...v2.12.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-css-modules
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 05:18:09 -05:00
1672c1fd1f Impl databake for all AST node types (#1047)
Databake doesn't have any derive for HashMap, so for NonCodeMeta I decided to skip serializing the non_code_nodes. This should be OK for now.

See <https://github.com/unicode-org/icu4x/issues/4266> for the Databake hashmap issue.
2023-11-09 16:39:12 -06:00
6ec5881985 top level expressions fix (#1046)
#1033 top level expressions fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2023-11-09 13:08:11 -08:00
7272cc9fbd Describe Rust version for devs (#1044)
Fixes #1042
2023-11-09 17:01:52 +00:00
b925ed9b65 KCL stdlib and circle function (#1029)
Allows stdlib functions to be written as KCL, not as Rust. 

Rust stdlib functions will hereafter be referred to as "core" not "std".

Right now the only stdlib function I implemented is a circle function (it's a wrapper around the core arc function which sets the arc's start/end to 0 and 360 respectively). I know I want to change this function as soon as KCL has enums, which is my next task. So, I don't want users to start using this right away. To that end, I've named this function "unstable_stdlib_circle" not "circle". Once the function is ready to be stabilized, I can rename it to just "circle".

Note that this PR modifies the existing "sketch and extrude a cylinder" KCL test so that instead of using a user-defined circle function, it uses the unstable_stdlib_circle function now. And the twenty-twenty tests pass, so we know my stdlib is working.

https://github.com/KittyCAD/modeling-app/issues/922
2023-11-09 09:58:20 -06:00
0db5db2181 Bump js-sys from 0.3.64 to 0.3.65 in /src/wasm-lib (#980)
Bumps [js-sys](https://github.com/rustwasm/wasm-bindgen) from 0.3.64 to 0.3.65.
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

---
updated-dependencies:
- dependency-name: js-sys
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 23:41:53 -06:00
898e3db9d1 AST function nodes no longer have stdlib function members (#1031)
* AST function nodes no longer have stdlib function members

IMO the AST should not need an actual pointer to a stdlib function -- that is a completely separate concern from the AST.

Instead, the AST nodes can just store function names, and the executor will have a stdlib which it can look up those names in.

* Fix tests

* Update snapshot tests
2023-11-08 20:23:59 -06:00
d337ac2546 Test with a circle function (#1030) 2023-11-08 15:06:41 -06:00
371d8e08f7 Refactor the call_fn fn to be more readable (#1028) 2023-11-08 13:44:31 -06:00
338c43a29d Fix auto-version in nightly builds (#1026)
* WIP Fix auto-version in nightly builds
Fixes #1015

* WIP

* Revert "WIP"

This reverts commit 7838bf1298.

* Need to update src-tauri/tauri.release.conf.json after CI changes

* Fixes just to test

* Clean up after tests
2023-11-08 13:58:37 +00:00
52bb5a2657 Bump @sentry/react from 7.65.0 to 7.77.0 (#977)
Bumps [@sentry/react](https://github.com/getsentry/sentry-javascript) from 7.65.0 to 7.77.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.65.0...7.77.0)

---
updated-dependencies:
- dependency-name: "@sentry/react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 10:39:40 +00:00
1b6a06d266 Bump vscode-languageserver-protocol from 3.17.3 to 3.17.5 (#978)
Bumps [vscode-languageserver-protocol](https://github.com/Microsoft/vscode-languageserver-node/tree/HEAD/protocol) from 3.17.3 to 3.17.5.
- [Commits](https://github.com/Microsoft/vscode-languageserver-node/commits/release/types/3.17.5/protocol)

---
updated-dependencies:
- dependency-name: vscode-languageserver-protocol
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 05:28:24 -05:00
c68d4778a5 Bump @tauri-apps/api from 1.5.0 to 1.5.1 (#979)
Bumps [@tauri-apps/api](https://github.com/tauri-apps/tauri) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/api-v1.5...@tauri-apps/api-v1.5.1)

---
updated-dependencies:
- dependency-name: "@tauri-apps/api"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 05:28:01 -05:00
a8abea4fb5 Bump eslint from 8.46.0 to 8.53.0 (#1001)
Bumps [eslint](https://github.com/eslint/eslint) from 8.46.0 to 8.53.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.46.0...v8.53.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 05:27:13 -05:00
a0678d22a8 fix epsilon bug (#1025) 2023-11-08 09:27:53 +00:00
acbfae2e65 Bump wasm-bindgen from 0.2.87 to 0.2.88 in /src/wasm-lib (#981)
Bumps [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) from 0.2.87 to 0.2.88.
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/compare/0.2.87...0.2.88)

---
updated-dependencies:
- dependency-name: wasm-bindgen
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 23:56:23 -06:00
1e1bec6a8a Bump winnow (#1024) 2023-11-07 23:55:45 -06:00
06462b5a65 Bump syn from 2.0.38 to 2.0.39 in /src/wasm-lib (#1000)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.38 to 2.0.39.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.38...2.0.39)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 22:45:58 -06:00
2f292fb1be Bump tauri-plugin-fs-extra from 11048fd to 6865299 in /src-tauri (#1023)
Bumps [tauri-plugin-fs-extra](https://github.com/tauri-apps/plugins-workspace) from `11048fd` to `6865299`.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](11048fd997...6865299149)

---
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-11-07 22:45:20 -06:00
8184e7b376 Bump serde from 1.0.190 to 1.0.192 in /src-tauri (#1009)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.190 to 1.0.192.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.190...v1.0.192)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 22:45:03 -06:00
b1084cbf80 Bump serde from 1.0.190 to 1.0.192 in /src/wasm-lib (#1012)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.190 to 1.0.192.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.190...v1.0.192)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 22:44:55 -06:00
548b45905e Cut release v0.11.3 (#1020)
cut release v0.11.3
2023-11-08 12:57:00 +11:00
141fd2f3f1 fix variables panel and others (#1021) 2023-11-08 01:27:43 +00:00
604d931962 selections fix follow up (#1019) 2023-11-07 23:10:30 +00:00
b1668410f8 Neaten up stdlib code (#1017) 2023-11-07 12:12:18 -06:00
13176cec38 Cut release v0.11.2 (#1005)
* Cut release v0.11.2

* Replace 'release' with '*' for artifact upload

* New logic to prevent top-level artifact.zip changes

* Fix upload

---------

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2023-11-07 05:20:26 -05:00
3a59ae13b6 fix selections (#1013) 2023-11-07 07:21:32 +00:00
57c2481943 unused imports (#1011) 2023-11-07 03:29:50 +00:00
a1c555c51e clear errors on good parse (#1008) 2023-11-07 02:02:44 +00:00
4d520541be Build release & sign only on merge / release / release PR (#991)
* Add env variable for release || schedule || Cut out v PR

* Skip Windows, Apple, and Tauri Updater signing

* Add tauri args to bypass updater on debug

* Trying to address includeRelease and includeDebug issues

* WIP

* Clean up, fix bool eval

* -c to --config

* Remove src-tauri

* inline config

* Cleanup

* Remove concurrency block

* Test release

* Escape backslash

* Clean up

* Add back concurrency and BUILD_RELEASE eval

* Back to build:wasm (no speed impr noticed)

* Adam's suggestions

Co-authored-by: Adam Chalmers <adam.chalmers@kittycad.io>

* New logic to prevent top-level artifact.zip changes

---------

Co-authored-by: Adam Chalmers <adam.chalmers@kittycad.io>
2023-11-06 19:51:32 -05:00
82586f002b Test Jess's KCL error (#1004) 2023-11-06 14:01:51 -06:00
4bd08f7444 safe parse (#996)
* safe parse

* use safe parse on mouse up, stream
2023-11-06 06:47:45 +00:00
6b2603b1c4 don't overwrite current file on onboarding-replay (#1003)
don't over write file on onboarding
2023-11-06 04:03:21 +00:00
af49bebde3 compare formated asts before execute (#1002) 2023-11-06 03:43:01 +00:00
ca056996fd stop double execute on project open (#997) 2023-11-06 14:33:19 +11:00
34163da361 start of fixing changing files and cleaning up after execute (#897)
* start of fixing changing files and cleaning up after execute

* stop constraints from leaving artifacts

* don't write file on initial load
2023-11-06 11:49:13 +11:00
7c22bac638 Remove unwraps from binary expression algorithm (#992) 2023-11-03 13:30:19 -05:00
37a65b166b Fix silly mistakes in previous CI.yml PRs (#988)
* Fix silly mistakes in previous CI.yml PRs

This is what happens when I code before my morning matcha

Part of #987
2023-11-02 12:34:38 -05:00
1189f272ba Use debug builds for wasm-pack on PRs (#986) 2023-11-02 09:55:58 -05:00
ca5bc880dc Build tauri app in debug mode on PRs, release mode on releases (#985)
Build tauri app in debug mode on PRs, release mode on merges.

Release builds are very slow and should only be used for actual releases. Fast debug builds should be used for CI on PRs.
2023-11-02 09:55:36 -05:00
828daba304 Tweak Codespell CI (#975)
Ensure codespell CI job actually catches typos
2023-11-01 23:35:41 +00:00
0b9ba55bb4 Nicer error messages for unknown tokens (#974) 2023-11-01 23:08:22 +00:00
2d2a85ae7d remove view change from debug panel (#866)
remove view change from debug
2023-11-01 23:03:58 +00:00
cc57a302cc Update twenty-twenty (#973)
Due to engine PR #1566
2023-11-01 22:35:17 +00:00
fdbfd0c4b6 Fix typos (#972)
* Update twenty-twenty

Due to engine PR #1566

* Fix typos
2023-11-01 22:34:54 +00:00
2e419907e6 Tokenizing fallibility (#883)
Tokenization tracks invalid tokens and produces a nice error about them

---------

Co-authored-by: Adam Chalmers <adam.chalmers@kittycad.io>
2023-11-01 17:20:49 -05:00
3d0c5c10b0 KCL literals are typed, not JSON values (#971)
We now control the KCL type system instead of reusing JSON's type system.
2023-11-01 13:52:50 -05:00
4d47c067b7 Snapshot testing for parser (#969)
See https://docs.rs/insta for more.
2023-11-01 12:40:40 -05:00
145 changed files with 7543 additions and 1469 deletions

3
.codespellrc Normal file
View File

@ -0,0 +1,3 @@
[codespell]
ignore-words-list: crate,everytime
skip: **/target,node_modules,build

View File

@ -11,6 +11,7 @@
"semi": [
"error",
"never"
]
],
"react-hooks/exhaustive-deps": "off"
}
}

View File

@ -12,9 +12,13 @@ on:
# Daily at 04:00 AM UTC
# Will checkout the last commit from the default branch (main as of 2023-10-04)
env:
BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && contains(github.event.pull_request.title, 'Cut release v') }}
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
check-format:
runs-on: 'ubuntu-latest'
@ -46,6 +50,20 @@ jobs:
- run: yarn tsc
check-typos:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
- name: Install codespell
run: |
python -m pip install codespell
- name: Run codespell
run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration.
build-test-web:
runs-on: ubuntu-latest
steps:
@ -88,7 +106,7 @@ jobs:
run: |
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
echo "$(jq --arg url 'https://dl.kittycad.io/releases/modeling-app/nightly/last_update.json' \
'.tauri.updater.endpoints[]=$url' src-tauri/tauri.conf.json --indent 2)" > src-tauri/tauri.conf.json
'.tauri.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
- uses: actions/upload-artifact@v3
if: github.event_name == 'schedule'
@ -96,13 +114,14 @@ jobs:
path: |
package.json
src-tauri/tauri.conf.json
src-tauri/tauri.release.conf.json
- id: export_version
run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT"
build-test-apps:
needs: [check-format, build-test-web, prepare-json-files, check-types]
needs: [prepare-json-files]
runs-on: ${{ matrix.os }}
strategy:
matrix:
@ -118,8 +137,9 @@ jobs:
ls -l artifact
cp artifact/package.json package.json
cp artifact/src-tauri/tauri.conf.json src-tauri/tauri.conf.json
cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json
- name: install ubuntu system dependencies
- name: Install ubuntu system dependencies
if: matrix.os == 'ubuntu-latest'
run: >
sudo apt-get update &&
@ -139,10 +159,10 @@ jobs:
- run: yarn install
- name: Rust setup
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust cache
- name: Setup Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
@ -151,24 +171,27 @@ jobs:
with:
workspaces: './src/wasm-lib'
- name: wasm prep
- name: Run build:wasm manually
shell: bash
env:
MODE: ${{ env.BUILD_RELEASE == 'true' && '--release' || '--debug' }}
run: |
mkdir src/wasm-lib/pkg; cd src/wasm-lib
npx wasm-pack build --target web --out-dir pkg
echo "building with ${{ env.MODE }}"
npx wasm-pack build --target web --out-dir pkg ${{ env.MODE }}
cd ../../
cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
- name: Fix format
run: yarn fmt
- name: install apple silicon target mac
- name: Install Universal target (MacOS only)
if: matrix.os == 'macos-latest'
run: |
rustup target add aarch64-apple-darwin
- name: Prepare Windows certificate and variables
if: matrix.os == 'windows-latest'
- name: Prepare certificate and variables (Windows only)
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }}
run: |
echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
cat /d/Certificate_pkcs12.p12
@ -182,8 +205,8 @@ jobs:
echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH
shell: bash
- name: Setup Windows certicate with SSM KSP
if: matrix.os == 'windows-latest'
- name: Setup certicate with SSM KSP (Windows only)
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }}
run: |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi
msiexec /i smtools-windows-x64.msi /quiet /qn
@ -193,8 +216,17 @@ jobs:
smksp_cert_sync.exe
shell: cmd
- name: Build and sign the app for the current platform
- name: Build the app (debug)
uses: tauri-apps/tauri-action@v0
if: ${{ env.BUILD_RELEASE == 'false' }}
with:
includeRelease: false
includeDebug: true
args: ${{ matrix.os == 'macos-latest' && '--target universal-apple-darwin' || '' }}
- name: Build the app (release) and sign
uses: tauri-apps/tauri-action@v0
if: ${{ env.BUILD_RELEASE == 'true' }}
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
@ -204,29 +236,35 @@ jobs:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
TAURI_CONF_ARGS: "--config ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}"
with:
args: ${{ matrix.os == 'macos-latest' && '--target universal-apple-darwin' || '' }}
args: "${{ matrix.os == 'macos-latest' && '--target universal-apple-darwin' || '' }} ${{ env.TAURI_CONF_ARGS }}"
- uses: actions/upload-artifact@v3
env:
PREFIX: ${{ matrix.os == 'macos-latest' && 'src-tauri/target/universal-apple-darwin' || 'src-tauri/target' }}
MODE: ${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}
with:
path: ${{ matrix.os == 'macos-latest' && 'src-tauri/target/universal-apple-darwin/release/bundle/*/*' || 'src-tauri/target/release/bundle/*/*' }}
path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*"
- name: Install tauri-driver for e2e tests
- name: Install tauri-driver for e2e tests (linux only)
if: matrix.os == 'ubuntu-latest'
uses: actions-rs/cargo@v1
with:
command: install
args: tauri-driver
- name: Run e2e tests
- name: Run e2e tests (linux only)
if: matrix.os == 'ubuntu-latest'
run: xvfb-run yarn test:e2e
env:
MODE: ${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}
publish-apps-release:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }}
needs: [build-test-web, prepare-json-files, build-test-apps]
needs: [check-format, check-types, check-typos, build-test-web, prepare-json-files, build-test-apps]
env:
VERSION_NO_V: ${{ needs.prepare-json-files.outputs.version }}
VERSION: ${{ github.event_name == 'release' && format('v{0}', needs.prepare-json-files.outputs.version) || needs.prepare-json-files.outputs.version }}

View File

@ -48,7 +48,7 @@ We recommend downloading the latest application binary from [our Releases page](
## Running a development build
First, [install Rust via `rustup`](https://www.rust-lang.org/tools/install). This project uses a lot of Rust compiled to [WASM](https://webassembly.org/) within it. Then, run:
First, [install Rust via `rustup`](https://www.rust-lang.org/tools/install). This project uses a lot of Rust compiled to [WASM](https://webassembly.org/) within it. We always use the latest stable version of Rust, so you may need to run `rustup update stable`. Then, run:
```
yarn install
@ -104,7 +104,7 @@ To spin up up tauri dev, `yarn install` and `yarn build:wasm-dev` need to have b
yarn tauri dev
```
Will spin up the web app before opening up the tauri dev desktop app. Note that it's probably a good idea to close the browser tab that gets opened since at the time of writting they can conflict.
Will spin up the web app before opening up the tauri dev desktop app. Note that it's probably a good idea to close the browser tab that gets opened since at the time of writing they can conflict.
The dev instance automatically opens up the browser devtools which can be disabled by [commenting it out](https://github.com/KittyCAD/modeling-app/blob/main/src-tauri/src/main.rs#L92.)

View File

@ -1,6 +1,6 @@
{
"name": "untitled-app",
"version": "0.11.1",
"version": "0.12.0",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.10.2",
@ -8,15 +8,15 @@
"@fortawesome/free-brands-svg-icons": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.13",
"@headlessui/react": "^1.7.17",
"@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "^0.0.45",
"@lezer/javascript": "^1.4.7",
"@open-rpc/client-js": "^1.8.1",
"@react-hook/resize-observer": "^1.2.6",
"@replit/codemirror-interact": "^6.3.0",
"@sentry/react": "^7.65.0",
"@tauri-apps/api": "^1.5.0",
"@sentry/react": "^7.77.0",
"@tauri-apps/api": "^1.5.1",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.5.1",
@ -30,7 +30,7 @@
"crypto-js": "^4.2.0",
"debounce-promise": "^3.1.2",
"formik": "^2.4.3",
"fuse.js": "^6.6.2",
"fuse.js": "^7.0.0",
"http-server": "^14.1.1",
"json-rpc-2.0": "^1.6.0",
"re-resizable": "^6.9.11",
@ -51,7 +51,7 @@
"uuid": "^9.0.1",
"vitest": "^0.34.6",
"vscode-jsonrpc": "^8.1.0",
"vscode-languageserver-protocol": "^3.17.3",
"vscode-languageserver-protocol": "^3.17.5",
"wasm-pack": "^0.12.1",
"web-vitals": "^3.5.0",
"ws": "^8.13.0",
@ -102,7 +102,7 @@
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.22.9",
"@babel/preset-env": "^7.23.3",
"@tauri-apps/cli": "^1.5.6",
"@types/crypto-js": "^4.1.1",
"@types/debounce-promise": "^3.1.8",
@ -111,18 +111,18 @@
"@types/uuid": "^9.0.4",
"@types/wicg-file-system-access": "^2020.9.6",
"@types/ws": "^8.5.5",
"@vitejs/plugin-react": "^4.0.3",
"@vitejs/plugin-react": "^4.1.1",
"@vitest/coverage-istanbul": "^0.34.1",
"autoprefixer": "^10.4.13",
"eslint": "^8.44.0",
"eslint": "^8.53.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-css-modules": "^2.11.0",
"eslint-plugin-css-modules": "^2.12.0",
"happy-dom": "^10.8.0",
"husky": "^8.0.3",
"postcss": "^8.4.31",
"prettier": "^2.8.0",
"setimmediate": "^1.0.5",
"tailwindcss": "^3.2.4",
"tailwindcss": "^3.3.5",
"vite": "^4.5.0",
"vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.2.1",

49
src-tauri/Cargo.lock generated
View File

@ -1732,9 +1732,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.148"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libm"
@ -1913,12 +1913,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "minisign-verify"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881"
[[package]]
name = "miniz_oxide"
version = "0.6.2"
@ -1940,9 +1934,9 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.8"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
@ -3215,9 +3209,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.190"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
@ -3233,9 +3227,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.190"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
@ -3438,9 +3432,9 @@ dependencies = [
[[package]]
name = "socket2"
version = "0.5.4"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
dependencies = [
"libc",
"windows-sys 0.48.0",
@ -3745,7 +3739,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bfe673cf125ef364d6f56b15e8ce7537d9ca7e4dae1cf6fbbdeed2e024db3d9"
dependencies = [
"anyhow",
"base64 0.21.2",
"bytes",
"cocoa",
"dirs-next",
@ -3759,7 +3752,6 @@ dependencies = [
"heck 0.4.1",
"http",
"ignore",
"minisign-verify",
"objc",
"once_cell",
"open",
@ -3784,14 +3776,12 @@ dependencies = [
"tauri-utils",
"tempfile",
"thiserror",
"time",
"tokio",
"url",
"uuid",
"webkit2gtk",
"webview2-com",
"windows 0.39.0",
"zip",
]
[[package]]
@ -3856,7 +3846,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs-extra"
version = "0.0.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#11048fd9975bf89e9bc2f192b735ac339f6bb43b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#61e862597e7234ddca9d9c4b07700855841888f3"
dependencies = [
"log",
"serde",
@ -4035,9 +4025,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.33.0"
version = "1.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
dependencies = [
"backtrace",
"bytes",
@ -4045,7 +4035,7 @@ dependencies = [
"mio",
"num_cpus",
"pin-project-lite",
"socket2 0.5.4",
"socket2 0.5.5",
"windows-sys 0.48.0",
]
@ -5012,14 +5002,3 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zip"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
dependencies = [
"byteorder",
"crc32fast",
"crossbeam-utils",
]

View File

@ -22,7 +22,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tauri = { version = "1.5.2", features = [ "os-all", "dialog-all", "fs-all", "http-request", "path-all", "shell-open", "shell-open-api", "updater", "devtools"] }
tauri-plugin-fs-extra = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
tokio = { version = "1.33.0", features = ["time"] }
tokio = { version = "1.34.0", features = ["time"] }
toml = "0.8.2"
[features]

View File

@ -68,7 +68,7 @@ async fn login(app: tauri::AppHandle, host: &str) -> Result<String, InvokeError>
};
// Open the system browser with the auth_uri.
// We do this in the browser and not a seperate window because we want 1password and
// We do this in the browser and not a separate window because we want 1password and
// other crap to work well.
tauri::api::shell::open(&app.shell_scope(), auth_uri.secret(), None)
.map_err(|e| InvokeError::from_anyhow(e.into()))?;

View File

@ -8,7 +8,7 @@
},
"package": {
"productName": "kittycad-modeling",
"version": "0.11.1"
"version": "0.12.0"
},
"tauri": {
"allowlist": {
@ -72,23 +72,13 @@
},
"resources": [],
"shortDescription": "",
"targets": "all",
"windows": {
"certificateThumbprint": "F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D",
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com"
}
"targets": "all"
},
"security": {
"csp": null
},
"updater": {
"active": true,
"endpoints": [
"https://dl.kittycad.io/releases/modeling-app/last_update.json"
],
"dialog": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUzNzA4MjBEQjFBRTY4NzYKUldSMmFLNnhEWUp3NCtsT21Jd05wQktOaGVkOVp6MUFma0hNTDRDSnI2RkJJTEZOWG1ncFhqcU8K"
"active": false
},
"windows": [
{

View File

@ -1,4 +1,3 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": {

View File

@ -0,0 +1,21 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"tauri": {
"updater": {
"active": true,
"endpoints": [
"https://dl.kittycad.io/releases/modeling-app/last_update.json"
],
"dialog": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUzNzA4MjBEQjFBRTY4NzYKUldSMmFLNnhEWUp3NCtsT21Jd05wQktOaGVkOVp6MUFma0hNTDRDSnI2RkJJTEZOWG1ncFhqcU8K"
},
"bundle": {
"identifier": "io.kittycad.modeling-app",
"windows": {
"certificateThumbprint": "F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D",
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com"
}
}
}
}

View File

@ -1,4 +1,3 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": {

View File

@ -1,4 +1,4 @@
import { useEffect, useCallback, MouseEventHandler } from 'react'
import { useCallback, MouseEventHandler } from 'react'
import { DebugPanel } from './components/DebugPanel'
import { v4 as uuidv4 } from 'uuid'
import { PaneType, useStore } from './useStore'
@ -19,7 +19,6 @@ import {
} from '@fortawesome/free-solid-svg-icons'
import { useHotkeys } from 'react-hotkeys-hook'
import { getNormalisedCoordinates } from './lib/utils'
import { isTauri } from './lib/isTauri'
import { useLoaderData } from 'react-router-dom'
import { IndexLoaderData } from './Router'
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
@ -31,11 +30,10 @@ import { TextEditor } from 'components/TextEditor'
import { Themes, getSystemTheme } from 'lib/theme'
import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions'
import { engineCommandManager } from './lang/std/engineConnection'
import { kclManager } from 'lang/KclSinglton'
import { useModelingContext } from 'hooks/useModelingContext'
export function App() {
const { code: loadedCode, project, file } = useLoaderData() as IndexLoaderData
const { project, file } = useLoaderData() as IndexLoaderData
useHotKeyListener()
const {
@ -82,26 +80,6 @@ export function App() {
? 'opacity-40'
: ''
// Use file code loaded from disk
// on mount, and overwrite any locally-stored code
useEffect(() => {
if (isTauri() && loadedCode !== null) {
if (kclManager.engineCommandManager.engineConnection?.isReady()) {
// If the engine is ready, promptly execute the loaded code
kclManager.setCodeAndExecute(loadedCode)
} else {
// Otherwise, just set the code and wait for the connection to complete
kclManager.setCode(loadedCode)
}
}
return () => {
// Clear code on unmount if in desktop app
if (isTauri()) {
kclManager.setCode('')
}
}
}, [loadedCode])
useEngineConnectionSubscriptions()
const debounceSocketSend = throttle<EngineCommand>((message) => {
@ -248,7 +226,7 @@ export function App() {
<Stream className="absolute inset-0 z-0" />
{showDebugPanel && (
<DebugPanel
title="Debug"
title="Debug (AST Explorer)"
className={
'transition-opacity transition-duration-75 ' +
paneOpacity +

View File

@ -42,7 +42,7 @@ import CommandBarProvider from 'components/CommandBar'
import { TEST, VITE_KC_SENTRY_DSN } from './env'
import * as Sentry from '@sentry/react'
import ModelingMachineProvider from 'components/ModelingMachineProvider'
import { KclContextProvider } from 'lang/KclSinglton'
import { KclContextProvider, kclManager } from 'lang/KclSinglton'
import FileMachineProvider from 'components/FileMachineProvider'
import { sep } from '@tauri-apps/api/path'
@ -207,6 +207,7 @@ const router = createBrowserRouter(
projectPath + sep + PROJECT_ENTRYPOINT
)
const children = await readDir(projectPath, { recursive: true })
kclManager.setCodeAndExecute(code, false)
return {
code,

View File

@ -1,5 +1,5 @@
import { useEffect, useState, useRef } from 'react'
import { parse, BinaryPart, Value, executor } from '../lang/wasm'
import { parse, BinaryPart, Value } from '../lang/wasm'
import {
createIdentifier,
createLiteral,
@ -10,6 +10,7 @@ import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst'
import { engineCommandManager } from '../lang/std/engineConnection'
import { kclManager, useKclContext } from 'lang/KclSinglton'
import { useModelingContext } from 'hooks/useModelingContext'
import { executeAst } from 'useStore'
export const AvailableVars = ({
onVarClick,
@ -130,27 +131,29 @@ export function useCalc({
if (!programMemory || !selectionRange) return
const varInfo = findAllPreviousVariables(
kclManager.ast,
programMemory,
kclManager.programMemory,
selectionRange
)
setAvailableVarInfo(varInfo)
}, [kclManager.ast, programMemory, selectionRange])
}, [kclManager.ast, kclManager.programMemory, selectionRange])
useEffect(() => {
try {
const code = `const __result__ = ${value}\nshow(__result__)`
const code = `const __result__ = ${value}`
const ast = parse(code)
const _programMem: any = { root: {}, return: null }
availableVarInfo.variables.forEach(({ key, value }) => {
_programMem.root[key] = { type: 'userVal', value, __meta: [] }
})
executor(
executeAst({
ast,
_programMem,
engineCommandManager,
kclManager.defaultPlanes
).then((programMemory) => {
defaultPlanes: kclManager.defaultPlanes,
useFakeExecutor: true,
programMemoryOverride: JSON.parse(
JSON.stringify(kclManager.programMemory)
),
}).then(({ programMemory }) => {
const resultDeclaration = ast.body.find(
(a) =>
a.type === 'VariableDeclaration' &&
@ -167,7 +170,7 @@ export function useCalc({
setCalcResult('NAN')
setValueNode(null)
}
}, [value])
}, [value, availableVarInfo])
return {
valueNode,
@ -212,7 +215,10 @@ export const CreateNewVariable = ({
}) => {
return (
<>
<label htmlFor="create-new-variable" className="block mt-3 font-mono">
<label
htmlFor="create-new-variable"
className="block mt-3 font-mono text-gray-900"
>
Create new variable
</label>
<div className="mt-1 flex gap-2 items-center">
@ -223,6 +229,7 @@ export const CreateNewVariable = ({
onChange={(e) => {
setShouldCreateVariable(e.target.checked)
}}
className="bg-white text-gray-900"
/>
)}
<input

View File

@ -1,29 +1,7 @@
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { v4 as uuidv4 } from 'uuid'
import { EngineCommand } from '../lang/std/engineConnection'
import { useState } from 'react'
import { ActionButton } from '../components/ActionButton'
import { faCheck } from '@fortawesome/free-solid-svg-icons'
import { isReducedMotion } from 'lang/util'
import { AstExplorer } from './AstExplorer'
import { engineCommandManager } from '../lang/std/engineConnection'
type SketchModeCmd = Extract<
Extract<EngineCommand, { type: 'modeling_cmd_req' }>['cmd'],
{ type: 'default_camera_enable_sketch_mode' }
>
export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
const [sketchModeCmd, setSketchModeCmd] = useState<SketchModeCmd>({
type: 'default_camera_enable_sketch_mode',
origin: { x: 0, y: 0, z: 0 },
x_axis: { x: 1, y: 0, z: 0 },
y_axis: { x: 0, y: 1, z: 0 },
distance_to_plane: 100,
ortho: true,
animated: !isReducedMotion(),
})
if (!sketchModeCmd) return null
return (
<CollapsiblePanel
{...props}
@ -34,67 +12,6 @@ export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
style={{ maxHeight: 'calc(100% - 3rem - 1.25rem - 1.25rem)' }}
>
<section className="p-4 flex flex-col gap-4">
<Xyz
onChange={setSketchModeCmd}
pointKey="origin"
data={sketchModeCmd}
/>
<Xyz
onChange={setSketchModeCmd}
pointKey="x_axis"
data={sketchModeCmd}
/>
<Xyz
onChange={setSketchModeCmd}
pointKey="y_axis"
data={sketchModeCmd}
/>
<div className="flex">
<div className="pr-4">distance_to_plane</div>
<input
className="w-16 dark:bg-chalkboard-90"
type="number"
value={sketchModeCmd.distance_to_plane}
onChange={({ target }) => {
setSketchModeCmd({
...sketchModeCmd,
distance_to_plane: Number(target.value),
})
}}
/>
<div className="pr-4">ortho</div>
<input
className="w-16"
type="checkbox"
checked={sketchModeCmd.ortho}
onChange={(a) =>
setSketchModeCmd({
...sketchModeCmd,
ortho: a.target.checked,
})
}
/>
</div>
<ActionButton
Element="button"
onClick={() => {
engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: sketchModeCmd,
cmd_id: uuidv4(),
})
}}
className="hover:border-succeed-50"
icon={{
icon: faCheck,
bgClassName:
'bg-succeed-80 group-hover:bg-succeed-70 hover:bg-succeed-70',
iconClassName:
'text-succeed-20 group-hover:text-succeed-10 hover:text-succeed-10',
}}
>
Send sketch mode command
</ActionButton>
<div style={{ height: '400px' }} className="overflow-y-auto">
<AstExplorer />
</div>
@ -102,41 +19,3 @@ export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
</CollapsiblePanel>
)
}
const Xyz = ({
pointKey,
data,
onChange,
}: {
pointKey: 'origin' | 'y_axis' | 'x_axis'
data: SketchModeCmd
onChange: (a: SketchModeCmd) => void
}) => {
if (!data) return null
return (
<div className="flex">
<div className="pr-4">{pointKey}</div>
{Object.entries(data[pointKey]).map(([axis, val]) => {
return (
<div key={axis} className="flex">
<div className="w-4">{axis}</div>
<input
className="w-16 dark:bg-chalkboard-90"
type="number"
value={val}
onChange={({ target }) => {
onChange({
...data,
[pointKey]: {
...data[pointKey],
[axis]: Number(target.value),
},
})
}}
/>
</div>
)
})}
</div>
)
}

View File

@ -9,7 +9,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { useFileContext } from 'hooks/useFileContext'
import { useHotkeys } from 'react-hotkeys-hook'
import { kclManager } from 'lang/KclSinglton'
import styles from './FileTree.module.css'
import { sortProject } from 'lib/tauriFS'
@ -163,7 +162,6 @@ const FileTreeItem = ({
function openFile() {
if (fileOrDir.children !== undefined) return // Don't open directories
kclManager.setCode('')
navigate(`${paths.FILE}/${encodeURIComponent(fileOrDir.path)}`)
closePanel()
}

View File

@ -147,7 +147,7 @@ export const ModelingMachineProvider = ({
engineCommandManager.artifactMap[sketchEnginePathId] = {
type: 'result',
range: [startProfileAtCallExp.start, startProfileAtCallExp.end],
commandType: 'extend_path',
commandType: 'start_path',
data: null,
raw: {} as any,
}

View File

@ -108,7 +108,7 @@ export const SetAngleLengthModal = ({
</label>
<div className="mt-1 flex">
<button
className="border border-gray-300 px-2"
className="border border-gray-300 px-2 text-gray-900"
onClick={() => setSign(-sign)}
>
{sign > 0 ? '+' : '-'}
@ -118,7 +118,7 @@ export const SetAngleLengthModal = ({
type="text"
name="val"
id="val"
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono pl-1"
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono pl-1 text-gray-900"
value={value}
onChange={(e) => {
setValue(e.target.value)

View File

@ -87,7 +87,7 @@ export const GetInfoModal = ({
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white/90 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-900"
@ -109,7 +109,7 @@ export const GetInfoModal = ({
</label>
<div className="mt-1 flex">
<button
className="border border-gray-300 px-2 mr-1"
className="border border-gray-400 px-2 mr-1 text-gray-900"
onClick={() => setSign(-sign)}
>
{sign > 0 ? '+' : '-'}
@ -119,7 +119,7 @@ export const GetInfoModal = ({
name="val"
id="val"
ref={inputRef}
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono"
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm text-gray-900 border-gray-300 rounded-md font-mono"
value={value}
onChange={(e) => {
setValue(e.target.value)
@ -139,7 +139,7 @@ export const GetInfoModal = ({
name="segName"
id="segName"
disabled={!isSegNameEditable}
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono"
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm text-gray-900 border-gray-300 rounded-md font-mono"
value={segName}
onChange={(e) => {
setSegName(e.target.value)

View File

@ -14,7 +14,7 @@ import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
import { CameraDragInteractionType_type } from '@kittycad/lib/dist/types/src/models'
import { Models } from '@kittycad/lib'
import { getNodeFromPath } from 'lang/queryAst'
import { VariableDeclarator, recast, parse, CallExpression } from 'lang/wasm'
import { VariableDeclarator, recast, CallExpression } from 'lang/wasm'
import { engineCommandManager } from '../lang/std/engineConnection'
import { useModelingContext } from 'hooks/useModelingContext'
import { kclManager, useKclContext } from 'lang/KclSinglton'
@ -342,7 +342,8 @@ export const Stream = ({ className = '' }) => {
// update artifact map ranges now that we have updated the ast.
code = recast(modded.modifiedAst)
const astWithCurrentRanges = parse(code)
const astWithCurrentRanges = kclManager.safeParse(code)
if (!astWithCurrentRanges) return
const updateNode = getNodeFromPath<CallExpression>(
astWithCurrentRanges,
modded.pathToNode

View File

@ -17,15 +17,7 @@ import { useStore } from 'useStore'
import { processCodeMirrorRanges } from 'lib/selections'
import { LanguageServerClient } from 'editor/lsp'
import kclLanguage from 'editor/lsp/language'
import { isTauri } from 'lib/isTauri'
import { useParams } from 'react-router-dom'
import { writeTextFile } from '@tauri-apps/api/fs'
import { toast } from 'react-hot-toast'
import {
EditorView,
addLineHighlight,
lineHighlightField,
} from 'editor/highlightextension'
import { EditorView, lineHighlightField } from 'editor/highlightextension'
import { roundOff } from 'lib/utils'
import { kclErrToDiagnostic } from 'lang/errors'
import { CSSRuleObject } from 'tailwindcss/types/config'
@ -50,7 +42,6 @@ export const TextEditor = ({
}: {
theme: Themes.Light | Themes.Dark
}) => {
const pathParams = useParams()
const { editorView, isLSPServerReady, setEditorView, setIsLSPServerReady } =
useStore((s) => ({
editorView: s.editorView,
@ -92,7 +83,7 @@ export const TextEditor = ({
// Here we initialize the plugin which will start the client.
// When we have multi-file support the name of the file will be a dep of
// this use memo, as well as the directory structure, which I think is
// a good setup becuase it will restart the client but not the server :)
// a good setup because it will restart the client but not the server :)
// We do not want to restart the server, its just wasteful.
const kclLSP = useMemo(() => {
let plugin = null
@ -113,18 +104,6 @@ export const TextEditor = ({
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
const onChange = (newCode: string) => {
kclManager.setCodeAndExecute(newCode)
if (isTauri() && pathParams.id) {
// Save the file to disk
// Note that PROJECT_ENTRYPOINT is hardcoded until we support multiple files
writeTextFile(pathParams.id, newCode).catch((err) => {
// TODO: add Sentry per GH issue #254 (https://github.com/KittyCAD/modeling-app/issues/254)
console.error('error saving file', err)
toast.error('Error saving file, please check file permissions')
})
}
if (editorView) {
editorView?.dispatch({ effects: addLineHighlight.of([0, 0]) })
}
} //, []);
const onUpdate = (viewUpdate: ViewUpdate) => {
if (!editorView) {

View File

@ -26,7 +26,7 @@ export class Codec {
}
}
// FIXME: tracing effiency
// FIXME: tracing efficiency
export class IntoServer
extends Queue<Uint8Array>
implements AsyncGenerator<Uint8Array, never, void>

View File

@ -35,7 +35,7 @@ export function useEngineConnectionSubscriptions() {
const event = await getEventForSelectWithPoint(engineEvent, {
sketchEnginePathId: context.sketchEnginePathId,
})
send(event)
event && send(event)
},
})
return () => {

View File

@ -26,10 +26,6 @@ export function useSetupEngineManager(
const hasSetNonZeroDimensions = useRef<boolean>(false)
useEffect(() => {
kclManager.executeCode()
}, [])
useLayoutEffect(() => {
// Load the engine command manager once with the initial width and height,
// then we do not want to reload it.
@ -86,9 +82,14 @@ export function useSetupEngineManager(
}
function getDimensions(streamWidth?: number, streamHeight?: number) {
const maxResolution = 2000
const width = streamWidth ? streamWidth : 0
const quadWidth = Math.round(width / 4) * 4
const height = streamHeight ? streamHeight : 0
const quadHeight = Math.round(height / 4) * 4
const ratio = Math.min(
Math.min(maxResolution / width, maxResolution / height),
1.0
)
const quadWidth = Math.round((width * ratio) / 4) * 4
const quadHeight = Math.round((height * ratio) / 4) * 4
return { width: quadWidth, height: quadHeight }
}

View File

@ -18,7 +18,11 @@ import { bracket } from 'lib/exampleKcl'
import { createContext, useContext, useEffect, useState } from 'react'
import { getNodeFromPath } from './queryAst'
import { IndexLoaderData } from 'Router'
import { useLoaderData } from 'react-router-dom'
import { Params, useLoaderData } from 'react-router-dom'
import { isTauri } from 'lib/isTauri'
import { writeTextFile } from '@tauri-apps/api/fs'
import { toast } from 'react-hot-toast'
import { useParams } from 'react-router-dom'
const PERSIST_CODE_TOKEN = 'persistCode'
@ -41,10 +45,20 @@ class KclManager {
private _kclErrors: KCLError[] = []
private _isExecuting = false
private _wasmInitFailed = true
private _params: Params<string> = {}
engineCommandManager: EngineCommandManager
private _defferer = deferExecution((code: string) => {
const ast = parse(code)
const ast = this.safeParse(code)
if (!ast) return
try {
const fmtAndStringify = (ast: Program) =>
JSON.stringify(parse(recast(ast)))
const isAstTheSame = fmtAndStringify(ast) === fmtAndStringify(this._ast)
if (isAstTheSame) return
} catch (e) {
console.error(e)
}
this.executeAst(ast)
}, 600)
@ -71,6 +85,21 @@ class KclManager {
set code(code) {
this._code = code
this._codeCallBack(code)
if (isTauri()) {
setTimeout(() => {
// Wait one event loop to give a chance for params to be set
// Save the file to disk
// Note that PROJECT_ENTRYPOINT is hardcoded until we support multiple files
this._params.id &&
writeTextFile(this._params.id, code).catch((err) => {
// TODO: add Sentry per GH issue #254 (https://github.com/KittyCAD/modeling-app/issues/254)
console.error('error saving file', err)
toast.error('Error saving file, please check file permissions')
})
})
} else {
localStorage.setItem(PERSIST_CODE_TOKEN, code)
}
}
get programMemory() {
@ -117,10 +146,19 @@ class KclManager {
this._wasmInitFailedCallback(wasmInitFailed)
}
setParams(params: Params<string>) {
this._params = params
}
constructor(engineCommandManager: EngineCommandManager) {
this.engineCommandManager = engineCommandManager
if (isTauri()) {
this.code = ''
return
}
const storedCode = localStorage.getItem(PERSIST_CODE_TOKEN)
// TODO #819 remove zustand persistance logic in a few months
// TODO #819 remove zustand persistence logic in a few months
// short term migration, shouldn't make a difference for tauri app users
// anyway since that's filesystem based.
const zustandStore = JSON.parse(localStorage.getItem('store') || '{}')
@ -130,6 +168,7 @@ class KclManager {
zustandStore.state.code = ''
localStorage.setItem('store', JSON.stringify(zustandStore))
} else if (storedCode === null) {
console.log('stored brack thing')
this.code = bracket
} else {
this.code = storedCode
@ -164,6 +203,21 @@ class KclManager {
this._executeCallback = callback
}
safeParse(code: string): Program | null {
try {
const ast = parse(code)
this.kclErrors = []
return ast
} catch (e) {
console.error('error parsing code', e)
if (e instanceof KCLError) {
this.kclErrors = [e]
if (e.msg === 'file is empty') engineCommandManager.endSession()
}
return null
}
}
async ensureWasmInit() {
try {
await initPromise
@ -184,20 +238,20 @@ class KclManager {
defaultPlanes: this.defaultPlanes,
})
this.isExecuting = false
this._logs = logs
this._kclErrors = errors
this._programMemory = programMemory
this._ast = { ...ast }
this.logs = logs
this.kclErrors = errors
this.programMemory = programMemory
this.ast = { ...ast }
if (updateCode) {
this._code = recast(ast)
this._codeCallBack(this._code)
this.code = recast(ast)
}
this._executeCallback()
}
async executeAstMock(ast: Program = this._ast, updateCode = false) {
await this.ensureWasmInit()
const newCode = recast(ast)
const newAst = parse(newCode)
const newAst = this.safeParse(newCode)
if (!newAst) return
await this?.engineCommandManager?.waitForReady
if (updateCode) {
this.setCode(recast(ast))
@ -233,13 +287,17 @@ class KclManager {
this.ast = ast
if (code) this.code = code
}
setCode(code: string) {
setCode(code: string, shouldWriteFile = true) {
if (shouldWriteFile) {
// use the normal code setter
this.code = code
return
}
this._code = code
this._codeCallBack(code)
localStorage.setItem(PERSIST_CODE_TOKEN, code)
}
setCodeAndExecute(code: string) {
this.setCode(code)
setCodeAndExecute(code: string, shouldWriteFile = true) {
this.setCode(code, shouldWriteFile)
if (code.trim()) {
this._defferer(code)
return
@ -260,9 +318,11 @@ class KclManager {
this.engineCommandManager.endSession()
}
format() {
this.code = recast(parse(kclManager.code))
const ast = this.safeParse(this.code)
if (!ast) return
this.code = recast(ast)
}
// There's overlapping resposibility between updateAst and executeAst.
// There's overlapping responsibility between updateAst and executeAst.
// updateAst was added as it was used a lot before xState migration so makes the port easier.
// but should probably have think about which of the function to keep
async updateAst(
@ -270,15 +330,13 @@ class KclManager {
execute: boolean,
optionalParams?: {
focusPath?: PathToNode
callBack?: (ast: Program) => void
}
): Promise<Selections | null> {
const newCode = recast(ast)
const astWithUpdatedSource = parse(newCode)
optionalParams?.callBack?.(astWithUpdatedSource)
const astWithUpdatedSource = this.safeParse(newCode)
if (!astWithUpdatedSource) return null
let returnVal: Selections | null = null
this.code = newCode
if (optionalParams?.focusPath) {
const { node } = getNodeFromPath<any>(
astWithUpdatedSource,
@ -299,12 +357,12 @@ class KclManager {
if (execute) {
// Call execute on the set ast.
await this.executeAst(astWithUpdatedSource)
await this.executeAst(astWithUpdatedSource, true)
} else {
// When we don't re-execute, we still want to update the program
// memory with the new ast. So we will hit the mock executor
// instead.
await this.executeAstMock(astWithUpdatedSource)
await this.executeAstMock(astWithUpdatedSource, true)
}
return returnVal
}
@ -369,6 +427,11 @@ export function KclContextProvider({
setWasmInitFailed,
})
}, [])
const params = useParams()
useEffect(() => {
kclManager.setParams(params)
}, [params])
return (
<KclContext.Provider
value={{

View File

@ -331,9 +331,6 @@ const myVar = funcN(1, 2)`
raw: '2',
},
],
function: {
type: 'InMemory',
},
optional: false,
},
},
@ -403,7 +400,6 @@ describe('testing pipe operator special', () => {
],
},
],
function: expect.any(Object),
optional: false,
},
{
@ -440,7 +436,6 @@ describe('testing pipe operator special', () => {
},
{ type: 'PipeSubstitution', start: 59, end: 60 },
],
function: expect.any(Object),
optional: false,
},
{
@ -513,7 +508,6 @@ describe('testing pipe operator special', () => {
},
{ type: 'PipeSubstitution', start: 105, end: 106 },
],
function: expect.any(Object),
optional: false,
},
{
@ -550,7 +544,6 @@ describe('testing pipe operator special', () => {
},
{ type: 'PipeSubstitution', start: 128, end: 129 },
],
function: expect.any(Object),
optional: false,
},
{
@ -573,9 +566,6 @@ describe('testing pipe operator special', () => {
},
{ type: 'PipeSubstitution', start: 143, end: 144 },
],
function: {
type: 'InMemory',
},
optional: false,
},
],
@ -655,9 +645,6 @@ describe('testing pipe operator special', () => {
end: 35,
},
],
function: {
type: 'InMemory',
},
optional: false,
},
],
@ -1345,7 +1332,7 @@ describe('nests binary expressions correctly', () => {
],
})
})
it('should nest properly with two opperators of equal precedence', () => {
it('should nest properly with two operators of equal precedence', () => {
const code = `const yo = 1 + 2 - 3`
const { body } = parse(code)
expect((body[0] as any).declarations[0].init).toEqual({
@ -1382,7 +1369,7 @@ describe('nests binary expressions correctly', () => {
},
})
})
it('should nest properly with two opperators of equal (but higher) precedence', () => {
it('should nest properly with two operators of equal (but higher) precedence', () => {
const code = `const yo = 1 * 2 / 3`
const { body } = parse(code)
expect((body[0] as any).declarations[0].init).toEqual({
@ -1567,7 +1554,6 @@ describe('test UnaryExpression', () => {
{ type: 'Literal', start: 19, end: 20, value: 4, raw: '4' },
{ type: 'Literal', start: 22, end: 25, value: 100, raw: '100' },
],
function: expect.any(Object),
optional: false,
},
})
@ -1601,12 +1587,10 @@ describe('testing nested call expressions', () => {
{ type: 'Literal', start: 34, end: 35, value: 5, raw: '5' },
{ type: 'Literal', start: 37, end: 38, value: 3, raw: '3' },
],
function: expect.any(Object),
optional: false,
},
},
],
function: expect.any(Object),
optional: false,
})
})
@ -1638,7 +1622,6 @@ describe('should recognise callExpresions in binaryExpressions', () => {
},
{ type: 'PipeSubstitution', start: 25, end: 26 },
],
function: expect.any(Object),
optional: false,
},
right: { type: 'Literal', value: 1, raw: '1', start: 30, end: 31 },

View File

@ -18,6 +18,20 @@ export class KCLError {
}
}
export class KCLLexicalError extends KCLError {
constructor(msg: string, sourceRanges: [number, number][]) {
super('lexical', msg, sourceRanges)
Object.setPrototypeOf(this, KCLSyntaxError.prototype)
}
}
export class KCLInternalError extends KCLError {
constructor(msg: string, sourceRanges: [number, number][]) {
super('internal', msg, sourceRanges)
Object.setPrototypeOf(this, KCLSyntaxError.prototype)
}
}
export class KCLSyntaxError extends KCLError {
constructor(msg: string, sourceRanges: [number, number][]) {
super('syntax', msg, sourceRanges)

View File

@ -480,21 +480,6 @@ export function createCallExpressionStdLib(
end: 0,
name,
},
function: {
type: 'StdLib',
func: {
// We only need the name here to map it back when it serializes
// to rust, don't worry about the rest.
name,
summary: '',
description: '',
tags: [],
returnValue: { type: '', required: false, name: '', schema: {} },
args: [],
unpublished: false,
deprecated: false,
},
},
optional: false,
arguments: args,
}
@ -514,9 +499,6 @@ export function createCallExpression(
end: 0,
name,
},
function: {
type: 'InMemory',
},
optional: false,
arguments: args,
}

View File

@ -2,5 +2,5 @@ The std is as expected, tools that are provided with the language.
For this language that means functions.
However because programatically changing the source code is a first class citizen in this lang, there needs to be helpes for adding and modifying these function calls,
However because programmatically changing the source code is a first class citizen in this lang, there needs to be helpers for adding and modifying these function calls,
So it makes sense to group some of these together.

View File

@ -216,6 +216,26 @@ export class EngineConnection {
}
})
this.pc.addEventListener('icecandidateerror', (_event) => {
const event = _event as RTCPeerConnectionIceErrorEvent
console.error(
`ICE candidate returned an error: ${event.errorCode}: ${event.errorText} for ${event.url}`
)
})
this.pc.addEventListener('connectionstatechange', (event) => {
if (this.pc?.iceConnectionState === 'connected') {
if (this.shouldTrace()) {
iceSpan.resolve?.()
}
} else if (this.pc?.iceConnectionState === 'failed') {
// failed is a terminal state; let's explicitly kill the
// connection to the server at this point.
console.log('failed to negotiate ice connection; restarting')
this.close()
}
})
this.websocket.addEventListener('open', (event) => {
if (this.shouldTrace()) {
websocketSpan.resolve?.()
@ -351,19 +371,6 @@ export class EngineConnection {
// until the end of this function is setup of our end of the
// PeerConnection and waiting for events to fire our callbacks.
this.pc.addEventListener('connectionstatechange', (event) => {
if (this.pc?.iceConnectionState === 'connected') {
if (this.shouldTrace()) {
iceSpan.resolve?.()
}
} else if (this.pc?.iceConnectionState === 'failed') {
// failed is a terminal state; let's explicitly kill the
// connection to the server at this point.
console.log('failed to negotiate ice connection; restarting')
this.close()
}
})
this.pc.addEventListener('icecandidate', (event) => {
if (!this.pc || !this.websocket) return
if (event.candidate !== null) {
@ -633,7 +640,10 @@ export class EngineCommandManager {
// If we already have an engine connection, just need to resize the stream.
if (this.engineConnection) {
this.handleResize({ streamWidth: width, streamHeight: height })
this.handleResize({
streamWidth: width,
streamHeight: height,
})
return
}
@ -664,7 +674,7 @@ export class EngineCommandManager {
},
})
// Inisialize the planes.
// Initialize the planes.
this.initPlanes().then(() => {
// We execute the code here to make sure if the stream was to
// restart in a session, we want to make sure to execute the code.
@ -887,8 +897,9 @@ export class EngineCommandManager {
}
endSession() {
// TODO: instead of sending a single command with `object_ids: Object.keys(this.artifactMap)`
// we need to loop over them each individualy because if the engine doesn't recognise a single
// we need to loop over them each individually because if the engine doesn't recognise a single
// id the whole command fails.
const artifactsToDelete: any = {}
Object.entries(this.artifactMap).forEach(([id, artifact]) => {
const artifactTypesToDelete: ArtifactMap[string]['commandType'][] = [
// 'start_path' creates a new scene object for the path, which is why it needs to be deleted,
@ -898,7 +909,9 @@ export class EngineCommandManager {
'start_path',
]
if (!artifactTypesToDelete.includes(artifact.commandType)) return
artifactsToDelete[id] = artifact
})
Object.keys(artifactsToDelete).forEach((id) => {
const deletCmd: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),

View File

@ -946,7 +946,7 @@ export function compareVec2Epsilon(
) {
const compareEpsilon = 0.015625 // or 2^-6
const xDifference = Math.abs(vec1[0] - vec2[0])
const yDifference = Math.abs(vec1[0] - vec2[0])
const yDifference = Math.abs(vec1[1] - vec2[1])
return xDifference < compareEpsilon && yDifference < compareEpsilon
}

View File

@ -50,7 +50,7 @@ async function testingSwapSketchFnCall({
}
}
describe('testing swaping out sketch calls with xLine/xLineTo', () => {
describe('testing swapping out sketch calls with xLine/xLineTo', () => {
const bigExampleArr = [
`const part001 = startSketchOn('XY')`,
` |> startProfileAt([0, 0], %)`,
@ -178,7 +178,7 @@ describe('testing swaping out sketch calls with xLine/xLineTo', () => {
constraintType: 'horizontal',
})
const expectedLine = "xLine({ length: -0.86, tag: 'abc4' }, %)"
// hmm "-0.86" is correct since the angle is 104, but need to make sure this is compatiable `-myVar`
// hmm "-0.86" is correct since the angle is 104, but need to make sure this is compatible `-myVar`
expect(newCode).toContain(expectedLine)
// new line should start at the same place as the old line
expect(originalRange[0]).toBe(newCode.indexOf(expectedLine))
@ -268,7 +268,7 @@ describe('testing swaping out sketch calls with xLine/xLineTo', () => {
})
})
describe('testing swaping out sketch calls with xLine/xLineTo while keeping variable/identifiers intact', () => {
describe('testing swapping out sketch calls with xLine/xLineTo while keeping variable/identifiers intact', () => {
// Enable rotations #152
const variablesExampleArr = [
`const lineX = -1`,

View File

@ -108,7 +108,7 @@ const part001 = startSketchOn('XY')
|> line([myVar, 1], %) // ln-should use legLen for y
|> line([myVar, -1], %) // ln-legLen but negative
|> line([-0.62, -1.54], %) // ln-should become angledLine
|> angledLine([myVar, 1.04], %) // ln-use segLen for secound arg
|> angledLine([myVar, 1.04], %) // ln-use segLen for second arg
|> angledLine([45, 1.04], %) // ln-segLen again
|> angledLineOfXLength([54, 2.35], %) // ln-should be transformed to angledLine
|> angledLineOfXLength([50, myVar], %) // ln-should use legAngX to calculate angle
@ -163,7 +163,7 @@ const part001 = startSketchOn('XY')
-legLen(segLen('seg01', %), myVar)
], %) // ln-legLen but negative
|> angledLine([-112, segLen('seg01', %)], %) // ln-should become angledLine
|> angledLine([myVar, segLen('seg01', %)], %) // ln-use segLen for secound arg
|> angledLine([myVar, segLen('seg01', %)], %) // ln-use segLen for second arg
|> angledLine([45, segLen('seg01', %)], %) // ln-segLen again
|> angledLine([54, segLen('seg01', %)], %) // ln-should be transformed to angledLine
|> angledLineOfXLength([
@ -471,7 +471,7 @@ async function helperThing(
}
describe('testing getConstraintLevelFromSourceRange', () => {
it('should devide up lines into free, partial and fully contrained', () => {
it('should divide up lines into free, partial and fully contrained', () => {
const code = `const baseLength = 3
const baseThick = 1
const armThick = 0.5

View File

@ -26,5 +26,4 @@ const bracket = startSketchOn('XY')
|> close(%)
|> extrude(width, %)
show(bracket)
`

View File

@ -15,7 +15,7 @@ app needs these selections to be based on cursors, therefore the app must
be in control of selections. On top of that because we need to set cursor
positions in code-mirror for selections, both from app logic, and still
allow the user to add multiple cursors like a normal editor, it's best to
let code mirror control cursor positions and assosiate those source ranges
let code mirror control cursor positions and associate those source ranges
with entity ids from code-mirror events later.
So it's a lot of back and forth. conceptually the back and forth is:
@ -43,7 +43,7 @@ In detail:
1) Click commands are mostly sent in stream.tsx search for
"select_with_point"
2) The handler for when the engine sends back entitiy ids calls
2) The handler for when the engine sends back entity ids calls
getEventForSelectWithPoint, it fires an XState event to update our
selections is xstate context
3 and 4) The XState handler for the above uses handleSelectionBatch and
@ -102,8 +102,8 @@ export async function getEventForSelectWithPoint(
Models['OkModelingCmdResponse_type'],
{ type: 'select_with_point' }
>,
{ sketchEnginePathId }: { sketchEnginePathId: string }
): Promise<ModelingMachineEvent> {
{ sketchEnginePathId }: { sketchEnginePathId?: string }
): Promise<ModelingMachineEvent | null> {
if (!data?.entity_id) {
return {
type: 'Set selection',
@ -120,6 +120,7 @@ export async function getEventForSelectWithPoint(
},
}
}
if (!sketchEnginePathId) return null
// selected a vertex
const res = await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
@ -303,7 +304,7 @@ export function resetAndSetEngineEntitySelectionCmds(
selections: SelectionToEngine[]
): Models['WebSocketRequest_type'][] {
if (!engineCommandManager.engineConnection?.isReady()) {
console.log('engine connection isnt ready')
console.log('engine connection is not ready')
return []
}
return [

View File

@ -9,7 +9,6 @@ import { documentDir, homeDir, sep } from '@tauri-apps/api/path'
import { isTauri } from './isTauri'
import { ProjectWithEntryPointMetadata } from '../Router'
import { metadata } from 'tauri-plugin-fs-extra-api'
import { bracket } from './exampleKcl'
const PROJECT_FOLDER = 'kittycad-modeling-projects'
export const FILE_EXT = '.kcl'
@ -211,7 +210,8 @@ export function sortProject(project: FileEntry[]): FileEntry[] {
// Creates a new file in the default directory with the default project name
// Returns the path to the new file
export async function createNewProject(
path: string
path: string,
initCode = ''
): Promise<ProjectWithEntryPointMetadata> {
if (!isTauri) {
throw new Error('createNewProject() can only be called from a Tauri app')
@ -225,10 +225,12 @@ export async function createNewProject(
})
}
await writeTextFile(path + sep + PROJECT_ENTRYPOINT, bracket).catch((err) => {
console.error('Error creating new file:', err)
throw err
})
await writeTextFile(path + sep + PROJECT_ENTRYPOINT, initCode).catch(
(err) => {
console.error('Error creating new file:', err)
throw err
}
)
const m = await metadata(path)

View File

@ -664,8 +664,8 @@ export const modelingMachine = createMachine(
on: {
Cancel: {
target: 'idle',
// TODO what if we're existing extrude equiped, should these actions still be fired?
// mabye cancel needs to have a guard for if else logic?
// TODO what if we're existing extrude equipped, should these actions still be fired?
// maybe cancel needs to have a guard for if else logic?
actions: [
'edit_mode_exit',
'default_camera_disable_sketch_mode',

View File

@ -43,7 +43,10 @@ function OnboardingWithNewFile() {
ONBOARDING_PROJECT_NAME,
nextIndex
)
const newFile = await createNewProject(defaultDirectory + sep + name)
const newFile = await createNewProject(
defaultDirectory + sep + name,
bracket
)
navigate(
`${paths.FILE}/${encodeURIComponent(
newFile.path + sep + PROJECT_ENTRYPOINT
@ -79,7 +82,7 @@ function OnboardingWithNewFile() {
<ActionButton
Element="button"
onClick={() => {
kclManager.setCode(bracket)
kclManager.setCodeAndExecute(bracket)
next()
}}
icon={{ icon: faArrowRight }}
@ -118,7 +121,7 @@ function OnboardingWithNewFile() {
Element="button"
onClick={() => {
createAndOpenNewProject()
kclManager.setCode(bracket)
kclManager.setCode(bracket, false)
dismiss()
}}
icon={{ icon: faArrowRight }}

View File

@ -32,6 +32,7 @@ import {
} from 'lib/tauriFS'
import { ONBOARDING_PROJECT_NAME } from './Onboarding'
import { sep } from '@tauri-apps/api/path'
import { bracket } from 'lib/exampleKcl'
export const Settings = () => {
const loaderData =
@ -96,7 +97,10 @@ export const Settings = () => {
ONBOARDING_PROJECT_NAME,
nextIndex
)
const newFile = await createNewProject(defaultDirectory + sep + name)
const newFile = await createNewProject(
defaultDirectory + sep + name,
bracket
)
navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)
}

View File

@ -253,11 +253,13 @@ export async function executeAst({
engineCommandManager,
defaultPlanes,
useFakeExecutor = false,
programMemoryOverride,
}: {
ast: Program
engineCommandManager: EngineCommandManager
defaultPlanes: DefaultPlanes
useFakeExecutor?: boolean
programMemoryOverride?: ProgramMemory
}): Promise<{
logs: string[]
errors: KCLError[]
@ -269,10 +271,13 @@ export async function executeAst({
engineCommandManager.startNewSession()
}
const programMemory = await (useFakeExecutor
? enginelessExecutor(ast, {
root: defaultProgramMemory,
return: null,
})
? enginelessExecutor(
ast,
programMemoryOverride || {
root: defaultProgramMemory,
return: null,
}
)
: _executor(
ast,
{

View File

@ -6,10 +6,10 @@
serial-integration = { max-threads = 4 }
[profile.default]
slow-timeout = { period = "60s", terminate-after = 1 }
slow-timeout = { period = "10s", terminate-after = 1 }
[profile.ci]
slow-timeout = { period = "120s", terminate-after = 10 }
slow-timeout = { period = "30s", terminate-after = 5 }
[[profile.default.overrides]]
filter = "test(serial_test_)"
@ -20,3 +20,7 @@ threads-required = 4
filter = "test(serial_test_)"
test-group = "serial-integration"
threads-required = 4
[[profile.default.overrides]]
filter = "test(parser::parser_impl::snapshot_tests)"
slow-timeout = { period = "1s", terminate-after = 5 }

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

@ -157,7 +157,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -168,7 +168,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -447,9 +447,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.7"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
dependencies = [
"clap_builder",
"clap_derive",
@ -457,9 +457,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.7"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
dependencies = [
"anstream",
"anstyle",
@ -479,7 +479,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -681,6 +681,30 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "databake"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "959b676312ba1aaafb2219c475560082e6b20c3bc572ec1483f93cecd748cf3d"
dependencies = [
"databake-derive",
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "databake-derive"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0694dfe255f1af0289d3d1b40787bb955e8603d96e96a6b14b225926e108fb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"synstructure",
]
[[package]]
name = "deranged"
version = "0.3.9"
@ -702,7 +726,7 @@ dependencies = [
"quote",
"serde",
"serde_tokenstream",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -716,7 +740,7 @@ dependencies = [
"quote",
"serde",
"serde_tokenstream",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -975,7 +999,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -1305,6 +1329,20 @@ dependencies = [
"serde",
]
[[package]]
name = "insta"
version = "1.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d64600be34b2fcfc267740a243fa7744441bb4947a619ac4e5bb6507f35fbfc"
dependencies = [
"console",
"lazy_static",
"linked-hash-map",
"serde",
"similar",
"yaml-rust",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -1369,9 +1407,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.64"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
dependencies = [
"wasm-bindgen",
]
@ -1398,9 +1436,11 @@ dependencies = [
"clap",
"criterion",
"dashmap",
"databake",
"derive-docs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"expectorate",
"futures",
"insta",
"itertools 0.11.0",
"js-sys",
"kittycad",
@ -1423,6 +1463,18 @@ dependencies = [
"winnow",
]
[[package]]
name = "kcl-macros"
version = "0.1.0"
dependencies = [
"databake",
"kcl-lib",
"pretty_assertions",
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "kittycad"
version = "0.2.41"
@ -1878,7 +1930,7 @@ dependencies = [
"regex",
"regex-syntax 0.7.5",
"structmeta",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -1931,7 +1983,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -2543,9 +2595,9 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
[[package]]
name = "serde"
version = "1.0.190"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
@ -2561,13 +2613,13 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.190"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -2601,7 +2653,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -2622,7 +2674,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -2833,7 +2885,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -2844,7 +2896,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -2882,15 +2934,27 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.38"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"unicode-xid",
]
[[package]]
name = "system-configuration"
version = "0.5.1"
@ -2993,7 +3057,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -3075,9 +3139,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.33.0"
version = "1.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
dependencies = [
"backtrace",
"bytes",
@ -3094,13 +3158,13 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "2.1.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -3241,7 +3305,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -3269,7 +3333,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]
@ -3355,7 +3419,7 @@ dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
"termcolor",
]
@ -3440,6 +3504,12 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "unsafe-libyaml"
version = "0.2.9"
@ -3533,9 +3603,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.87"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -3543,24 +3613,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.87"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.37"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
dependencies = [
"cfg-if",
"futures-core",
@ -3571,9 +3641,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3581,22 +3651,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.87"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.87"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
[[package]]
name = "wasm-lib"
@ -3653,9 +3723,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.64"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3847,9 +3917,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.5.18"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32"
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
dependencies = [
"memchr",
]
@ -3905,7 +3975,7 @@ checksum = "6b6093bc6d5265ff40b479c834cdd25d8e20784781a2a29a8106327393d0a9ff"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
"syn 2.0.39",
]
[[package]]

View File

@ -3,6 +3,7 @@ name = "wasm-lib"
version = "0.1.0"
edition = "2021"
repository = "https://github.com/KittyCAD/modeling-app"
rust-version = "1.73"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
@ -15,8 +16,8 @@ kcl-lib = { path = "kcl" }
kittycad = { workspace = true }
serde_json = "1.0.108"
uuid = { version = "1.5.0", features = ["v4", "js", "serde"] }
wasm-bindgen = "0.2.87"
wasm-bindgen-futures = "0.4.37"
wasm-bindgen = "0.2.88"
wasm-bindgen-futures = "0.4.38"
[dev-dependencies]
anyhow = "1"
@ -24,19 +25,19 @@ image = "0.24.7"
kittycad = { workspace = true, default-features = true }
pretty_assertions = "1.4.0"
reqwest = { version = "0.11.22", default-features = false }
tokio = { version = "1.33.0", features = ["rt-multi-thread", "macros", "time"] }
tokio = { version = "1.34.0", features = ["rt-multi-thread", "macros", "time"] }
twenty-twenty = "0.6.1"
uuid = { version = "1.5.0", features = ["v4", "js", "serde"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
futures = "0.3.29"
js-sys = "0.3.64"
js-sys = "0.3.65"
tower-lsp = { version = "0.20.0", default-features = false, features = ["runtime-agnostic"] }
wasm-bindgen-futures = { version = "0.4.37", features = ["futures-core-03-stream"] }
wasm-streams = "0.4.0"
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
version = "0.3.57"
version = "0.3.65"
features = [
"console",
"HtmlTextAreaElement",
@ -52,6 +53,7 @@ debug = true
members = [
"derive-docs",
"kcl",
"kcl-macros",
]
[workspace.dependencies]

View File

@ -5,6 +5,7 @@ version = "0.1.4"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"
rust-version = "1.73"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -15,9 +16,9 @@ proc-macro = true
convert_case = "0.6.0"
proc-macro2 = "1"
quote = "1"
serde = { version = "1.0.190", features = ["derive"] }
serde = { version = "1.0.192", features = ["derive"] }
serde_tokenstream = "0.2"
syn = { version = "2.0.38", features = ["full"] }
syn = { version = "2.0.39", features = ["full"] }
[dev-dependencies]
expectorate = "1.1.0"

View File

@ -0,0 +1,22 @@
[package]
name = "kcl-macros"
description = "Macro for compiling KCL to its AST during Rust compile-time"
version = "0.1.0"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
proc-macro = true
[dependencies]
databake = "0.1.6"
kcl-lib = { path = "../kcl" }
proc-macro2 = "1"
quote = "1"
syn = { version = "2.0.39", features = ["full"] }
[dev-dependencies]
pretty_assertions = "1.4.0"

View File

@ -0,0 +1,22 @@
use databake::*;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, LitStr};
/// Parses KCL into its AST at compile-time.
/// This macro takes exactly one argument: A string literal containing KCL.
/// # Examples
/// ```
/// extern crate alloc;
/// use kcl_compile_macro::parse_kcl;
/// let ast: kcl_lib::ast::types::Program = parse_kcl!("const y = 4");
/// ```
#[proc_macro]
pub fn parse(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as LitStr);
let kcl_src = input.value();
let tokens = kcl_lib::token::lexer(&kcl_src);
let ast = kcl_lib::parser::Parser::new(tokens).ast().unwrap();
let ast_struct = ast.bake(&Default::default());
quote!(#ast_struct).into()
}

View File

@ -0,0 +1,38 @@
extern crate alloc;
use kcl_lib::ast::types::{
BodyItem, Identifier, Literal, LiteralValue, NonCodeMeta, Program, Value, VariableDeclaration, VariableDeclarator,
VariableKind,
};
use kcl_macros::parse;
use pretty_assertions::assert_eq;
#[test]
fn basic() {
let actual = parse!("const y = 4");
let expected = Program {
start: 0,
end: 11,
body: vec![BodyItem::VariableDeclaration(VariableDeclaration {
start: 0,
end: 11,
declarations: vec![VariableDeclarator {
start: 6,
end: 11,
id: Identifier {
start: 6,
end: 7,
name: "y".to_owned(),
},
init: Value::Literal(Box::new(Literal {
start: 10,
end: 11,
value: LiteralValue::IInteger(4),
raw: "4".to_owned(),
})),
}],
kind: VariableKind::Const,
})],
non_code_meta: NonCodeMeta::default(),
};
assert_eq!(expected, actual);
}

View File

@ -5,6 +5,7 @@ version = "0.1.35"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"
rust-version = "1.73"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -12,15 +13,16 @@ repository = "https://github.com/KittyCAD/modeling-app"
anyhow = { version = "1.0.75", features = ["backtrace"] }
async-recursion = "1.0.5"
async-trait = "0.1.73"
clap = { version = "4.4.7", features = ["cargo", "derive", "env", "unicode"], optional = true }
clap = { version = "4.4.8", features = ["cargo", "derive", "env", "unicode"], optional = true }
dashmap = "5.5.3"
databake = { version = "0.1.6", features = ["derive"] }
derive-docs = { version = "0.1.4" }
#derive-docs = { path = "../derive-docs" }
kittycad = { workspace = true }
lazy_static = "1.4.0"
parse-display = "0.8.2"
schemars = { version = "0.8", features = ["impl_json_schema", "url", "uuid1"] }
serde = { version = "1.0.190", features = ["derive"] }
serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.108"
thiserror = "1.0.50"
ts-rs = { version = "7", package = "ts-rs-json-value", features = ["serde-json-impl", "schemars-impl", "uuid-impl"] }
@ -28,17 +30,17 @@ uuid = { version = "1.5.0", features = ["v4", "js", "serde"] }
winnow = "0.5.18"
[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = { version = "0.3.64" }
js-sys = { version = "0.3.65" }
tower-lsp = { version = "0.20.0", default-features = false, features = ["runtime-agnostic"] }
wasm-bindgen = "0.2.87"
wasm-bindgen-futures = "0.4.37"
web-sys = { version = "0.3.64", features = ["console"] }
wasm-bindgen = "0.2.88"
wasm-bindgen-futures = "0.4.38"
web-sys = { version = "0.3.65", features = ["console"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
bson = { version = "2.7.0", features = ["uuid-1", "chrono"] }
futures = { version = "0.3.29" }
reqwest = { version = "0.11.22", default-features = false }
tokio = { version = "1.33.0", features = ["full"] }
tokio = { version = "1.34.0", features = ["full"] }
tokio-tungstenite = { version = "0.20.0", features = ["rustls-tls-native-roots"] }
tower-lsp = { version = "0.20.0", features = ["proposed"] }
@ -57,9 +59,10 @@ debug = true # Flamegraphs of benchmarks require accurate debug symbols
[dev-dependencies]
criterion = "0.5.1"
expectorate = "1.1.0"
insta = { version = "1.34.0", features = ["json"] }
itertools = "0.11.0"
pretty_assertions = "1.4.0"
tokio = { version = "1.33.0", features = ["rt-multi-thread", "macros", "time"] }
tokio = { version = "1.34.0", features = ["rt-multi-thread", "macros", "time"] }
[[bench]]
name = "compiler_benchmark"

View File

@ -4,6 +4,7 @@ version = "0.0.0"
publish = false
edition = "2021"
repository = "https://github.com/KittyCAD/modeling-app"
rust-version = "1.73"
[package.metadata]
cargo-fuzz = true

View File

@ -3,19 +3,26 @@
use std::{collections::HashMap, fmt::Write};
use anyhow::Result;
use databake::*;
use parse_display::{Display, FromStr};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Map;
use serde_json::{Map, Value as JValue};
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, DocumentSymbol, Range as LspRange, SymbolKind};
pub use self::literal_value::LiteralValue;
use crate::{
docs::StdLibFn,
errors::{KclError, KclErrorDetails},
executor::{ExecutorContext, MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange, UserVal},
executor::{BodyType, ExecutorContext, MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange, UserVal},
parser::PIPE_OPERATOR,
std::{kcl_stdlib::KclStdLibFn, FunctionKind},
};
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
mod literal_value;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct Program {
@ -344,7 +351,8 @@ macro_rules! impl_value_meta {
pub(crate) use impl_value_meta;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub enum BodyItem {
@ -383,7 +391,8 @@ impl From<&BodyItem> for SourceRange {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub enum Value {
@ -546,7 +555,8 @@ impl From<&Value> for SourceRange {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub enum BinaryPart {
@ -702,7 +712,8 @@ impl BinaryPart {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct NonCodeNode {
@ -750,7 +761,8 @@ impl NonCodeNode {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum CommentStyle {
@ -760,7 +772,8 @@ pub enum CommentStyle {
Block,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum NonCodeValue {
@ -780,7 +793,7 @@ pub enum NonCodeValue {
/// 1 + 1
/// ```
/// Now this is important. The block comment is attached to the next line.
/// This is always the case. Also the block comment doesnt have a new line above it.
/// This is always the case. Also the block comment doesn't have a new line above it.
/// If it did it would be a `NewLineBlockComment`.
BlockComment {
value: String,
@ -805,6 +818,19 @@ pub struct NonCodeMeta {
pub start: Vec<NonCodeNode>,
}
impl Bake for NonCodeMeta {
fn bake(&self, env: &CrateEnv) -> TokenStream {
env.insert("kcl_lib::ast::types");
let start = self.start.bake(env);
databake::quote! {
kcl_lib::ast::types::NonCodeMeta {
non_code_nodes: std::collections::HashMap::new(),
start: #start,
}
}
}
}
// implement Deserialize manually because we to force the keys of non_code_nodes to be usize
// and by default the ts type { [statementIndex: number]: NonCodeNode } serializes to a string i.e. "0", "1", etc.
impl<'de> Deserialize<'de> for NonCodeMeta {
@ -838,7 +864,8 @@ impl NonCodeMeta {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct ExpressionStatement {
@ -849,7 +876,8 @@ pub struct ExpressionStatement {
impl_value_meta!(ExpressionStatement);
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct CallExpression {
@ -858,7 +886,6 @@ pub struct CallExpression {
pub callee: Identifier,
pub arguments: Vec<Value>,
pub optional: bool,
pub function: Function,
}
impl_value_meta!(CallExpression);
@ -871,22 +898,12 @@ impl From<CallExpression> for Value {
impl CallExpression {
pub fn new(name: &str, arguments: Vec<Value>) -> Result<Self, KclError> {
// Create our stdlib.
let stdlib = crate::std::StdLib::new();
let func = stdlib.get(name).ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails {
message: format!("Function {} is not defined", name),
source_ranges: vec![],
})
})?;
Ok(Self {
start: 0,
end: 0,
callee: Identifier::new(name),
arguments,
optional: false,
function: Function::StdLib { func },
})
}
@ -968,8 +985,8 @@ impl CallExpression {
fn_args.push(result);
}
match &self.function {
Function::StdLib { func } => {
match ctx.stdlib.get_either(&self.callee.name) {
FunctionKind::Core(func) => {
// Attempt to call the function.
let args = crate::std::Args::new(fn_args, self.into(), ctx.clone());
let result = func.std_lib_fn()(args).await?;
@ -981,14 +998,54 @@ impl CallExpression {
Ok(result)
}
}
Function::InMemory => {
FunctionKind::Std(func) => {
let function_expression = func.function();
if fn_args.len() != function_expression.params.len() {
return Err(KclError::Semantic(KclErrorDetails {
message: format!(
"Expected {} arguments, got {}",
function_expression.params.len(),
fn_args.len(),
),
source_ranges: vec![(function_expression).into()],
}));
}
// Add the arguments to the memory.
let mut fn_memory = memory.clone();
for (index, param) in function_expression.params.iter().enumerate() {
fn_memory.add(&param.name, fn_args.get(index).unwrap().clone(), param.into())?;
}
// Call the stdlib function
let p = func.function().clone().body;
let results = crate::executor::execute(p, &mut fn_memory, BodyType::Block, ctx).await?;
let out = results.return_;
let result = out.ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails {
message: format!("Result of stdlib function {} is undefined", fn_name),
source_ranges: vec![self.into()],
})
})?;
let result = result.get_value()?;
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(), ctx).await
} else {
Ok(result)
}
}
FunctionKind::UserDefined => {
let func = memory.get(&fn_name, self.into())?;
let result = func
.call_fn(fn_args, memory.clone(), ctx.clone())
.await?
.ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails {
message: format!("Result of function {} is undefined", fn_name),
message: format!("Result of user-defined function {} is undefined", fn_name),
source_ranges: vec![self.into()],
})
})?;
@ -1063,10 +1120,15 @@ impl CallExpression {
#[ts(export)]
#[serde(tag = "type")]
pub enum Function {
/// A stdlib function.
/// A stdlib function written in Rust (aka core lib).
StdLib {
/// The function.
func: Box<dyn crate::docs::StdLibFn>,
func: Box<dyn StdLibFn>,
},
/// A stdlib function written in KCL.
StdLibKcl {
/// The function.
func: Box<dyn KclStdLibFn>,
},
/// A function that is defined in memory.
#[default]
@ -1083,7 +1145,8 @@ impl PartialEq for Function {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct VariableDeclaration {
@ -1233,7 +1296,8 @@ impl VariableDeclaration {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(rename_all = "snake_case")]
#[display(style = "snake_case")]
@ -1277,7 +1341,8 @@ impl VariableKind {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct VariableDeclarator {
@ -1306,30 +1371,25 @@ impl VariableDeclarator {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct Literal {
pub start: usize,
pub end: usize,
pub value: serde_json::Value,
pub value: LiteralValue,
pub raw: String,
}
impl_value_meta!(Literal);
impl From<Literal> for Value {
fn from(literal: Literal) -> Self {
Value::Literal(Box::new(literal))
}
}
impl Literal {
pub fn new(value: serde_json::Value) -> Self {
pub fn new(value: LiteralValue) -> Self {
Self {
start: 0,
end: 0,
raw: value.to_string(),
raw: JValue::from(value.clone()).to_string(),
value,
}
}
@ -1343,11 +1403,19 @@ impl Literal {
}
fn recast(&self) -> String {
if let serde_json::Value::String(value) = &self.value {
let quote = if self.raw.trim().starts_with('"') { '"' } else { '\'' };
format!("{}{}{}", quote, value, quote)
} else {
self.value.to_string()
match self.value {
LiteralValue::Fractional(x) => {
if x.fract() == 0.0 {
format!("{x:?}")
} else {
self.raw.clone()
}
}
LiteralValue::IInteger(_) => self.raw.clone(),
LiteralValue::String(ref s) => {
let quote = if self.raw.trim().starts_with('"') { '"' } else { '\'' };
format!("{quote}{s}{quote}")
}
}
}
}
@ -1355,7 +1423,7 @@ impl Literal {
impl From<Literal> for MemoryItem {
fn from(literal: Literal) -> Self {
MemoryItem::UserVal(UserVal {
value: literal.value.clone(),
value: JValue::from(literal.value.clone()),
meta: vec![Metadata {
source_range: literal.into(),
}],
@ -1366,7 +1434,7 @@ impl From<Literal> for MemoryItem {
impl From<&Box<Literal>> for MemoryItem {
fn from(literal: &Box<Literal>) -> Self {
MemoryItem::UserVal(UserVal {
value: literal.value.clone(),
value: JValue::from(literal.value.clone()),
meta: vec![Metadata {
source_range: literal.into(),
}],
@ -1374,7 +1442,8 @@ impl From<&Box<Literal>> for MemoryItem {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct Identifier {
@ -1410,7 +1479,8 @@ impl Identifier {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct PipeSubstitution {
@ -1438,7 +1508,8 @@ impl From<PipeSubstitution> for Value {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct ArrayExpression {
@ -1598,7 +1669,8 @@ impl ArrayExpression {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct ObjectExpression {
@ -1755,7 +1827,8 @@ impl ObjectExpression {
impl_value_meta!(ObjectExpression);
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct ObjectProperty {
@ -1797,7 +1870,8 @@ impl ObjectProperty {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub enum MemberObject {
@ -1843,7 +1917,8 @@ impl From<&MemberObject> for SourceRange {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub enum LiteralIdentifier {
@ -1879,7 +1954,8 @@ impl From<&LiteralIdentifier> for SourceRange {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct MemberExpression {
@ -1967,17 +2043,21 @@ impl MemberExpression {
LiteralIdentifier::Identifier(identifier) => identifier.name.to_string(),
LiteralIdentifier::Literal(literal) => {
let value = literal.value.clone();
// Parse this as a string.
if let serde_json::Value::String(string) = value {
string
} else if let serde_json::Value::Number(_) = &value {
// It can also be a number if we are getting a member of an array.
return self.get_result_array(memory, parse_json_number_as_usize(&value, self.into())?);
} else {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("Expected string literal or number for property name, found {:?}", value),
source_ranges: vec![literal.into()],
}));
match value {
LiteralValue::IInteger(x) if x >= 0 => return self.get_result_array(memory, x as usize),
LiteralValue::IInteger(x) => {
return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![self.into()],
message: format!("invalid index: {x}"),
}))
}
LiteralValue::Fractional(x) => {
return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![self.into()],
message: format!("invalid index: {x}"),
}))
}
LiteralValue::String(s) => s,
}
}
};
@ -2038,7 +2118,8 @@ pub struct ObjectKeyInfo {
pub computed: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct BinaryExpression {
@ -2209,22 +2290,6 @@ pub fn parse_json_number_as_f64(j: &serde_json::Value, source_range: SourceRange
}
}
pub fn parse_json_number_as_usize(j: &serde_json::Value, source_range: SourceRange) -> Result<usize, KclError> {
if let serde_json::Value::Number(n) = &j {
Ok(n.as_i64().ok_or_else(|| {
KclError::Syntax(KclErrorDetails {
source_ranges: vec![source_range],
message: format!("Invalid index: {}", j),
})
})? as usize)
} else {
Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![source_range],
message: format!("Invalid index: {}", j),
}))
}
}
pub fn parse_json_value_as_string(j: &serde_json::Value) -> Option<String> {
if let serde_json::Value::String(n) = &j {
Some(n.clone())
@ -2233,7 +2298,8 @@ pub fn parse_json_value_as_string(j: &serde_json::Value) -> Option<String> {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(rename_all = "snake_case")]
#[display(style = "snake_case")]
@ -2301,7 +2367,8 @@ impl BinaryOperator {
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct UnaryExpression {
@ -2379,7 +2446,8 @@ impl UnaryExpression {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(rename_all = "snake_case")]
#[display(style = "snake_case")]
@ -2394,7 +2462,8 @@ pub enum UnaryOperator {
Not,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(rename_all = "camelCase", tag = "type")]
pub struct PipeExpression {
@ -2552,7 +2621,8 @@ async fn execute_pipe_body(
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct FunctionExpression {
@ -2602,7 +2672,8 @@ impl FunctionExpression {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(tag = "type")]
pub struct ReturnStatement {
@ -3289,4 +3360,40 @@ const thickness = sqrt(distance * p * FOS * 6 / (sigmaAllow * width))"#;
let recasted = program.recast(&Default::default(), 0);
assert_eq!(recasted.trim(), some_program_string);
}
#[test]
fn recast_literal() {
use winnow::Parser;
for (i, (raw, expected, reason)) in [
(
"5.0",
"5.0",
"fractional numbers should stay fractional, i.e. don't reformat this to '5'",
),
(
"5",
"5",
"integers should stay integral, i.e. don't reformat this to '5.0'",
),
(
"5.0000000",
"5.0",
"if the number is f64 but not fractional, use its canonical format",
),
("5.1", "5.1", "straightforward case works"),
]
.into_iter()
.enumerate()
{
let tokens = crate::token::lexer(raw);
let literal = crate::parser::parser_impl::unsigned_number_literal
.parse(&tokens)
.unwrap();
assert_eq!(
literal.recast(),
expected,
"failed test {i}, which is testing that {reason}"
);
}
}
}

View File

@ -0,0 +1,72 @@
use databake::*;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Value as JValue;
use super::{Literal, Value};
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)]
#[serde(untagged, rename_all = "snake_case")]
pub enum LiteralValue {
IInteger(i64),
Fractional(f64),
String(String),
}
impl From<Literal> for Value {
fn from(literal: Literal) -> Self {
Value::Literal(Box::new(literal))
}
}
impl From<LiteralValue> for JValue {
fn from(value: LiteralValue) -> Self {
match value {
LiteralValue::IInteger(x) => x.into(),
LiteralValue::Fractional(x) => x.into(),
LiteralValue::String(x) => x.into(),
}
}
}
impl From<f64> for LiteralValue {
fn from(value: f64) -> Self {
Self::Fractional(value)
}
}
impl From<i64> for LiteralValue {
fn from(value: i64) -> Self {
Self::IInteger(value)
}
}
impl From<String> for LiteralValue {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<u32> for LiteralValue {
fn from(value: u32) -> Self {
Self::IInteger(value as i64)
}
}
impl From<u16> for LiteralValue {
fn from(value: u16) -> Self {
Self::IInteger(value as i64)
}
}
impl From<u8> for LiteralValue {
fn from(value: u8) -> Self {
Self::IInteger(value as i64)
}
}
impl From<&'static str> for LiteralValue {
fn from(value: &'static str) -> Self {
// TODO: Make this Cow<str>
Self::String(value.to_owned())
}
}

View File

@ -193,7 +193,7 @@ pub trait StdLibFn: std::fmt::Debug + Send + Sync {
}
fn to_signature_help(&self) -> SignatureHelp {
// Fill this in based on the current positon of the cursor.
// Fill this in based on the current position of the cursor.
let active_parameter = None;
SignatureHelp {

View File

@ -8,6 +8,8 @@ use crate::executor::SourceRange;
#[ts(export)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum KclError {
#[error("lexical: {0:?}")]
Lexical(KclErrorDetails),
#[error("syntax: {0:?}")]
Syntax(KclErrorDetails),
#[error("semantic: {0:?}")]
@ -26,6 +28,8 @@ pub enum KclError {
InvalidExpression(KclErrorDetails),
#[error("engine: {0:?}")]
Engine(KclErrorDetails),
#[error("internal error, please report to KittyCAD team: {0:?}")]
Internal(KclErrorDetails),
}
#[derive(Debug, Serialize, Deserialize, ts_rs::TS, Clone)]
@ -40,20 +44,8 @@ pub struct KclErrorDetails {
impl KclError {
/// Get the error message, line and column from the error and input code.
pub fn get_message_line_column(&self, input: &str) -> (String, Option<usize>, Option<usize>) {
let (type_, source_range, message) = match &self {
KclError::Syntax(e) => ("syntax", e.source_ranges.clone(), e.message.clone()),
KclError::Semantic(e) => ("semantic", e.source_ranges.clone(), e.message.clone()),
KclError::Type(e) => ("type", e.source_ranges.clone(), e.message.clone()),
KclError::Unimplemented(e) => ("unimplemented", e.source_ranges.clone(), e.message.clone()),
KclError::Unexpected(e) => ("unexpected", e.source_ranges.clone(), e.message.clone()),
KclError::ValueAlreadyDefined(e) => ("value already defined", e.source_ranges.clone(), e.message.clone()),
KclError::UndefinedValue(e) => ("undefined value", e.source_ranges.clone(), e.message.clone()),
KclError::InvalidExpression(e) => ("invalid expression", e.source_ranges.clone(), e.message.clone()),
KclError::Engine(e) => ("engine", e.source_ranges.clone(), e.message.clone()),
};
// Calculate the line and column of the error from the source range.
let (line, column) = if let Some(range) = source_range.first() {
let (line, column) = if let Some(range) = self.source_ranges().first() {
let line = input[..range.0[0]].lines().count();
let column = input[..range.0[0]].lines().last().map(|l| l.len()).unwrap_or_default();
@ -62,11 +54,28 @@ impl KclError {
(None, None)
};
(format!("{}: {}", type_, message), line, column)
(format!("{}: {}", self.error_type(), self.message()), line, column)
}
pub fn error_type(&self) -> &'static str {
match self {
KclError::Lexical(_) => "lexical",
KclError::Syntax(_) => "syntax",
KclError::Semantic(_) => "semantic",
KclError::Type(_) => "type",
KclError::Unimplemented(_) => "unimplemented",
KclError::Unexpected(_) => "unexpected",
KclError::ValueAlreadyDefined(_) => "value already defined",
KclError::UndefinedValue(_) => "undefined value",
KclError::InvalidExpression(_) => "invalid expression",
KclError::Engine(_) => "engine",
KclError::Internal(_) => "internal",
}
}
pub fn source_ranges(&self) -> Vec<SourceRange> {
match &self {
KclError::Lexical(e) => e.source_ranges.clone(),
KclError::Syntax(e) => e.source_ranges.clone(),
KclError::Semantic(e) => e.source_ranges.clone(),
KclError::Type(e) => e.source_ranges.clone(),
@ -76,12 +85,14 @@ impl KclError {
KclError::UndefinedValue(e) => e.source_ranges.clone(),
KclError::InvalidExpression(e) => e.source_ranges.clone(),
KclError::Engine(e) => e.source_ranges.clone(),
KclError::Internal(e) => e.source_ranges.clone(),
}
}
/// Get the inner error message.
pub fn message(&self) -> &str {
match &self {
KclError::Lexical(e) => &e.message,
KclError::Syntax(e) => &e.message,
KclError::Semantic(e) => &e.message,
KclError::Type(e) => &e.message,
@ -91,6 +102,7 @@ impl KclError {
KclError::UndefinedValue(e) => &e.message,
KclError::InvalidExpression(e) => &e.message,
KclError::Engine(e) => &e.message,
KclError::Internal(e) => &e.message,
}
}

View File

@ -1,8 +1,9 @@
//! The executor for the AST.
use std::collections::HashMap;
use std::{collections::HashMap, sync::Arc};
use anyhow::Result;
use async_recursion::async_recursion;
use kittycad::types::{Color, ModelingCmd, Point3D};
use parse_display::{Display, FromStr};
use schemars::JsonSchema;
@ -10,9 +11,10 @@ use serde::{Deserialize, Serialize};
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
use crate::{
ast::types::{BodyItem, Function, FunctionExpression, Value},
ast::types::{BodyItem, FunctionExpression, Value},
engine::{EngineConnection, EngineManager},
errors::{KclError, KclErrorDetails},
std::{FunctionKind, StdLib},
};
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
@ -347,27 +349,27 @@ impl MemoryItem {
}
}
/// If this memory item is a function, call it with the given arguments, return its val as Ok.
/// If it's not a function, return Err.
pub async fn call_fn(
&self,
args: Vec<MemoryItem>,
memory: ProgramMemory,
ctx: ExecutorContext,
) -> Result<Option<ProgramReturn>, KclError> {
if let MemoryItem::Function { func, expression, meta } = &self {
if let Some(func) = func {
func(args, memory, expression.clone(), meta.clone(), ctx).await
} else {
Err(KclError::Semantic(KclErrorDetails {
message: format!("Not a function: {:?}", expression),
source_ranges: vec![],
}))
}
} else {
Err(KclError::Semantic(KclErrorDetails {
let MemoryItem::Function { func, expression, meta } = &self else {
return Err(KclError::Semantic(KclErrorDetails {
message: "not a in memory function".to_string(),
source_ranges: vec![],
}))
}
}));
};
let Some(func) = func else {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("Not a function: {:?}", expression),
source_ranges: vec![],
}));
};
func(args, memory, expression.clone(), meta.clone(), ctx).await
}
}
@ -776,9 +778,11 @@ impl Default for PipeInfo {
pub struct ExecutorContext {
pub engine: EngineConnection,
pub planes: DefaultPlanes,
pub stdlib: Arc<StdLib>,
}
/// Execute a AST's program.
#[async_recursion(?Send)]
pub async fn execute(
program: crate::ast::types::Program,
memory: &mut ProgramMemory,
@ -791,7 +795,9 @@ pub async fn execute(
for statement in &program.body {
match statement {
BodyItem::ExpressionStatement(expression_statement) => {
if let Value::CallExpression(call_expr) = &expression_statement.expression {
if let Value::PipeExpression(pipe_expr) = &expression_statement.expression {
pipe_expr.get_result(memory, &mut pipe_info, ctx).await?;
} else if let Value::CallExpression(call_expr) = &expression_statement.expression {
let fn_name = call_expr.callee.name.to_string();
let mut args: Vec<MemoryItem> = Vec::new();
for arg in &call_expr.arguments {
@ -826,24 +832,37 @@ pub async fn execute(
}
}
let _show_fn = Box::new(crate::std::Show);
if let Function::StdLib { func: _show_fn } = &call_expr.function {
if options != BodyType::Root {
return Err(KclError::Semantic(KclErrorDetails {
message: "Cannot call show outside of a root".to_string(),
source_ranges: vec![call_expr.into()],
}));
match ctx.stdlib.get_either(&call_expr.callee.name) {
FunctionKind::Core(func) => {
use crate::docs::StdLibFn;
if func.name() == _show_fn.name() {
if options != BodyType::Root {
return Err(KclError::Semantic(KclErrorDetails {
message: "Cannot call show outside of a root".to_string(),
source_ranges: vec![call_expr.into()],
}));
}
memory.return_ = Some(ProgramReturn::Arguments(call_expr.arguments.clone()));
}
}
FunctionKind::Std(func) => {
let mut newmem = memory.clone();
let result = execute(func.program().to_owned(), &mut newmem, BodyType::Block, ctx).await?;
memory.return_ = result.return_;
}
FunctionKind::UserDefined => {
if let Some(func) = memory.clone().root.get(&fn_name) {
let result = func.call_fn(args.clone(), memory.clone(), ctx.clone()).await?;
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.clone(), memory.clone(), ctx.clone()).await?;
memory.return_ = result;
} else {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("No such name {} defined", fn_name),
source_ranges: vec![call_expr.into()],
}));
memory.return_ = result;
} else {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("No such name {} defined", fn_name),
source_ranges: vec![call_expr.into()],
}));
}
}
}
}
}
@ -1011,7 +1030,11 @@ mod tests {
let mut mem: ProgramMemory = Default::default();
let engine = EngineConnection::new().await?;
let planes = DefaultPlanes::new(&engine).await?;
let ctx = ExecutorContext { engine, planes };
let ctx = ExecutorContext {
engine,
planes,
stdlib: Arc::new(StdLib::default()),
};
let memory = execute(program, &mut mem, BodyType::Root, &ctx).await?;
Ok(memory)

View File

@ -1,22 +1,50 @@
use crate::{ast::types::Program, errors::KclError, token::Token};
use crate::{
ast::types::Program,
errors::KclError,
errors::KclErrorDetails,
executor::SourceRange,
token::{Token, TokenType},
};
mod math;
mod parser_impl;
pub(crate) mod parser_impl;
pub const PIPE_SUBSTITUTION_OPERATOR: &str = "%";
pub const PIPE_OPERATOR: &str = "|>";
pub struct Parser {
pub tokens: Vec<Token>,
pub unknown_tokens: Vec<Token>,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Self { tokens }
let (tokens, unknown_tokens): (Vec<Token>, Vec<Token>) = tokens
.into_iter()
.partition(|token| token.token_type != TokenType::Unknown);
Self { tokens, unknown_tokens }
}
/// Run the parser
pub fn ast(&self) -> Result<Program, KclError> {
if self.tokens.is_empty() {
return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![],
message: "file is empty".to_string(),
}));
}
if !self.unknown_tokens.is_empty() {
let source_ranges = self.unknown_tokens.iter().map(SourceRange::from).collect();
let token_list = self.unknown_tokens.iter().map(|t| t.value.as_str()).collect::<Vec<_>>();
let message = if token_list.len() == 1 {
format!("found unknown token '{}'", token_list[0])
} else {
format!("found unknown tokens [{}]", token_list.join(", "))
};
return Err(KclError::Lexical(KclErrorDetails { source_ranges, message }));
}
parser_impl::run_parser(&mut self.tokens.as_slice())
}
}

View File

@ -1,20 +1,33 @@
use crate::ast::types::{BinaryExpression, BinaryOperator, BinaryPart};
use crate::{
ast::types::{BinaryExpression, BinaryOperator, BinaryPart},
errors::{KclError, KclErrorDetails},
executor::SourceRange,
};
/// Parses a list of tokens (in infix order, i.e. as the user typed them)
/// into a binary expression tree.
pub fn parse(infix_tokens: Vec<BinaryExpressionToken>) -> BinaryExpression {
pub fn parse(infix_tokens: Vec<BinaryExpressionToken>) -> Result<BinaryExpression, KclError> {
let rpn = postfix(infix_tokens);
evaluate(rpn)
}
/// Parses a list of tokens (in postfix order) into a binary expression tree.
fn evaluate(rpn: Vec<BinaryExpressionToken>) -> BinaryExpression {
let mut operand_stack = Vec::new();
fn evaluate(rpn: Vec<BinaryExpressionToken>) -> Result<BinaryExpression, KclError> {
let source_ranges = source_range(&rpn);
let mut operand_stack: Vec<BinaryPart> = Vec::new();
let e = KclError::Internal(KclErrorDetails {
source_ranges,
message: "error parsing binary math expressions".to_owned(),
});
for item in rpn {
let expr = match item {
BinaryExpressionToken::Operator(operator) => {
let right: BinaryPart = operand_stack.pop().unwrap();
let left = operand_stack.pop().unwrap();
let Some(right) = operand_stack.pop() else {
return Err(e);
};
let Some(left) = operand_stack.pop() else {
return Err(e);
};
BinaryPart::BinaryExpression(Box::new(BinaryExpression {
start: left.start(),
end: right.end(),
@ -27,10 +40,26 @@ fn evaluate(rpn: Vec<BinaryExpressionToken>) -> BinaryExpression {
};
operand_stack.push(expr)
}
if let BinaryPart::BinaryExpression(expr) = operand_stack.pop().unwrap() {
*expr
if let Some(BinaryPart::BinaryExpression(expr)) = operand_stack.pop() {
Ok(*expr)
} else {
panic!("Last expression was not a binary expression")
// If this branch is used, the evaluation algorithm has a bug and must be fixed.
// This is a programmer error, not a user error.
Err(e)
}
}
fn source_range(tokens: &[BinaryExpressionToken]) -> Vec<SourceRange> {
let sources: Vec<_> = tokens
.iter()
.filter_map(|op| match op {
BinaryExpressionToken::Operator(_) => None,
BinaryExpressionToken::Operand(o) => Some((o.start(), o.end())),
})
.collect();
match (sources.first(), sources.last()) {
(Some((start, _)), Some((_, end))) => vec![SourceRange([*start, *end])],
_ => Vec::new(),
}
}
@ -46,15 +75,16 @@ fn postfix(infix: Vec<BinaryExpressionToken>) -> Vec<BinaryExpressionToken> {
// there is an operator o2 at the top of the operator stack which is not a left parenthesis,
// and (o2 has greater precedence than o1 or (o1 and o2 have the same precedence and o1 is left-associative))
// )
while operator_stack
.last()
.map(|o2| {
(o2.precedence() > o1.precedence())
|| o1.precedence() == o2.precedence() && o1.associativity().is_left()
})
.unwrap_or(false)
{
output.push(BinaryExpressionToken::Operator(operator_stack.pop().unwrap()));
// pop o2 from the operator stack into the output queue
while let Some(o2) = operator_stack.pop() {
if (o2.precedence() > o1.precedence())
|| o1.precedence() == o2.precedence() && o1.associativity().is_left()
{
output.push(BinaryExpressionToken::Operator(o2));
} else {
operator_stack.push(o2);
break;
}
}
operator_stack.push(o1);
}
@ -127,8 +157,7 @@ mod tests {
];
for infix_input in tests {
let rpn = postfix(infix_input);
let tree = evaluate(rpn);
dbg!(tree);
let _tree = evaluate(rpn).unwrap();
}
}
}

View File

@ -1,47 +1,33 @@
use serde_json::{Number as JNumber, Value as JValue};
use winnow::{
combinator::{alt, delimited, opt, peek, preceded, repeat, separated0, terminated},
combinator::{alt, delimited, opt, peek, preceded, repeat, separated, terminated},
dispatch,
error::{ErrMode, StrContext, StrContextValue},
prelude::*,
token::{any, one_of},
};
use super::{math::BinaryExpressionToken, PIPE_OPERATOR, PIPE_SUBSTITUTION_OPERATOR};
use crate::{
ast::types::{
ArrayExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression, CommentStyle,
ExpressionStatement, FunctionExpression, Identifier, Literal, LiteralIdentifier, MemberExpression,
MemberObject, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty, PipeExpression,
PipeSubstitution, Program, ReturnStatement, UnaryExpression, UnaryOperator, Value, VariableDeclaration,
VariableDeclarator, VariableKind,
ExpressionStatement, FunctionExpression, Identifier, Literal, LiteralIdentifier, LiteralValue,
MemberExpression, MemberObject, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty,
PipeExpression, PipeSubstitution, Program, ReturnStatement, UnaryExpression, UnaryOperator, Value,
VariableDeclaration, VariableDeclarator, VariableKind,
},
errors::{KclError, KclErrorDetails},
executor::SourceRange,
parser::parser_impl::error::ContextError,
std::StdLib,
token::{Token, TokenType},
};
use super::{math::BinaryExpressionToken, PIPE_OPERATOR, PIPE_SUBSTITUTION_OPERATOR};
mod error;
type PResult<O, E = error::ContextError> = winnow::prelude::PResult<O, E>;
lazy_static::lazy_static! {
static ref STDLIB: StdLib = StdLib::new();
}
type TokenSlice<'slice, 'input> = &'slice mut &'input [Token];
pub fn run_parser(i: TokenSlice) -> Result<Program, KclError> {
if i.is_empty() {
return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![],
message: "file is empty".to_string(),
}));
}
program.parse(i).map_err(KclError::from)
}
@ -216,7 +202,7 @@ pub fn string_literal(i: TokenSlice) -> PResult<Literal> {
.try_map(|token: Token| match token.token_type {
TokenType::String => {
let s = token.value[1..token.value.len() - 1].to_string();
Ok((JValue::String(s), token))
Ok((LiteralValue::from(s), token))
}
_ => Err(KclError::Syntax(KclErrorDetails {
source_ranges: token.as_source_ranges(),
@ -234,12 +220,12 @@ pub fn string_literal(i: TokenSlice) -> PResult<Literal> {
}
/// Parse a KCL literal number, with no - sign.
fn unsigned_number_literal(i: TokenSlice) -> PResult<Literal> {
pub(crate) fn unsigned_number_literal(i: TokenSlice) -> PResult<Literal> {
let (value, token) = any
.try_map(|token: Token| match token.token_type {
TokenType::Number => {
if let Ok(x) = token.value.parse::<i64>() {
return Ok((JValue::Number(JNumber::from(x)), token));
if let Ok(x) = token.value.parse::<u64>() {
return Ok((LiteralValue::IInteger(x as i64), token));
}
let x: f64 = token.value.parse().map_err(|_| {
KclError::Syntax(KclErrorDetails {
@ -248,13 +234,7 @@ fn unsigned_number_literal(i: TokenSlice) -> PResult<Literal> {
})
})?;
match JNumber::from_f64(x) {
Some(n) => Ok((JValue::Number(n), token)),
None => Err(KclError::Syntax(KclErrorDetails {
source_ranges: token.as_source_ranges(),
message: format!("Invalid float: {}", token.value),
})),
}
Ok((LiteralValue::Fractional(x), token))
}
_ => Err(KclError::Syntax(KclErrorDetails {
source_ranges: token.as_source_ranges(),
@ -387,7 +367,7 @@ fn equals(i: TokenSlice) -> PResult<Token> {
fn array(i: TokenSlice) -> PResult<ArrayExpression> {
let start = open_bracket(i)?.start;
ignore_whitespace(i);
let elements = alt((integer_range, separated0(value, comma_sep)))
let elements = alt((integer_range, separated(0.., value, comma_sep)))
.context(expected(
"array contents, either a numeric range (like 0..10) or a list of elements (like [1, 2, 3])",
))
@ -404,10 +384,11 @@ fn integer_range(i: TokenSlice) -> PResult<Vec<Value>> {
let (_token1, ceiling) = integer.parse_next(i)?;
Ok((floor..=ceiling)
.map(|num| {
let num = num as i64;
Value::Literal(Box::new(Literal {
start: token0.start,
end: token0.end,
value: JValue::Number(num.into()),
value: num.into(),
raw: num.to_string(),
}))
})
@ -443,7 +424,7 @@ fn object_property(i: TokenSlice) -> PResult<ObjectProperty> {
fn object(i: TokenSlice) -> PResult<ObjectExpression> {
let start = open_brace(i)?.start;
ignore_whitespace(i);
let properties = separated0(object_property, comma_sep)
let properties = separated(0.., object_property, comma_sep)
.context(expected(
"a comma-separated list of key-value pairs, e.g. 'height: 4, width: 3'",
))
@ -1052,7 +1033,8 @@ fn binary_expression(i: TokenSlice) -> PResult<BinaryExpression> {
// Pass the token slice into the specialized math parser, for things like
// precedence and converting infix operations to an AST.
Ok(super::math::parse(tokens))
let expr = super::math::parse(tokens).map_err(|e| ErrMode::Backtrack(e.into()))?;
Ok(expr)
}
fn binary_expr_in_parens(i: TokenSlice) -> PResult<BinaryExpression> {
@ -1221,7 +1203,7 @@ fn comma_sep(i: TokenSlice) -> PResult<()> {
/// Arguments are passed into a function.
fn arguments(i: TokenSlice) -> PResult<Vec<Value>> {
separated0(value, comma_sep)
separated(0.., value, comma_sep)
.context(expected("function arguments"))
.parse_next(i)
}
@ -1234,7 +1216,7 @@ fn not_close_paren(i: TokenSlice) -> PResult<Token> {
/// Parameters are declared in a function signature, and used within a function.
fn parameters(i: TokenSlice) -> PResult<Vec<Identifier>> {
// Get all tokens until the next ), because that ends the parameter list.
let candidates: Vec<Token> = separated0(not_close_paren, comma_sep)
let candidates: Vec<Token> = separated(0.., not_close_paren, comma_sep)
.context(expected("function parameters"))
.parse_next(i)?;
// Make sure all those tokens are valid parameters.
@ -1249,7 +1231,7 @@ fn parameters(i: TokenSlice) -> PResult<Vec<Identifier>> {
impl Identifier {
fn into_valid_binding_name(self) -> Result<Identifier, KclError> {
// Make sure they are not assigning a variable to a stdlib function.
if STDLIB.fns.contains_key(&self.name) {
if crate::std::name_in_stdlib(&self.name) {
return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![SourceRange([self.start, self.end])],
message: format!("Cannot assign a variable to a reserved keyword: {}", self.name),
@ -1273,18 +1255,12 @@ fn fn_call(i: TokenSlice) -> PResult<CallExpression> {
let _ = terminated(open_paren, opt(whitespace)).parse_next(i)?;
let args = arguments(i)?;
let end = preceded(opt(whitespace), close_paren).parse_next(i)?.end;
let function = if let Some(stdlib_fn) = STDLIB.get(&fn_name.name) {
crate::ast::types::Function::StdLib { func: stdlib_fn }
} else {
crate::ast::types::Function::InMemory
};
Ok(CallExpression {
start: fn_name.start,
end,
callee: fn_name,
arguments: args,
optional: false,
function,
})
}
@ -1412,7 +1388,7 @@ const mySk1 = startSketchAt([0, 0])"#;
let Value::PipeExpression(pipe) = val else {
panic!("expected pipe");
};
let mut noncode = dbg!(pipe.non_code_meta);
let mut noncode = pipe.non_code_meta;
assert_eq!(noncode.non_code_nodes.len(), 1);
let comment = noncode.non_code_nodes.remove(&0).unwrap().pop().unwrap();
assert_eq!(
@ -1459,7 +1435,7 @@ const mySk1 = startSketchAt([0, 0])"#;
argument: Value::Literal(Box::new(Literal {
start: 32,
end: 33,
value: JValue::Number(JNumber::from(2)),
value: 2u32.into(),
raw: "2".to_owned(),
})),
})],
@ -1614,7 +1590,7 @@ const mySk1 = startSketchAt([0, 0])"#;
BinaryPart::Literal(Box::new(Literal {
start: 9,
end: 10,
value: JValue::Number(JNumber::from(3)),
value: 3u32.into(),
raw: "3".to_owned(),
}))
);
@ -1675,95 +1651,6 @@ const mySk1 = startSketchAt([0, 0])"#;
assert_eq!(inner.operator, BinaryOperator::Sub);
}
#[test]
fn check_parsers_work_the_same() {
for (i, test_program) in [
r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %)
|> tangentialArc([-5, 5], %)
|> line([5, -15], %)
|> extrude(10, %)
"#,
"const myVar = min(5 , -legLen(5, 4))", // Space before comma
"const myVar = min(-legLen(5, 4), 5)",
"const myVar = 5 + 6 |> myFunc(45, %)",
"let x = 1 * (3 - 4)",
r#"const x = 1 // this is an inline comment"#,
r#"fn x = () => {
return sg
return sg
}"#,
r#"const x = -leg2 + thickness"#,
r#"const obj = { a: 1, b: 2 }
const height = 1 - obj.a"#,
r#"const obj = { a: 1, b: 2 }
const height = 1 - obj["a"]"#,
r#"const obj = { a: 1, b: 2 }
const height = obj["a"] - 1"#,
r#"const obj = { a: 1, b: 2 }
const height = [1 - obj["a"], 0]"#,
r#"const obj = { a: 1, b: 2 }
const height = [obj["a"] - 1, 0]"#,
r#"const obj = { a: 1, b: 2 }
const height = [obj["a"] -1, 0]"#,
"const height = 1 - obj.a",
"const six = 1 + 2 + 3",
"const five = 3 * 1 + 2",
r#"const height = [ obj["a"], 0 ]"#,
r#"const obj = { a: 1, b: 2 }
const height = obj["a"]"#,
r#"const prop = yo["one"][two]"#,
r#"const pt1 = b1[x]"#,
"const prop = yo.one.two.three.four",
r#"const pt1 = b1[0]"#,
r#"const pt1 = b1['zero']"#,
r#"const pt1 = b1.zero"#,
"const sg = startSketchAt(pos)",
"const sg = startSketchAt(pos) |> line([0, -scale], %)",
r#"const sg = -scale"#,
"lineTo({ to: [0, -1] })",
"const myArray = [0..10]",
r#"
fn firstPrimeNumber = () => {
return 2
}
firstPrimeNumber()"#,
r#"fn thing = (param) => {
return true
}
thing(false)"#,
r#"const mySketch = startSketchAt([0,0])
|> lineTo({ to: [0, 1], tag: 'myPath' }, %)
|> lineTo([1, 1], %)
|> lineTo({ to: [1,0], tag: "rightPath" }, %)
|> close(%)"#,
"const mySketch = startSketchAt([0,0]) |> lineTo([1, 1], %) |> close(%)",
"const myBox = startSketchAt(p)",
r#"const myBox = f(1) |> g(2)"#,
r#"const myBox = startSketchAt(p) |> line([0, l], %)"#,
"lineTo({ to: [0, 1] })",
"lineTo({ to: [0, 1], from: [3, 3] })",
"lineTo({to:[0, 1]})",
"lineTo({ to: [0, 1], from: [3, 3]})",
"lineTo({ to: [0, 1],from: [3, 3] })",
"const mySketch = startSketchAt([0,0])",
"log(5, \"hello\", aIdentifier)",
r#"5 + "a""#,
"line([0, l], %)",
]
.into_iter()
.enumerate()
{
// Run the original parser
let tokens = crate::token::lexer(test_program);
// TODO: get snapshots of what this outputs.
let _actual = match program.parse(&tokens) {
Ok(x) => x,
Err(_e) => panic!("could not parse test {i}"),
};
}
}
#[test]
fn binary_expression_ignores_whitespace() {
let tests = ["1 - 2", "1- 2", "1 -2", "1-2"];
@ -1774,11 +1661,11 @@ const mySk1 = startSketchAt([0, 0])"#;
let BinaryPart::Literal(left) = actual.left else {
panic!("should be expression");
};
assert_eq!(left.value, serde_json::Value::Number(1.into()));
assert_eq!(left.value, 1u32.into());
let BinaryPart::Literal(right) = actual.right else {
panic!("should be expression");
};
assert_eq!(right.value, serde_json::Value::Number(2.into()));
assert_eq!(right.value, 2u32.into());
}
}
@ -1957,12 +1844,10 @@ const mySk1 = startSketchAt([0, 0])"#;
let parsed_literal = literal.parse(&tokens).unwrap();
assert_eq!(
parsed_literal.value,
JValue::String(
"
"
// a comment
"
.to_owned()
)
.into()
);
}
@ -2067,13 +1952,13 @@ const mySk1 = startSketchAt([0, 0])"#;
left: BinaryPart::Literal(Box::new(Literal {
start: 0,
end: 1,
value: serde_json::Value::Number(serde_json::Number::from(5)),
value: 5u32.into(),
raw: "5".to_owned(),
})),
right: BinaryPart::Literal(Box::new(Literal {
start: 4,
end: 7,
value: serde_json::Value::String("a".to_owned()),
value: "a".into(),
raw: r#""a""#.to_owned(),
})),
};
@ -2180,14 +2065,14 @@ const mySk1 = startSketchAt([0, 0])"#;
left: BinaryPart::Literal(Box::new(Literal {
start: 0,
end: 1,
value: serde_json::Value::Number(serde_json::Number::from(5)),
value: 5u32.into(),
raw: "5".to_string(),
})),
operator: BinaryOperator::Add,
right: BinaryPart::Literal(Box::new(Literal {
start: 3,
end: 4,
value: serde_json::Value::Number(serde_json::Number::from(6)),
value: 6u32.into(),
raw: "6".to_string(),
})),
})),
@ -2318,9 +2203,10 @@ const secondExtrude = startSketchOn('XY')
let tokens = crate::token::lexer(">!");
let parser = crate::parser::Parser::new(tokens);
let err = parser.ast().unwrap_err();
// TODO: Better errors when program cannot tokenize.
// https://github.com/KittyCAD/modeling-app/issues/696
assert!(err.to_string().contains("file is empty"));
assert_eq!(
err.to_string(),
r#"lexical: KclErrorDetails { source_ranges: [SourceRange([1, 2])], message: "found unknown token '!'" }"#
);
}
#[test]
@ -2376,11 +2262,9 @@ z(-[["#,
let parser = crate::parser::Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
// TODO: Better errors when program cannot tokenize.
// https://github.com/KittyCAD/modeling-app/issues/696
assert_eq!(
result.err().unwrap().to_string(),
r#"syntax: KclErrorDetails { source_ranges: [], message: "file is empty" }"#
r#"lexical: KclErrorDetails { source_ranges: [SourceRange([6, 7])], message: "found unknown token '#'" }"#
);
}
@ -2390,11 +2274,9 @@ z(-[["#,
let parser = crate::parser::Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
// TODO: Better errors when program cannot tokenize.
// https://github.com/KittyCAD/modeling-app/issues/696
assert_eq!(
result.err().unwrap().to_string(),
r#"syntax: KclErrorDetails { source_ranges: [], message: "file is empty" }"#
r#"lexical: KclErrorDetails { source_ranges: [SourceRange([25, 26]), SourceRange([26, 27])], message: "found unknown tokens [#, #]" }"#
);
}
@ -2466,67 +2348,67 @@ e
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 0.into(),
value: 0u32.into(),
raw: "0".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 1.into(),
value: 1u32.into(),
raw: "1".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 2.into(),
value: 2u32.into(),
raw: "2".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 3.into(),
value: 3u32.into(),
raw: "3".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 4.into(),
value: 4u32.into(),
raw: "4".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 5.into(),
value: 5u32.into(),
raw: "5".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 6.into(),
value: 6u32.into(),
raw: "6".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 7.into(),
value: 7u32.into(),
raw: "7".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 8.into(),
value: 8u32.into(),
raw: "8".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 9.into(),
value: 9u32.into(),
raw: "9".to_string(),
})),
Value::Literal(Box::new(Literal {
start: 17,
end: 18,
value: 10.into(),
value: 10u32.into(),
raw: "10".to_string(),
})),
],
@ -2680,6 +2562,22 @@ thing(false)
);
}
#[test]
fn random_words_fail() {
let test_program = r#"const part001 = startSketchOn('-XZ')
|> startProfileAt([8.53, 11.8], %)
asdasd asdasd
|> line([11.12, -14.82], %)
|> line([-13.27, -6.98], %)
|> line([-5.09, 12.33], %)
asdasd
"#;
let tokens = crate::token::lexer(test_program);
let parser = crate::parser::Parser::new(tokens);
let result = parser.ast();
let _e = result.unwrap_err();
}
#[test]
fn test_member_expression_sketch_group() {
let some_program_string = r#"fn cube = (pos, scale) => {
@ -2733,24 +2631,174 @@ show(myBox)"#;
let parser = crate::parser::Parser::new(tokens);
parser.ast().unwrap();
}
#[test]
fn test_math() {
for math_expression in [
"1 + 2",
"1+2",
"1 -2",
"1 + 2 * 3",
"1 * ( 2 + 3 )",
"1 * ( 2 + 3 ) / 4",
"1 + ( 2 + 3 ) / 4",
"1 * (( 2 + 3 ) / 4 + 5 )",
"1 * ((( 2 + 3 )))",
"distance * p * FOS * 6 / (sigmaAllow * width)",
"2 + (((3)))",
] {
let tokens = crate::token::lexer(math_expression);
let _expr = binary_expression.parse(&tokens).unwrap();
}
}
}
#[cfg(test)]
mod snapshot_math_tests {
use super::*;
// This macro generates a test function with the given function name.
// The macro takes a KCL program, ensures it tokenizes and parses, then compares
// its parsed AST to a snapshot (kept in this repo in a file under snapshots/ dir)
macro_rules! snapshot_test {
($func_name:ident, $test_kcl_program:expr) => {
#[test]
fn $func_name() {
let tokens = crate::token::lexer($test_kcl_program);
let actual = match binary_expression.parse(&tokens) {
Ok(x) => x,
Err(_e) => panic!("could not parse test"),
};
insta::assert_json_snapshot!(actual);
}
};
}
snapshot_test!(a, "1 + 2");
snapshot_test!(b, "1+2");
snapshot_test!(c, "1 -2");
snapshot_test!(d, "1 + 2 * 3");
snapshot_test!(e, "1 * ( 2 + 3 )");
snapshot_test!(f, "1 * ( 2 + 3 ) / 4");
snapshot_test!(g, "1 + ( 2 + 3 ) / 4");
snapshot_test!(h, "1 * (( 2 + 3 ) / 4 + 5 )");
snapshot_test!(i, "1 * ((( 2 + 3 )))");
snapshot_test!(j, "distance * p * FOS * 6 / (sigmaAllow * width)");
snapshot_test!(k, "2 + (((3)))");
}
#[cfg(test)]
mod snapshot_tests {
use super::*;
// This macro generates a test function with the given function name.
// The macro takes a KCL program, ensures it tokenizes and parses, then compares
// its parsed AST to a snapshot (kept in this repo in a file under snapshots/ dir)
macro_rules! snapshot_test {
($func_name:ident, $test_kcl_program:expr) => {
#[test]
fn $func_name() {
let tokens = crate::token::lexer($test_kcl_program);
let actual = match program.parse(&tokens) {
Ok(x) => x,
Err(_e) => panic!("could not parse test"),
};
insta::assert_json_snapshot!(actual);
}
};
}
snapshot_test!(
a,
r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %)
|> tangentialArc([-5, 5], %)
|> line([5, -15], %)
|> extrude(10, %)
"#
);
snapshot_test!(b, "const myVar = min(5 , -legLen(5, 4))"); // Space before comma
snapshot_test!(c, "const myVar = min(-legLen(5, 4), 5)");
snapshot_test!(d, "const myVar = 5 + 6 |> myFunc(45, %)");
snapshot_test!(e, "let x = 1 * (3 - 4)");
snapshot_test!(f, r#"const x = 1 // this is an inline comment"#);
snapshot_test!(
g,
r#"fn x = () => {
return sg
return sg
}"#
);
snapshot_test!(d2, r#"const x = -leg2 + thickness"#);
snapshot_test!(
h,
r#"const obj = { a: 1, b: 2 }
const height = 1 - obj.a"#
);
snapshot_test!(
i,
r#"const obj = { a: 1, b: 2 }
const height = 1 - obj["a"]"#
);
snapshot_test!(
j,
r#"const obj = { a: 1, b: 2 }
const height = obj["a"] - 1"#
);
snapshot_test!(
k,
r#"const obj = { a: 1, b: 2 }
const height = [1 - obj["a"], 0]"#
);
snapshot_test!(
l,
r#"const obj = { a: 1, b: 2 }
const height = [obj["a"] - 1, 0]"#
);
snapshot_test!(
m,
r#"const obj = { a: 1, b: 2 }
const height = [obj["a"] -1, 0]"#
);
snapshot_test!(n, "const height = 1 - obj.a");
snapshot_test!(o, "const six = 1 + 2 + 3");
snapshot_test!(p, "const five = 3 * 1 + 2");
snapshot_test!(q, r#"const height = [ obj["a"], 0 ]"#);
snapshot_test!(
r,
r#"const obj = { a: 1, b: 2 }
const height = obj["a"]"#
);
snapshot_test!(s, r#"const prop = yo["one"][two]"#);
snapshot_test!(t, r#"const pt1 = b1[x]"#);
snapshot_test!(u, "const prop = yo.one.two.three.four");
snapshot_test!(v, r#"const pt1 = b1[0]"#);
snapshot_test!(w, r#"const pt1 = b1['zero']"#);
snapshot_test!(x, r#"const pt1 = b1.zero"#);
snapshot_test!(y, "const sg = startSketchAt(pos)");
snapshot_test!(z, "const sg = startSketchAt(pos) |> line([0, -scale], %)");
snapshot_test!(aa, r#"const sg = -scale"#);
snapshot_test!(ab, "lineTo({ to: [0, -1] })");
snapshot_test!(ac, "const myArray = [0..10]");
snapshot_test!(
ad,
r#"
fn firstPrimeNumber = () => {
return 2
}
firstPrimeNumber()"#
);
snapshot_test!(
ae,
r#"fn thing = (param) => {
return true
}
thing(false)"#
);
snapshot_test!(
af,
r#"const mySketch = startSketchAt([0,0])
|> lineTo({ to: [0, 1], tag: 'myPath' }, %)
|> lineTo([1, 1], %)
|> lineTo({ to: [1,0], tag: "rightPath" }, %)
|> close(%)"#
);
snapshot_test!(
ag,
"const mySketch = startSketchAt([0,0]) |> lineTo([1, 1], %) |> close(%)"
);
snapshot_test!(ah, "const myBox = startSketchAt(p)");
snapshot_test!(ai, r#"const myBox = f(1) |> g(2)"#);
snapshot_test!(aj, r#"const myBox = startSketchAt(p) |> line([0, l], %)"#);
snapshot_test!(ak, "lineTo({ to: [0, 1] })");
snapshot_test!(al, "lineTo({ to: [0, 1], from: [3, 3] })");
snapshot_test!(am, "lineTo({to:[0, 1]})");
snapshot_test!(an, "lineTo({ to: [0, 1], from: [3, 3]})");
snapshot_test!(ao, "lineTo({ to: [0, 1],from: [3, 3] })");
snapshot_test!(ap, "const mySketch = startSketchAt([0,0])");
snapshot_test!(aq, "log(5, \"hello\", aIdentifier)");
snapshot_test!(ar, r#"5 + "a""#);
snapshot_test!(at, "line([0, l], %)");
snapshot_test!(au, include_str!("../../../tests/executor/inputs/cylinder.kcl"));
}

View File

@ -0,0 +1,26 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 5,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 4,
"end": 5,
"value": 2,
"raw": "2"
}
}

View File

@ -0,0 +1,26 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 3,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 2,
"end": 3,
"value": 2,
"raw": "2"
}
}

View File

@ -0,0 +1,26 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 4,
"operator": "-",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 3,
"end": 4,
"value": 2,
"raw": "2"
}
}

View File

@ -0,0 +1,41 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 9,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 4,
"end": 9,
"operator": "*",
"left": {
"type": "Literal",
"type": "Literal",
"start": 4,
"end": 5,
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 8,
"end": 9,
"value": 3,
"raw": "3"
}
}
}

View File

@ -0,0 +1,41 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 11,
"operator": "*",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 6,
"end": 11,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 6,
"end": 7,
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 10,
"end": 11,
"value": 3,
"raw": "3"
}
}
}

View File

@ -0,0 +1,56 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 17,
"operator": "/",
"left": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 0,
"end": 11,
"operator": "*",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 6,
"end": 11,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 6,
"end": 7,
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 10,
"end": 11,
"value": 3,
"raw": "3"
}
}
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 16,
"end": 17,
"value": 4,
"raw": "4"
}
}

View File

@ -0,0 +1,56 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 17,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 6,
"end": 17,
"operator": "/",
"left": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 6,
"end": 11,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 6,
"end": 7,
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 10,
"end": 11,
"value": 3,
"raw": "3"
}
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 16,
"end": 17,
"value": 4,
"raw": "4"
}
}
}

View File

@ -0,0 +1,71 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 22,
"operator": "*",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 7,
"end": 22,
"operator": "+",
"left": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 7,
"end": 18,
"operator": "/",
"left": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 7,
"end": 12,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 7,
"end": 8,
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 11,
"end": 12,
"value": 3,
"raw": "3"
}
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 4,
"raw": "4"
}
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 21,
"end": 22,
"value": 5,
"raw": "5"
}
}
}

View File

@ -0,0 +1,41 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 13,
"operator": "*",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 8,
"end": 13,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 8,
"end": 9,
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 12,
"end": 13,
"value": 3,
"raw": "3"
}
}
}

View File

@ -0,0 +1,81 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 44,
"operator": "/",
"left": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 0,
"end": 22,
"operator": "*",
"left": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 0,
"end": 18,
"operator": "*",
"left": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 0,
"end": 12,
"operator": "*",
"left": {
"type": "Identifier",
"type": "Identifier",
"start": 0,
"end": 8,
"name": "distance"
},
"right": {
"type": "Identifier",
"type": "Identifier",
"start": 11,
"end": 12,
"name": "p"
}
},
"right": {
"type": "Identifier",
"type": "Identifier",
"start": 15,
"end": 18,
"name": "FOS"
}
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 21,
"end": 22,
"value": 6,
"raw": "6"
}
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 26,
"end": 44,
"operator": "*",
"left": {
"type": "Identifier",
"type": "Identifier",
"start": 26,
"end": 36,
"name": "sigmaAllow"
},
"right": {
"type": "Identifier",
"type": "Identifier",
"start": 39,
"end": 44,
"name": "width"
}
}
}

View File

@ -0,0 +1,26 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"type": "BinaryExpression",
"start": 0,
"end": 8,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 7,
"end": 8,
"value": 3,
"raw": "3"
}
}

View File

@ -0,0 +1,263 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 144,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 143,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 143,
"id": {
"type": "Identifier",
"start": 6,
"end": 15,
"name": "boxSketch"
},
"init": {
"type": "PipeExpression",
"type": "PipeExpression",
"start": 18,
"end": 143,
"body": [
{
"type": "CallExpression",
"type": "CallExpression",
"start": 18,
"end": 39,
"callee": {
"type": "Identifier",
"start": 18,
"end": 31,
"name": "startSketchAt"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 32,
"end": 38,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 33,
"end": 34,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 36,
"end": 37,
"value": 0,
"raw": "0"
}
]
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 47,
"end": 63,
"callee": {
"type": "Identifier",
"start": 47,
"end": 51,
"name": "line"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 52,
"end": 59,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 53,
"end": 54,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 56,
"end": 58,
"value": 10,
"raw": "10"
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 61,
"end": 62
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 71,
"end": 96,
"callee": {
"type": "Identifier",
"start": 71,
"end": 84,
"name": "tangentialArc"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 85,
"end": 92,
"elements": [
{
"type": "UnaryExpression",
"type": "UnaryExpression",
"start": 86,
"end": 88,
"operator": "-",
"argument": {
"type": "Literal",
"type": "Literal",
"start": 87,
"end": 88,
"value": 5,
"raw": "5"
}
},
{
"type": "Literal",
"type": "Literal",
"start": 90,
"end": 91,
"value": 5,
"raw": "5"
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 94,
"end": 95
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 104,
"end": 121,
"callee": {
"type": "Identifier",
"start": 104,
"end": 108,
"name": "line"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 109,
"end": 117,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 110,
"end": 111,
"value": 5,
"raw": "5"
},
{
"type": "UnaryExpression",
"type": "UnaryExpression",
"start": 113,
"end": 116,
"operator": "-",
"argument": {
"type": "Literal",
"type": "Literal",
"start": 114,
"end": 116,
"value": 15,
"raw": "15"
}
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 119,
"end": 120
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 129,
"end": 143,
"callee": {
"type": "Identifier",
"start": 129,
"end": 136,
"name": "extrude"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 137,
"end": 139,
"value": 10,
"raw": "10"
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 141,
"end": 142
}
],
"optional": false
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,48 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 17,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 17,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 17,
"id": {
"type": "Identifier",
"start": 6,
"end": 8,
"name": "sg"
},
"init": {
"type": "UnaryExpression",
"type": "UnaryExpression",
"start": 11,
"end": 17,
"operator": "-",
"argument": {
"type": "Identifier",
"type": "Identifier",
"start": 12,
"end": 17,
"name": "scale"
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,85 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 23,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 23,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 23,
"callee": {
"type": "Identifier",
"start": 0,
"end": 6,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 7,
"end": 22,
"properties": [
{
"type": "ObjectProperty",
"start": 9,
"end": 20,
"key": {
"type": "Identifier",
"start": 9,
"end": 11,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 13,
"end": 20,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 14,
"end": 15,
"value": 0,
"raw": "0"
},
{
"type": "UnaryExpression",
"type": "UnaryExpression",
"start": 17,
"end": 19,
"operator": "-",
"argument": {
"type": "Literal",
"type": "Literal",
"start": 18,
"end": 19,
"value": 1,
"raw": "1"
}
}
]
}
}
]
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,130 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 23,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 23,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 23,
"id": {
"type": "Identifier",
"start": 6,
"end": 13,
"name": "myArray"
},
"init": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 16,
"end": 23,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 2,
"raw": "2"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 3,
"raw": "3"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 4,
"raw": "4"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 5,
"raw": "5"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 6,
"raw": "6"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 7,
"raw": "7"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 8,
"raw": "8"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 9,
"raw": "9"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 10,
"raw": "10"
}
]
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,85 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 80,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 5,
"end": 57,
"declarations": [
{
"type": "VariableDeclarator",
"start": 8,
"end": 57,
"id": {
"type": "Identifier",
"start": 8,
"end": 24,
"name": "firstPrimeNumber"
},
"init": {
"type": "FunctionExpression",
"type": "FunctionExpression",
"start": 27,
"end": 57,
"params": [],
"body": {
"start": 33,
"end": 57,
"body": [
{
"type": "ReturnStatement",
"type": "ReturnStatement",
"start": 43,
"end": 51,
"argument": {
"type": "Literal",
"type": "Literal",
"start": 50,
"end": 51,
"value": 2,
"raw": "2"
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
}
],
"kind": "fn"
},
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 62,
"end": 80,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 62,
"end": 80,
"callee": {
"type": "Identifier",
"start": 62,
"end": 78,
"name": "firstPrimeNumber"
},
"arguments": [],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,99 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 66,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 49,
"declarations": [
{
"type": "VariableDeclarator",
"start": 3,
"end": 49,
"id": {
"type": "Identifier",
"start": 3,
"end": 8,
"name": "thing"
},
"init": {
"type": "FunctionExpression",
"type": "FunctionExpression",
"start": 11,
"end": 49,
"params": [
{
"type": "Identifier",
"start": 12,
"end": 17,
"name": "param"
}
],
"body": {
"start": 22,
"end": 49,
"body": [
{
"type": "ReturnStatement",
"type": "ReturnStatement",
"start": 32,
"end": 43,
"argument": {
"type": "Identifier",
"type": "Identifier",
"start": 39,
"end": 43,
"name": "true"
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
}
],
"kind": "fn"
},
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 54,
"end": 66,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 54,
"end": 66,
"callee": {
"type": "Identifier",
"start": 54,
"end": 59,
"name": "thing"
},
"arguments": [
{
"type": "Identifier",
"type": "Identifier",
"start": 60,
"end": 65,
"name": "false"
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,317 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 192,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 192,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 192,
"id": {
"type": "Identifier",
"start": 6,
"end": 14,
"name": "mySketch"
},
"init": {
"type": "PipeExpression",
"type": "PipeExpression",
"start": 17,
"end": 192,
"body": [
{
"type": "CallExpression",
"type": "CallExpression",
"start": 17,
"end": 37,
"callee": {
"type": "Identifier",
"start": 17,
"end": 30,
"name": "startSketchAt"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 31,
"end": 36,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 32,
"end": 33,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 34,
"end": 35,
"value": 0,
"raw": "0"
}
]
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 49,
"end": 89,
"callee": {
"type": "Identifier",
"start": 49,
"end": 55,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 56,
"end": 85,
"properties": [
{
"type": "ObjectProperty",
"start": 58,
"end": 68,
"key": {
"type": "Identifier",
"start": 58,
"end": 60,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 62,
"end": 68,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 63,
"end": 64,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 66,
"end": 67,
"value": 1,
"raw": "1"
}
]
}
},
{
"type": "ObjectProperty",
"start": 70,
"end": 83,
"key": {
"type": "Identifier",
"start": 70,
"end": 73,
"name": "tag"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 75,
"end": 83,
"value": "myPath",
"raw": "'myPath'"
}
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 87,
"end": 88
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 101,
"end": 118,
"callee": {
"type": "Identifier",
"start": 101,
"end": 107,
"name": "lineTo"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 108,
"end": 114,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 109,
"end": 110,
"value": 1,
"raw": "1"
},
{
"type": "Literal",
"type": "Literal",
"start": 112,
"end": 113,
"value": 1,
"raw": "1"
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 116,
"end": 117
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 130,
"end": 172,
"callee": {
"type": "Identifier",
"start": 130,
"end": 136,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 137,
"end": 168,
"properties": [
{
"type": "ObjectProperty",
"start": 139,
"end": 148,
"key": {
"type": "Identifier",
"start": 139,
"end": 141,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 143,
"end": 148,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 144,
"end": 145,
"value": 1,
"raw": "1"
},
{
"type": "Literal",
"type": "Literal",
"start": 146,
"end": 147,
"value": 0,
"raw": "0"
}
]
}
},
{
"type": "ObjectProperty",
"start": 150,
"end": 166,
"key": {
"type": "Identifier",
"start": 150,
"end": 153,
"name": "tag"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 155,
"end": 166,
"value": "rightPath",
"raw": "\"rightPath\""
}
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 170,
"end": 171
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 184,
"end": 192,
"callee": {
"type": "Identifier",
"start": 184,
"end": 189,
"name": "close"
},
"arguments": [
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 190,
"end": 191
}
],
"optional": false
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,151 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 70,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 70,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 70,
"id": {
"type": "Identifier",
"start": 6,
"end": 14,
"name": "mySketch"
},
"init": {
"type": "PipeExpression",
"type": "PipeExpression",
"start": 17,
"end": 70,
"body": [
{
"type": "CallExpression",
"type": "CallExpression",
"start": 17,
"end": 37,
"callee": {
"type": "Identifier",
"start": 17,
"end": 30,
"name": "startSketchAt"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 31,
"end": 36,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 32,
"end": 33,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 34,
"end": 35,
"value": 0,
"raw": "0"
}
]
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 41,
"end": 58,
"callee": {
"type": "Identifier",
"start": 41,
"end": 47,
"name": "lineTo"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 48,
"end": 54,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 49,
"end": 50,
"value": 1,
"raw": "1"
},
{
"type": "Literal",
"type": "Literal",
"start": 52,
"end": 53,
"value": 1,
"raw": "1"
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 56,
"end": 57
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 62,
"end": 70,
"callee": {
"type": "Identifier",
"start": 62,
"end": 67,
"name": "close"
},
"arguments": [
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 68,
"end": 69
}
],
"optional": false
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,56 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 30,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 30,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 30,
"id": {
"type": "Identifier",
"start": 6,
"end": 11,
"name": "myBox"
},
"init": {
"type": "CallExpression",
"type": "CallExpression",
"start": 14,
"end": 30,
"callee": {
"type": "Identifier",
"start": 14,
"end": 27,
"name": "startSketchAt"
},
"arguments": [
{
"type": "Identifier",
"type": "Identifier",
"start": 28,
"end": 29,
"name": "p"
}
],
"optional": false
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,92 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 26,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 26,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 26,
"id": {
"type": "Identifier",
"start": 6,
"end": 11,
"name": "myBox"
},
"init": {
"type": "PipeExpression",
"type": "PipeExpression",
"start": 14,
"end": 26,
"body": [
{
"type": "CallExpression",
"type": "CallExpression",
"start": 14,
"end": 18,
"callee": {
"type": "Identifier",
"start": 14,
"end": 15,
"name": "f"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 16,
"end": 17,
"value": 1,
"raw": "1"
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 22,
"end": 26,
"callee": {
"type": "Identifier",
"start": 22,
"end": 23,
"name": "g"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 24,
"end": 25,
"value": 2,
"raw": "2"
}
],
"optional": false
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,112 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 49,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 49,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 49,
"id": {
"type": "Identifier",
"start": 6,
"end": 11,
"name": "myBox"
},
"init": {
"type": "PipeExpression",
"type": "PipeExpression",
"start": 14,
"end": 49,
"body": [
{
"type": "CallExpression",
"type": "CallExpression",
"start": 14,
"end": 30,
"callee": {
"type": "Identifier",
"start": 14,
"end": 27,
"name": "startSketchAt"
},
"arguments": [
{
"type": "Identifier",
"type": "Identifier",
"start": 28,
"end": 29,
"name": "p"
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 34,
"end": 49,
"callee": {
"type": "Identifier",
"start": 34,
"end": 38,
"name": "line"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 39,
"end": 45,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 40,
"end": 41,
"value": 0,
"raw": "0"
},
{
"type": "Identifier",
"type": "Identifier",
"start": 43,
"end": 44,
"name": "l"
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 47,
"end": 48
}
],
"optional": false
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,78 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 22,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 22,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 22,
"callee": {
"type": "Identifier",
"start": 0,
"end": 6,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 7,
"end": 21,
"properties": [
{
"type": "ObjectProperty",
"start": 9,
"end": 19,
"key": {
"type": "Identifier",
"start": 9,
"end": 11,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 13,
"end": 19,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 14,
"end": 15,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
}
]
}
}
]
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,113 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 36,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 36,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 36,
"callee": {
"type": "Identifier",
"start": 0,
"end": 6,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 7,
"end": 35,
"properties": [
{
"type": "ObjectProperty",
"start": 9,
"end": 19,
"key": {
"type": "Identifier",
"start": 9,
"end": 11,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 13,
"end": 19,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 14,
"end": 15,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
}
]
}
},
{
"type": "ObjectProperty",
"start": 21,
"end": 33,
"key": {
"type": "Identifier",
"start": 21,
"end": 25,
"name": "from"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 27,
"end": 33,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 28,
"end": 29,
"value": 3,
"raw": "3"
},
{
"type": "Literal",
"type": "Literal",
"start": 31,
"end": 32,
"value": 3,
"raw": "3"
}
]
}
}
]
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,78 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 19,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 19,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 19,
"callee": {
"type": "Identifier",
"start": 0,
"end": 6,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 7,
"end": 18,
"properties": [
{
"type": "ObjectProperty",
"start": 8,
"end": 17,
"key": {
"type": "Identifier",
"start": 8,
"end": 10,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 11,
"end": 17,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 12,
"end": 13,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 15,
"end": 16,
"value": 1,
"raw": "1"
}
]
}
}
]
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,113 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 35,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 35,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 35,
"callee": {
"type": "Identifier",
"start": 0,
"end": 6,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 7,
"end": 34,
"properties": [
{
"type": "ObjectProperty",
"start": 9,
"end": 19,
"key": {
"type": "Identifier",
"start": 9,
"end": 11,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 13,
"end": 19,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 14,
"end": 15,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
}
]
}
},
{
"type": "ObjectProperty",
"start": 21,
"end": 33,
"key": {
"type": "Identifier",
"start": 21,
"end": 25,
"name": "from"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 27,
"end": 33,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 28,
"end": 29,
"value": 3,
"raw": "3"
},
{
"type": "Literal",
"type": "Literal",
"start": 31,
"end": 32,
"value": 3,
"raw": "3"
}
]
}
}
]
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,113 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 35,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 35,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 35,
"callee": {
"type": "Identifier",
"start": 0,
"end": 6,
"name": "lineTo"
},
"arguments": [
{
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 7,
"end": 34,
"properties": [
{
"type": "ObjectProperty",
"start": 9,
"end": 19,
"key": {
"type": "Identifier",
"start": 9,
"end": 11,
"name": "to"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 13,
"end": 19,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 14,
"end": 15,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
}
]
}
},
{
"type": "ObjectProperty",
"start": 20,
"end": 32,
"key": {
"type": "Identifier",
"start": 20,
"end": 24,
"name": "from"
},
"value": {
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 26,
"end": 32,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 27,
"end": 28,
"value": 3,
"raw": "3"
},
{
"type": "Literal",
"type": "Literal",
"start": 30,
"end": 31,
"value": 3,
"raw": "3"
}
]
}
}
]
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,73 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 37,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 37,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 37,
"id": {
"type": "Identifier",
"start": 6,
"end": 14,
"name": "mySketch"
},
"init": {
"type": "CallExpression",
"type": "CallExpression",
"start": 17,
"end": 37,
"callee": {
"type": "Identifier",
"start": 17,
"end": 30,
"name": "startSketchAt"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 31,
"end": 36,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 32,
"end": 33,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 34,
"end": 35,
"value": 0,
"raw": "0"
}
]
}
],
"optional": false
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,58 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 28,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 28,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 28,
"callee": {
"type": "Identifier",
"start": 0,
"end": 3,
"name": "log"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 4,
"end": 5,
"value": 5,
"raw": "5"
},
{
"type": "Literal",
"type": "Literal",
"start": 7,
"end": 14,
"value": "hello",
"raw": "\"hello\""
},
{
"type": "Identifier",
"type": "Identifier",
"start": 16,
"end": 27,
"name": "aIdentifier"
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,43 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 7,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 7,
"expression": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 0,
"end": 7,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 0,
"end": 1,
"value": 5,
"raw": "5"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 4,
"end": 7,
"value": "a",
"raw": "\"a\""
}
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,64 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 15,
"body": [
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 0,
"end": 15,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 0,
"end": 15,
"callee": {
"type": "Identifier",
"start": 0,
"end": 4,
"name": "line"
},
"arguments": [
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 5,
"end": 11,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 6,
"end": 7,
"value": 0,
"raw": "0"
},
{
"type": "Identifier",
"type": "Identifier",
"start": 9,
"end": 10,
"name": "l"
}
]
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 13,
"end": 14
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,158 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 90,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 74,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 74,
"id": {
"type": "Identifier",
"start": 6,
"end": 14,
"name": "cylinder"
},
"init": {
"type": "PipeExpression",
"type": "PipeExpression",
"start": 17,
"end": 74,
"body": [
{
"type": "CallExpression",
"type": "CallExpression",
"start": 17,
"end": 56,
"callee": {
"type": "Identifier",
"start": 17,
"end": 39,
"name": "unstable_stdlib_circle"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 40,
"end": 44,
"value": "XY",
"raw": "'XY'"
},
{
"type": "ArrayExpression",
"type": "ArrayExpression",
"start": 46,
"end": 51,
"elements": [
{
"type": "Literal",
"type": "Literal",
"start": 47,
"end": 48,
"value": 0,
"raw": "0"
},
{
"type": "Literal",
"type": "Literal",
"start": 49,
"end": 50,
"value": 0,
"raw": "0"
}
]
},
{
"type": "Literal",
"type": "Literal",
"start": 53,
"end": 55,
"value": 22,
"raw": "22"
}
],
"optional": false
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 60,
"end": 74,
"callee": {
"type": "Identifier",
"start": 60,
"end": 67,
"name": "extrude"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 68,
"end": 70,
"value": 14,
"raw": "14"
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 72,
"end": 73
}
],
"optional": false
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
],
"kind": "const"
},
{
"type": "ExpressionStatement",
"type": "ExpressionStatement",
"start": 75,
"end": 89,
"expression": {
"type": "CallExpression",
"type": "CallExpression",
"start": 75,
"end": 89,
"callee": {
"type": "Identifier",
"start": 75,
"end": 79,
"name": "show"
},
"arguments": [
{
"type": "Identifier",
"type": "Identifier",
"start": 80,
"end": 88,
"name": "cylinder"
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,95 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 36,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 36,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 36,
"id": {
"type": "Identifier",
"start": 6,
"end": 11,
"name": "myVar"
},
"init": {
"type": "CallExpression",
"type": "CallExpression",
"start": 14,
"end": 36,
"callee": {
"type": "Identifier",
"start": 14,
"end": 17,
"name": "min"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 18,
"end": 19,
"value": 5,
"raw": "5"
},
{
"type": "UnaryExpression",
"type": "UnaryExpression",
"start": 22,
"end": 35,
"operator": "-",
"argument": {
"type": "CallExpression",
"type": "CallExpression",
"start": 23,
"end": 35,
"callee": {
"type": "Identifier",
"start": 23,
"end": 29,
"name": "legLen"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 30,
"end": 31,
"value": 5,
"raw": "5"
},
{
"type": "Literal",
"type": "Literal",
"start": 33,
"end": 34,
"value": 4,
"raw": "4"
}
],
"optional": false
}
}
],
"optional": false
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,95 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 35,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 35,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 35,
"id": {
"type": "Identifier",
"start": 6,
"end": 11,
"name": "myVar"
},
"init": {
"type": "CallExpression",
"type": "CallExpression",
"start": 14,
"end": 35,
"callee": {
"type": "Identifier",
"start": 14,
"end": 17,
"name": "min"
},
"arguments": [
{
"type": "UnaryExpression",
"type": "UnaryExpression",
"start": 18,
"end": 31,
"operator": "-",
"argument": {
"type": "CallExpression",
"type": "CallExpression",
"start": 19,
"end": 31,
"callee": {
"type": "Identifier",
"start": 19,
"end": 25,
"name": "legLen"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 26,
"end": 27,
"value": 5,
"raw": "5"
},
{
"type": "Literal",
"type": "Literal",
"start": 29,
"end": 30,
"value": 4,
"raw": "4"
}
],
"optional": false
}
},
{
"type": "Literal",
"type": "Literal",
"start": 33,
"end": 34,
"value": 5,
"raw": "5"
}
],
"optional": false
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,98 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 36,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 36,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 36,
"id": {
"type": "Identifier",
"start": 6,
"end": 11,
"name": "myVar"
},
"init": {
"type": "PipeExpression",
"type": "PipeExpression",
"start": 14,
"end": 36,
"body": [
{
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 14,
"end": 19,
"operator": "+",
"left": {
"type": "Literal",
"type": "Literal",
"start": 14,
"end": 15,
"value": 5,
"raw": "5"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 18,
"end": 19,
"value": 6,
"raw": "6"
}
},
{
"type": "CallExpression",
"type": "CallExpression",
"start": 23,
"end": 36,
"callee": {
"type": "Identifier",
"start": 23,
"end": 29,
"name": "myFunc"
},
"arguments": [
{
"type": "Literal",
"type": "Literal",
"start": 30,
"end": 32,
"value": 45,
"raw": "45"
},
{
"type": "PipeSubstitution",
"type": "PipeSubstitution",
"start": 34,
"end": 35
}
],
"optional": false
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,62 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 27,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 27,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 27,
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"name": "x"
},
"init": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 10,
"end": 27,
"operator": "+",
"left": {
"type": "UnaryExpression",
"type": "UnaryExpression",
"start": 10,
"end": 15,
"operator": "-",
"argument": {
"type": "Identifier",
"type": "Identifier",
"start": 11,
"end": 15,
"name": "leg2"
}
},
"right": {
"type": "Identifier",
"type": "Identifier",
"start": 18,
"end": 27,
"name": "thickness"
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,72 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 18,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 18,
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 18,
"id": {
"type": "Identifier",
"start": 4,
"end": 5,
"name": "x"
},
"init": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 8,
"end": 18,
"operator": "*",
"left": {
"type": "Literal",
"type": "Literal",
"start": 8,
"end": 9,
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 13,
"end": 18,
"operator": "-",
"left": {
"type": "Literal",
"type": "Literal",
"start": 13,
"end": 14,
"value": 3,
"raw": "3"
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 4,
"raw": "4"
}
}
}
}
],
"kind": "let"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,55 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 40,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 11,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 11,
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"name": "x"
},
"init": {
"type": "Literal",
"type": "Literal",
"start": 10,
"end": 11,
"value": 1,
"raw": "1"
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {
"0": [
{
"type": "NonCodeNode",
"start": 11,
"end": 40,
"value": {
"type": "inlineComment",
"value": "this is an inline comment",
"style": "line"
}
}
]
},
"start": []
}
}

View File

@ -0,0 +1,77 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 58,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 58,
"declarations": [
{
"type": "VariableDeclarator",
"start": 3,
"end": 58,
"id": {
"type": "Identifier",
"start": 3,
"end": 4,
"name": "x"
},
"init": {
"type": "FunctionExpression",
"type": "FunctionExpression",
"start": 7,
"end": 58,
"params": [],
"body": {
"start": 13,
"end": 58,
"body": [
{
"type": "ReturnStatement",
"type": "ReturnStatement",
"start": 23,
"end": 32,
"argument": {
"type": "Identifier",
"type": "Identifier",
"start": 30,
"end": 32,
"name": "sg"
}
},
{
"type": "ReturnStatement",
"type": "ReturnStatement",
"start": 41,
"end": 50,
"argument": {
"type": "Identifier",
"type": "Identifier",
"start": 48,
"end": 50,
"name": "sg"
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
}
],
"kind": "fn"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,136 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 55,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 26,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 26,
"id": {
"type": "Identifier",
"start": 6,
"end": 9,
"name": "obj"
},
"init": {
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 12,
"end": 26,
"properties": [
{
"type": "ObjectProperty",
"start": 14,
"end": 18,
"key": {
"type": "Identifier",
"start": 14,
"end": 15,
"name": "a"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
}
},
{
"type": "ObjectProperty",
"start": 20,
"end": 24,
"key": {
"type": "Identifier",
"start": 20,
"end": 21,
"name": "b"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 23,
"end": 24,
"value": 2,
"raw": "2"
}
}
]
}
}
],
"kind": "const"
},
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 31,
"end": 55,
"declarations": [
{
"type": "VariableDeclarator",
"start": 37,
"end": 55,
"id": {
"type": "Identifier",
"start": 37,
"end": 43,
"name": "height"
},
"init": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 46,
"end": 55,
"operator": "-",
"left": {
"type": "Literal",
"type": "Literal",
"start": 46,
"end": 47,
"value": 1,
"raw": "1"
},
"right": {
"type": "MemberExpression",
"type": "MemberExpression",
"start": 50,
"end": 55,
"object": {
"type": "Identifier",
"type": "Identifier",
"start": 50,
"end": 53,
"name": "obj"
},
"property": {
"type": "Identifier",
"type": "Identifier",
"start": 54,
"end": 55,
"name": "a"
},
"computed": false
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,137 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 59,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 26,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 26,
"id": {
"type": "Identifier",
"start": 6,
"end": 9,
"name": "obj"
},
"init": {
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 12,
"end": 26,
"properties": [
{
"type": "ObjectProperty",
"start": 14,
"end": 18,
"key": {
"type": "Identifier",
"start": 14,
"end": 15,
"name": "a"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
}
},
{
"type": "ObjectProperty",
"start": 20,
"end": 24,
"key": {
"type": "Identifier",
"start": 20,
"end": 21,
"name": "b"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 23,
"end": 24,
"value": 2,
"raw": "2"
}
}
]
}
}
],
"kind": "const"
},
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 32,
"end": 59,
"declarations": [
{
"type": "VariableDeclarator",
"start": 38,
"end": 59,
"id": {
"type": "Identifier",
"start": 38,
"end": 44,
"name": "height"
},
"init": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 47,
"end": 59,
"operator": "-",
"left": {
"type": "Literal",
"type": "Literal",
"start": 47,
"end": 48,
"value": 1,
"raw": "1"
},
"right": {
"type": "MemberExpression",
"type": "MemberExpression",
"start": 51,
"end": 59,
"object": {
"type": "Identifier",
"type": "Identifier",
"start": 51,
"end": 54,
"name": "obj"
},
"property": {
"type": "Literal",
"type": "Literal",
"start": 55,
"end": 58,
"value": "a",
"raw": "\"a\""
},
"computed": false
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -0,0 +1,137 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
---
{
"start": 0,
"end": 58,
"body": [
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 0,
"end": 26,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 26,
"id": {
"type": "Identifier",
"start": 6,
"end": 9,
"name": "obj"
},
"init": {
"type": "ObjectExpression",
"type": "ObjectExpression",
"start": 12,
"end": 26,
"properties": [
{
"type": "ObjectProperty",
"start": 14,
"end": 18,
"key": {
"type": "Identifier",
"start": 14,
"end": 15,
"name": "a"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 17,
"end": 18,
"value": 1,
"raw": "1"
}
},
{
"type": "ObjectProperty",
"start": 20,
"end": 24,
"key": {
"type": "Identifier",
"start": 20,
"end": 21,
"name": "b"
},
"value": {
"type": "Literal",
"type": "Literal",
"start": 23,
"end": 24,
"value": 2,
"raw": "2"
}
}
]
}
}
],
"kind": "const"
},
{
"type": "VariableDeclaration",
"type": "VariableDeclaration",
"start": 31,
"end": 58,
"declarations": [
{
"type": "VariableDeclarator",
"start": 37,
"end": 58,
"id": {
"type": "Identifier",
"start": 37,
"end": 43,
"name": "height"
},
"init": {
"type": "BinaryExpression",
"type": "BinaryExpression",
"start": 46,
"end": 58,
"operator": "-",
"left": {
"type": "MemberExpression",
"type": "MemberExpression",
"start": 46,
"end": 54,
"object": {
"type": "Identifier",
"type": "Identifier",
"start": 46,
"end": 49,
"name": "obj"
},
"property": {
"type": "Literal",
"type": "Literal",
"start": 50,
"end": 53,
"value": "a",
"raw": "\"a\""
},
"computed": false
},
"right": {
"type": "Literal",
"type": "Literal",
"start": 57,
"end": 58,
"value": 1,
"raw": "1"
}
}
}
],
"kind": "const"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

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