Compare commits

..

6 Commits

Author SHA1 Message Date
dec538590a Tests for recasting literals 2023-11-01 11:22:34 -05:00
9523eef52c Fix some more 2023-11-01 10:30:58 -05:00
20ae39dec3 Trying to make tests pass again 2023-11-01 10:30:57 -05:00
8ebba16796 Remove unsigned integer type for now 2023-11-01 10:30:57 -05:00
038de47e5d Frontend should never cast LiteralValue directly to string
Instead, it should cast the LiteralValue's `.data` field.
2023-11-01 10:30:57 -05:00
61563bee97 KCL literals have their own type system instead of reusing JSON.
We now distinguish between KCL literals of:
- String
- f64
- i64
- u64

instead of reusing JSON values as the only KCL literal.
2023-11-01 10:30:57 -05:00
153 changed files with 1597 additions and 7770 deletions

View File

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

View File

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

View File

@ -12,13 +12,9 @@ on:
# Daily at 04:00 AM UTC # Daily at 04:00 AM UTC
# Will checkout the last commit from the default branch (main as of 2023-10-04) # 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: concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
check-format: check-format:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
@ -50,20 +46,6 @@ jobs:
- run: yarn tsc - 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: build-test-web:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -106,7 +88,7 @@ jobs:
run: | run: |
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
echo "$(jq --arg url 'https://dl.kittycad.io/releases/modeling-app/nightly/last_update.json' \ echo "$(jq --arg url 'https://dl.kittycad.io/releases/modeling-app/nightly/last_update.json' \
'.tauri.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json '.tauri.updater.endpoints[]=$url' src-tauri/tauri.conf.json --indent 2)" > src-tauri/tauri.conf.json
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
if: github.event_name == 'schedule' if: github.event_name == 'schedule'
@ -114,14 +96,13 @@ jobs:
path: | path: |
package.json package.json
src-tauri/tauri.conf.json src-tauri/tauri.conf.json
src-tauri/tauri.release.conf.json
- id: export_version - id: export_version
run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT" run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT"
build-test-apps: build-test-apps:
needs: [prepare-json-files] needs: [check-format, build-test-web, prepare-json-files, check-types]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
@ -137,9 +118,8 @@ jobs:
ls -l artifact ls -l artifact
cp artifact/package.json package.json cp artifact/package.json package.json
cp artifact/src-tauri/tauri.conf.json src-tauri/tauri.conf.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' if: matrix.os == 'ubuntu-latest'
run: > run: >
sudo apt-get update && sudo apt-get update &&
@ -159,10 +139,10 @@ jobs:
- run: yarn install - run: yarn install
- name: Setup Rust - name: Rust setup
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
- name: Setup Rust cache - name: Rust cache
uses: swatinem/rust-cache@v2 uses: swatinem/rust-cache@v2
with: with:
workspaces: './src-tauri -> target' workspaces: './src-tauri -> target'
@ -171,27 +151,24 @@ jobs:
with: with:
workspaces: './src/wasm-lib' workspaces: './src/wasm-lib'
- name: Run build:wasm manually - name: wasm prep
shell: bash shell: bash
env:
MODE: ${{ env.BUILD_RELEASE == 'true' && '--release' || '--debug' }}
run: | run: |
mkdir src/wasm-lib/pkg; cd src/wasm-lib mkdir src/wasm-lib/pkg; cd src/wasm-lib
echo "building with ${{ env.MODE }}" npx wasm-pack build --target web --out-dir pkg
npx wasm-pack build --target web --out-dir pkg ${{ env.MODE }}
cd ../../ cd ../../
cp src/wasm-lib/pkg/wasm_lib_bg.wasm public cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
- name: Fix format - name: Fix format
run: yarn fmt run: yarn fmt
- name: Install Universal target (MacOS only) - name: install apple silicon target mac
if: matrix.os == 'macos-latest' if: matrix.os == 'macos-latest'
run: | run: |
rustup target add aarch64-apple-darwin rustup target add aarch64-apple-darwin
- name: Prepare certificate and variables (Windows only) - name: Prepare Windows certificate and variables
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }} if: matrix.os == 'windows-latest'
run: | run: |
echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12 echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
cat /d/Certificate_pkcs12.p12 cat /d/Certificate_pkcs12.p12
@ -205,8 +182,8 @@ jobs:
echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH
shell: bash shell: bash
- name: Setup certicate with SSM KSP (Windows only) - name: Setup Windows certicate with SSM KSP
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }} if: matrix.os == 'windows-latest'
run: | 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 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 msiexec /i smtools-windows-x64.msi /quiet /qn
@ -216,17 +193,8 @@ jobs:
smksp_cert_sync.exe smksp_cert_sync.exe
shell: cmd shell: cmd
- name: Build the app (debug) - name: Build and sign the app for the current platform
uses: tauri-apps/tauri-action@v0 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: env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
@ -236,35 +204,29 @@ jobs:
APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} 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: with:
args: "${{ matrix.os == 'macos-latest' && '--target universal-apple-darwin' || '' }} ${{ env.TAURI_CONF_ARGS }}" args: ${{ matrix.os == 'macos-latest' && '--target universal-apple-darwin' || '' }}
- uses: actions/upload-artifact@v3 - 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: with:
path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*" path: ${{ matrix.os == 'macos-latest' && 'src-tauri/target/universal-apple-darwin/release/bundle/*/*' || 'src-tauri/target/release/bundle/*/*' }}
- name: Install tauri-driver for e2e tests (linux only) - name: Install tauri-driver for e2e tests
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: install command: install
args: tauri-driver args: tauri-driver
- name: Run e2e tests (linux only) - name: Run e2e tests
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
run: xvfb-run yarn test:e2e run: xvfb-run yarn test:e2e
env:
MODE: ${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}
publish-apps-release: publish-apps-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }} if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }}
needs: [check-format, check-types, check-typos, build-test-web, prepare-json-files, build-test-apps] needs: [build-test-web, prepare-json-files, build-test-apps]
env: env:
VERSION_NO_V: ${{ needs.prepare-json-files.outputs.version }} 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 }} 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 ## 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. We always use the latest stable version of Rust, so you may need to run `rustup update stable`. 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. Then, run:
``` ```
yarn install 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 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 writing 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 writting 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.) 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", "name": "untitled-app",
"version": "0.12.0", "version": "0.11.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.10.2", "@codemirror/autocomplete": "^6.10.2",
@ -8,15 +8,15 @@
"@fortawesome/free-brands-svg-icons": "^6.4.2", "@fortawesome/free-brands-svg-icons": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.17", "@headlessui/react": "^1.7.13",
"@headlessui/tailwindcss": "^0.2.0", "@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "^0.0.45", "@kittycad/lib": "^0.0.45",
"@lezer/javascript": "^1.4.7", "@lezer/javascript": "^1.4.7",
"@open-rpc/client-js": "^1.8.1", "@open-rpc/client-js": "^1.8.1",
"@react-hook/resize-observer": "^1.2.6", "@react-hook/resize-observer": "^1.2.6",
"@replit/codemirror-interact": "^6.3.0", "@replit/codemirror-interact": "^6.3.0",
"@sentry/react": "^7.77.0", "@sentry/react": "^7.65.0",
"@tauri-apps/api": "^1.5.1", "@tauri-apps/api": "^1.5.0",
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^14.0.0", "@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.5.1", "@testing-library/user-event": "^14.5.1",
@ -30,7 +30,7 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"debounce-promise": "^3.1.2", "debounce-promise": "^3.1.2",
"formik": "^2.4.3", "formik": "^2.4.3",
"fuse.js": "^7.0.0", "fuse.js": "^6.6.2",
"http-server": "^14.1.1", "http-server": "^14.1.1",
"json-rpc-2.0": "^1.6.0", "json-rpc-2.0": "^1.6.0",
"re-resizable": "^6.9.11", "re-resizable": "^6.9.11",
@ -51,7 +51,7 @@
"uuid": "^9.0.1", "uuid": "^9.0.1",
"vitest": "^0.34.6", "vitest": "^0.34.6",
"vscode-jsonrpc": "^8.1.0", "vscode-jsonrpc": "^8.1.0",
"vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-protocol": "^3.17.3",
"wasm-pack": "^0.12.1", "wasm-pack": "^0.12.1",
"web-vitals": "^3.5.0", "web-vitals": "^3.5.0",
"ws": "^8.13.0", "ws": "^8.13.0",
@ -102,7 +102,7 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.23.3", "@babel/preset-env": "^7.22.9",
"@tauri-apps/cli": "^1.5.6", "@tauri-apps/cli": "^1.5.6",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
"@types/debounce-promise": "^3.1.8", "@types/debounce-promise": "^3.1.8",
@ -111,18 +111,18 @@
"@types/uuid": "^9.0.4", "@types/uuid": "^9.0.4",
"@types/wicg-file-system-access": "^2020.9.6", "@types/wicg-file-system-access": "^2020.9.6",
"@types/ws": "^8.5.5", "@types/ws": "^8.5.5",
"@vitejs/plugin-react": "^4.1.1", "@vitejs/plugin-react": "^4.0.3",
"@vitest/coverage-istanbul": "^0.34.6", "@vitest/coverage-istanbul": "^0.34.1",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"eslint": "^8.53.0", "eslint": "^8.44.0",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"eslint-plugin-css-modules": "^2.12.0", "eslint-plugin-css-modules": "^2.11.0",
"happy-dom": "^10.8.0", "happy-dom": "^10.8.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"postcss": "^8.4.31", "postcss": "^8.4.31",
"prettier": "^2.8.0", "prettier": "^2.8.0",
"setimmediate": "^1.0.5", "setimmediate": "^1.0.5",
"tailwindcss": "^3.3.5", "tailwindcss": "^3.2.4",
"vite": "^4.5.0", "vite": "^4.5.0",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.2.1", "vite-tsconfig-paths": "^4.2.1",

40
src-tauri/Cargo.lock generated
View File

@ -1664,9 +1664,9 @@ dependencies = [
[[package]] [[package]]
name = "kittycad" name = "kittycad"
version = "0.2.42" version = "0.2.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aa554d86b6dbbd976a659c912ae25ce817b4378eb12a5684907e263410f0a7b" checksum = "874914cd40bfd43674406683bb3f0924d41780698a4ade96f2e180a73678bdd1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1732,9 +1732,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.150" version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]] [[package]]
name = "libm" name = "libm"
@ -1940,9 +1940,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.9" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [ dependencies = [
"libc", "libc",
"wasi 0.11.0+wasi-snapshot-preview1", "wasi 0.11.0+wasi-snapshot-preview1",
@ -3112,9 +3112,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.16" version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"bytes", "bytes",
@ -3129,9 +3129,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.16" version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3215,9 +3215,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.192" version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -3233,9 +3233,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.192" version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3438,9 +3438,9 @@ dependencies = [
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.5.5" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.48.0", "windows-sys 0.48.0",
@ -3856,7 +3856,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-fs-extra" name = "tauri-plugin-fs-extra"
version = "0.0.0" version = "0.0.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#20ef22fc3ab76cab770c2c0dac0cc75dfc982c22" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#11048fd9975bf89e9bc2f192b735ac339f6bb43b"
dependencies = [ dependencies = [
"log", "log",
"serde", "serde",
@ -4035,9 +4035,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.34.0" version = "1.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -4045,7 +4045,7 @@ dependencies = [
"mio", "mio",
"num_cpus", "num_cpus",
"pin-project-lite", "pin-project-lite",
"socket2 0.5.5", "socket2 0.5.4",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]

View File

@ -16,13 +16,13 @@ tauri-build = { version = "1.5.0", features = [] }
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
kittycad = "0.2.42" kittycad = "0.2.41"
oauth2 = "4.4.2" oauth2 = "4.4.2"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" 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 = { 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" } tauri-plugin-fs-extra = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
tokio = { version = "1.34.0", features = ["time"] } tokio = { version = "1.33.0", features = ["time"] }
toml = "0.8.2" toml = "0.8.2"
[features] [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. // Open the system browser with the auth_uri.
// We do this in the browser and not a separate window because we want 1password and // We do this in the browser and not a seperate window because we want 1password and
// other crap to work well. // other crap to work well.
tauri::api::shell::open(&app.shell_scope(), auth_uri.secret(), None) tauri::api::shell::open(&app.shell_scope(), auth_uri.secret(), None)
.map_err(|e| InvokeError::from_anyhow(e.into()))?; .map_err(|e| InvokeError::from_anyhow(e.into()))?;

View File

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

View File

@ -1,6 +1,7 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/schema.json", "$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": { "package": {
"productName": "KittyCAD Modeling" "productName": "KittyCAD Modeling"
} }
} }

View File

@ -1,21 +0,0 @@
{
"$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,6 +1,7 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/schema.json", "$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": { "package": {
"productName": "KittyCAD Modeling" "productName": "KittyCAD Modeling"
} }
} }

View File

@ -1,4 +1,4 @@
import { useCallback, MouseEventHandler } from 'react' import { useEffect, useCallback, MouseEventHandler } from 'react'
import { DebugPanel } from './components/DebugPanel' import { DebugPanel } from './components/DebugPanel'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { PaneType, useStore } from './useStore' import { PaneType, useStore } from './useStore'
@ -19,6 +19,7 @@ import {
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
import { useHotkeys } from 'react-hotkeys-hook' import { useHotkeys } from 'react-hotkeys-hook'
import { getNormalisedCoordinates } from './lib/utils' import { getNormalisedCoordinates } from './lib/utils'
import { isTauri } from './lib/isTauri'
import { useLoaderData } from 'react-router-dom' import { useLoaderData } from 'react-router-dom'
import { IndexLoaderData } from './Router' import { IndexLoaderData } from './Router'
import { useGlobalStateContext } from 'hooks/useGlobalStateContext' import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
@ -30,10 +31,11 @@ import { TextEditor } from 'components/TextEditor'
import { Themes, getSystemTheme } from 'lib/theme' import { Themes, getSystemTheme } from 'lib/theme'
import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions' import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions'
import { engineCommandManager } from './lang/std/engineConnection' import { engineCommandManager } from './lang/std/engineConnection'
import { kclManager } from 'lang/KclSinglton'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
export function App() { export function App() {
const { project, file } = useLoaderData() as IndexLoaderData const { code: loadedCode, project, file } = useLoaderData() as IndexLoaderData
useHotKeyListener() useHotKeyListener()
const { const {
@ -80,6 +82,26 @@ export function App() {
? 'opacity-40' ? '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() useEngineConnectionSubscriptions()
const debounceSocketSend = throttle<EngineCommand>((message) => { const debounceSocketSend = throttle<EngineCommand>((message) => {
@ -226,7 +248,7 @@ export function App() {
<Stream className="absolute inset-0 z-0" /> <Stream className="absolute inset-0 z-0" />
{showDebugPanel && ( {showDebugPanel && (
<DebugPanel <DebugPanel
title="Debug (AST Explorer)" title="Debug"
className={ className={
'transition-opacity transition-duration-75 ' + 'transition-opacity transition-duration-75 ' +
paneOpacity + paneOpacity +

View File

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

View File

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

View File

@ -1,7 +1,29 @@
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel' 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 { 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) => { 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 ( return (
<CollapsiblePanel <CollapsiblePanel
{...props} {...props}
@ -12,6 +34,67 @@ export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
style={{ maxHeight: 'calc(100% - 3rem - 1.25rem - 1.25rem)' }} style={{ maxHeight: 'calc(100% - 3rem - 1.25rem - 1.25rem)' }}
> >
<section className="p-4 flex flex-col gap-4"> <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"> <div style={{ height: '400px' }} className="overflow-y-auto">
<AstExplorer /> <AstExplorer />
</div> </div>
@ -19,3 +102,41 @@ export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
</CollapsiblePanel> </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,6 +9,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons' import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { useFileContext } from 'hooks/useFileContext' import { useFileContext } from 'hooks/useFileContext'
import { useHotkeys } from 'react-hotkeys-hook' import { useHotkeys } from 'react-hotkeys-hook'
import { kclManager } from 'lang/KclSinglton'
import styles from './FileTree.module.css' import styles from './FileTree.module.css'
import { sortProject } from 'lib/tauriFS' import { sortProject } from 'lib/tauriFS'
@ -162,6 +163,7 @@ const FileTreeItem = ({
function openFile() { function openFile() {
if (fileOrDir.children !== undefined) return // Don't open directories if (fileOrDir.children !== undefined) return // Don't open directories
kclManager.setCode('')
navigate(`${paths.FILE}/${encodeURIComponent(fileOrDir.path)}`) navigate(`${paths.FILE}/${encodeURIComponent(fileOrDir.path)}`)
closePanel() closePanel()
} }

View File

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

View File

@ -108,7 +108,7 @@ export const SetAngleLengthModal = ({
</label> </label>
<div className="mt-1 flex"> <div className="mt-1 flex">
<button <button
className="border border-gray-300 px-2 text-gray-900" className="border border-gray-300 px-2"
onClick={() => setSign(-sign)} onClick={() => setSign(-sign)}
> >
{sign > 0 ? '+' : '-'} {sign > 0 ? '+' : '-'}
@ -118,7 +118,7 @@ export const SetAngleLengthModal = ({
type="text" type="text"
name="val" name="val"
id="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 text-gray-900" 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"
value={value} value={value}
onChange={(e) => { onChange={(e) => {
setValue(e.target.value) setValue(e.target.value)

View File

@ -87,7 +87,7 @@ export const GetInfoModal = ({
leaveFrom="opacity-100 scale-100" leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95" leaveTo="opacity-0 scale-95"
> >
<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.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.Title <Dialog.Title
as="h3" as="h3"
className="text-lg font-medium leading-6 text-gray-900" className="text-lg font-medium leading-6 text-gray-900"
@ -109,7 +109,7 @@ export const GetInfoModal = ({
</label> </label>
<div className="mt-1 flex"> <div className="mt-1 flex">
<button <button
className="border border-gray-400 px-2 mr-1 text-gray-900" className="border border-gray-300 px-2 mr-1"
onClick={() => setSign(-sign)} onClick={() => setSign(-sign)}
> >
{sign > 0 ? '+' : '-'} {sign > 0 ? '+' : '-'}
@ -119,7 +119,7 @@ export const GetInfoModal = ({
name="val" name="val"
id="val" id="val"
ref={inputRef} ref={inputRef}
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" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono"
value={value} value={value}
onChange={(e) => { onChange={(e) => {
setValue(e.target.value) setValue(e.target.value)
@ -139,7 +139,7 @@ export const GetInfoModal = ({
name="segName" name="segName"
id="segName" id="segName"
disabled={!isSegNameEditable} disabled={!isSegNameEditable}
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" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono"
value={segName} value={segName}
onChange={(e) => { onChange={(e) => {
setSegName(e.target.value) 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 { CameraDragInteractionType_type } from '@kittycad/lib/dist/types/src/models'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { getNodeFromPath } from 'lang/queryAst' import { getNodeFromPath } from 'lang/queryAst'
import { VariableDeclarator, recast, CallExpression } from 'lang/wasm' import { VariableDeclarator, recast, parse, CallExpression } from 'lang/wasm'
import { engineCommandManager } from '../lang/std/engineConnection' import { engineCommandManager } from '../lang/std/engineConnection'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { kclManager, useKclContext } from 'lang/KclSinglton' import { kclManager, useKclContext } from 'lang/KclSinglton'
@ -342,8 +342,7 @@ export const Stream = ({ className = '' }) => {
// update artifact map ranges now that we have updated the ast. // update artifact map ranges now that we have updated the ast.
code = recast(modded.modifiedAst) code = recast(modded.modifiedAst)
const astWithCurrentRanges = kclManager.safeParse(code) const astWithCurrentRanges = parse(code)
if (!astWithCurrentRanges) return
const updateNode = getNodeFromPath<CallExpression>( const updateNode = getNodeFromPath<CallExpression>(
astWithCurrentRanges, astWithCurrentRanges,
modded.pathToNode modded.pathToNode

View File

@ -17,7 +17,15 @@ import { useStore } from 'useStore'
import { processCodeMirrorRanges } from 'lib/selections' import { processCodeMirrorRanges } from 'lib/selections'
import { LanguageServerClient } from 'editor/lsp' import { LanguageServerClient } from 'editor/lsp'
import kclLanguage from 'editor/lsp/language' import kclLanguage from 'editor/lsp/language'
import { EditorView, lineHighlightField } from 'editor/highlightextension' 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 { roundOff } from 'lib/utils' import { roundOff } from 'lib/utils'
import { kclErrToDiagnostic } from 'lang/errors' import { kclErrToDiagnostic } from 'lang/errors'
import { CSSRuleObject } from 'tailwindcss/types/config' import { CSSRuleObject } from 'tailwindcss/types/config'
@ -42,6 +50,7 @@ export const TextEditor = ({
}: { }: {
theme: Themes.Light | Themes.Dark theme: Themes.Light | Themes.Dark
}) => { }) => {
const pathParams = useParams()
const { editorView, isLSPServerReady, setEditorView, setIsLSPServerReady } = const { editorView, isLSPServerReady, setEditorView, setIsLSPServerReady } =
useStore((s) => ({ useStore((s) => ({
editorView: s.editorView, editorView: s.editorView,
@ -83,7 +92,7 @@ export const TextEditor = ({
// Here we initialize the plugin which will start the client. // 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 // 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 // this use memo, as well as the directory structure, which I think is
// a good setup because it will restart the client but not the server :) // a good setup becuase it will restart the client but not the server :)
// We do not want to restart the server, its just wasteful. // We do not want to restart the server, its just wasteful.
const kclLSP = useMemo(() => { const kclLSP = useMemo(() => {
let plugin = null let plugin = null
@ -104,6 +113,18 @@ export const TextEditor = ({
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => { // const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
const onChange = (newCode: string) => { const onChange = (newCode: string) => {
kclManager.setCodeAndExecute(newCode) 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) => { const onUpdate = (viewUpdate: ViewUpdate) => {
if (!editorView) { if (!editorView) {

View File

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

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ describe('testing AST', () => {
type: 'Literal', type: 'Literal',
start: 0, start: 0,
end: 1, end: 1,
value: 5, value: { type: 'i_integer', data: 5 },
raw: '5', raw: '5',
}, },
operator: '+', operator: '+',
@ -28,7 +28,7 @@ describe('testing AST', () => {
type: 'Literal', type: 'Literal',
start: 3, start: 3,
end: 4, end: 4,
value: 6, value: { type: 'i_integer', data: 6 },
raw: '6', raw: '6',
}, },
}, },
@ -58,7 +58,7 @@ describe('testing AST', () => {
type: 'Literal', type: 'Literal',
start: 14, start: 14,
end: 15, end: 15,
value: 5, value: { type: 'i_integer', data: 5 },
raw: '5', raw: '5',
}, },
}, },
@ -92,7 +92,7 @@ const newVar = myVar + 1
type: 'Literal', type: 'Literal',
start: 14, start: 14,
end: 15, end: 15,
value: 5, value: { type: 'i_integer', data: 5 },
raw: '5', raw: '5',
}, },
}, },
@ -129,7 +129,7 @@ const newVar = myVar + 1
type: 'Literal', type: 'Literal',
start: 39, start: 39,
end: 40, end: 40,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
}, },
@ -169,24 +169,16 @@ describe('testing function declaration', () => {
end: 39, end: 39,
params: [ params: [
{ {
type: 'Parameter', type: 'Identifier',
identifier: { start: 12,
type: 'Identifier', end: 13,
start: 12, name: 'a',
end: 13,
name: 'a',
},
optional: false,
}, },
{ {
type: 'Parameter', type: 'Identifier',
identifier: { start: 15,
type: 'Identifier', end: 16,
start: 15, name: 'b',
end: 16,
name: 'b',
},
optional: false,
}, },
], ],
body: { body: {
@ -252,24 +244,16 @@ const myVar = funcN(1, 2)`
end: 37, end: 37,
params: [ params: [
{ {
type: 'Parameter', type: 'Identifier',
identifier: { start: 12,
type: 'Identifier', end: 13,
start: 12, name: 'a',
end: 13,
name: 'a',
},
optional: false,
}, },
{ {
type: 'Parameter', type: 'Identifier',
identifier: { start: 15,
type: 'Identifier', end: 16,
start: 15, name: 'b',
end: 16,
name: 'b',
},
optional: false,
}, },
], ],
body: { body: {
@ -336,17 +320,20 @@ const myVar = funcN(1, 2)`
type: 'Literal', type: 'Literal',
start: 58, start: 58,
end: 59, end: 59,
value: 1, value: { data: 1, type: 'i_integer' },
raw: '1', raw: '1',
}, },
{ {
type: 'Literal', type: 'Literal',
start: 61, start: 61,
end: 62, end: 62,
value: 2, value: { data: 2, type: 'i_integer' },
raw: '2', raw: '2',
}, },
], ],
function: {
type: 'InMemory',
},
optional: false, optional: false,
}, },
}, },
@ -403,19 +390,20 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 32, start: 32,
end: 33, end: 33,
value: 0, value: { type: 'i_integer', data: 0 },
raw: '0', raw: '0',
}, },
{ {
type: 'Literal', type: 'Literal',
start: 35, start: 35,
end: 36, end: 36,
value: 0, value: { type: 'i_integer', data: 0 },
raw: '0', raw: '0',
}, },
], ],
}, },
], ],
function: expect.any(Object),
optional: false, optional: false,
}, },
{ {
@ -438,20 +426,21 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 52, start: 52,
end: 53, end: 53,
value: 2, value: { type: 'i_integer', data: 2 },
raw: '2', raw: '2',
}, },
{ {
type: 'Literal', type: 'Literal',
start: 55, start: 55,
end: 56, end: 56,
value: 3, value: { type: 'i_integer', data: 3 },
raw: '3', raw: '3',
}, },
], ],
}, },
{ type: 'PipeSubstitution', start: 59, end: 60 }, { type: 'PipeSubstitution', start: 59, end: 60 },
], ],
function: expect.any(Object),
optional: false, optional: false,
}, },
{ {
@ -489,14 +478,14 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 81, start: 81,
end: 82, end: 82,
value: 0, value: { type: 'i_integer', data: 0 },
raw: '0', raw: '0',
}, },
{ {
type: 'Literal', type: 'Literal',
start: 84, start: 84,
end: 85, end: 85,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
], ],
@ -516,7 +505,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 93, start: 93,
end: 101, end: 101,
value: 'myPath', value: { type: 'string', data: 'myPath' },
raw: '"myPath"', raw: '"myPath"',
}, },
}, },
@ -524,6 +513,7 @@ describe('testing pipe operator special', () => {
}, },
{ type: 'PipeSubstitution', start: 105, end: 106 }, { type: 'PipeSubstitution', start: 105, end: 106 },
], ],
function: expect.any(Object),
optional: false, optional: false,
}, },
{ {
@ -546,20 +536,21 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 121, start: 121,
end: 122, end: 122,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
{ {
type: 'Literal', type: 'Literal',
start: 124, start: 124,
end: 125, end: 125,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
], ],
}, },
{ type: 'PipeSubstitution', start: 128, end: 129 }, { type: 'PipeSubstitution', start: 128, end: 129 },
], ],
function: expect.any(Object),
optional: false, optional: false,
}, },
{ {
@ -577,11 +568,14 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 139, start: 139,
end: 141, end: 141,
value: 45, value: { type: 'i_integer', data: 45 },
raw: '45', raw: '45',
}, },
{ type: 'PipeSubstitution', start: 143, end: 144 }, { type: 'PipeSubstitution', start: 143, end: 144 },
], ],
function: {
type: 'InMemory',
},
optional: false, optional: false,
}, },
], ],
@ -625,7 +619,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 14, start: 14,
end: 15, end: 15,
value: 5, value: { type: 'i_integer', data: 5 },
raw: '5', raw: '5',
}, },
operator: '+', operator: '+',
@ -633,7 +627,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 18, start: 18,
end: 19, end: 19,
value: 6, value: { type: 'i_integer', data: 6 },
raw: '6', raw: '6',
}, },
}, },
@ -652,7 +646,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 30, start: 30,
end: 32, end: 32,
value: 45, value: { type: 'i_integer', data: 45 },
raw: '45', raw: '45',
}, },
{ {
@ -661,6 +655,9 @@ describe('testing pipe operator special', () => {
end: 35, end: 35,
}, },
], ],
function: {
type: 'InMemory',
},
optional: false, optional: false,
}, },
], ],
@ -699,14 +696,14 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 12, start: 12,
end: 13, end: 13,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
{ {
type: 'Literal', type: 'Literal',
start: 15, start: 15,
end: 18, end: 18,
value: '2', value: { type: 'string', data: '2' },
raw: "'2'", raw: "'2'",
}, },
{ {
@ -723,7 +720,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 27, start: 27,
end: 28, end: 28,
value: 4, value: { type: 'i_integer', data: 4 },
raw: '4', raw: '4',
}, },
operator: '+', operator: '+',
@ -731,7 +728,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 31, start: 31,
end: 32, end: 32,
value: 5, value: { type: 'i_integer', data: 5 },
raw: '5', raw: '5',
}, },
}, },
@ -769,7 +766,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 14, start: 14,
end: 15, end: 15,
value: 3, value: { type: 'i_integer', data: 3 },
raw: '3', raw: '3',
}, },
}, },
@ -810,7 +807,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 34, start: 34,
end: 39, end: 39,
value: 'str', value: { type: 'string', data: 'str' },
raw: "'str'", raw: "'str'",
}, },
}, },
@ -828,7 +825,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 47, start: 47,
end: 48, end: 48,
value: 2, value: { type: 'i_integer', data: 2 },
raw: '2', raw: '2',
}, },
}, },
@ -867,7 +864,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 77, start: 77,
end: 78, end: 78,
value: 4, value: { type: 'i_integer', data: 4 },
raw: '4', raw: '4',
}, },
operator: '+', operator: '+',
@ -875,7 +872,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 81, start: 81,
end: 82, end: 82,
value: 5, value: { type: 'i_integer', data: 5 },
raw: '5', raw: '5',
}, },
}, },
@ -943,7 +940,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 27, start: 27,
end: 34, end: 34,
value: 'value', value: { type: 'string', data: 'value' },
raw: "'value'", raw: "'value'",
}, },
}, },
@ -1001,14 +998,14 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 18, start: 18,
end: 19, end: 19,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
{ {
type: 'Literal', type: 'Literal',
start: 21, start: 21,
end: 24, end: 24,
value: '2', value: { type: 'string', data: '2' },
raw: "'2'", raw: "'2'",
}, },
], ],
@ -1123,7 +1120,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 20, start: 20,
end: 25, end: 25,
value: 'two', value: { type: 'string', data: 'two' },
raw: '"two"', raw: '"two"',
}, },
}, },
@ -1172,7 +1169,7 @@ describe('testing pipe operator special', () => {
type: 'Literal', type: 'Literal',
start: 16, start: 16,
end: 21, end: 21,
value: 'one', value: { type: 'string', data: 'one' },
raw: '"one"', raw: '"one"',
}, },
}, },
@ -1218,7 +1215,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 11, start: 11,
end: 12, end: 12,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
operator: '+', operator: '+',
@ -1226,7 +1223,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 15, start: 15,
end: 16, end: 16,
value: 2, value: { type: 'i_integer', data: 2 },
raw: '2', raw: '2',
}, },
}, },
@ -1266,7 +1263,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 11, start: 11,
end: 12, end: 12,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
operator: '*', operator: '*',
@ -1274,7 +1271,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 15, start: 15,
end: 16, end: 16,
value: 2, value: { type: 'i_integer', data: 2 },
raw: '2', raw: '2',
}, },
}, },
@ -1283,7 +1280,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 19, start: 19,
end: 20, end: 20,
value: 3, value: { type: 'i_integer', data: 3 },
raw: '3', raw: '3',
}, },
}, },
@ -1319,7 +1316,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 11, start: 11,
end: 12, end: 12,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
operator: '+', operator: '+',
@ -1331,7 +1328,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 15, start: 15,
end: 16, end: 16,
value: 2, value: { type: 'i_integer', data: 2 },
raw: '2', raw: '2',
}, },
operator: '*', operator: '*',
@ -1339,7 +1336,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 19, start: 19,
end: 20, end: 20,
value: 3, value: { type: 'i_integer', data: 3 },
raw: '3', raw: '3',
}, },
}, },
@ -1348,7 +1345,7 @@ describe('nests binary expressions correctly', () => {
], ],
}) })
}) })
it('should nest properly with two operators of equal precedence', () => { it('should nest properly with two opperators of equal precedence', () => {
const code = `const yo = 1 + 2 - 3` const code = `const yo = 1 + 2 - 3`
const { body } = parse(code) const { body } = parse(code)
expect((body[0] as any).declarations[0].init).toEqual({ expect((body[0] as any).declarations[0].init).toEqual({
@ -1363,7 +1360,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 11, start: 11,
end: 12, end: 12,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
operator: '+', operator: '+',
@ -1371,7 +1368,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 15, start: 15,
end: 16, end: 16,
value: 2, value: { type: 'i_integer', data: 2 },
raw: '2', raw: '2',
}, },
}, },
@ -1380,12 +1377,12 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 19, start: 19,
end: 20, end: 20,
value: 3, value: { type: 'i_integer', data: 3 },
raw: '3', raw: '3',
}, },
}) })
}) })
it('should nest properly with two operators of equal (but higher) precedence', () => { it('should nest properly with two opperators of equal (but higher) precedence', () => {
const code = `const yo = 1 * 2 / 3` const code = `const yo = 1 * 2 / 3`
const { body } = parse(code) const { body } = parse(code)
expect((body[0] as any).declarations[0].init).toEqual({ expect((body[0] as any).declarations[0].init).toEqual({
@ -1400,7 +1397,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 11, start: 11,
end: 12, end: 12,
value: 1, value: { type: 'i_integer', data: 1 },
raw: '1', raw: '1',
}, },
operator: '*', operator: '*',
@ -1408,7 +1405,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 15, start: 15,
end: 16, end: 16,
value: 2, value: { type: 'i_integer', data: 2 },
raw: '2', raw: '2',
}, },
}, },
@ -1417,7 +1414,7 @@ describe('nests binary expressions correctly', () => {
type: 'Literal', type: 'Literal',
start: 19, start: 19,
end: 20, end: 20,
value: 3, value: { type: 'i_integer', data: 3 },
raw: '3', raw: '3',
}, },
}) })
@ -1436,7 +1433,13 @@ describe('nests binary expressions correctly', () => {
operator: '+', operator: '+',
start: 11, start: 11,
end: 30, end: 30,
left: { type: 'Literal', value: 1, raw: '1', start: 11, end: 12 }, left: {
type: 'Literal',
value: { type: 'i_integer', data: 1 },
raw: '1',
start: 11,
end: 12,
},
right: { right: {
type: 'BinaryExpression', type: 'BinaryExpression',
operator: '/', operator: '/',
@ -1447,26 +1450,50 @@ describe('nests binary expressions correctly', () => {
operator: '*', operator: '*',
start: 15, start: 15,
end: 25, end: 25,
left: { type: 'Literal', value: 2, raw: '2', start: 15, end: 16 }, left: {
type: 'Literal',
value: { type: 'i_integer', data: 2 },
raw: '2',
start: 15,
end: 16,
},
right: { right: {
type: 'BinaryExpression', type: 'BinaryExpression',
operator: '-', operator: '-',
start: 20, start: 20,
end: 25, end: 25,
left: { type: 'Literal', value: 3, raw: '3', start: 20, end: 21 }, left: {
type: 'Literal',
value: { type: 'i_integer', data: 3 },
raw: '3',
start: 20,
end: 21,
},
right: { right: {
type: 'Literal', type: 'Literal',
value: 4, value: { type: 'i_integer', data: 4 },
raw: '4', raw: '4',
start: 24, start: 24,
end: 25, end: 25,
}, },
}, },
}, },
right: { type: 'Literal', value: 5, raw: '5', start: 29, end: 30 }, right: {
type: 'Literal',
value: { type: 'i_integer', data: 5 },
raw: '5',
start: 29,
end: 30,
},
}, },
}, },
right: { type: 'Literal', value: 6, raw: '6', start: 33, end: 34 }, right: {
type: 'Literal',
value: { type: 'i_integer', data: 6 },
raw: '6',
start: 33,
end: 34,
},
}) })
}) })
}) })
@ -1484,7 +1511,7 @@ const key = 'c'`
value: { value: {
type: 'blockComment', type: 'blockComment',
style: 'line', style: 'line',
value: 'this is a comment', value: { type: 'string', data: 'this is a comment' },
}, },
} }
const { nonCodeMeta } = parse(code) const { nonCodeMeta } = parse(code)
@ -1567,9 +1594,22 @@ describe('test UnaryExpression', () => {
end: 26, end: 26,
callee: { type: 'Identifier', start: 15, end: 18, name: 'min' }, callee: { type: 'Identifier', start: 15, end: 18, name: 'min' },
arguments: [ arguments: [
{ type: 'Literal', start: 19, end: 20, value: 4, raw: '4' }, {
{ type: 'Literal', start: 22, end: 25, value: 100, raw: '100' }, type: 'Literal',
start: 19,
end: 20,
value: { type: 'i_integer', data: 4 },
raw: '4',
},
{
type: 'Literal',
start: 22,
end: 25,
value: { type: 'i_integer', data: 100 },
raw: '100',
},
], ],
function: expect.any(Object),
optional: false, optional: false,
}, },
}) })
@ -1587,26 +1627,52 @@ describe('testing nested call expressions', () => {
end: 40, end: 40,
callee: { type: 'Identifier', start: 14, end: 17, name: 'min' }, callee: { type: 'Identifier', start: 14, end: 17, name: 'min' },
arguments: [ arguments: [
{ type: 'Literal', start: 18, end: 21, value: 100, raw: '100' }, {
type: 'Literal',
start: 18,
end: 21,
value: { type: 'i_integer', data: 100 },
raw: '100',
},
{ {
type: 'BinaryExpression', type: 'BinaryExpression',
operator: '+', operator: '+',
start: 23, start: 23,
end: 39, end: 39,
left: { type: 'Literal', value: 1, raw: '1', start: 23, end: 24 }, left: {
type: 'Literal',
value: { type: 'i_integer', data: 1 },
raw: '1',
start: 23,
end: 24,
},
right: { right: {
type: 'CallExpression', type: 'CallExpression',
start: 27, start: 27,
end: 39, end: 39,
callee: { type: 'Identifier', start: 27, end: 33, name: 'legLen' }, callee: { type: 'Identifier', start: 27, end: 33, name: 'legLen' },
arguments: [ arguments: [
{ type: 'Literal', start: 34, end: 35, value: 5, raw: '5' }, {
{ type: 'Literal', start: 37, end: 38, value: 3, raw: '3' }, type: 'Literal',
start: 34,
end: 35,
value: { type: 'i_integer', data: 5 },
raw: '5',
},
{
type: 'Literal',
start: 37,
end: 38,
value: { type: 'i_integer', data: 3 },
raw: '3',
},
], ],
function: expect.any(Object),
optional: false, optional: false,
}, },
}, },
], ],
function: expect.any(Object),
optional: false, optional: false,
}) })
}) })
@ -1633,14 +1699,21 @@ describe('should recognise callExpresions in binaryExpressions', () => {
type: 'Literal', type: 'Literal',
start: 16, start: 16,
end: 23, end: 23,
value: 'seg02', value: { type: 'string', data: 'seg02' },
raw: "'seg02'", raw: "'seg02'",
}, },
{ type: 'PipeSubstitution', start: 25, end: 26 }, { type: 'PipeSubstitution', start: 25, end: 26 },
], ],
function: expect.any(Object),
optional: false, optional: false,
}, },
right: { type: 'Literal', value: 1, raw: '1', start: 30, end: 31 }, right: {
type: 'Literal',
value: { type: 'i_integer', data: 1 },
raw: '1',
start: 30,
end: 31,
},
}, },
{ type: 'PipeSubstitution', start: 33, end: 34 }, { type: 'PipeSubstitution', start: 33, end: 34 },
]) ])

View File

@ -18,20 +18,6 @@ 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 { export class KCLSyntaxError extends KCLError {
constructor(msg: string, sourceRanges: [number, number][]) { constructor(msg: string, sourceRanges: [number, number][]) {
super('syntax', msg, sourceRanges) super('syntax', msg, sourceRanges)

View File

@ -1,5 +1,5 @@
import { getNodePathFromSourceRange, getNodeFromPath } from './queryAst' import { getNodePathFromSourceRange, getNodeFromPath } from './queryAst'
import { Identifier, parse, initPromise, Parameter } from './wasm' import { Identifier, parse, initPromise } from './wasm'
beforeAll(() => initPromise) beforeAll(() => initPromise)
@ -46,7 +46,7 @@ const b1 = cube([0,0], 10)`
const ast = parse(code) const ast = parse(code)
const nodePath = getNodePathFromSourceRange(ast, sourceRange) const nodePath = getNodePathFromSourceRange(ast, sourceRange)
const node = getNodeFromPath<Parameter>(ast, nodePath).node const node = getNodeFromPath<Identifier>(ast, nodePath).node
expect(nodePath).toEqual([ expect(nodePath).toEqual([
['body', ''], ['body', ''],
@ -57,8 +57,8 @@ const b1 = cube([0,0], 10)`
['params', 'FunctionExpression'], ['params', 'FunctionExpression'],
[0, 'index'], [0, 'index'],
]) ])
expect(node.type).toBe('Parameter') expect(node.type).toBe('Identifier')
expect(node.identifier.name).toBe('pos') expect(node.name).toBe('pos')
}) })
it('gets path right for deep within function definition body', () => { it('gets path right for deep within function definition body', () => {
const code = `fn cube = (pos, scale) => { const code = `fn cube = (pos, scale) => {

View File

@ -21,7 +21,7 @@ describe('Testing createLiteral', () => {
it('should create a literal', () => { it('should create a literal', () => {
const result = createLiteral(5) const result = createLiteral(5)
expect(result.type).toBe('Literal') expect(result.type).toBe('Literal')
expect(result.value).toBe(5) expect(result.value.data).toBe(5)
}) })
}) })
describe('Testing createIdentifier', () => { describe('Testing createIdentifier', () => {
@ -38,7 +38,7 @@ describe('Testing createCallExpression', () => {
expect(result.callee.type).toBe('Identifier') expect(result.callee.type).toBe('Identifier')
expect(result.callee.name).toBe('myFunc') expect(result.callee.name).toBe('myFunc')
expect(result.arguments[0].type).toBe('Literal') expect(result.arguments[0].type).toBe('Literal')
expect((result.arguments[0] as any).value).toBe(5) expect((result.arguments[0] as any).value.data).toBe(5)
}) })
}) })
describe('Testing createObjectExpression', () => { describe('Testing createObjectExpression', () => {
@ -50,7 +50,7 @@ describe('Testing createObjectExpression', () => {
expect(result.properties[0].type).toBe('ObjectProperty') expect(result.properties[0].type).toBe('ObjectProperty')
expect(result.properties[0].key.name).toBe('myProp') expect(result.properties[0].key.name).toBe('myProp')
expect(result.properties[0].value.type).toBe('Literal') expect(result.properties[0].value.type).toBe('Literal')
expect((result.properties[0].value as any).value).toBe(5) expect((result.properties[0].value as any).value.data).toBe(5)
}) })
}) })
describe('Testing createArrayExpression', () => { describe('Testing createArrayExpression', () => {
@ -58,7 +58,7 @@ describe('Testing createArrayExpression', () => {
const result = createArrayExpression([createLiteral(5)]) const result = createArrayExpression([createLiteral(5)])
expect(result.type).toBe('ArrayExpression') expect(result.type).toBe('ArrayExpression')
expect(result.elements[0].type).toBe('Literal') expect(result.elements[0].type).toBe('Literal')
expect((result.elements[0] as any).value).toBe(5) expect((result.elements[0] as any).value.data).toBe(5)
}) })
}) })
describe('Testing createPipeSubstitution', () => { describe('Testing createPipeSubstitution', () => {
@ -75,7 +75,7 @@ describe('Testing createVariableDeclaration', () => {
expect(result.declarations[0].id.type).toBe('Identifier') expect(result.declarations[0].id.type).toBe('Identifier')
expect(result.declarations[0].id.name).toBe('myVar') expect(result.declarations[0].id.name).toBe('myVar')
expect(result.declarations[0].init.type).toBe('Literal') expect(result.declarations[0].init.type).toBe('Literal')
expect((result.declarations[0].init as any).value).toBe(5) expect((result.declarations[0].init as any).value.data).toBe(5)
}) })
}) })
describe('Testing createPipeExpression', () => { describe('Testing createPipeExpression', () => {
@ -83,7 +83,7 @@ describe('Testing createPipeExpression', () => {
const result = createPipeExpression([createLiteral(5)]) const result = createPipeExpression([createLiteral(5)])
expect(result.type).toBe('PipeExpression') expect(result.type).toBe('PipeExpression')
expect(result.body[0].type).toBe('Literal') expect(result.body[0].type).toBe('Literal')
expect((result.body[0] as any).value).toBe(5) expect((result.body[0] as any).value.data).toBe(5)
}) })
}) })

View File

@ -440,11 +440,15 @@ export function splitPathAtPipeExpression(pathToNode: PathToNode): {
} }
export function createLiteral(value: string | number): Literal { export function createLiteral(value: string | number): Literal {
const literalValue =
typeof value === 'string'
? ({ type: 'string', data: value } as const)
: ({ type: 'fractional', data: value } as const)
return { return {
type: 'Literal', type: 'Literal',
start: 0, start: 0,
end: 0, end: 0,
value, value: literalValue,
raw: `${value}`, raw: `${value}`,
} }
} }
@ -480,6 +484,21 @@ export function createCallExpressionStdLib(
end: 0, end: 0,
name, 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, optional: false,
arguments: args, arguments: args,
} }
@ -499,6 +518,9 @@ export function createCallExpression(
end: 0, end: 0,
name, name,
}, },
function: {
type: 'InMemory',
},
optional: false, optional: false,
arguments: args, arguments: args,
} }
@ -623,7 +645,7 @@ export function giveSketchFnCallTag(
const isTagExisting = !!firstArg.tag const isTagExisting = !!firstArg.tag
const tagValue = (firstArg.tag || const tagValue = (firstArg.tag ||
createLiteral(tag || findUniqueName(ast, 'seg', 2))) as Literal createLiteral(tag || findUniqueName(ast, 'seg', 2))) as Literal
const tagStr = String(tagValue.value) const tagStr = String(tagValue.value.data)
const newFirstArg = createFirstArg( const newFirstArg = createFirstArg(
primaryCallExp.callee.name as ToolTip, primaryCallExp.callee.name as ToolTip,
firstArg.val, firstArg.val,

View File

@ -247,10 +247,10 @@ function moreNodePathFromSourceRange(
if (_node.type === 'FunctionExpression' && isInRange) { if (_node.type === 'FunctionExpression' && isInRange) {
for (let i = 0; i < _node.params.length; i++) { for (let i = 0; i < _node.params.length; i++) {
const param = _node.params[i] const param = _node.params[i]
if (param.identifier.start <= start && param.identifier.end >= end) { if (param.start <= start && param.end >= end) {
path.push(['params', 'FunctionExpression']) path.push(['params', 'FunctionExpression'])
path.push([i, 'index']) path.push([i, 'index'])
return moreNodePathFromSourceRange(param.identifier, sourceRange, path) return moreNodePathFromSourceRange(param, sourceRange, path)
} }
} }
if (_node.body.start <= start && _node.body.end >= end) { if (_node.body.start <= start && _node.body.end >= end) {

View File

@ -2,5 +2,5 @@ The std is as expected, tools that are provided with the language.
For this language that means functions. For this language that means functions.
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, 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,
So it makes sense to group some of these together. So it makes sense to group some of these together.

View File

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

View File

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

View File

@ -50,7 +50,7 @@ async function testingSwapSketchFnCall({
} }
} }
describe('testing swapping out sketch calls with xLine/xLineTo', () => { describe('testing swaping out sketch calls with xLine/xLineTo', () => {
const bigExampleArr = [ const bigExampleArr = [
`const part001 = startSketchOn('XY')`, `const part001 = startSketchOn('XY')`,
` |> startProfileAt([0, 0], %)`, ` |> startProfileAt([0, 0], %)`,
@ -178,7 +178,7 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
constraintType: 'horizontal', constraintType: 'horizontal',
}) })
const expectedLine = "xLine({ length: -0.86, tag: 'abc4' }, %)" 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 compatible `-myVar` // hmm "-0.86" is correct since the angle is 104, but need to make sure this is compatiable `-myVar`
expect(newCode).toContain(expectedLine) expect(newCode).toContain(expectedLine)
// new line should start at the same place as the old line // new line should start at the same place as the old line
expect(originalRange[0]).toBe(newCode.indexOf(expectedLine)) expect(originalRange[0]).toBe(newCode.indexOf(expectedLine))
@ -268,7 +268,7 @@ describe('testing swapping out sketch calls with xLine/xLineTo', () => {
}) })
}) })
describe('testing swapping out sketch calls with xLine/xLineTo while keeping variable/identifiers intact', () => { describe('testing swaping out sketch calls with xLine/xLineTo while keeping variable/identifiers intact', () => {
// Enable rotations #152 // Enable rotations #152
const variablesExampleArr = [ const variablesExampleArr = [
`const lineX = -1`, `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-should use legLen for y
|> line([myVar, -1], %) // ln-legLen but negative |> line([myVar, -1], %) // ln-legLen but negative
|> line([-0.62, -1.54], %) // ln-should become angledLine |> line([-0.62, -1.54], %) // ln-should become angledLine
|> angledLine([myVar, 1.04], %) // ln-use segLen for second arg |> angledLine([myVar, 1.04], %) // ln-use segLen for secound arg
|> angledLine([45, 1.04], %) // ln-segLen again |> angledLine([45, 1.04], %) // ln-segLen again
|> angledLineOfXLength([54, 2.35], %) // ln-should be transformed to angledLine |> angledLineOfXLength([54, 2.35], %) // ln-should be transformed to angledLine
|> angledLineOfXLength([50, myVar], %) // ln-should use legAngX to calculate angle |> angledLineOfXLength([50, myVar], %) // ln-should use legAngX to calculate angle
@ -163,7 +163,7 @@ const part001 = startSketchOn('XY')
-legLen(segLen('seg01', %), myVar) -legLen(segLen('seg01', %), myVar)
], %) // ln-legLen but negative ], %) // ln-legLen but negative
|> angledLine([-112, segLen('seg01', %)], %) // ln-should become angledLine |> angledLine([-112, segLen('seg01', %)], %) // ln-should become angledLine
|> angledLine([myVar, segLen('seg01', %)], %) // ln-use segLen for second arg |> angledLine([myVar, segLen('seg01', %)], %) // ln-use segLen for secound arg
|> angledLine([45, segLen('seg01', %)], %) // ln-segLen again |> angledLine([45, segLen('seg01', %)], %) // ln-segLen again
|> angledLine([54, segLen('seg01', %)], %) // ln-should be transformed to angledLine |> angledLine([54, segLen('seg01', %)], %) // ln-should be transformed to angledLine
|> angledLineOfXLength([ |> angledLineOfXLength([
@ -471,7 +471,7 @@ async function helperThing(
} }
describe('testing getConstraintLevelFromSourceRange', () => { describe('testing getConstraintLevelFromSourceRange', () => {
it('should divide up lines into free, partial and fully contrained', () => { it('should devide up lines into free, partial and fully contrained', () => {
const code = `const baseLength = 3 const code = `const baseLength = 3
const baseThick = 1 const baseThick = 1
const armThick = 0.5 const armThick = 0.5

View File

@ -1426,7 +1426,7 @@ export function transformAstSketchLines({
referenceSegName || referenceSegName ||
(_referencedSegmentNameVal && (_referencedSegmentNameVal &&
_referencedSegmentNameVal.type === 'Literal' && _referencedSegmentNameVal.type === 'Literal' &&
String(_referencedSegmentNameVal.value)) || String(_referencedSegmentNameVal.value.data)) ||
'' ''
const [varValA, varValB] = Array.isArray(val) ? val : [val, val] const [varValA, varValB] = Array.isArray(val) ? val : [val, val]

View File

@ -20,7 +20,6 @@ export type { ObjectExpression } from '../wasm-lib/kcl/bindings/ObjectExpression
export type { MemberExpression } from '../wasm-lib/kcl/bindings/MemberExpression' export type { MemberExpression } from '../wasm-lib/kcl/bindings/MemberExpression'
export type { PipeExpression } from '../wasm-lib/kcl/bindings/PipeExpression' export type { PipeExpression } from '../wasm-lib/kcl/bindings/PipeExpression'
export type { VariableDeclaration } from '../wasm-lib/kcl/bindings/VariableDeclaration' export type { VariableDeclaration } from '../wasm-lib/kcl/bindings/VariableDeclaration'
export type { Parameter } from '../wasm-lib/kcl/bindings/Parameter'
export type { PipeSubstitution } from '../wasm-lib/kcl/bindings/PipeSubstitution' export type { PipeSubstitution } from '../wasm-lib/kcl/bindings/PipeSubstitution'
export type { Identifier } from '../wasm-lib/kcl/bindings/Identifier' export type { Identifier } from '../wasm-lib/kcl/bindings/Identifier'
export type { UnaryExpression } from '../wasm-lib/kcl/bindings/UnaryExpression' export type { UnaryExpression } from '../wasm-lib/kcl/bindings/UnaryExpression'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@ -157,7 +157,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -168,7 +168,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -447,9 +447,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.8" version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -457,9 +457,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.4.8" version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -479,7 +479,7 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -681,29 +681,6 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "databake"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82175d72e69414ceafbe2b49686794d3a8bed846e0d50267355f83ea8fdd953a"
dependencies = [
"databake-derive",
"proc-macro2",
"quote",
]
[[package]]
name = "databake-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"synstructure",
]
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.3.9" version = "0.3.9"
@ -725,7 +702,7 @@ dependencies = [
"quote", "quote",
"serde", "serde",
"serde_tokenstream", "serde_tokenstream",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -739,7 +716,7 @@ dependencies = [
"quote", "quote",
"serde", "serde",
"serde_tokenstream", "serde_tokenstream",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -998,7 +975,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -1328,20 +1305,6 @@ dependencies = [
"serde", "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]] [[package]]
name = "instant" name = "instant"
version = "0.1.12" version = "0.1.12"
@ -1382,9 +1345,9 @@ dependencies = [
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.12.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [ dependencies = [
"either", "either",
] ]
@ -1406,9 +1369,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.65" version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -1426,7 +1389,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-lib" name = "kcl-lib"
version = "0.1.37" version = "0.1.35"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-recursion", "async-recursion",
@ -1435,12 +1398,10 @@ dependencies = [
"clap", "clap",
"criterion", "criterion",
"dashmap", "dashmap",
"databake",
"derive-docs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "derive-docs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"expectorate", "expectorate",
"futures", "futures",
"insta", "itertools 0.11.0",
"itertools 0.12.0",
"js-sys", "js-sys",
"kittycad", "kittycad",
"lazy_static", "lazy_static",
@ -1462,23 +1423,11 @@ dependencies = [
"winnow", "winnow",
] ]
[[package]]
name = "kcl-macros"
version = "0.1.0"
dependencies = [
"databake",
"kcl-lib",
"pretty_assertions",
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]] [[package]]
name = "kittycad" name = "kittycad"
version = "0.2.43" version = "0.2.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ab6de34cc4ab06519d65a613d4030ade14036ac619d8fee5ce6f35d1766c11" checksum = "874914cd40bfd43674406683bb3f0924d41780698a4ade96f2e180a73678bdd1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1783,7 +1732,7 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]] [[package]]
name = "openapitor" name = "openapitor"
version = "0.0.9" version = "0.0.9"
source = "git+https://github.com/KittyCAD/kittycad.rs?branch=main#9caff1f4f00c64632ff5a226251e3dc68210b455" source = "git+https://github.com/KittyCAD/kittycad.rs?branch=main#1b2562f4b3ecd26a3683c3fc48a0d33707097a36"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"anyhow", "anyhow",
@ -1929,7 +1878,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.7.5", "regex-syntax 0.7.5",
"structmeta", "structmeta",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -1953,7 +1902,7 @@ dependencies = [
"bincode", "bincode",
"either", "either",
"fnv", "fnv",
"itertools 0.10.5", "itertools 0.11.0",
"lazy_static", "lazy_static",
"nom", "nom",
"quick-xml", "quick-xml",
@ -1982,7 +1931,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -2520,9 +2469,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.16" version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"bytes", "bytes",
@ -2537,9 +2486,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.16" version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2594,9 +2543,9 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.192" version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -2612,13 +2561,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.192" version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -2652,7 +2601,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -2673,7 +2622,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde", "serde",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -2884,7 +2833,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive", "structmeta-derive",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -2895,7 +2844,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -2933,27 +2882,15 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.39" version = "2.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-ident", "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]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.5.1" version = "0.5.1"
@ -3056,7 +2993,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -3138,9 +3075,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.34.0" version = "1.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -3157,13 +3094,13 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.2.0" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -3304,7 +3241,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -3332,7 +3269,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -3418,7 +3355,7 @@ dependencies = [
"Inflector", "Inflector",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
"termcolor", "termcolor",
] ]
@ -3503,12 +3440,6 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]] [[package]]
name = "unsafe-libyaml" name = "unsafe-libyaml"
version = "0.2.9" version = "0.2.9"
@ -3547,9 +3478,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.6.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c58fe91d841bc04822c9801002db4ea904b9e4b8e6bbad25127b46eff8dc516b" checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
dependencies = [ dependencies = [
"atomic", "atomic",
"getrandom", "getrandom",
@ -3602,9 +3533,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.88" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@ -3612,24 +3543,24 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.88" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.38" version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"futures-core", "futures-core",
@ -3640,9 +3571,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.88" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -3650,22 +3581,22 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.88" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.88" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]] [[package]]
name = "wasm-lib" name = "wasm-lib"
@ -3722,9 +3653,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.65" version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -3916,9 +3847,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.19" version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -3974,7 +3905,7 @@ checksum = "6b6093bc6d5265ff40b479c834cdd25d8e20784781a2a29a8106327393d0a9ff"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.39", "syn 2.0.38",
] ]
[[package]] [[package]]

View File

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

View File

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

View File

@ -1,22 +0,0 @@
[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.7"
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

@ -1,23 +0,0 @@
//! This crate contains macros for parsing KCL at Rust compile-time.
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

@ -1,38 +0,0 @@
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

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

View File

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

View File

@ -3,26 +3,23 @@
use std::{collections::HashMap, fmt::Write}; use std::{collections::HashMap, fmt::Write};
use anyhow::Result; use anyhow::Result;
use databake::*;
use parse_display::{Display, FromStr}; use parse_display::{Display, FromStr};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{Map, Value as JValue}; use serde_json::Map;
use serde_json::Value as JValue;
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, DocumentSymbol, Range as LspRange, SymbolKind}; use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, DocumentSymbol, Range as LspRange, SymbolKind};
pub use self::literal_value::LiteralValue; pub use self::literal_value::LiteralValue;
use crate::{ use crate::{
docs::StdLibFn,
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{BodyType, ExecutorContext, MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange, UserVal}, executor::{ExecutorContext, MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange, UserVal},
parser::PIPE_OPERATOR, parser::PIPE_OPERATOR,
std::{kcl_stdlib::KclStdLibFn, FunctionKind},
}; };
mod literal_value; mod literal_value;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Program { pub struct Program {
@ -221,11 +218,11 @@ impl Program {
if let Some(Value::FunctionExpression(ref mut function_expression)) = &mut value { if let Some(Value::FunctionExpression(ref mut function_expression)) = &mut value {
// Check if the params to the function expression contain the position. // Check if the params to the function expression contain the position.
for param in &mut function_expression.params { for param in &mut function_expression.params {
let param_source_range: SourceRange = (&param.identifier).into(); let param_source_range: SourceRange = param.clone().into();
if param_source_range.contains(pos) { if param_source_range.contains(pos) {
let old_name = param.identifier.name.clone(); let old_name = param.name.clone();
// Rename the param. // Rename the param.
param.identifier.rename(&old_name, new_name); param.rename(&old_name, new_name);
// Now rename all the identifiers in the rest of the program. // Now rename all the identifiers in the rest of the program.
function_expression.body.rename_identifiers(&old_name, new_name); function_expression.body.rename_identifiers(&old_name, new_name);
return; return;
@ -351,8 +348,7 @@ macro_rules! impl_value_meta {
pub(crate) use impl_value_meta; pub(crate) use impl_value_meta;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum BodyItem { pub enum BodyItem {
@ -391,8 +387,7 @@ impl From<&BodyItem> for SourceRange {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Value { pub enum Value {
@ -555,8 +550,7 @@ impl From<&Value> for SourceRange {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum BinaryPart { pub enum BinaryPart {
@ -712,8 +706,7 @@ impl BinaryPart {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct NonCodeNode { pub struct NonCodeNode {
@ -761,8 +754,7 @@ impl NonCodeNode {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub enum CommentStyle { pub enum CommentStyle {
@ -772,8 +764,7 @@ pub enum CommentStyle {
Block, Block,
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type", rename_all = "camelCase")] #[serde(tag = "type", rename_all = "camelCase")]
pub enum NonCodeValue { pub enum NonCodeValue {
@ -793,7 +784,7 @@ pub enum NonCodeValue {
/// 1 + 1 /// 1 + 1
/// ``` /// ```
/// Now this is important. The block comment is attached to the next line. /// Now this is important. The block comment is attached to the next line.
/// This is always the case. Also the block comment doesn't have a new line above it. /// This is always the case. Also the block comment doesnt have a new line above it.
/// If it did it would be a `NewLineBlockComment`. /// If it did it would be a `NewLineBlockComment`.
BlockComment { BlockComment {
value: String, value: String,
@ -810,8 +801,7 @@ pub enum NonCodeValue {
NewLine, NewLine,
} }
#[derive(Debug, Default, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Default, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct NonCodeMeta { pub struct NonCodeMeta {
@ -852,8 +842,7 @@ impl NonCodeMeta {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct ExpressionStatement { pub struct ExpressionStatement {
@ -864,8 +853,7 @@ pub struct ExpressionStatement {
impl_value_meta!(ExpressionStatement); impl_value_meta!(ExpressionStatement);
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct CallExpression { pub struct CallExpression {
@ -874,6 +862,7 @@ pub struct CallExpression {
pub callee: Identifier, pub callee: Identifier,
pub arguments: Vec<Value>, pub arguments: Vec<Value>,
pub optional: bool, pub optional: bool,
pub function: Function,
} }
impl_value_meta!(CallExpression); impl_value_meta!(CallExpression);
@ -886,12 +875,22 @@ impl From<CallExpression> for Value {
impl CallExpression { impl CallExpression {
pub fn new(name: &str, arguments: Vec<Value>) -> Result<Self, KclError> { 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 { Ok(Self {
start: 0, start: 0,
end: 0, end: 0,
callee: Identifier::new(name), callee: Identifier::new(name),
arguments, arguments,
optional: false, optional: false,
function: Function::StdLib { func },
}) })
} }
@ -973,8 +972,8 @@ impl CallExpression {
fn_args.push(result); fn_args.push(result);
} }
match ctx.stdlib.get_either(&self.callee.name) { match &self.function {
FunctionKind::Core(func) => { Function::StdLib { func } => {
// Attempt to call the function. // Attempt to call the function.
let args = crate::std::Args::new(fn_args, self.into(), ctx.clone()); let args = crate::std::Args::new(fn_args, self.into(), ctx.clone());
let result = func.std_lib_fn()(args).await?; let result = func.std_lib_fn()(args).await?;
@ -986,58 +985,14 @@ impl CallExpression {
Ok(result) Ok(result)
} }
} }
FunctionKind::Std(func) => { Function::InMemory => {
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.identifier.name,
fn_args.get(index).unwrap().clone(),
param.identifier.clone().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 func = memory.get(&fn_name, self.into())?;
let result = func let result = func
.call_fn(fn_args, memory.clone(), ctx.clone()) .call_fn(fn_args, memory.clone(), ctx.clone())
.await? .await?
.ok_or_else(|| { .ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails { KclError::UndefinedValue(KclErrorDetails {
message: format!("Result of user-defined function {} is undefined", fn_name), message: format!("Result of function {} is undefined", fn_name),
source_ranges: vec![self.into()], source_ranges: vec![self.into()],
}) })
})?; })?;
@ -1112,15 +1067,10 @@ impl CallExpression {
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Function { pub enum Function {
/// A stdlib function written in Rust (aka core lib). /// A stdlib function.
StdLib { StdLib {
/// The function. /// The function.
func: Box<dyn StdLibFn>, func: Box<dyn crate::docs::StdLibFn>,
},
/// A stdlib function written in KCL.
StdLibKcl {
/// The function.
func: Box<dyn KclStdLibFn>,
}, },
/// A function that is defined in memory. /// A function that is defined in memory.
#[default] #[default]
@ -1137,8 +1087,7 @@ impl PartialEq for Function {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct VariableDeclaration { pub struct VariableDeclaration {
@ -1241,10 +1190,10 @@ impl VariableDeclaration {
symbol_kind = SymbolKind::FUNCTION; symbol_kind = SymbolKind::FUNCTION;
let mut children = vec![]; let mut children = vec![];
for param in &function_expression.params { for param in &function_expression.params {
let param_source_range: SourceRange = (&param.identifier).into(); let param_source_range: SourceRange = param.into();
#[allow(deprecated)] #[allow(deprecated)]
children.push(DocumentSymbol { children.push(DocumentSymbol {
name: param.identifier.name.clone(), name: param.name.clone(),
detail: None, detail: None,
kind: SymbolKind::VARIABLE, kind: SymbolKind::VARIABLE,
range: param_source_range.to_lsp_range(code), range: param_source_range.to_lsp_range(code),
@ -1288,8 +1237,7 @@ impl VariableDeclaration {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
#[display(style = "snake_case")] #[display(style = "snake_case")]
@ -1333,8 +1281,7 @@ impl VariableKind {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct VariableDeclarator { pub struct VariableDeclarator {
@ -1363,8 +1310,7 @@ impl VariableDeclarator {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct Literal { pub struct Literal {
@ -1434,8 +1380,7 @@ impl From<&Box<Literal>> for MemoryItem {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake, Eq)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct Identifier { pub struct Identifier {
@ -1471,8 +1416,7 @@ impl Identifier {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct PipeSubstitution { pub struct PipeSubstitution {
@ -1500,8 +1444,7 @@ impl From<PipeSubstitution> for Value {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct ArrayExpression { pub struct ArrayExpression {
@ -1661,8 +1604,7 @@ impl ArrayExpression {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct ObjectExpression { pub struct ObjectExpression {
@ -1819,8 +1761,7 @@ impl ObjectExpression {
impl_value_meta!(ObjectExpression); impl_value_meta!(ObjectExpression);
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct ObjectProperty { pub struct ObjectProperty {
@ -1862,8 +1803,7 @@ impl ObjectProperty {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum MemberObject { pub enum MemberObject {
@ -1909,8 +1849,7 @@ impl From<&MemberObject> for SourceRange {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum LiteralIdentifier { pub enum LiteralIdentifier {
@ -1946,8 +1885,7 @@ impl From<&LiteralIdentifier> for SourceRange {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct MemberExpression { pub struct MemberExpression {
@ -2110,8 +2048,7 @@ pub struct ObjectKeyInfo {
pub computed: bool, pub computed: bool,
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct BinaryExpression { pub struct BinaryExpression {
@ -2290,8 +2227,7 @@ 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, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
#[display(style = "snake_case")] #[display(style = "snake_case")]
@ -2359,8 +2295,7 @@ impl BinaryOperator {
} }
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct UnaryExpression { pub struct UnaryExpression {
@ -2438,8 +2373,7 @@ impl UnaryExpression {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, FromStr, Display)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
#[display(style = "snake_case")] #[display(style = "snake_case")]
@ -2454,8 +2388,7 @@ pub enum UnaryOperator {
Not, Not,
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase", tag = "type")] #[serde(rename_all = "camelCase", tag = "type")]
pub struct PipeExpression { pub struct PipeExpression {
@ -2613,26 +2546,13 @@ async fn execute_pipe_body(
} }
} }
/// Parameter of a KCL 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 Parameter {
/// The parameter's label or name.
pub identifier: Identifier,
/// Is the parameter optional?
pub optional: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct FunctionExpression { pub struct FunctionExpression {
pub start: usize, pub start: usize,
pub end: usize, pub end: usize,
pub params: Vec<Parameter>, pub params: Vec<Identifier>,
pub body: Program, pub body: Program,
} }
@ -2658,7 +2578,7 @@ impl FunctionExpression {
"({}) => {{\n{}{}\n}}", "({}) => {{\n{}{}\n}}",
self.params self.params
.iter() .iter()
.map(|param| param.identifier.name.clone()) .map(|param| param.name.clone())
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", "), .join(", "),
options.get_indentation(indentation_level + 1), options.get_indentation(indentation_level + 1),
@ -2676,8 +2596,7 @@ impl FunctionExpression {
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub struct ReturnStatement { pub struct ReturnStatement {

View File

@ -1,14 +1,12 @@
use databake::*;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value as JValue; use serde_json::Value as JValue;
use super::{Literal, Value}; use super::{Literal, Value};
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(untagged, rename_all = "snake_case")] #[serde(tag = "type", content = "data", rename_all = "snake_case")]
pub enum LiteralValue { pub enum LiteralValue {
IInteger(i64), IInteger(i64),
Fractional(f64), Fractional(f64),

View File

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

View File

@ -88,7 +88,11 @@ impl EngineConnection {
let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket( let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
ws, ws,
tokio_tungstenite::tungstenite::protocol::Role::Client, tokio_tungstenite::tungstenite::protocol::Role::Client,
Some(tokio_tungstenite::tungstenite::protocol::WebSocketConfig { ..Default::default() }), Some(tokio_tungstenite::tungstenite::protocol::WebSocketConfig {
write_buffer_size: 1024 * 128,
max_write_buffer_size: 1024 * 256,
..Default::default()
}),
) )
.await; .await;

View File

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

View File

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

View File

@ -1,7 +1,3 @@
//! Rust support for KCL (aka the KittyCAD Language).
//!
//! KCL is written in Rust. This crate contains the compiler tooling (e.g. parser, lexer, code generation),
//! the standard library implementation, a LSP implementation, generator for the docs, and more.
#![recursion_limit = "1024"] #![recursion_limit = "1024"]
pub mod ast; pub mod ast;

View File

@ -1,10 +1,4 @@
use crate::{ use crate::{ast::types::Program, errors::KclError, token::Token};
ast::types::Program,
errors::KclError,
errors::KclErrorDetails,
executor::SourceRange,
token::{Token, TokenType},
};
mod math; mod math;
pub(crate) mod parser_impl; pub(crate) mod parser_impl;
@ -14,37 +8,15 @@ pub const PIPE_OPERATOR: &str = "|>";
pub struct Parser { pub struct Parser {
pub tokens: Vec<Token>, pub tokens: Vec<Token>,
pub unknown_tokens: Vec<Token>,
} }
impl Parser { impl Parser {
pub fn new(tokens: Vec<Token>) -> Self { pub fn new(tokens: Vec<Token>) -> Self {
let (tokens, unknown_tokens): (Vec<Token>, Vec<Token>) = tokens Self { tokens }
.into_iter()
.partition(|token| token.token_type != TokenType::Unknown);
Self { tokens, unknown_tokens }
} }
/// Run the parser /// Run the parser
pub fn ast(&self) -> Result<Program, KclError> { 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()) parser_impl::run_parser(&mut self.tokens.as_slice())
} }
} }

View File

@ -1,33 +1,20 @@
use crate::{ use crate::ast::types::{BinaryExpression, BinaryOperator, BinaryPart};
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) /// Parses a list of tokens (in infix order, i.e. as the user typed them)
/// into a binary expression tree. /// into a binary expression tree.
pub fn parse(infix_tokens: Vec<BinaryExpressionToken>) -> Result<BinaryExpression, KclError> { pub fn parse(infix_tokens: Vec<BinaryExpressionToken>) -> BinaryExpression {
let rpn = postfix(infix_tokens); let rpn = postfix(infix_tokens);
evaluate(rpn) evaluate(rpn)
} }
/// Parses a list of tokens (in postfix order) into a binary expression tree. /// Parses a list of tokens (in postfix order) into a binary expression tree.
fn evaluate(rpn: Vec<BinaryExpressionToken>) -> Result<BinaryExpression, KclError> { fn evaluate(rpn: Vec<BinaryExpressionToken>) -> BinaryExpression {
let source_ranges = source_range(&rpn); let mut operand_stack = Vec::new();
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 { for item in rpn {
let expr = match item { let expr = match item {
BinaryExpressionToken::Operator(operator) => { BinaryExpressionToken::Operator(operator) => {
let Some(right) = operand_stack.pop() else { let right: BinaryPart = operand_stack.pop().unwrap();
return Err(e); let left = operand_stack.pop().unwrap();
};
let Some(left) = operand_stack.pop() else {
return Err(e);
};
BinaryPart::BinaryExpression(Box::new(BinaryExpression { BinaryPart::BinaryExpression(Box::new(BinaryExpression {
start: left.start(), start: left.start(),
end: right.end(), end: right.end(),
@ -40,26 +27,10 @@ fn evaluate(rpn: Vec<BinaryExpressionToken>) -> Result<BinaryExpression, KclErro
}; };
operand_stack.push(expr) operand_stack.push(expr)
} }
if let Some(BinaryPart::BinaryExpression(expr)) = operand_stack.pop() { if let BinaryPart::BinaryExpression(expr) = operand_stack.pop().unwrap() {
Ok(*expr) *expr
} else { } else {
// If this branch is used, the evaluation algorithm has a bug and must be fixed. panic!("Last expression was not a binary expression")
// 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(),
} }
} }
@ -75,16 +46,15 @@ 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, // 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)) // and (o2 has greater precedence than o1 or (o1 and o2 have the same precedence and o1 is left-associative))
// ) // )
// pop o2 from the operator stack into the output queue while operator_stack
while let Some(o2) = operator_stack.pop() { .last()
if (o2.precedence() > o1.precedence()) .map(|o2| {
|| o1.precedence() == o2.precedence() && o1.associativity().is_left() (o2.precedence() > o1.precedence())
{ || o1.precedence() == o2.precedence() && o1.associativity().is_left()
output.push(BinaryExpressionToken::Operator(o2)); })
} else { .unwrap_or(false)
operator_stack.push(o2); {
break; output.push(BinaryExpressionToken::Operator(operator_stack.pop().unwrap()));
}
} }
operator_stack.push(o1); operator_stack.push(o1);
} }
@ -124,7 +94,7 @@ mod tests {
#[test] #[test]
fn parse_and_evaluate() { fn parse_and_evaluate() {
/// Make a literal /// Make a literal
fn lit(n: u8) -> BinaryPart { fn lit(n: i64) -> BinaryPart {
BinaryPart::Literal(Box::new(Literal { BinaryPart::Literal(Box::new(Literal {
start: 0, start: 0,
end: 0, end: 0,
@ -157,7 +127,8 @@ mod tests {
]; ];
for infix_input in tests { for infix_input in tests {
let rpn = postfix(infix_input); let rpn = postfix(infix_input);
let _tree = evaluate(rpn).unwrap(); let tree = evaluate(rpn);
dbg!(tree);
} }
} }
} }

View File

@ -1,33 +1,46 @@
use winnow::{ use winnow::{
combinator::{alt, delimited, opt, peek, preceded, repeat, separated, terminated}, combinator::{alt, delimited, opt, peek, preceded, repeat, separated0, terminated},
dispatch, dispatch,
error::{ErrMode, StrContext, StrContextValue}, error::{ErrMode, StrContext, StrContextValue},
prelude::*, prelude::*,
token::{any, one_of}, token::{any, one_of},
}; };
use super::{math::BinaryExpressionToken, PIPE_OPERATOR, PIPE_SUBSTITUTION_OPERATOR};
use crate::{ use crate::{
ast::types::{ ast::types::{
ArrayExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression, CommentStyle, ArrayExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression, CommentStyle,
ExpressionStatement, FunctionExpression, Identifier, Literal, LiteralIdentifier, LiteralValue, ExpressionStatement, FunctionExpression, Identifier, Literal, LiteralIdentifier, LiteralValue,
MemberExpression, MemberObject, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty, MemberExpression, MemberObject, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty,
Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement, UnaryExpression, UnaryOperator, Value, PipeExpression, PipeSubstitution, Program, ReturnStatement, UnaryExpression, UnaryOperator, Value,
VariableDeclaration, VariableDeclarator, VariableKind, VariableDeclaration, VariableDeclarator, VariableKind,
}, },
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::SourceRange, executor::SourceRange,
parser::parser_impl::error::ContextError, parser::parser_impl::error::ContextError,
std::StdLib,
token::{Token, TokenType}, token::{Token, TokenType},
}; };
use super::{math::BinaryExpressionToken, PIPE_OPERATOR, PIPE_SUBSTITUTION_OPERATOR};
mod error; mod error;
type PResult<O, E = error::ContextError> = winnow::prelude::PResult<O, E>; 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]; type TokenSlice<'slice, 'input> = &'slice mut &'input [Token];
pub fn run_parser(i: TokenSlice) -> Result<Program, KclError> { 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) program.parse(i).map_err(KclError::from)
} }
@ -367,7 +380,7 @@ fn equals(i: TokenSlice) -> PResult<Token> {
fn array(i: TokenSlice) -> PResult<ArrayExpression> { fn array(i: TokenSlice) -> PResult<ArrayExpression> {
let start = open_bracket(i)?.start; let start = open_bracket(i)?.start;
ignore_whitespace(i); ignore_whitespace(i);
let elements = alt((integer_range, separated(0.., value, comma_sep))) let elements = alt((integer_range, separated0(value, comma_sep)))
.context(expected( .context(expected(
"array contents, either a numeric range (like 0..10) or a list of elements (like [1, 2, 3])", "array contents, either a numeric range (like 0..10) or a list of elements (like [1, 2, 3])",
)) ))
@ -424,7 +437,7 @@ fn object_property(i: TokenSlice) -> PResult<ObjectProperty> {
fn object(i: TokenSlice) -> PResult<ObjectExpression> { fn object(i: TokenSlice) -> PResult<ObjectExpression> {
let start = open_brace(i)?.start; let start = open_brace(i)?.start;
ignore_whitespace(i); ignore_whitespace(i);
let properties = separated(0.., object_property, comma_sep) let properties = separated0(object_property, comma_sep)
.context(expected( .context(expected(
"a comma-separated list of key-value pairs, e.g. 'height: 4, width: 3'", "a comma-separated list of key-value pairs, e.g. 'height: 4, width: 3'",
)) ))
@ -1033,8 +1046,7 @@ fn binary_expression(i: TokenSlice) -> PResult<BinaryExpression> {
// Pass the token slice into the specialized math parser, for things like // Pass the token slice into the specialized math parser, for things like
// precedence and converting infix operations to an AST. // precedence and converting infix operations to an AST.
let expr = super::math::parse(tokens).map_err(|e| ErrMode::Backtrack(e.into()))?; Ok(super::math::parse(tokens))
Ok(expr)
} }
fn binary_expr_in_parens(i: TokenSlice) -> PResult<BinaryExpression> { fn binary_expr_in_parens(i: TokenSlice) -> PResult<BinaryExpression> {
@ -1203,71 +1215,35 @@ fn comma_sep(i: TokenSlice) -> PResult<()> {
/// Arguments are passed into a function. /// Arguments are passed into a function.
fn arguments(i: TokenSlice) -> PResult<Vec<Value>> { fn arguments(i: TokenSlice) -> PResult<Vec<Value>> {
separated(0.., value, comma_sep) separated0(value, comma_sep)
.context(expected("function arguments")) .context(expected("function arguments"))
.parse_next(i) .parse_next(i)
} }
fn required_param(i: TokenSlice) -> PResult<Token> { fn not_close_paren(i: TokenSlice) -> PResult<Token> {
any.verify(|token: &Token| !matches!(token.token_type, TokenType::Brace) || token.value != ")") any.verify(|token: &Token| !matches!(token.token_type, TokenType::Brace) || token.value != ")")
.parse_next(i) .parse_next(i)
} }
fn optional_param(i: TokenSlice) -> PResult<Token> {
let token = required_param.parse_next(i)?;
let _question_mark = one_of(TokenType::QuestionMark).parse_next(i)?;
Ok(token)
}
/// Parameters are declared in a function signature, and used within a function. /// Parameters are declared in a function signature, and used within a function.
fn parameters(i: TokenSlice) -> PResult<Vec<Parameter>> { fn parameters(i: TokenSlice) -> PResult<Vec<Identifier>> {
// Get all tokens until the next ), because that ends the parameter list. // Get all tokens until the next ), because that ends the parameter list.
let candidates: Vec<_> = separated( let candidates: Vec<Token> = separated0(not_close_paren, comma_sep)
0.., .context(expected("function parameters"))
alt((optional_param.map(|t| (t, true)), required_param.map(|t| (t, false)))), .parse_next(i)?;
comma_sep,
)
.context(expected("function parameters"))
.parse_next(i)?;
// Make sure all those tokens are valid parameters. // Make sure all those tokens are valid parameters.
let params: Vec<Parameter> = candidates let params = candidates
.into_iter() .into_iter()
.map(|(token, optional)| { .map(|token| Identifier::try_from(token).and_then(Identifier::into_valid_binding_name))
let identifier = Identifier::try_from(token).and_then(Identifier::into_valid_binding_name)?;
Ok(Parameter { identifier, optional })
})
.collect::<Result<_, _>>() .collect::<Result<_, _>>()
.map_err(|e: KclError| ErrMode::Backtrack(ContextError::from(e)))?; .map_err(|e| ErrMode::Backtrack(ContextError::from(e)))?;
// Make sure optional parameters are last.
if let Err(e) = optional_after_required(&params) {
return Err(ErrMode::Cut(ContextError::from(e)));
}
Ok(params) Ok(params)
} }
fn optional_after_required(params: &[Parameter]) -> Result<(), KclError> {
let mut found_optional = false;
for p in params {
if p.optional {
found_optional = true;
}
if !p.optional && found_optional {
let e = KclError::Syntax(KclErrorDetails {
source_ranges: vec![(&p.identifier).into()],
message: "mandatory parameters must be declared before optional parameters".to_owned(),
});
return Err(e);
}
}
Ok(())
}
impl Identifier { impl Identifier {
fn into_valid_binding_name(self) -> Result<Identifier, KclError> { fn into_valid_binding_name(self) -> Result<Identifier, KclError> {
// Make sure they are not assigning a variable to a stdlib function. // Make sure they are not assigning a variable to a stdlib function.
if crate::std::name_in_stdlib(&self.name) { if STDLIB.fns.contains_key(&self.name) {
return Err(KclError::Syntax(KclErrorDetails { return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![SourceRange([self.start, self.end])], source_ranges: vec![SourceRange([self.start, self.end])],
message: format!("Cannot assign a variable to a reserved keyword: {}", self.name), message: format!("Cannot assign a variable to a reserved keyword: {}", self.name),
@ -1291,12 +1267,18 @@ fn fn_call(i: TokenSlice) -> PResult<CallExpression> {
let _ = terminated(open_paren, opt(whitespace)).parse_next(i)?; let _ = terminated(open_paren, opt(whitespace)).parse_next(i)?;
let args = arguments(i)?; let args = arguments(i)?;
let end = preceded(opt(whitespace), close_paren).parse_next(i)?.end; 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 { Ok(CallExpression {
start: fn_name.start, start: fn_name.start,
end, end,
callee: fn_name, callee: fn_name,
arguments: args, arguments: args,
optional: false, optional: false,
function,
}) })
} }
@ -1424,7 +1406,7 @@ const mySk1 = startSketchAt([0, 0])"#;
let Value::PipeExpression(pipe) = val else { let Value::PipeExpression(pipe) = val else {
panic!("expected pipe"); panic!("expected pipe");
}; };
let mut noncode = pipe.non_code_meta; let mut noncode = dbg!(pipe.non_code_meta);
assert_eq!(noncode.non_code_nodes.len(), 1); assert_eq!(noncode.non_code_nodes.len(), 1);
let comment = noncode.non_code_nodes.remove(&0).unwrap().pop().unwrap(); let comment = noncode.non_code_nodes.remove(&0).unwrap().pop().unwrap();
assert_eq!( assert_eq!(
@ -1687,6 +1669,95 @@ const mySk1 = startSketchAt([0, 0])"#;
assert_eq!(inner.operator, BinaryOperator::Sub); 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] #[test]
fn binary_expression_ignores_whitespace() { fn binary_expression_ignores_whitespace() {
let tests = ["1 - 2", "1- 2", "1 -2", "1-2"]; let tests = ["1 - 2", "1- 2", "1 -2", "1-2"];
@ -1931,7 +2002,7 @@ const mySk1 = startSketchAt([0, 0])"#;
let tokens = crate::token::lexer(input); let tokens = crate::token::lexer(input);
let actual = parameters.parse(&tokens); let actual = parameters.parse(&tokens);
assert!(actual.is_ok(), "could not parse test {i}"); assert!(actual.is_ok(), "could not parse test {i}");
let actual_ids: Vec<_> = actual.unwrap().into_iter().map(|p| p.identifier.name).collect(); let actual_ids: Vec<_> = actual.unwrap().into_iter().map(|id| id.name).collect();
assert_eq!(actual_ids, expected); assert_eq!(actual_ids, expected);
} }
} }
@ -2239,10 +2310,9 @@ const secondExtrude = startSketchOn('XY')
let tokens = crate::token::lexer(">!"); let tokens = crate::token::lexer(">!");
let parser = crate::parser::Parser::new(tokens); let parser = crate::parser::Parser::new(tokens);
let err = parser.ast().unwrap_err(); let err = parser.ast().unwrap_err();
assert_eq!( // TODO: Better errors when program cannot tokenize.
err.to_string(), // https://github.com/KittyCAD/modeling-app/issues/696
r#"lexical: KclErrorDetails { source_ranges: [SourceRange([1, 2])], message: "found unknown token '!'" }"# assert!(err.to_string().contains("file is empty"));
);
} }
#[test] #[test]
@ -2298,9 +2368,11 @@ z(-[["#,
let parser = crate::parser::Parser::new(tokens); let parser = crate::parser::Parser::new(tokens);
let result = parser.ast(); let result = parser.ast();
assert!(result.is_err()); assert!(result.is_err());
// TODO: Better errors when program cannot tokenize.
// https://github.com/KittyCAD/modeling-app/issues/696
assert_eq!( assert_eq!(
result.err().unwrap().to_string(), result.err().unwrap().to_string(),
r#"lexical: KclErrorDetails { source_ranges: [SourceRange([6, 7])], message: "found unknown token '#'" }"# r#"syntax: KclErrorDetails { source_ranges: [], message: "file is empty" }"#
); );
} }
@ -2310,9 +2382,11 @@ z(-[["#,
let parser = crate::parser::Parser::new(tokens); let parser = crate::parser::Parser::new(tokens);
let result = parser.ast(); let result = parser.ast();
assert!(result.is_err()); assert!(result.is_err());
// TODO: Better errors when program cannot tokenize.
// https://github.com/KittyCAD/modeling-app/issues/696
assert_eq!( assert_eq!(
result.err().unwrap().to_string(), result.err().unwrap().to_string(),
r#"lexical: KclErrorDetails { source_ranges: [SourceRange([25, 26]), SourceRange([26, 27])], message: "found unknown tokens [#, #]" }"# r#"syntax: KclErrorDetails { source_ranges: [], message: "file is empty" }"#
); );
} }
@ -2358,82 +2432,6 @@ e
assert!(result.err().unwrap().to_string().contains("Unexpected token")); assert!(result.err().unwrap().to_string().contains("Unexpected token"));
} }
#[test]
fn test_optional_param_order() {
for (i, (params, expect_ok)) in [
(
vec![Parameter {
identifier: Identifier {
start: 0,
end: 0,
name: "a".to_owned(),
},
optional: true,
}],
true,
),
(
vec![Parameter {
identifier: Identifier {
start: 0,
end: 0,
name: "a".to_owned(),
},
optional: false,
}],
true,
),
(
vec![
Parameter {
identifier: Identifier {
start: 0,
end: 0,
name: "a".to_owned(),
},
optional: false,
},
Parameter {
identifier: Identifier {
start: 0,
end: 0,
name: "b".to_owned(),
},
optional: true,
},
],
true,
),
(
vec![
Parameter {
identifier: Identifier {
start: 0,
end: 0,
name: "a".to_owned(),
},
optional: true,
},
Parameter {
identifier: Identifier {
start: 0,
end: 0,
name: "b".to_owned(),
},
optional: false,
},
],
false,
),
]
.into_iter()
.enumerate()
{
let actual = optional_after_required(&params);
assert_eq!(actual.is_ok(), expect_ok, "failed test {i}");
}
}
#[test] #[test]
fn test_parse_expand_array() { fn test_parse_expand_array() {
let code = "const myArray = [0..10]"; let code = "const myArray = [0..10]";
@ -2674,22 +2672,6 @@ 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] #[test]
fn test_member_expression_sketch_group() { fn test_member_expression_sketch_group() {
let some_program_string = r#"fn cube = (pos, scale) => { let some_program_string = r#"fn cube = (pos, scale) => {
@ -2743,175 +2725,24 @@ show(myBox)"#;
let parser = crate::parser::Parser::new(tokens); let parser = crate::parser::Parser::new(tokens);
parser.ast().unwrap(); parser.ast().unwrap();
} }
}
#[test]
#[cfg(test)] fn test_math() {
mod snapshot_math_tests { for math_expression in [
use super::*; "1 + 2",
"1+2",
// This macro generates a test function with the given function name. "1 -2",
// The macro takes a KCL program, ensures it tokenizes and parses, then compares "1 + 2 * 3",
// its parsed AST to a snapshot (kept in this repo in a file under snapshots/ dir) "1 * ( 2 + 3 )",
macro_rules! snapshot_test { "1 * ( 2 + 3 ) / 4",
($func_name:ident, $test_kcl_program:expr) => { "1 + ( 2 + 3 ) / 4",
#[test] "1 * (( 2 + 3 ) / 4 + 5 )",
fn $func_name() { "1 * ((( 2 + 3 )))",
let tokens = crate::token::lexer($test_kcl_program); "distance * p * FOS * 6 / (sigmaAllow * width)",
let actual = match binary_expression.parse(&tokens) { "2 + (((3)))",
Ok(x) => x, ] {
Err(_e) => panic!("could not parse test"), let tokens = crate::token::lexer(math_expression);
}; let _expr = binary_expression.parse(&tokens).unwrap();
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"));
snapshot_test!(av, "fn f = (angle?) => { return default(angle, 360) }");
} }

View File

@ -1,26 +0,0 @@
---
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

@ -1,26 +0,0 @@
---
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

@ -1,26 +0,0 @@
---
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

@ -1,41 +0,0 @@
---
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

@ -1,41 +0,0 @@
---
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

@ -1,56 +0,0 @@
---
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

@ -1,56 +0,0 @@
---
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

@ -1,71 +0,0 @@
---
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

@ -1,41 +0,0 @@
---
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

@ -1,81 +0,0 @@
---
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

@ -1,26 +0,0 @@
---
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

@ -1,263 +0,0 @@
---
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

@ -1,48 +0,0 @@
---
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

@ -1,85 +0,0 @@
---
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

@ -1,130 +0,0 @@
---
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

@ -1,85 +0,0 @@
---
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

@ -1,102 +0,0 @@
---
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": [
{
"identifier": {
"type": "Identifier",
"start": 12,
"end": 17,
"name": "param"
},
"optional": false
}
],
"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

@ -1,317 +0,0 @@
---
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

@ -1,151 +0,0 @@
---
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

@ -1,56 +0,0 @@
---
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

@ -1,92 +0,0 @@
---
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

@ -1,112 +0,0 @@
---
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

@ -1,78 +0,0 @@
---
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

@ -1,113 +0,0 @@
---
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

@ -1,78 +0,0 @@
---
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

@ -1,113 +0,0 @@
---
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

@ -1,113 +0,0 @@
---
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

@ -1,73 +0,0 @@
---
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

@ -1,58 +0,0 @@
---
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

@ -1,43 +0,0 @@
---
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

@ -1,64 +0,0 @@
---
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

@ -1,158 +0,0 @@
---
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

@ -1,97 +0,0 @@
---
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": 3,
"end": 49,
"id": {
"type": "Identifier",
"start": 3,
"end": 4,
"name": "f"
},
"init": {
"type": "FunctionExpression",
"type": "FunctionExpression",
"start": 7,
"end": 49,
"params": [
{
"identifier": {
"type": "Identifier",
"start": 8,
"end": 13,
"name": "angle"
},
"optional": true
}
],
"body": {
"start": 19,
"end": 49,
"body": [
{
"type": "ReturnStatement",
"type": "ReturnStatement",
"start": 21,
"end": 47,
"argument": {
"type": "CallExpression",
"type": "CallExpression",
"start": 28,
"end": 47,
"callee": {
"type": "Identifier",
"start": 28,
"end": 35,
"name": "default"
},
"arguments": [
{
"type": "Identifier",
"type": "Identifier",
"start": 36,
"end": 41,
"name": "angle"
},
{
"type": "Literal",
"type": "Literal",
"start": 43,
"end": 46,
"value": 360,
"raw": "360"
}
],
"optional": false
}
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}
}
}
],
"kind": "fn"
}
],
"nonCodeMeta": {
"nonCodeNodes": {},
"start": []
}
}

View File

@ -1,95 +0,0 @@
---
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

@ -1,95 +0,0 @@
---
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": []
}
}

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