Compare commits
1 Commits
kcl_prelud
...
achalmers/
| Author | SHA1 | Date | |
|---|---|---|---|
| e1f1051fe0 |
@ -1,3 +1,3 @@
|
|||||||
[codespell]
|
[codespell]
|
||||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey
|
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo
|
||||||
skip: **/target,node_modules,build,**/Cargo.lock
|
skip: **/target,node_modules,build,**/Cargo.lock
|
||||||
|
|||||||
50
.github/workflows/cargo-build.yml
vendored
Normal file
50
.github/workflows/cargo-build.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- '**.rs'
|
||||||
|
- '**/Cargo.toml'
|
||||||
|
- '**/Cargo.lock'
|
||||||
|
- '**/rust-toolchain.toml'
|
||||||
|
- .github/workflows/cargo-build.yml
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '**.rs'
|
||||||
|
- '**/Cargo.toml'
|
||||||
|
- '**/Cargo.lock'
|
||||||
|
- '**/rust-toolchain.toml'
|
||||||
|
- .github/workflows/cargo-build.yml
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
name: cargo build
|
||||||
|
jobs:
|
||||||
|
cargobuild:
|
||||||
|
name: cargo build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
dir: ['src/wasm-lib']
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install latest rust
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: install dependencies
|
||||||
|
if: matrix.dir == 'src-tauri'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
|
||||||
|
- name: Rust Cache
|
||||||
|
uses: Swatinem/rust-cache@v2.6.1
|
||||||
|
|
||||||
|
- name: Run cargo build
|
||||||
|
run: |
|
||||||
|
cd "${{ matrix.dir }}"
|
||||||
|
cargo build --all
|
||||||
|
shell: bash
|
||||||
6
.github/workflows/cargo-clippy.yml
vendored
6
.github/workflows/cargo-clippy.yml
vendored
@ -9,6 +9,12 @@ on:
|
|||||||
- '**.rs'
|
- '**.rs'
|
||||||
- .github/workflows/cargo-clippy.yml
|
- .github/workflows/cargo-clippy.yml
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '**/Cargo.toml'
|
||||||
|
- '**/Cargo.lock'
|
||||||
|
- '**/rust-toolchain.toml'
|
||||||
|
- '**.rs'
|
||||||
|
- .github/workflows/cargo-build.yml
|
||||||
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
|
||||||
|
|||||||
36
.github/workflows/check-exampleKcl.yml
vendored
36
.github/workflows/check-exampleKcl.yml
vendored
@ -1,36 +0,0 @@
|
|||||||
name: Check Onboarding KCL
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize]
|
|
||||||
paths:
|
|
||||||
- 'src/lib/exampleKcl.ts'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
comment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Comment on PR
|
|
||||||
uses: actions/github-script@v6
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const message = '`src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.';
|
|
||||||
const issue_number = context.payload.pull_request.number;
|
|
||||||
const owner = context.repo.owner;
|
|
||||||
const repo = context.repo.repo;
|
|
||||||
|
|
||||||
// Post a comment on the PR
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
issue_number,
|
|
||||||
body: message,
|
|
||||||
});
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.16.0",
|
"version": "0.15.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.10.2",
|
"@codemirror/autocomplete": "^6.10.2",
|
||||||
|
|||||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@ -3876,7 +3876,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#6db4320e98a4278d605dd05d4d87e1433939a7cd"
|
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#d95a1b382f512a0be748e7a89e0f8fc4278010e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "zoo-modeling-app",
|
"productName": "zoo-modeling-app",
|
||||||
"version": "0.16.0"
|
"version": "0.15.6"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|||||||
@ -59,7 +59,6 @@ const router = createBrowserRouter([
|
|||||||
{
|
{
|
||||||
loader: fileLoader,
|
loader: fileLoader,
|
||||||
id: paths.FILE,
|
id: paths.FILE,
|
||||||
path: paths.FILE + '/:id',
|
|
||||||
element: (
|
element: (
|
||||||
<Auth>
|
<Auth>
|
||||||
<FileMachineProvider>
|
<FileMachineProvider>
|
||||||
@ -75,11 +74,8 @@ const router = createBrowserRouter([
|
|||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
path: paths.FILE + '/:id',
|
||||||
loader: onboardingRedirectLoader,
|
loader: onboardingRedirectLoader,
|
||||||
index: true,
|
|
||||||
element: <></>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: makeUrlPathRelative(paths.SETTINGS),
|
path: makeUrlPathRelative(paths.SETTINGS),
|
||||||
|
|||||||
@ -30,7 +30,7 @@ describe('NetworkHealthIndicator tests', () => {
|
|||||||
fireEvent.click(screen.getByTestId('network-toggle'))
|
fireEvent.click(screen.getByTestId('network-toggle'))
|
||||||
|
|
||||||
expect(screen.getByTestId('network')).toHaveTextContent(
|
expect(screen.getByTestId('network')).toHaveTextContent(
|
||||||
NETWORK_HEALTH_TEXT[NetworkHealthState.Ok]
|
NETWORK_HEALTH_TEXT[NetworkHealthState.Issue]
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,8 @@ import {
|
|||||||
ConnectingTypeGroup,
|
ConnectingTypeGroup,
|
||||||
DisconnectingType,
|
DisconnectingType,
|
||||||
engineCommandManager,
|
engineCommandManager,
|
||||||
EngineConnectionState,
|
EngineCommandManagerEvents,
|
||||||
|
EngineConnectionEvents,
|
||||||
EngineConnectionStateType,
|
EngineConnectionStateType,
|
||||||
ErrorType,
|
ErrorType,
|
||||||
initialConnectingTypeGroupState,
|
initialConnectingTypeGroupState,
|
||||||
@ -81,37 +82,35 @@ const overallConnectionStateIcon: Record<
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useNetworkStatus() {
|
export function useNetworkStatus() {
|
||||||
const [steps, setSteps] = useState(initialConnectingTypeGroupState)
|
const [steps, setSteps] = useState(
|
||||||
|
structuredClone(initialConnectingTypeGroupState)
|
||||||
|
)
|
||||||
const [internetConnected, setInternetConnected] = useState<boolean>(true)
|
const [internetConnected, setInternetConnected] = useState<boolean>(true)
|
||||||
const [overallState, setOverallState] = useState<NetworkHealthState>(
|
const [overallState, setOverallState] = useState<NetworkHealthState>(
|
||||||
NetworkHealthState.Ok
|
NetworkHealthState.Disconnected
|
||||||
)
|
)
|
||||||
|
const [pingPongHealth, setPingPongHealth] = useState<'OK' | 'BAD'>('BAD')
|
||||||
const [hasCopied, setHasCopied] = useState<boolean>(false)
|
const [hasCopied, setHasCopied] = useState<boolean>(false)
|
||||||
|
|
||||||
const [error, setError] = useState<ErrorType | undefined>(undefined)
|
const [error, setError] = useState<ErrorType | undefined>(undefined)
|
||||||
|
|
||||||
const issues: Record<ConnectingTypeGroup, boolean> = {
|
const hasIssue = (i: [ConnectingType, boolean | undefined]) =>
|
||||||
[ConnectingTypeGroup.WebSocket]: steps[ConnectingTypeGroup.WebSocket].some(
|
i[1] === undefined ? i[1] : !i[1]
|
||||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
|
||||||
),
|
|
||||||
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].some(
|
|
||||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
|
||||||
),
|
|
||||||
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].some(
|
|
||||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasIssues: boolean =
|
const [issues, setIssues] = useState<
|
||||||
issues[ConnectingTypeGroup.WebSocket] ||
|
Record<ConnectingTypeGroup, boolean | undefined>
|
||||||
issues[ConnectingTypeGroup.ICE] ||
|
>({
|
||||||
issues[ConnectingTypeGroup.WebRTC]
|
[ConnectingTypeGroup.WebSocket]: undefined,
|
||||||
|
[ConnectingTypeGroup.ICE]: undefined,
|
||||||
|
[ConnectingTypeGroup.WebRTC]: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [hasIssues, setHasIssues] = useState<boolean | undefined>(undefined)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setOverallState(
|
setOverallState(
|
||||||
!internetConnected
|
!internetConnected
|
||||||
? NetworkHealthState.Disconnected
|
? NetworkHealthState.Disconnected
|
||||||
: hasIssues
|
: hasIssues || hasIssues === undefined
|
||||||
? NetworkHealthState.Issue
|
? NetworkHealthState.Issue
|
||||||
: NetworkHealthState.Ok
|
: NetworkHealthState.Ok
|
||||||
)
|
)
|
||||||
@ -134,19 +133,59 @@ export function useNetworkStatus() {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
engineCommandManager.onConnectionStateChange(
|
console.log(pingPongHealth)
|
||||||
(engineConnectionState: EngineConnectionState) => {
|
}, [pingPongHealth])
|
||||||
let hasSetAStep = false
|
|
||||||
|
useEffect(() => {
|
||||||
|
const issues = {
|
||||||
|
[ConnectingTypeGroup.WebSocket]: steps[
|
||||||
|
ConnectingTypeGroup.WebSocket
|
||||||
|
].reduce(
|
||||||
|
(acc: boolean | undefined, a) =>
|
||||||
|
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].reduce(
|
||||||
|
(acc: boolean | undefined, a) =>
|
||||||
|
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].reduce(
|
||||||
|
(acc: boolean | undefined, a) =>
|
||||||
|
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||||
|
false
|
||||||
|
),
|
||||||
|
}
|
||||||
|
setIssues(issues)
|
||||||
|
}, [steps])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasIssues(
|
||||||
|
issues[ConnectingTypeGroup.WebSocket] ||
|
||||||
|
issues[ConnectingTypeGroup.ICE] ||
|
||||||
|
issues[ConnectingTypeGroup.WebRTC]
|
||||||
|
)
|
||||||
|
}, [issues])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onPingPongChange = ({ detail: state }: CustomEvent) => {
|
||||||
|
setPingPongHealth(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onConnectionStateChange = ({
|
||||||
|
detail: engineConnectionState,
|
||||||
|
}: CustomEvent) => {
|
||||||
|
setSteps((steps) => {
|
||||||
|
let nextSteps = structuredClone(steps)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
engineConnectionState.type === EngineConnectionStateType.Connecting
|
engineConnectionState.type === EngineConnectionStateType.Connecting
|
||||||
) {
|
) {
|
||||||
const groups = Object.values(steps)
|
const groups = Object.values(nextSteps)
|
||||||
for (let group of groups) {
|
for (let group of groups) {
|
||||||
for (let step of group) {
|
for (let step of group) {
|
||||||
if (step[0] !== engineConnectionState.value.type) continue
|
if (step[0] !== engineConnectionState.value.type) continue
|
||||||
step[1] = true
|
step[1] = true
|
||||||
hasSetAStep = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,7 +193,7 @@ export function useNetworkStatus() {
|
|||||||
if (
|
if (
|
||||||
engineConnectionState.type === EngineConnectionStateType.Disconnecting
|
engineConnectionState.type === EngineConnectionStateType.Disconnecting
|
||||||
) {
|
) {
|
||||||
const groups = Object.values(steps)
|
const groups = Object.values(nextSteps)
|
||||||
for (let group of groups) {
|
for (let group of groups) {
|
||||||
for (let step of group) {
|
for (let step of group) {
|
||||||
if (
|
if (
|
||||||
@ -165,7 +204,6 @@ export function useNetworkStatus() {
|
|||||||
?.type === step[0]
|
?.type === step[0]
|
||||||
) {
|
) {
|
||||||
step[1] = false
|
step[1] = false
|
||||||
hasSetAStep = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,11 +214,50 @@ export function useNetworkStatus() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSetAStep) {
|
// Reset the state of all steps if we have disconnected.
|
||||||
setSteps(steps)
|
if (
|
||||||
|
engineConnectionState.type === EngineConnectionStateType.Disconnected
|
||||||
|
) {
|
||||||
|
return structuredClone(initialConnectingTypeGroupState)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return nextSteps
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onEngineAvailable = ({ detail: engineConnection }: CustomEvent) => {
|
||||||
|
engineConnection.addEventListener(
|
||||||
|
EngineConnectionEvents.PingPongChanged,
|
||||||
|
onPingPongChange as EventListener
|
||||||
|
)
|
||||||
|
engineConnection.addEventListener(
|
||||||
|
EngineConnectionEvents.ConnectionStateChanged,
|
||||||
|
onConnectionStateChange as EventListener
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
engineCommandManager.addEventListener(
|
||||||
|
EngineCommandManagerEvents.EngineAvailable,
|
||||||
|
onEngineAvailable as EventListener
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
engineCommandManager.removeEventListener(
|
||||||
|
EngineCommandManagerEvents.EngineAvailable,
|
||||||
|
onEngineAvailable as EventListener
|
||||||
|
)
|
||||||
|
|
||||||
|
// When the component is unmounted these should be assigned, but it's possible
|
||||||
|
// the component mounts and unmounts before engine is available.
|
||||||
|
engineCommandManager.engineConnection?.addEventListener(
|
||||||
|
EngineConnectionEvents.PingPongChanged,
|
||||||
|
onPingPongChange as EventListener
|
||||||
|
)
|
||||||
|
engineCommandManager.engineConnection?.addEventListener(
|
||||||
|
EngineConnectionEvents.ConnectionStateChanged,
|
||||||
|
onConnectionStateChange as EventListener
|
||||||
|
)
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -192,6 +269,7 @@ export function useNetworkStatus() {
|
|||||||
error,
|
error,
|
||||||
setHasCopied,
|
setHasCopied,
|
||||||
hasCopied,
|
hasCopied,
|
||||||
|
pingPongHealth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,18 +334,18 @@ export const NetworkHealthIndicator = () => {
|
|||||||
size="lg"
|
size="lg"
|
||||||
icon={
|
icon={
|
||||||
hasIssueToIcon[
|
hasIssueToIcon[
|
||||||
issues[name as ConnectingTypeGroup].toString()
|
String(issues[name as ConnectingTypeGroup])
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
iconClassName={
|
iconClassName={
|
||||||
hasIssueToIconColors[
|
hasIssueToIconColors[
|
||||||
issues[name as ConnectingTypeGroup].toString()
|
String(issues[name as ConnectingTypeGroup])
|
||||||
].icon
|
].icon
|
||||||
}
|
}
|
||||||
bgClassName={
|
bgClassName={
|
||||||
'rounded-sm ' +
|
'rounded-sm ' +
|
||||||
hasIssueToIconColors[
|
hasIssueToIconColors[
|
||||||
issues[name as ConnectingTypeGroup].toString()
|
String(issues[name as ConnectingTypeGroup])
|
||||||
].bg
|
].bg
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -32,6 +32,7 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
const { state } = useModelingContext()
|
const { state } = useModelingContext()
|
||||||
const { isExecuting } = useKclContext()
|
const { isExecuting } = useKclContext()
|
||||||
const { overallState } = useNetworkStatus()
|
const { overallState } = useNetworkStatus()
|
||||||
|
|
||||||
const isNetworkOkay = overallState === NetworkHealthState.Ok
|
const isNetworkOkay = overallState === NetworkHealthState.Ok
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { PathToNode, Program, SourceRange } from 'lang/wasm'
|
import { PathToNode, Program, SourceRange } from 'lang/wasm'
|
||||||
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env'
|
import { VITE_KC_API_WS_MODELING_URL } from 'env'
|
||||||
import { Models } from '@kittycad/lib'
|
import { Models } from '@kittycad/lib'
|
||||||
import { exportSave } from 'lib/exportSave'
|
import { exportSave } from 'lib/exportSave'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
@ -8,6 +8,9 @@ import { sceneInfra } from 'clientSideScene/sceneInfra'
|
|||||||
|
|
||||||
let lastMessage = ''
|
let lastMessage = ''
|
||||||
|
|
||||||
|
// TODO(paultag): This ought to be tweakable.
|
||||||
|
const pingIntervalMs = 10000
|
||||||
|
|
||||||
interface CommandInfo {
|
interface CommandInfo {
|
||||||
commandType: CommandTypes
|
commandType: CommandTypes
|
||||||
range: SourceRange
|
range: SourceRange
|
||||||
@ -37,11 +40,6 @@ export interface ArtifactMap {
|
|||||||
[key: string]: ResultCommand | PendingCommand | FailedCommand
|
[key: string]: ResultCommand | PendingCommand | FailedCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NewTrackArgs {
|
|
||||||
conn: EngineConnection
|
|
||||||
mediaStream: MediaStream
|
|
||||||
}
|
|
||||||
|
|
||||||
// This looks funny, I know. This is needed because node and the browser
|
// This looks funny, I know. This is needed because node and the browser
|
||||||
// disagree as to the type. In a browser it's a number, but in node it's a
|
// disagree as to the type. In a browser it's a number, but in node it's a
|
||||||
// "Timeout".
|
// "Timeout".
|
||||||
@ -158,10 +156,28 @@ export type EngineConnectionState =
|
|||||||
| State<EngineConnectionStateType.Disconnecting, DisconnectingValue>
|
| State<EngineConnectionStateType.Disconnecting, DisconnectingValue>
|
||||||
| State<EngineConnectionStateType.Disconnected, void>
|
| State<EngineConnectionStateType.Disconnected, void>
|
||||||
|
|
||||||
|
export type PingPongState = 'OK' | 'BAD'
|
||||||
|
|
||||||
|
export enum EngineConnectionEvents {
|
||||||
|
// Fires for each ping-pong success or failure.
|
||||||
|
PingPongChanged = 'ping-pong-changed', // (state: PingPongState) => void
|
||||||
|
|
||||||
|
// For now, this is only used by the NetworkHealthIndicator.
|
||||||
|
// We can eventually use it for more, but one step at a time.
|
||||||
|
ConnectionStateChanged = 'connection-state-changed', // (state: EngineConnectionState) => void
|
||||||
|
|
||||||
|
// These are used for the EngineCommandManager and were created
|
||||||
|
// before onConnectionStateChange existed.
|
||||||
|
ConnectionStarted = 'connection-started', // (engineConnection: EngineConnection) => void
|
||||||
|
Opened = 'opened', // (engineConnection: EngineConnection) => void
|
||||||
|
Closed = 'closed', // (engineConnection: EngineConnection) => void
|
||||||
|
NewTrack = 'new-track', // (track: NewTrackArgs) => void
|
||||||
|
}
|
||||||
|
|
||||||
// EngineConnection encapsulates the connection(s) to the Engine
|
// EngineConnection encapsulates the connection(s) to the Engine
|
||||||
// for the EngineCommandManager; namely, the underlying WebSocket
|
// for the EngineCommandManager; namely, the underlying WebSocket
|
||||||
// and WebRTC connections.
|
// and WebRTC connections.
|
||||||
class EngineConnection {
|
class EngineConnection extends EventTarget {
|
||||||
websocket?: WebSocket
|
websocket?: WebSocket
|
||||||
pc?: RTCPeerConnection
|
pc?: RTCPeerConnection
|
||||||
unreliableDataChannel?: RTCDataChannel
|
unreliableDataChannel?: RTCDataChannel
|
||||||
@ -195,7 +211,12 @@ class EngineConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._state = next
|
this._state = next
|
||||||
this.onConnectionStateChange(this._state)
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EngineConnectionEvents.ConnectionStateChanged, {
|
||||||
|
detail: this._state,
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private failedConnTimeout: Timeout | null
|
private failedConnTimeout: Timeout | null
|
||||||
@ -203,74 +224,39 @@ class EngineConnection {
|
|||||||
readonly url: string
|
readonly url: string
|
||||||
private readonly token?: string
|
private readonly token?: string
|
||||||
|
|
||||||
// For now, this is only used by the NetworkHealthIndicator.
|
|
||||||
// We can eventually use it for more, but one step at a time.
|
|
||||||
private onConnectionStateChange: (state: EngineConnectionState) => void
|
|
||||||
|
|
||||||
// These are used for the EngineCommandManager and were created
|
|
||||||
// before onConnectionStateChange existed.
|
|
||||||
private onEngineConnectionOpen: (engineConnection: EngineConnection) => void
|
|
||||||
private onConnectionStarted: (engineConnection: EngineConnection) => void
|
|
||||||
private onClose: (engineConnection: EngineConnection) => void
|
|
||||||
private onNewTrack: (track: NewTrackArgs) => void
|
|
||||||
|
|
||||||
// TODO: actual type is ClientMetrics
|
// TODO: actual type is ClientMetrics
|
||||||
private webrtcStatsCollector?: () => Promise<ClientMetrics>
|
private webrtcStatsCollector?: () => Promise<ClientMetrics>
|
||||||
|
|
||||||
constructor({
|
private pingPongSpan: { ping?: Date; pong?: Date }
|
||||||
url,
|
|
||||||
token,
|
constructor({ url, token }: { url: string; token?: string }) {
|
||||||
onConnectionStateChange = () => {},
|
super()
|
||||||
onNewTrack = () => {},
|
|
||||||
onEngineConnectionOpen = () => {},
|
|
||||||
onConnectionStarted = () => {},
|
|
||||||
onClose = () => {},
|
|
||||||
}: {
|
|
||||||
url: string
|
|
||||||
token?: string
|
|
||||||
onConnectionStateChange?: (state: EngineConnectionState) => void
|
|
||||||
onEngineConnectionOpen?: (engineConnection: EngineConnection) => void
|
|
||||||
onConnectionStarted?: (engineConnection: EngineConnection) => void
|
|
||||||
onClose?: (engineConnection: EngineConnection) => void
|
|
||||||
onNewTrack?: (track: NewTrackArgs) => void
|
|
||||||
}) {
|
|
||||||
this.url = url
|
this.url = url
|
||||||
this.token = token
|
this.token = token
|
||||||
this.failedConnTimeout = null
|
this.failedConnTimeout = null
|
||||||
this.onConnectionStateChange = onConnectionStateChange
|
|
||||||
this.onEngineConnectionOpen = onEngineConnectionOpen
|
|
||||||
this.onConnectionStarted = onConnectionStarted
|
|
||||||
|
|
||||||
this.onClose = onClose
|
this.pingPongSpan = { ping: undefined, pong: undefined }
|
||||||
this.onNewTrack = onNewTrack
|
|
||||||
|
|
||||||
// TODO(paultag): This ought to be tweakable.
|
|
||||||
const pingIntervalMs = 10000
|
|
||||||
|
|
||||||
// Without an interval ping, our connection will timeout.
|
// Without an interval ping, our connection will timeout.
|
||||||
let pingInterval = setInterval(() => {
|
setInterval(() => {
|
||||||
switch (this.state.type as EngineConnectionStateType) {
|
switch (this.state.type as EngineConnectionStateType) {
|
||||||
case EngineConnectionStateType.ConnectionEstablished:
|
case EngineConnectionStateType.ConnectionEstablished:
|
||||||
this.send({ type: 'ping' })
|
this.send({ type: 'ping' })
|
||||||
|
this.pingPongSpan.ping = new Date()
|
||||||
break
|
break
|
||||||
case EngineConnectionStateType.Disconnecting:
|
case EngineConnectionStateType.Disconnecting:
|
||||||
case EngineConnectionStateType.Disconnected:
|
case EngineConnectionStateType.Disconnected:
|
||||||
clearInterval(pingInterval)
|
// Reconnect if we have disconnected.
|
||||||
|
if (!this.isConnecting()) this.connect()
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
if (this.isConnecting()) break
|
||||||
|
// Means we never could do an initial connection. Reconnect everything.
|
||||||
|
if (!this.pingPongSpan.ping) this.connect()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}, pingIntervalMs)
|
}, pingIntervalMs)
|
||||||
|
|
||||||
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
|
|
||||||
let connectRetryInterval = setInterval(() => {
|
|
||||||
if (this.state.type !== EngineConnectionStateType.Disconnected) return
|
|
||||||
|
|
||||||
// Only try reconnecting when completely disconnected.
|
|
||||||
clearInterval(connectRetryInterval)
|
|
||||||
console.log('Trying to reconnect')
|
|
||||||
this.connect()
|
|
||||||
}, connectionTimeoutMs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnecting() {
|
isConnecting() {
|
||||||
@ -352,7 +338,11 @@ class EngineConnection {
|
|||||||
// dance is it safest to connect the video tracks / stream
|
// dance is it safest to connect the video tracks / stream
|
||||||
case 'connected':
|
case 'connected':
|
||||||
// Let the browser attach to the video stream now
|
// Let the browser attach to the video stream now
|
||||||
this.onNewTrack({ conn: this, mediaStream: this.mediaStream! })
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EngineConnectionEvents.NewTrack, {
|
||||||
|
detail: { conn: this, mediaStream: this.mediaStream! },
|
||||||
|
})
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 'failed':
|
case 'failed':
|
||||||
this.disconnectAll()
|
this.disconnectAll()
|
||||||
@ -468,7 +458,9 @@ class EngineConnection {
|
|||||||
// Everything is now connected.
|
// Everything is now connected.
|
||||||
this.state = { type: EngineConnectionStateType.ConnectionEstablished }
|
this.state = { type: EngineConnectionStateType.ConnectionEstablished }
|
||||||
|
|
||||||
this.onEngineConnectionOpen(this)
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EngineConnectionEvents.Opened, { detail: this })
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.unreliableDataChannel.addEventListener('close', (event) => {
|
this.unreliableDataChannel.addEventListener('close', (event) => {
|
||||||
@ -510,6 +502,10 @@ class EngineConnection {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send an initial ping
|
||||||
|
this.send({ type: 'ping' })
|
||||||
|
this.pingPongSpan.ping = new Date()
|
||||||
|
|
||||||
// This is required for when KCMA is running stand-alone / within Tauri.
|
// This is required for when KCMA is running stand-alone / within Tauri.
|
||||||
// Otherwise when run in a browser, the token is sent implicitly via
|
// Otherwise when run in a browser, the token is sent implicitly via
|
||||||
// the Cookie header.
|
// the Cookie header.
|
||||||
@ -575,12 +571,34 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
|||||||
let resp = message.resp
|
let resp = message.resp
|
||||||
|
|
||||||
// If there's no body to the response, we can bail here.
|
// If there's no body to the response, we can bail here.
|
||||||
// !resp.type is usually "pong" response for our "ping"
|
|
||||||
if (!resp || !resp.type) {
|
if (!resp || !resp.type) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (resp.type) {
|
switch (resp.type) {
|
||||||
|
case 'pong':
|
||||||
|
this.pingPongSpan.pong = new Date()
|
||||||
|
if (this.pingPongSpan.ping && this.pingPongSpan.pong) {
|
||||||
|
if (
|
||||||
|
Math.abs(
|
||||||
|
this.pingPongSpan.pong.valueOf() -
|
||||||
|
this.pingPongSpan.ping.valueOf()
|
||||||
|
) >= pingIntervalMs
|
||||||
|
) {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EngineConnectionEvents.PingPongChanged, {
|
||||||
|
detail: 'BAD',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EngineConnectionEvents.PingPongChanged, {
|
||||||
|
detail: 'OK',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
case 'ice_server_info':
|
case 'ice_server_info':
|
||||||
let ice_servers = resp.data?.ice_servers
|
let ice_servers = resp.data?.ice_servers
|
||||||
|
|
||||||
@ -727,27 +745,11 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
|
this.dispatchEvent(
|
||||||
if (this.failedConnTimeout) {
|
new CustomEvent(EngineConnectionEvents.ConnectionStarted, {
|
||||||
clearTimeout(this.failedConnTimeout)
|
detail: this,
|
||||||
this.failedConnTimeout = null
|
})
|
||||||
}
|
)
|
||||||
this.failedConnTimeout = setTimeout(() => {
|
|
||||||
if (this.isReady()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.failedConnTimeout = null
|
|
||||||
this.state = {
|
|
||||||
type: EngineConnectionStateType.Disconnecting,
|
|
||||||
value: {
|
|
||||||
type: DisconnectingType.Timeout,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
this.disconnectAll()
|
|
||||||
this.finalizeIfAllConnectionsClosed()
|
|
||||||
}, connectionTimeoutMs)
|
|
||||||
|
|
||||||
this.onConnectionStarted(this)
|
|
||||||
}
|
}
|
||||||
unreliableSend(message: object | string) {
|
unreliableSend(message: object | string) {
|
||||||
// TODO(paultag): Add in logic to determine the connection state and
|
// TODO(paultag): Add in logic to determine the connection state and
|
||||||
@ -796,6 +798,8 @@ interface UnreliableSubscription<T extends UnreliableResponses['type']> {
|
|||||||
callback: (data: Extract<UnreliableResponses, { type: T }>) => void
|
callback: (data: Extract<UnreliableResponses, { type: T }>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Should eventually be replaced with native EventTarget event system,
|
||||||
|
// as it manages events in a more familiar way to other developers.
|
||||||
export interface Subscription<T extends ModelTypes> {
|
export interface Subscription<T extends ModelTypes> {
|
||||||
event: T
|
event: T
|
||||||
callback: (
|
callback: (
|
||||||
@ -823,7 +827,11 @@ export type CommandLog =
|
|||||||
data: null
|
data: null
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EngineCommandManager {
|
export enum EngineCommandManagerEvents {
|
||||||
|
EngineAvailable = 'engine-available',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EngineCommandManager extends EventTarget {
|
||||||
artifactMap: ArtifactMap = {}
|
artifactMap: ArtifactMap = {}
|
||||||
lastArtifactMap: ArtifactMap = {}
|
lastArtifactMap: ArtifactMap = {}
|
||||||
sceneCommandArtifacts: ArtifactMap = {}
|
sceneCommandArtifacts: ArtifactMap = {}
|
||||||
@ -857,10 +865,9 @@ export class EngineCommandManager {
|
|||||||
}
|
}
|
||||||
} = {} as any
|
} = {} as any
|
||||||
|
|
||||||
callbacksEngineStateConnection: ((state: EngineConnectionState) => void)[] =
|
|
||||||
[]
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super()
|
||||||
|
|
||||||
this.engineConnection = undefined
|
this.engineConnection = undefined
|
||||||
;(async () => {
|
;(async () => {
|
||||||
// circular dependency needs one to be lazy loaded
|
// circular dependency needs one to be lazy loaded
|
||||||
@ -901,12 +908,17 @@ export class EngineCommandManager {
|
|||||||
this.engineConnection = new EngineConnection({
|
this.engineConnection = new EngineConnection({
|
||||||
url,
|
url,
|
||||||
token,
|
token,
|
||||||
onConnectionStateChange: (state: EngineConnectionState) => {
|
})
|
||||||
for (let cb of this.callbacksEngineStateConnection) {
|
|
||||||
cb(state)
|
this.dispatchEvent(
|
||||||
}
|
new CustomEvent(EngineCommandManagerEvents.EngineAvailable, {
|
||||||
},
|
detail: this.engineConnection,
|
||||||
onEngineConnectionOpen: () => {
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
this.engineConnection.addEventListener(
|
||||||
|
EngineConnectionEvents.Opened,
|
||||||
|
() => {
|
||||||
// Make the axis gizmo.
|
// Make the axis gizmo.
|
||||||
// We do this after the connection opened to avoid a race condition.
|
// We do this after the connection opened to avoid a race condition.
|
||||||
// Connected opened is the last thing that happens when the stream
|
// Connected opened is the last thing that happens when the stream
|
||||||
@ -941,78 +953,98 @@ export class EngineCommandManager {
|
|||||||
setIsStreamReady(true)
|
setIsStreamReady(true)
|
||||||
executeCode(undefined, true)
|
executeCode(undefined, true)
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
onClose: () => {
|
)
|
||||||
setIsStreamReady(false)
|
|
||||||
},
|
|
||||||
onConnectionStarted: (engineConnection) => {
|
|
||||||
engineConnection?.pc?.addEventListener('datachannel', (event) => {
|
|
||||||
let unreliableDataChannel = event.channel
|
|
||||||
|
|
||||||
unreliableDataChannel.addEventListener('message', (event) => {
|
this.engineConnection.addEventListener(
|
||||||
const result: UnreliableResponses = JSON.parse(event.data)
|
EngineConnectionEvents.Closed,
|
||||||
Object.values(
|
() => {
|
||||||
this.unreliableSubscriptions[result.type] || {}
|
setIsStreamReady(false)
|
||||||
).forEach(
|
}
|
||||||
// TODO: There is only one response that uses the unreliable channel atm,
|
)
|
||||||
// highlight_set_entity, if there are more it's likely they will all have the same
|
|
||||||
// sequence logic, but I'm not sure if we use a single global sequence or a sequence
|
this.engineConnection.addEventListener(
|
||||||
// per unreliable subscription.
|
EngineConnectionEvents.ConnectionStarted,
|
||||||
(callback) => {
|
(({ detail: engineConnection }: CustomEvent) => {
|
||||||
if (
|
engineConnection?.pc?.addEventListener(
|
||||||
result?.data?.sequence &&
|
'datachannel',
|
||||||
result?.data.sequence > this.inSequence &&
|
(event: RTCDataChannelEvent) => {
|
||||||
result.type === 'highlight_set_entity'
|
let unreliableDataChannel = event.channel
|
||||||
) {
|
|
||||||
this.inSequence = result.data.sequence
|
unreliableDataChannel.addEventListener(
|
||||||
callback(result)
|
'message',
|
||||||
}
|
(event: MessageEvent) => {
|
||||||
|
const result: UnreliableResponses = JSON.parse(event.data)
|
||||||
|
Object.values(
|
||||||
|
this.unreliableSubscriptions[result.type] || {}
|
||||||
|
).forEach(
|
||||||
|
// TODO: There is only one response that uses the unreliable channel atm,
|
||||||
|
// highlight_set_entity, if there are more it's likely they will all have the same
|
||||||
|
// sequence logic, but I'm not sure if we use a single global sequence or a sequence
|
||||||
|
// per unreliable subscription.
|
||||||
|
(callback) => {
|
||||||
|
if (
|
||||||
|
result?.data?.sequence &&
|
||||||
|
result?.data.sequence > this.inSequence &&
|
||||||
|
result.type === 'highlight_set_entity'
|
||||||
|
) {
|
||||||
|
this.inSequence = result.data.sequence
|
||||||
|
callback(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
// When the EngineConnection starts a connection, we want to register
|
// When the EngineConnection starts a connection, we want to register
|
||||||
// callbacks into the WebSocket/PeerConnection.
|
// callbacks into the WebSocket/PeerConnection.
|
||||||
engineConnection.websocket?.addEventListener('message', (event) => {
|
engineConnection.websocket?.addEventListener(
|
||||||
if (event.data instanceof ArrayBuffer) {
|
'message',
|
||||||
// If the data is an ArrayBuffer, it's the result of an export command,
|
(event: MessageEvent) => {
|
||||||
// because in all other cases we send JSON strings. But in the case of
|
if (event.data instanceof ArrayBuffer) {
|
||||||
// export we send a binary blob.
|
// If the data is an ArrayBuffer, it's the result of an export command,
|
||||||
// Pass this to our export function.
|
// because in all other cases we send JSON strings. But in the case of
|
||||||
void exportSave(event.data)
|
// export we send a binary blob.
|
||||||
} else {
|
// Pass this to our export function.
|
||||||
const message: Models['WebSocketResponse_type'] = JSON.parse(
|
void exportSave(event.data)
|
||||||
event.data
|
} else {
|
||||||
)
|
const message: Models['WebSocketResponse_type'] = JSON.parse(
|
||||||
if (
|
event.data
|
||||||
message.success &&
|
)
|
||||||
message.resp.type === 'modeling' &&
|
if (
|
||||||
message.request_id
|
message.success &&
|
||||||
) {
|
message.resp.type === 'modeling' &&
|
||||||
this.handleModelingCommand(message.resp, message.request_id)
|
message.request_id
|
||||||
} else if (
|
) {
|
||||||
!message.success &&
|
this.handleModelingCommand(message.resp, message.request_id)
|
||||||
message.request_id &&
|
} else if (
|
||||||
this.artifactMap[message.request_id]
|
!message.success &&
|
||||||
) {
|
message.request_id &&
|
||||||
this.handleFailedModelingCommand(message)
|
this.artifactMap[message.request_id]
|
||||||
|
) {
|
||||||
|
this.handleFailedModelingCommand(message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
},
|
}) as EventListener
|
||||||
onNewTrack: ({ mediaStream }) => {
|
)
|
||||||
console.log('received track', mediaStream)
|
|
||||||
|
|
||||||
mediaStream.getVideoTracks()[0].addEventListener('mute', () => {
|
this.engineConnection.addEventListener(EngineConnectionEvents.NewTrack, (({
|
||||||
console.log('peer is not sending video to us')
|
detail: { mediaStream },
|
||||||
// this.engineConnection?.close()
|
}: CustomEvent) => {
|
||||||
// this.engineConnection?.connect()
|
console.log('received track', mediaStream)
|
||||||
})
|
|
||||||
|
|
||||||
setMediaStream(mediaStream)
|
mediaStream.getVideoTracks()[0].addEventListener('mute', () => {
|
||||||
},
|
console.log('peer is not sending video to us')
|
||||||
})
|
// this.engineConnection?.close()
|
||||||
|
// this.engineConnection?.connect()
|
||||||
|
})
|
||||||
|
|
||||||
|
setMediaStream(mediaStream)
|
||||||
|
}) as EventListener)
|
||||||
|
|
||||||
this.engineConnection?.connect()
|
this.engineConnection?.connect()
|
||||||
}
|
}
|
||||||
@ -1202,9 +1234,6 @@ export class EngineCommandManager {
|
|||||||
) {
|
) {
|
||||||
delete this.unreliableSubscriptions[event][id]
|
delete this.unreliableSubscriptions[event][id]
|
||||||
}
|
}
|
||||||
onConnectionStateChange(callback: (state: EngineConnectionState) => void) {
|
|
||||||
this.callbacksEngineStateConnection.push(callback)
|
|
||||||
}
|
|
||||||
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 individually because if the engine doesn't recognise a single
|
||||||
|
|||||||
@ -149,7 +149,7 @@ export const lineTo: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('default'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const line: SketchLineHelper = {
|
export const line: SketchLineHelper = {
|
||||||
@ -240,7 +240,7 @@ export const line: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('default'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const xLineTo: SketchLineHelper = {
|
export const xLineTo: SketchLineHelper = {
|
||||||
@ -288,7 +288,7 @@ export const xLineTo: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('default'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const yLineTo: SketchLineHelper = {
|
export const yLineTo: SketchLineHelper = {
|
||||||
@ -336,7 +336,7 @@ export const yLineTo: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('default'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const xLine: SketchLineHelper = {
|
export const xLine: SketchLineHelper = {
|
||||||
@ -386,7 +386,7 @@ export const xLine: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('length'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const yLine: SketchLineHelper = {
|
export const yLine: SketchLineHelper = {
|
||||||
@ -430,7 +430,7 @@ export const yLine: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('length'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tangentialArcTo: SketchLineHelper = {
|
export const tangentialArcTo: SketchLineHelper = {
|
||||||
@ -510,7 +510,7 @@ export const tangentialArcTo: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO copy-paste from angledLine
|
// TODO copy-paste from angledLine
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('angleLength'),
|
||||||
}
|
}
|
||||||
export const angledLine: SketchLineHelper = {
|
export const angledLine: SketchLineHelper = {
|
||||||
add: ({
|
add: ({
|
||||||
@ -576,7 +576,7 @@ export const angledLine: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('angleLength'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineOfXLength: SketchLineHelper = {
|
export const angledLineOfXLength: SketchLineHelper = {
|
||||||
@ -649,7 +649,7 @@ export const angledLineOfXLength: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('angleLength'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineOfYLength: SketchLineHelper = {
|
export const angledLineOfYLength: SketchLineHelper = {
|
||||||
@ -723,7 +723,7 @@ export const angledLineOfYLength: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('angleLength'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineToX: SketchLineHelper = {
|
export const angledLineToX: SketchLineHelper = {
|
||||||
@ -792,7 +792,7 @@ export const angledLineToX: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('angleTo'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineToY: SketchLineHelper = {
|
export const angledLineToY: SketchLineHelper = {
|
||||||
@ -862,7 +862,7 @@ export const angledLineToY: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(),
|
addTag: addTagWithTo('angleTo'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineThatIntersects: SketchLineHelper = {
|
export const angledLineThatIntersects: SketchLineHelper = {
|
||||||
@ -951,7 +951,7 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTag: addTag(), // TODO might be wrong
|
addTag: addTagWithTo('angleTo'), // TODO might be wrong
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
||||||
@ -1174,31 +1174,29 @@ function isAngleLiteral(lineArugement: Value): boolean {
|
|||||||
|
|
||||||
type addTagFn = (a: ModifyAstBase) => { modifiedAst: Program; tag: string }
|
type addTagFn = (a: ModifyAstBase) => { modifiedAst: Program; tag: string }
|
||||||
|
|
||||||
function addTag(): addTagFn {
|
function addTagWithTo(
|
||||||
|
argType: 'angleLength' | 'angleTo' | 'default' | 'length'
|
||||||
|
): addTagFn {
|
||||||
return ({ node, pathToNode }) => {
|
return ({ node, pathToNode }) => {
|
||||||
|
let tagName = findUniqueName(node, 'seg', 2)
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const { node: primaryCallExp } = getNodeFromPath<CallExpression>(
|
const { node: callExpression } = getNodeFromPath<CallExpression>(
|
||||||
_node,
|
_node,
|
||||||
pathToNode,
|
pathToNode
|
||||||
'CallExpression'
|
|
||||||
)
|
)
|
||||||
// Tag is always 3rd expression now, using arg index feels brittle
|
const tagArg = callExpression.arguments?.[2]
|
||||||
// but we can come up with a better way to identify tag later.
|
if (tagArg) {
|
||||||
const thirdArg = primaryCallExp.arguments?.[2]
|
|
||||||
const tagLiteral =
|
|
||||||
thirdArg || (createLiteral(findUniqueName(_node, 'seg', 2)) as Literal)
|
|
||||||
const isTagExisting = !!thirdArg
|
|
||||||
if (!isTagExisting) {
|
|
||||||
primaryCallExp.arguments[2] = tagLiteral
|
|
||||||
}
|
|
||||||
if ('value' in tagLiteral) {
|
|
||||||
// Now TypeScript knows tagLiteral has a value property
|
|
||||||
return {
|
return {
|
||||||
modifiedAst: _node,
|
modifiedAst: _node,
|
||||||
tag: String(tagLiteral.value),
|
tag: String(tagArg),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unable to assign tag without value')
|
callExpression.arguments[2] = createLiteral(tagName)
|
||||||
|
|
||||||
|
return {
|
||||||
|
modifiedAst: _node,
|
||||||
|
tag: tagName,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/wasm-lib/Cargo.lock
generated
22
src/wasm-lib/Cargo.lock
generated
@ -1471,9 +1471,7 @@ dependencies = [
|
|||||||
name = "grackle"
|
name = "grackle"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"image",
|
|
||||||
"kcl-lib",
|
"kcl-lib",
|
||||||
"kcl-macros",
|
|
||||||
"kittycad",
|
"kittycad",
|
||||||
"kittycad-execution-plan",
|
"kittycad-execution-plan",
|
||||||
"kittycad-execution-plan-macros",
|
"kittycad-execution-plan-macros",
|
||||||
@ -1484,7 +1482,6 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"twenty-twenty",
|
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2010,7 +2007,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-execution-plan"
|
name = "kittycad-execution-plan"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#0fa02b1829e16ab67aca2f6153dc29e3fe3a358b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"insta",
|
"insta",
|
||||||
@ -2030,7 +2027,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-execution-plan-macros"
|
name = "kittycad-execution-plan-macros"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#0fa02b1829e16ab67aca2f6153dc29e3fe3a358b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2040,7 +2037,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-execution-plan-traits"
|
name = "kittycad-execution-plan-traits"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#0fa02b1829e16ab67aca2f6153dc29e3fe3a358b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -2050,7 +2047,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-modeling-cmds"
|
name = "kittycad-modeling-cmds"
|
||||||
version = "0.1.32"
|
version = "0.1.32"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#0fa02b1829e16ab67aca2f6153dc29e3fe3a358b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -2078,7 +2075,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-modeling-cmds-macros"
|
name = "kittycad-modeling-cmds-macros"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#0fa02b1829e16ab67aca2f6153dc29e3fe3a358b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2088,12 +2085,11 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-modeling-session"
|
name = "kittycad-modeling-session"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#0fa02b1829e16ab67aca2f6153dc29e3fe3a358b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"kittycad",
|
"kittycad",
|
||||||
"kittycad-modeling-cmds",
|
"kittycad-modeling-cmds",
|
||||||
"lsystem",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -2191,12 +2187,6 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lsystem"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "23c47210f2a9f5ae2073e7b847026e3233bcb012aa6845201c69c26481762a81"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
|||||||
@ -6,9 +6,7 @@ description = "A new executor for KCL which compiles to Execution Plans"
|
|||||||
# 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
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
image = { version = "0.24.7", default-features = false, features = ["png"] }
|
|
||||||
kcl-lib = { path = "../kcl" }
|
kcl-lib = { path = "../kcl" }
|
||||||
kcl-macros = { path = "../kcl-macros/" }
|
|
||||||
kittycad = { workspace = true }
|
kittycad = { workspace = true }
|
||||||
kittycad-execution-plan = { workspace = true }
|
kittycad-execution-plan = { workspace = true }
|
||||||
kittycad-execution-plan-traits = { workspace = true }
|
kittycad-execution-plan-traits = { workspace = true }
|
||||||
@ -17,7 +15,6 @@ kittycad-modeling-cmds = { workspace = true }
|
|||||||
kittycad-modeling-session = { workspace = true }
|
kittycad-modeling-session = { workspace = true }
|
||||||
thiserror = "1.0.57"
|
thiserror = "1.0.57"
|
||||||
tokio = { version = "1.36.0", features = ["macros", "rt"] }
|
tokio = { version = "1.36.0", features = ["macros", "rt"] }
|
||||||
twenty-twenty = "0.7.0"
|
|
||||||
uuid = "1.7"
|
uuid = "1.7"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 81 KiB |
@ -2,16 +2,13 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use kcl_lib::ast::types::{LiteralIdentifier, LiteralValue};
|
use kcl_lib::ast::types::{LiteralIdentifier, LiteralValue};
|
||||||
|
|
||||||
use kittycad_execution_plan::constants;
|
|
||||||
use kittycad_execution_plan_traits::Primitive;
|
|
||||||
|
|
||||||
use super::{native_functions, Address};
|
use super::{native_functions, Address};
|
||||||
use crate::{CompileError, KclFunction};
|
use crate::{CompileError, KclFunction};
|
||||||
|
|
||||||
/// KCL values which can be written to KCEP memory.
|
/// KCL values which can be written to KCEP memory.
|
||||||
/// This is recursive. For example, the bound value might be an array, which itself contains bound values.
|
/// This is recursive. For example, the bound value might be an array, which itself contains bound values.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
pub enum EpBinding {
|
pub enum EpBinding {
|
||||||
/// A KCL value which gets stored in a particular address in KCEP memory.
|
/// A KCL value which gets stored in a particular address in KCEP memory.
|
||||||
Single(Address),
|
Single(Address),
|
||||||
@ -26,8 +23,6 @@ pub enum EpBinding {
|
|||||||
properties: HashMap<String, EpBinding>,
|
properties: HashMap<String, EpBinding>,
|
||||||
},
|
},
|
||||||
/// Not associated with a KCEP address.
|
/// Not associated with a KCEP address.
|
||||||
Constant(Primitive),
|
|
||||||
/// Not associated with a KCEP address.
|
|
||||||
Function(KclFunction),
|
Function(KclFunction),
|
||||||
/// SketchGroups have their own storage.
|
/// SketchGroups have their own storage.
|
||||||
SketchGroup { index: usize },
|
SketchGroup { index: usize },
|
||||||
@ -57,13 +52,11 @@ impl EpBinding {
|
|||||||
EpBinding::SketchGroup { .. } => Err(CompileError::CannotIndex),
|
EpBinding::SketchGroup { .. } => Err(CompileError::CannotIndex),
|
||||||
EpBinding::Single(_) => Err(CompileError::CannotIndex),
|
EpBinding::Single(_) => Err(CompileError::CannotIndex),
|
||||||
EpBinding::Function(_) => Err(CompileError::CannotIndex),
|
EpBinding::Function(_) => Err(CompileError::CannotIndex),
|
||||||
EpBinding::Constant(_) => Err(CompileError::CannotIndex),
|
|
||||||
},
|
},
|
||||||
// Objects can be indexed by string properties.
|
// Objects can be indexed by string properties.
|
||||||
LiteralValue::String(property) => match self {
|
LiteralValue::String(property) => match self {
|
||||||
EpBinding::Single(_) => Err(CompileError::NoProperties),
|
EpBinding::Single(_) => Err(CompileError::NoProperties),
|
||||||
EpBinding::Function(_) => Err(CompileError::NoProperties),
|
EpBinding::Function(_) => Err(CompileError::NoProperties),
|
||||||
EpBinding::Constant(_) => Err(CompileError::CannotIndex),
|
|
||||||
EpBinding::SketchGroup { .. } => Err(CompileError::NoProperties),
|
EpBinding::SketchGroup { .. } => Err(CompileError::NoProperties),
|
||||||
EpBinding::Sequence { .. } => Err(CompileError::ArrayDoesNotHaveProperties),
|
EpBinding::Sequence { .. } => Err(CompileError::ArrayDoesNotHaveProperties),
|
||||||
EpBinding::Map {
|
EpBinding::Map {
|
||||||
@ -110,58 +103,8 @@ impl BindingScope {
|
|||||||
// TODO: Actually put the stdlib prelude in here,
|
// TODO: Actually put the stdlib prelude in here,
|
||||||
// things like `startSketchAt` and `line`.
|
// things like `startSketchAt` and `line`.
|
||||||
ep_bindings: HashMap::from([
|
ep_bindings: HashMap::from([
|
||||||
("E".into(), EpBinding::Constant(constants::E)),
|
|
||||||
("PI".into(), EpBinding::Constant(constants::PI)),
|
|
||||||
("id".into(), EpBinding::from(KclFunction::Id(native_functions::Id))),
|
("id".into(), EpBinding::from(KclFunction::Id(native_functions::Id))),
|
||||||
("abs".into(), EpBinding::from(KclFunction::Abs(native_functions::Abs))),
|
|
||||||
(
|
|
||||||
"acos".into(),
|
|
||||||
EpBinding::from(KclFunction::Acos(native_functions::Acos)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"asin".into(),
|
|
||||||
EpBinding::from(KclFunction::Asin(native_functions::Asin)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"atan".into(),
|
|
||||||
EpBinding::from(KclFunction::Atan(native_functions::Atan)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ceil".into(),
|
|
||||||
EpBinding::from(KclFunction::Ceil(native_functions::Ceil)),
|
|
||||||
),
|
|
||||||
("cos".into(), EpBinding::from(KclFunction::Cos(native_functions::Cos))),
|
|
||||||
(
|
|
||||||
"floor".into(),
|
|
||||||
EpBinding::from(KclFunction::Floor(native_functions::Floor)),
|
|
||||||
),
|
|
||||||
("ln".into(), EpBinding::from(KclFunction::Ln(native_functions::Ln))),
|
|
||||||
(
|
|
||||||
"log10".into(),
|
|
||||||
EpBinding::from(KclFunction::Log10(native_functions::Log10)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"log2".into(),
|
|
||||||
EpBinding::from(KclFunction::Log2(native_functions::Log2)),
|
|
||||||
),
|
|
||||||
("sin".into(), EpBinding::from(KclFunction::Sin(native_functions::Sin))),
|
|
||||||
(
|
|
||||||
"sqrt".into(),
|
|
||||||
EpBinding::from(KclFunction::Sqrt(native_functions::Sqrt)),
|
|
||||||
),
|
|
||||||
("tan".into(), EpBinding::from(KclFunction::Tan(native_functions::Tan))),
|
|
||||||
(
|
|
||||||
"toDegrees".into(),
|
|
||||||
EpBinding::from(KclFunction::ToDegrees(native_functions::ToDegrees)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"toRadians".into(),
|
|
||||||
EpBinding::from(KclFunction::ToRadians(native_functions::ToRadians)),
|
|
||||||
),
|
|
||||||
("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
|
("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
|
||||||
("log".into(), EpBinding::from(KclFunction::Log(native_functions::Log))),
|
|
||||||
("max".into(), EpBinding::from(KclFunction::Max(native_functions::Max))),
|
|
||||||
("min".into(), EpBinding::from(KclFunction::Min(native_functions::Min))),
|
|
||||||
(
|
(
|
||||||
"startSketchAt".into(),
|
"startSketchAt".into(),
|
||||||
EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
|
EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
|
||||||
@ -170,26 +113,6 @@ impl BindingScope {
|
|||||||
"lineTo".into(),
|
"lineTo".into(),
|
||||||
EpBinding::from(KclFunction::LineTo(native_functions::sketch::LineTo)),
|
EpBinding::from(KclFunction::LineTo(native_functions::sketch::LineTo)),
|
||||||
),
|
),
|
||||||
(
|
|
||||||
"line".into(),
|
|
||||||
EpBinding::from(KclFunction::Line(native_functions::sketch::Line)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"xLineTo".into(),
|
|
||||||
EpBinding::from(KclFunction::XLineTo(native_functions::sketch::XLineTo)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"xLine".into(),
|
|
||||||
EpBinding::from(KclFunction::XLine(native_functions::sketch::XLine)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"yLineTo".into(),
|
|
||||||
EpBinding::from(KclFunction::YLineTo(native_functions::sketch::YLineTo)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"yLine".into(),
|
|
||||||
EpBinding::from(KclFunction::YLine(native_functions::sketch::YLine)),
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
"extrude".into(),
|
"extrude".into(),
|
||||||
EpBinding::from(KclFunction::Extrude(native_functions::sketch::Extrude)),
|
EpBinding::from(KclFunction::Extrude(native_functions::sketch::Extrude)),
|
||||||
|
|||||||
@ -61,7 +61,7 @@ pub enum Error {
|
|||||||
#[error("Failed on instruction {instruction_index}:\n{error}\n\nInstruction contents were {instruction:#?}")]
|
#[error("Failed on instruction {instruction_index}:\n{error}\n\nInstruction contents were {instruction:#?}")]
|
||||||
Execution {
|
Execution {
|
||||||
error: ExecutionError,
|
error: ExecutionError,
|
||||||
instruction: Instruction,
|
instruction: Option<Instruction>,
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ impl From<ExecutionFailed> for Error {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self::Execution {
|
Self::Execution {
|
||||||
error,
|
error,
|
||||||
instruction: instruction.expect("no instruction"),
|
instruction,
|
||||||
instruction_index,
|
instruction_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,6 @@ use kcl_lib::{
|
|||||||
ast,
|
ast,
|
||||||
ast::types::{BodyItem, FunctionExpressionParts, KclNone, LiteralValue, Program},
|
ast::types::{BodyItem, FunctionExpressionParts, KclNone, LiteralValue, Program},
|
||||||
};
|
};
|
||||||
extern crate alloc;
|
|
||||||
use kcl_macros::parse_file;
|
|
||||||
use kcl_value_group::into_single_value;
|
use kcl_value_group::into_single_value;
|
||||||
use kittycad_execution_plan::{self as ep, Destination, Instruction};
|
use kittycad_execution_plan::{self as ep, Destination, Instruction};
|
||||||
use kittycad_execution_plan_traits as ept;
|
use kittycad_execution_plan_traits as ept;
|
||||||
@ -26,11 +24,9 @@ use self::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Execute a KCL program by compiling into an execution plan, then running that.
|
/// Execute a KCL program by compiling into an execution plan, then running that.
|
||||||
/// Include a `prelude.kcl` inlined as a `Program` struct thanks to a proc_macro `parse!`.
|
pub async fn execute(ast: Program, session: &mut Option<Session>) -> Result<ep::Memory, Error> {
|
||||||
/// This makes additional functions available to the user.
|
|
||||||
pub async fn execute(ast_user: Program, session: &mut Option<Session>) -> Result<ep::Memory, Error> {
|
|
||||||
let mut planner = Planner::new();
|
let mut planner = Planner::new();
|
||||||
let (plan, _retval) = planner.build_plan(ast_user)?;
|
let (plan, _retval) = planner.build_plan(ast)?;
|
||||||
let mut mem = ep::Memory::default();
|
let mut mem = ep::Memory::default();
|
||||||
ep::execute(&mut mem, plan, session).await?;
|
ep::execute(&mut mem, plan, session).await?;
|
||||||
Ok(mem)
|
Ok(mem)
|
||||||
@ -58,9 +54,7 @@ impl Planner {
|
|||||||
|
|
||||||
/// If successful, return the KCEP instructions for executing the given program.
|
/// If successful, return the KCEP instructions for executing the given program.
|
||||||
/// If the program is a function with a return, then it also returns the KCL function's return value.
|
/// If the program is a function with a return, then it also returns the KCL function's return value.
|
||||||
fn build_plan(&mut self, ast_user: Program) -> Result<(Vec<Instruction>, Option<EpBinding>), CompileError> {
|
fn build_plan(&mut self, program: Program) -> Result<(Vec<Instruction>, Option<EpBinding>), CompileError> {
|
||||||
let ast_prelude = parse_file!("./prelude.kcl");
|
|
||||||
let program = ast_prelude.merge(ast_user);
|
|
||||||
program
|
program
|
||||||
.body
|
.body
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -265,32 +259,9 @@ impl Planner {
|
|||||||
binding,
|
binding,
|
||||||
} = match callee {
|
} = match callee {
|
||||||
KclFunction::Id(f) => f.call(&mut ctx, args)?,
|
KclFunction::Id(f) => f.call(&mut ctx, args)?,
|
||||||
KclFunction::Abs(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Acos(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Asin(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Atan(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Ceil(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Cos(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Floor(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Ln(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Log10(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Log2(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Sin(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Sqrt(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Tan(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::ToDegrees(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::ToRadians(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Log(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Max(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Min(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::StartSketchAt(f) => f.call(&mut ctx, args)?,
|
KclFunction::StartSketchAt(f) => f.call(&mut ctx, args)?,
|
||||||
KclFunction::Extrude(f) => f.call(&mut ctx, args)?,
|
KclFunction::Extrude(f) => f.call(&mut ctx, args)?,
|
||||||
KclFunction::LineTo(f) => f.call(&mut ctx, args)?,
|
KclFunction::LineTo(f) => f.call(&mut ctx, args)?,
|
||||||
KclFunction::Line(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::XLineTo(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::XLine(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::YLineTo(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::YLine(f) => f.call(&mut ctx, args)?,
|
|
||||||
KclFunction::Add(f) => f.call(&mut ctx, args)?,
|
KclFunction::Add(f) => f.call(&mut ctx, args)?,
|
||||||
KclFunction::Close(f) => f.call(&mut ctx, args)?,
|
KclFunction::Close(f) => f.call(&mut ctx, args)?,
|
||||||
KclFunction::UserDefined(f) => {
|
KclFunction::UserDefined(f) => {
|
||||||
@ -658,32 +629,9 @@ impl Eq for UserDefinedFunction {}
|
|||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
enum KclFunction {
|
enum KclFunction {
|
||||||
Id(native_functions::Id),
|
Id(native_functions::Id),
|
||||||
Abs(native_functions::Abs),
|
|
||||||
Acos(native_functions::Acos),
|
|
||||||
Asin(native_functions::Asin),
|
|
||||||
Atan(native_functions::Atan),
|
|
||||||
Ceil(native_functions::Ceil),
|
|
||||||
Cos(native_functions::Cos),
|
|
||||||
Floor(native_functions::Floor),
|
|
||||||
Ln(native_functions::Ln),
|
|
||||||
Log10(native_functions::Log10),
|
|
||||||
Log2(native_functions::Log2),
|
|
||||||
Sin(native_functions::Sin),
|
|
||||||
Sqrt(native_functions::Sqrt),
|
|
||||||
Tan(native_functions::Tan),
|
|
||||||
ToDegrees(native_functions::ToDegrees),
|
|
||||||
ToRadians(native_functions::ToRadians),
|
|
||||||
StartSketchAt(native_functions::sketch::StartSketchAt),
|
StartSketchAt(native_functions::sketch::StartSketchAt),
|
||||||
LineTo(native_functions::sketch::LineTo),
|
LineTo(native_functions::sketch::LineTo),
|
||||||
Line(native_functions::sketch::Line),
|
|
||||||
XLineTo(native_functions::sketch::XLineTo),
|
|
||||||
XLine(native_functions::sketch::XLine),
|
|
||||||
YLineTo(native_functions::sketch::YLineTo),
|
|
||||||
YLine(native_functions::sketch::YLine),
|
|
||||||
Add(native_functions::Add),
|
Add(native_functions::Add),
|
||||||
Log(native_functions::Log),
|
|
||||||
Max(native_functions::Max),
|
|
||||||
Min(native_functions::Min),
|
|
||||||
UserDefined(UserDefinedFunction),
|
UserDefined(UserDefinedFunction),
|
||||||
Extrude(native_functions::sketch::Extrude),
|
Extrude(native_functions::sketch::Extrude),
|
||||||
Close(native_functions::sketch::Close),
|
Close(native_functions::sketch::Close),
|
||||||
|
|||||||
@ -2,15 +2,18 @@
|
|||||||
//! This includes some of the stdlib, e.g. `startSketchAt`.
|
//! This includes some of the stdlib, e.g. `startSketchAt`.
|
||||||
//! But some other stdlib functions will be written in KCL.
|
//! But some other stdlib functions will be written in KCL.
|
||||||
|
|
||||||
use kittycad_execution_plan::{
|
use kittycad_execution_plan::{BinaryArithmetic, Destination, Instruction};
|
||||||
BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand, UnaryArithmetic, UnaryOperation,
|
|
||||||
};
|
|
||||||
use kittycad_execution_plan_traits::Address;
|
use kittycad_execution_plan_traits::Address;
|
||||||
|
|
||||||
use crate::{CompileError, EpBinding, EvalPlan};
|
use crate::{CompileError, EpBinding, EvalPlan};
|
||||||
|
|
||||||
pub mod sketch;
|
pub mod sketch;
|
||||||
|
|
||||||
|
/// The identity function. Always returns its first input.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
|
pub struct Id;
|
||||||
|
|
||||||
pub trait Callable {
|
pub trait Callable {
|
||||||
fn call(&self, ctx: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError>;
|
fn call(&self, ctx: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError>;
|
||||||
}
|
}
|
||||||
@ -29,65 +32,6 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unary operator macro to quickly create new bindings.
|
|
||||||
macro_rules! define_unary {
|
|
||||||
() => {};
|
|
||||||
($fn_name:ident$( $rest:ident)*) => {
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct $fn_name;
|
|
||||||
|
|
||||||
impl Callable for $fn_name {
|
|
||||||
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
|
||||||
if args.len() > 1 {
|
|
||||||
return Err(CompileError::TooManyArgs {
|
|
||||||
fn_name: "$fn_name".into(),
|
|
||||||
maximum: 1,
|
|
||||||
actual: args.len(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let not_enough_args = CompileError::NotEnoughArgs {
|
|
||||||
fn_name: "$fn_name".into(),
|
|
||||||
required: 1,
|
|
||||||
actual: args.len(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args.clone())? else {
|
|
||||||
return Err(CompileError::InvalidOperand("A single value binding is expected"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let destination = ctx.next_address.offset_by(1);
|
|
||||||
let instructions = vec![
|
|
||||||
Instruction::UnaryArithmetic {
|
|
||||||
arithmetic: UnaryArithmetic {
|
|
||||||
operation: UnaryOperation::$fn_name,
|
|
||||||
operand: Operand::Reference(arg0)
|
|
||||||
},
|
|
||||||
destination: Destination::Address(destination)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
Ok(EvalPlan {
|
|
||||||
instructions,
|
|
||||||
binding: EpBinding::Single(destination),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_unary!($($rest)*);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
define_unary!(Abs Acos Asin Atan Ceil Cos Floor Ln Log10 Log2 Sin Sqrt Tan ToDegrees ToRadians);
|
|
||||||
|
|
||||||
/// The identity function. Always returns its first input.
|
|
||||||
/// Implemented purely on the KCL side so it doesn't need to be in the
|
|
||||||
/// define_unary! macro above.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct Id;
|
|
||||||
|
|
||||||
impl Callable for Id {
|
impl Callable for Id {
|
||||||
fn call(&self, _: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
fn call(&self, _: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
@ -112,53 +56,44 @@ impl Callable for Id {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Binary operator macro to quickly create new bindings.
|
/// A test function that adds two numbers.
|
||||||
macro_rules! define_binary {
|
#[derive(Debug, Clone)]
|
||||||
() => {};
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
($fn_name:ident$( $rest:ident)*) => {
|
pub struct Add;
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct $fn_name;
|
|
||||||
|
|
||||||
impl Callable for $fn_name {
|
impl Callable for Add {
|
||||||
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||||
let len = args.len();
|
let len = args.len();
|
||||||
if len > 2 {
|
if len > 2 {
|
||||||
return Err(CompileError::TooManyArgs {
|
return Err(CompileError::TooManyArgs {
|
||||||
fn_name: "$fn_name".into(),
|
fn_name: "add".into(),
|
||||||
maximum: 2,
|
maximum: 2,
|
||||||
actual: len,
|
actual: len,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
let not_enough_args = CompileError::NotEnoughArgs {
|
|
||||||
fn_name: "$fn_name".into(),
|
|
||||||
required: 2,
|
|
||||||
actual: len,
|
|
||||||
};
|
|
||||||
const ERR: &str = "cannot use composite values (e.g. array) as arguments to $fn_name";
|
|
||||||
let EpBinding::Single(arg1) = args.pop().ok_or(not_enough_args.clone())? else {
|
|
||||||
return Err(CompileError::InvalidOperand(ERR));
|
|
||||||
};
|
|
||||||
let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args)? else {
|
|
||||||
return Err(CompileError::InvalidOperand(ERR));
|
|
||||||
};
|
|
||||||
let destination = ctx.next_address.offset_by(1);
|
|
||||||
Ok(EvalPlan {
|
|
||||||
instructions: vec![Instruction::BinaryArithmetic {
|
|
||||||
arithmetic: BinaryArithmetic {
|
|
||||||
operation: BinaryOperation::$fn_name,
|
|
||||||
operand0: Operand::Reference(arg0),
|
|
||||||
operand1: Operand::Reference(arg1),
|
|
||||||
},
|
|
||||||
destination: Destination::Address(destination),
|
|
||||||
}],
|
|
||||||
binding: EpBinding::Single(destination),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
let not_enough_args = CompileError::NotEnoughArgs {
|
||||||
|
fn_name: "add".into(),
|
||||||
|
required: 2,
|
||||||
|
actual: len,
|
||||||
|
};
|
||||||
|
const ERR: &str = "cannot use composite values (e.g. array) as arguments to Add";
|
||||||
|
let EpBinding::Single(arg1) = args.pop().ok_or(not_enough_args.clone())? else {
|
||||||
|
return Err(CompileError::InvalidOperand(ERR));
|
||||||
|
};
|
||||||
|
let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args)? else {
|
||||||
|
return Err(CompileError::InvalidOperand(ERR));
|
||||||
|
};
|
||||||
|
let destination = ctx.next_address.offset_by(1);
|
||||||
|
Ok(EvalPlan {
|
||||||
|
instructions: vec![Instruction::BinaryArithmetic {
|
||||||
|
arithmetic: BinaryArithmetic {
|
||||||
|
operation: kittycad_execution_plan::BinaryOperation::Add,
|
||||||
|
operand0: kittycad_execution_plan::Operand::Reference(arg0),
|
||||||
|
operand1: kittycad_execution_plan::Operand::Reference(arg1),
|
||||||
|
},
|
||||||
|
destination: Destination::Address(destination),
|
||||||
|
}],
|
||||||
|
binding: EpBinding::Single(destination),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
define_binary!($($rest)*);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
define_binary!(Add Log Max Min);
|
|
||||||
|
|||||||
@ -3,4 +3,4 @@
|
|||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod stdlib_functions;
|
pub mod stdlib_functions;
|
||||||
|
|
||||||
pub use stdlib_functions::{Close, Extrude, Line, LineTo, StartSketchAt, XLine, XLineTo, YLine, YLineTo};
|
pub use stdlib_functions::{Close, Extrude, LineTo, StartSketchAt};
|
||||||
|
|||||||
@ -67,12 +67,6 @@ pub fn sg_binding(
|
|||||||
actual: "function".to_owned(),
|
actual: "function".to_owned(),
|
||||||
arg_number,
|
arg_number,
|
||||||
}),
|
}),
|
||||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
|
||||||
fn_name,
|
|
||||||
expected,
|
|
||||||
actual: "constant".to_owned(),
|
|
||||||
arg_number,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn single_binding(
|
pub fn single_binding(
|
||||||
@ -107,12 +101,6 @@ pub fn single_binding(
|
|||||||
actual: "function".to_owned(),
|
actual: "function".to_owned(),
|
||||||
arg_number,
|
arg_number,
|
||||||
}),
|
}),
|
||||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
|
||||||
fn_name,
|
|
||||||
expected,
|
|
||||||
actual: "constant".to_owned(),
|
|
||||||
arg_number,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,16 +136,10 @@ pub fn sequence_binding(
|
|||||||
actual: "function".to_owned(),
|
actual: "function".to_owned(),
|
||||||
arg_number,
|
arg_number,
|
||||||
}),
|
}),
|
||||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
|
||||||
fn_name,
|
|
||||||
expected,
|
|
||||||
actual: "constant".to_owned(),
|
|
||||||
arg_number,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract a 2D point from an argument to a KCL Function.
|
/// Extract a 2D point from an argument to a Cabble.
|
||||||
pub fn arg_point2d(
|
pub fn arg_point2d(
|
||||||
arg: EpBinding,
|
arg: EpBinding,
|
||||||
fn_name: &'static str,
|
fn_name: &'static str,
|
||||||
@ -166,7 +148,7 @@ pub fn arg_point2d(
|
|||||||
arg_number: usize,
|
arg_number: usize,
|
||||||
) -> Result<Address, CompileError> {
|
) -> Result<Address, CompileError> {
|
||||||
let expected = "2D point (array with length 2)";
|
let expected = "2D point (array with length 2)";
|
||||||
let elements = sequence_binding(arg, fn_name, "an array of length 2", arg_number)?;
|
let elements = sequence_binding(arg, "startSketchAt", "an array of length 2", arg_number)?;
|
||||||
if elements.len() != 2 {
|
if elements.len() != 2 {
|
||||||
return Err(CompileError::ArgWrongType {
|
return Err(CompileError::ArgWrongType {
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -183,12 +165,12 @@ pub fn arg_point2d(
|
|||||||
let start_z = start + 2;
|
let start_z = start + 2;
|
||||||
instructions.extend([
|
instructions.extend([
|
||||||
Instruction::Copy {
|
Instruction::Copy {
|
||||||
source: single_binding(elements[0].clone(), fn_name, "number", arg_number)?,
|
source: single_binding(elements[0].clone(), "startSketchAt", "number", arg_number)?,
|
||||||
destination: Destination::Address(start_x),
|
destination: Destination::Address(start_x),
|
||||||
length: 1,
|
length: 1,
|
||||||
},
|
},
|
||||||
Instruction::Copy {
|
Instruction::Copy {
|
||||||
source: single_binding(elements[1].clone(), fn_name, "number", arg_number)?,
|
source: single_binding(elements[1].clone(), "startSketchAt", "number", arg_number)?,
|
||||||
destination: Destination::Address(start_y),
|
destination: Destination::Address(start_y),
|
||||||
length: 1,
|
length: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use kittycad_execution_plan::{
|
use kittycad_execution_plan::{
|
||||||
api_request::ApiRequest,
|
api_request::ApiRequest,
|
||||||
sketch_types::{self, Axes, BasePath, Plane, SketchGroup},
|
sketch_types::{self, Axes, BasePath, Plane, SketchGroup},
|
||||||
BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand,
|
Destination, Instruction,
|
||||||
};
|
};
|
||||||
use kittycad_execution_plan_traits::{Address, InMemory, Primitive, Value};
|
use kittycad_execution_plan_traits::{Address, InMemory, Primitive, Value};
|
||||||
use kittycad_modeling_cmds::{
|
use kittycad_modeling_cmds::{
|
||||||
@ -13,22 +13,6 @@ use uuid::Uuid;
|
|||||||
use super::helpers::{arg_point2d, no_arg_api_call, sg_binding, single_binding, stack_api_call};
|
use super::helpers::{arg_point2d, no_arg_api_call, sg_binding, single_binding, stack_api_call};
|
||||||
use crate::{binding_scope::EpBinding, error::CompileError, native_functions::Callable, EvalPlan};
|
use crate::{binding_scope::EpBinding, error::CompileError, native_functions::Callable, EvalPlan};
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub enum At {
|
|
||||||
RelativeXY,
|
|
||||||
AbsoluteXY,
|
|
||||||
RelativeX,
|
|
||||||
AbsoluteX,
|
|
||||||
RelativeY,
|
|
||||||
AbsoluteY,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl At {
|
|
||||||
pub fn is_relative(&self) -> bool {
|
|
||||||
*self == At::RelativeX || *self == At::RelativeY || *self == At::RelativeXY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
pub struct Close;
|
pub struct Close;
|
||||||
@ -156,124 +140,25 @@ impl Callable for LineTo {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut crate::native_functions::Context<'_>,
|
ctx: &mut crate::native_functions::Context<'_>,
|
||||||
args: Vec<EpBinding>,
|
args: Vec<EpBinding>,
|
||||||
) -> Result<EvalPlan, CompileError> {
|
|
||||||
LineBare::call(ctx, "lineTo", args, LineBareOptions { at: At::AbsoluteXY })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct Line;
|
|
||||||
|
|
||||||
impl Callable for Line {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
ctx: &mut crate::native_functions::Context<'_>,
|
|
||||||
args: Vec<EpBinding>,
|
|
||||||
) -> Result<EvalPlan, CompileError> {
|
|
||||||
LineBare::call(ctx, "line", args, LineBareOptions { at: At::RelativeXY })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct XLineTo;
|
|
||||||
|
|
||||||
impl Callable for XLineTo {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
ctx: &mut crate::native_functions::Context<'_>,
|
|
||||||
args: Vec<EpBinding>,
|
|
||||||
) -> Result<EvalPlan, CompileError> {
|
|
||||||
LineBare::call(ctx, "xLineTo", args, LineBareOptions { at: At::AbsoluteX })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct XLine;
|
|
||||||
|
|
||||||
impl Callable for XLine {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
ctx: &mut crate::native_functions::Context<'_>,
|
|
||||||
args: Vec<EpBinding>,
|
|
||||||
) -> Result<EvalPlan, CompileError> {
|
|
||||||
LineBare::call(ctx, "xLine", args, LineBareOptions { at: At::RelativeX })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct YLineTo;
|
|
||||||
|
|
||||||
impl Callable for YLineTo {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
ctx: &mut crate::native_functions::Context<'_>,
|
|
||||||
args: Vec<EpBinding>,
|
|
||||||
) -> Result<EvalPlan, CompileError> {
|
|
||||||
LineBare::call(ctx, "yLineTo", args, LineBareOptions { at: At::AbsoluteY })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct YLine;
|
|
||||||
|
|
||||||
impl Callable for YLine {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
ctx: &mut crate::native_functions::Context<'_>,
|
|
||||||
args: Vec<EpBinding>,
|
|
||||||
) -> Result<EvalPlan, CompileError> {
|
|
||||||
LineBare::call(ctx, "yLine", args, LineBareOptions { at: At::RelativeY })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
/// Exposes all the possible arguments the `line` modeling command can take.
|
|
||||||
/// Reduces code for the other line functions needed.
|
|
||||||
/// We do not expose this to the developer since it does not align with
|
|
||||||
/// the documentation (there is no "lineBare").
|
|
||||||
pub struct LineBare;
|
|
||||||
|
|
||||||
/// Used to configure the call to handle different line variants.
|
|
||||||
pub struct LineBareOptions {
|
|
||||||
/// Where to start coordinates at, ex: At::RelativeXY.
|
|
||||||
at: At,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LineBare {
|
|
||||||
fn call(
|
|
||||||
ctx: &mut crate::native_functions::Context<'_>,
|
|
||||||
fn_name: &'static str,
|
|
||||||
args: Vec<EpBinding>,
|
|
||||||
opts: LineBareOptions,
|
|
||||||
) -> Result<EvalPlan, CompileError> {
|
) -> Result<EvalPlan, CompileError> {
|
||||||
let mut instructions = Vec::new();
|
let mut instructions = Vec::new();
|
||||||
|
let fn_name = "lineTo";
|
||||||
let required = 2;
|
// Get both required params.
|
||||||
|
|
||||||
let mut args_iter = args.into_iter();
|
let mut args_iter = args.into_iter();
|
||||||
|
|
||||||
let Some(to) = args_iter.next() else {
|
let Some(to) = args_iter.next() else {
|
||||||
return Err(CompileError::NotEnoughArgs {
|
return Err(CompileError::NotEnoughArgs {
|
||||||
fn_name: fn_name.into(),
|
fn_name: fn_name.into(),
|
||||||
required,
|
required: 2,
|
||||||
actual: args_iter.count(),
|
actual: 0,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(sketch_group) = args_iter.next() else {
|
let Some(sketch_group) = args_iter.next() else {
|
||||||
return Err(CompileError::NotEnoughArgs {
|
return Err(CompileError::NotEnoughArgs {
|
||||||
fn_name: fn_name.into(),
|
fn_name: fn_name.into(),
|
||||||
required,
|
required: 2,
|
||||||
actual: args_iter.count(),
|
actual: 1,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let tag = match args_iter.next() {
|
let tag = match args_iter.next() {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
None => {
|
None => {
|
||||||
@ -286,90 +171,26 @@ impl LineBare {
|
|||||||
EpBinding::Single(empty_string_addr)
|
EpBinding::Single(empty_string_addr)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check the type of required params.
|
// Check the type of required params.
|
||||||
// We don't check `to` here because it can take on either a
|
let to = arg_point2d(to, fn_name, &mut instructions, ctx, 0)?;
|
||||||
// EpBinding::Sequence or EpBinding::Single.
|
|
||||||
|
|
||||||
let sg = sg_binding(sketch_group, fn_name, "sketch group", 1)?;
|
let sg = sg_binding(sketch_group, fn_name, "sketch group", 1)?;
|
||||||
let tag = single_binding(tag, fn_name, "string tag", 2)?;
|
let tag = single_binding(tag, fn_name, "string tag", 2)?;
|
||||||
let id = Uuid::new_v4();
|
let id = Uuid::new_v4();
|
||||||
|
|
||||||
// Start of the path segment (which is a straight line).
|
// Start of the path segment (which is a straight line).
|
||||||
let length_of_3d_point = Point3d::<f64>::default().into_parts().len();
|
let length_of_3d_point = Point3d::<f64>::default().into_parts().len();
|
||||||
let start_of_line = ctx.next_address.offset_by(1);
|
let start_of_line = ctx.next_address.offset_by(1);
|
||||||
|
|
||||||
// Reserve space for the line's end, and the `relative: bool` field.
|
// Reserve space for the line's end, and the `relative: bool` field.
|
||||||
ctx.next_address.offset_by(length_of_3d_point + 1);
|
ctx.next_address.offset_by(length_of_3d_point + 1);
|
||||||
let new_sg_index = ctx.assign_sketch_group();
|
let new_sg_index = ctx.assign_sketch_group();
|
||||||
|
|
||||||
// Copy based on the options.
|
|
||||||
match opts {
|
|
||||||
LineBareOptions { at: At::AbsoluteXY, .. } | LineBareOptions { at: At::RelativeXY, .. } => {
|
|
||||||
// Push the `to` 2D point onto the stack.
|
|
||||||
let EpBinding::Sequence { elements, length_at: _ } = to.clone() else {
|
|
||||||
return Err(CompileError::InvalidOperand("Must pass a list of length 2"));
|
|
||||||
};
|
|
||||||
let &[EpBinding::Single(el0), EpBinding::Single(el1)] = elements.as_slice() else {
|
|
||||||
return Err(CompileError::InvalidOperand("Must pass a sequence here."));
|
|
||||||
};
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::Copy {
|
|
||||||
// X
|
|
||||||
source: el0,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackPush,
|
|
||||||
},
|
|
||||||
Instruction::Copy {
|
|
||||||
// Y
|
|
||||||
source: el1,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::StackExtend { data: vec![0.0.into()] }, // Z
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
LineBareOptions { at: At::AbsoluteX, .. } | LineBareOptions { at: At::RelativeX, .. } => {
|
|
||||||
let EpBinding::Single(addr) = to else {
|
|
||||||
return Err(CompileError::InvalidOperand("Must pass a single value here."));
|
|
||||||
};
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::Copy {
|
|
||||||
// X
|
|
||||||
source: addr,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackPush,
|
|
||||||
},
|
|
||||||
Instruction::StackExtend {
|
|
||||||
data: vec![Primitive::from(0.0)],
|
|
||||||
}, // Y
|
|
||||||
Instruction::StackExtend {
|
|
||||||
data: vec![Primitive::from(0.0)],
|
|
||||||
}, // Z
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
LineBareOptions { at: At::AbsoluteY, .. } | LineBareOptions { at: At::RelativeY, .. } => {
|
|
||||||
let EpBinding::Single(addr) = to else {
|
|
||||||
return Err(CompileError::InvalidOperand("Must pass a single value here."));
|
|
||||||
};
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::StackPush {
|
|
||||||
data: vec![Primitive::from(0.0)],
|
|
||||||
}, // X
|
|
||||||
Instruction::Copy {
|
|
||||||
// Y
|
|
||||||
source: addr,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::StackExtend {
|
|
||||||
data: vec![Primitive::from(0.0)],
|
|
||||||
}, // Z
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instructions.extend([
|
instructions.extend([
|
||||||
|
// Push the `to` 2D point onto the stack.
|
||||||
|
Instruction::Copy {
|
||||||
|
source: to,
|
||||||
|
length: 2,
|
||||||
|
destination: Destination::StackPush,
|
||||||
|
},
|
||||||
|
// Make it a 3D point.
|
||||||
|
Instruction::StackExtend { data: vec![0.0.into()] },
|
||||||
// Append the new path segment to memory.
|
// Append the new path segment to memory.
|
||||||
// First comes its tag.
|
// First comes its tag.
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
@ -383,7 +204,7 @@ impl LineBare {
|
|||||||
// Then its `relative` field.
|
// Then its `relative` field.
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: start_of_line + 1 + length_of_3d_point,
|
address: start_of_line + 1 + length_of_3d_point,
|
||||||
value: opts.at.is_relative().into(),
|
value: false.into(),
|
||||||
},
|
},
|
||||||
// Push the path ID onto the stack.
|
// Push the path ID onto the stack.
|
||||||
Instruction::SketchGroupCopyFrom {
|
Instruction::SketchGroupCopyFrom {
|
||||||
@ -410,159 +231,16 @@ impl LineBare {
|
|||||||
data: vec![Primitive::from("ToPoint".to_owned())],
|
data: vec![Primitive::from("ToPoint".to_owned())],
|
||||||
},
|
},
|
||||||
// `BasePath::from` point.
|
// `BasePath::from` point.
|
||||||
// Place them in the secondary stack to prepare ToPoint structure.
|
|
||||||
Instruction::SketchGroupGetLastPoint {
|
Instruction::SketchGroupGetLastPoint {
|
||||||
source: sg,
|
source: sg,
|
||||||
destination: Destination::StackExtend,
|
destination: Destination::StackExtend,
|
||||||
},
|
},
|
||||||
]);
|
// `BasePath::to` point.
|
||||||
|
Instruction::Copy {
|
||||||
// Reserve space for the segment last point
|
source: start_of_line + 1,
|
||||||
let to_point_from = ctx.next_address.offset_by(2);
|
length: 2,
|
||||||
|
destination: Destination::StackExtend,
|
||||||
instructions.extend([
|
|
||||||
// Copy to the primary stack as well to be worked with.
|
|
||||||
Instruction::SketchGroupGetLastPoint {
|
|
||||||
source: sg,
|
|
||||||
destination: Destination::Address(to_point_from),
|
|
||||||
},
|
},
|
||||||
]);
|
|
||||||
|
|
||||||
// `BasePath::to` point.
|
|
||||||
|
|
||||||
// The copy here depends on the incoming `to` data.
|
|
||||||
// Sometimes it's a list, sometimes it's single datum.
|
|
||||||
// And the relative/not relative matters. When relative, we need to
|
|
||||||
// copy coords from `from` into the new `to` coord that don't change.
|
|
||||||
// At least everything else can be built up from these "primitives".
|
|
||||||
if let EpBinding::Sequence { elements, length_at: _ } = to.clone() {
|
|
||||||
if let &[EpBinding::Single(el0), EpBinding::Single(el1)] = elements.as_slice() {
|
|
||||||
match opts {
|
|
||||||
// ToPoint { from: { x1, y1 }, to: { x1 + x2, y1 + y2 } }
|
|
||||||
LineBareOptions { at: At::RelativeXY, .. } => {
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::BinaryArithmetic {
|
|
||||||
arithmetic: BinaryArithmetic {
|
|
||||||
operation: BinaryOperation::Add,
|
|
||||||
operand0: Operand::Reference(to_point_from + 0),
|
|
||||||
operand1: Operand::Reference(el0),
|
|
||||||
},
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::BinaryArithmetic {
|
|
||||||
arithmetic: BinaryArithmetic {
|
|
||||||
operation: BinaryOperation::Add,
|
|
||||||
operand0: Operand::Reference(to_point_from + 1),
|
|
||||||
operand1: Operand::Reference(el1),
|
|
||||||
},
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
// ToPoint { from: { x1, y1 }, to: { x2, y2 } }
|
|
||||||
LineBareOptions { at: At::AbsoluteXY, .. } => {
|
|
||||||
// Otherwise just directly copy the new points.
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::Copy {
|
|
||||||
source: el0,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::Copy {
|
|
||||||
source: el1,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(CompileError::InvalidOperand(
|
|
||||||
"A Sequence with At::...X or At::...Y is not valid here. Must be At::...XY.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let EpBinding::Single(addr) = to {
|
|
||||||
match opts {
|
|
||||||
// ToPoint { from: { x1, y1 }, to: { x1 + x2, y1 } }
|
|
||||||
LineBareOptions { at: At::RelativeX } => {
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::BinaryArithmetic {
|
|
||||||
arithmetic: BinaryArithmetic {
|
|
||||||
operation: BinaryOperation::Add,
|
|
||||||
operand0: Operand::Reference(to_point_from + 0),
|
|
||||||
operand1: Operand::Reference(addr),
|
|
||||||
},
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::Copy {
|
|
||||||
source: to_point_from + 1,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
// ToPoint { from: { x1, y1 }, to: { x2, y1 } }
|
|
||||||
LineBareOptions { at: At::AbsoluteX } => {
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::Copy {
|
|
||||||
source: addr,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::Copy {
|
|
||||||
source: to_point_from + 1,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
// ToPoint { from: { x1, y1 }, to: { x1, y1 + y2 } }
|
|
||||||
LineBareOptions { at: At::RelativeY } => {
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::Copy {
|
|
||||||
source: to_point_from + 0,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::BinaryArithmetic {
|
|
||||||
arithmetic: BinaryArithmetic {
|
|
||||||
operation: BinaryOperation::Add,
|
|
||||||
operand0: Operand::Reference(to_point_from + 1),
|
|
||||||
operand1: Operand::Reference(addr),
|
|
||||||
},
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
// ToPoint { from: { x1, y1 }, to: { x1, y2 } }
|
|
||||||
LineBareOptions { at: At::AbsoluteY } => {
|
|
||||||
instructions.extend([
|
|
||||||
Instruction::Copy {
|
|
||||||
source: to_point_from + 0,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
Instruction::Copy {
|
|
||||||
source: addr,
|
|
||||||
length: 1,
|
|
||||||
destination: Destination::StackExtend,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(CompileError::InvalidOperand(
|
|
||||||
"A Single binding with At::...XY is not valid here.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(CompileError::InvalidOperand(
|
|
||||||
"Must be a sequence or single value binding.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
instructions.extend([
|
|
||||||
// `BasePath::name` string.
|
// `BasePath::name` string.
|
||||||
Instruction::Copy {
|
Instruction::Copy {
|
||||||
source: tag,
|
source: tag,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::{collections::HashMap, env};
|
use std::{collections::HashMap, env};
|
||||||
|
|
||||||
use ep::{constants, sketch_types, Destination, UnaryArithmetic};
|
use ep::{sketch_types, Destination, UnaryArithmetic};
|
||||||
use ept::{ListHeader, ObjectHeader, Primitive};
|
use ept::{ListHeader, ObjectHeader};
|
||||||
use kittycad_modeling_cmds::shared::Point2d;
|
use kittycad_modeling_cmds::shared::Point2d;
|
||||||
use kittycad_modeling_session::SessionBuilder;
|
use kittycad_modeling_session::SessionBuilder;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
@ -1048,10 +1048,42 @@ fn store_object_with_array_property() {
|
|||||||
|
|
||||||
/// Write the program's plan to the KCVM debugger's normal input file.
|
/// Write the program's plan to the KCVM debugger's normal input file.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn kcvm_dbg(kcl_program: &str, path: &str) {
|
fn kcvm_dbg(kcl_program: &str) {
|
||||||
let (plan, _scope, _) = must_plan(kcl_program);
|
let (plan, _scope, _) = must_plan(kcl_program);
|
||||||
let plan_json = serde_json::to_string_pretty(&plan).unwrap();
|
let plan_json = serde_json::to_string_pretty(&plan).unwrap();
|
||||||
std::fs::write(path, plan_json).unwrap();
|
std::fs::write(
|
||||||
|
"/Users/adamchalmers/kc-repos/modeling-api/execution-plan-debugger/test_input.json",
|
||||||
|
plan_json,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn paul_qr_test() {
|
||||||
|
let program = include_str!("../testdata/paul_qr.kcl");
|
||||||
|
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||||
|
.ast()
|
||||||
|
.unwrap();
|
||||||
|
let mut client = Some(test_client().await);
|
||||||
|
crate::execute(ast, &mut client).await.unwrap();
|
||||||
|
use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||||
|
let out = client
|
||||||
|
.unwrap()
|
||||||
|
.run_command(
|
||||||
|
uuid::Uuid::new_v4().into(),
|
||||||
|
each_cmd::TakeSnapshot {
|
||||||
|
format: ImageFormat::Png,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let out = match out {
|
||||||
|
OkModelingCmdResponse::TakeSnapshot(b) => b,
|
||||||
|
other => panic!("wrong output: {other:?}"),
|
||||||
|
};
|
||||||
|
let out: Vec<u8> = out.contents.into();
|
||||||
|
std::fs::write("paul_qr_code.png", out).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -1065,6 +1097,8 @@ async fn stdlib_cube_partial() {
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(100.0, %)
|
|> extrude(100.0, %)
|
||||||
"#;
|
"#;
|
||||||
|
let (_plan, _scope, last_address) = must_plan(program);
|
||||||
|
assert_eq!(last_address, Address::ZERO + 66);
|
||||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||||
.ast()
|
.ast()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1107,115 +1141,23 @@ async fn stdlib_cube_partial() {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
// use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||||
let out = client
|
// let out = client
|
||||||
.unwrap()
|
// .unwrap()
|
||||||
.run_command(
|
// .run_command(
|
||||||
uuid::Uuid::new_v4().into(),
|
// uuid::Uuid::new_v4().into(),
|
||||||
kittycad_modeling_cmds::ModelingCmd::from(each_cmd::TakeSnapshot {
|
// each_cmd::TakeSnapshot {
|
||||||
format: ImageFormat::Png,
|
// format: ImageFormat::Png,
|
||||||
}),
|
// },
|
||||||
)
|
// )
|
||||||
.await
|
// .await
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
|
// let out = match out {
|
||||||
let out = match out {
|
// OkModelingCmdResponse::TakeSnapshot(b) => b,
|
||||||
OkModelingCmdResponse::TakeSnapshot(kittycad_modeling_cmds::output::TakeSnapshot { contents: b }) => b,
|
// other => panic!("wrong output: {other:?}"),
|
||||||
other => panic!("wrong output: {other:?}"),
|
// };
|
||||||
};
|
// let out: Vec<u8> = out.contents.into();
|
||||||
|
// std::fs::write("image.png", out).unwrap();
|
||||||
use image::io::Reader as ImageReader;
|
|
||||||
let img = ImageReader::new(std::io::Cursor::new(out))
|
|
||||||
.with_guessed_format()
|
|
||||||
.unwrap()
|
|
||||||
.decode()
|
|
||||||
.unwrap();
|
|
||||||
twenty_twenty::assert_image("fixtures/cube_lineTo.png", &img, 0.9999);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn stdlib_cube_xline_yline() {
|
|
||||||
let program = r#"
|
|
||||||
let cube = startSketchAt([0.0, 0.0], "adam")
|
|
||||||
|> xLine(210.0, %, "side0")
|
|
||||||
|> yLine(210.0, %, "side1")
|
|
||||||
|> xLine(-210.0, %, "side2")
|
|
||||||
|> yLine(-210.0, %, "side3")
|
|
||||||
|> close(%)
|
|
||||||
|> extrude(100.0, %)
|
|
||||||
"#;
|
|
||||||
kcvm_dbg(
|
|
||||||
program,
|
|
||||||
"/home/lee/Code/Zoo/modeling-api/execution-plan-debugger/cube_xyline.json",
|
|
||||||
);
|
|
||||||
let (_plan, _scope, _last_address) = must_plan(program);
|
|
||||||
|
|
||||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
|
||||||
.ast()
|
|
||||||
.unwrap();
|
|
||||||
let mut client = Some(test_client().await);
|
|
||||||
let mem = match crate::execute(ast, &mut client).await {
|
|
||||||
Ok(mem) => mem,
|
|
||||||
Err(e) => panic!("{e}"),
|
|
||||||
};
|
|
||||||
let sg = &mem.sketch_groups.last().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
sg.path_rest,
|
|
||||||
vec![
|
|
||||||
sketch_types::PathSegment::ToPoint {
|
|
||||||
base: sketch_types::BasePath {
|
|
||||||
from: Point2d { x: 0.0, y: 0.0 },
|
|
||||||
to: Point2d { x: 210.0, y: 0.0 },
|
|
||||||
name: "side0".into(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sketch_types::PathSegment::ToPoint {
|
|
||||||
base: sketch_types::BasePath {
|
|
||||||
from: Point2d { x: 210.0, y: 0.0 },
|
|
||||||
to: Point2d { x: 210.0, y: 210.0 },
|
|
||||||
name: "side1".into(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sketch_types::PathSegment::ToPoint {
|
|
||||||
base: sketch_types::BasePath {
|
|
||||||
from: Point2d { x: 210.0, y: 210.0 },
|
|
||||||
to: Point2d { x: 0.0, y: 210.0 },
|
|
||||||
name: "side2".into(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sketch_types::PathSegment::ToPoint {
|
|
||||||
base: sketch_types::BasePath {
|
|
||||||
from: Point2d { x: 0.0, y: 210.0 },
|
|
||||||
to: Point2d { x: 0.0, y: 0.0 },
|
|
||||||
name: "side3".into(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
|
||||||
use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
|
||||||
let out = client
|
|
||||||
.unwrap()
|
|
||||||
.run_command(
|
|
||||||
uuid::Uuid::new_v4().into(),
|
|
||||||
kittycad_modeling_cmds::ModelingCmd::from(each_cmd::TakeSnapshot {
|
|
||||||
format: ImageFormat::Png,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let out = match out {
|
|
||||||
OkModelingCmdResponse::TakeSnapshot(kittycad_modeling_cmds::output::TakeSnapshot { contents: b }) => b,
|
|
||||||
other => panic!("wrong output: {other:?}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
use image::io::Reader as ImageReader;
|
|
||||||
let img = ImageReader::new(std::io::Cursor::new(out))
|
|
||||||
.with_guessed_format()
|
|
||||||
.unwrap()
|
|
||||||
.decode()
|
|
||||||
.unwrap();
|
|
||||||
twenty_twenty::assert_image("fixtures/cube_xyLine.png", &img, 0.9999);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn test_client() -> Session {
|
async fn test_client() -> Session {
|
||||||
@ -1414,51 +1356,3 @@ fn mod_and_pow() {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[tokio::test]
|
|
||||||
async fn cos_sin_pi() {
|
|
||||||
let program = "
|
|
||||||
let x = cos(45.0)*10
|
|
||||||
let y = sin(45.0)*10
|
|
||||||
let z = PI
|
|
||||||
";
|
|
||||||
let (_plan, scope, _) = must_plan(program);
|
|
||||||
let Some(EpBinding::Single(x)) = scope.get("x") else {
|
|
||||||
panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
|
|
||||||
};
|
|
||||||
let Some(EpBinding::Single(y)) = scope.get("y") else {
|
|
||||||
panic!("Unexpected binding for variable 'y': {:?}", scope.get("y"));
|
|
||||||
};
|
|
||||||
let Some(EpBinding::Constant(z)) = scope.get("z") else {
|
|
||||||
panic!("Unexpected binding for variable 'z': {:?}", scope.get("z"));
|
|
||||||
};
|
|
||||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
|
||||||
.ast()
|
|
||||||
.unwrap();
|
|
||||||
let mem = crate::execute(ast, &mut None).await.unwrap();
|
|
||||||
use ept::ReadMemory;
|
|
||||||
assert_eq!(*mem.get(x).unwrap(), Primitive::from(5.253219888177298));
|
|
||||||
assert_eq!(*mem.get(y).unwrap(), Primitive::from(8.509035245341185));
|
|
||||||
|
|
||||||
// Constants don't live in memory.
|
|
||||||
assert_eq!(*z, constants::PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn kcl_prelude() {
|
|
||||||
let program = "
|
|
||||||
let the_answer_to_the_universe_is = hey_from_one_of_the_devs_of_the_past_i_wish_you_a_great_day_and_maybe_gave_you_a_little_smile_as_youve_found_this()
|
|
||||||
";
|
|
||||||
let (_plan, scope, _) = must_plan(program);
|
|
||||||
let Some(EpBinding::Single(the_answer_to_the_universe_is)) = scope.get("the_answer_to_the_universe_is") else {
|
|
||||||
panic!(
|
|
||||||
"Unexpected binding for variable 'the_answer_to_the_universe_is': {:?}",
|
|
||||||
scope.get("the_answer_to_the_universe_is")
|
|
||||||
);
|
|
||||||
};
|
|
||||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
|
||||||
.ast()
|
|
||||||
.unwrap();
|
|
||||||
let mem = crate::execute(ast, &mut None).await.unwrap();
|
|
||||||
use ept::ReadMemory;
|
|
||||||
assert_eq!(*mem.get(the_answer_to_the_universe_is).unwrap(), Primitive::from(42i64));
|
|
||||||
}
|
|
||||||
|
|||||||
2655
src/wasm-lib/grackle/testdata/paul_qr.kcl
vendored
Normal file
2655
src/wasm-lib/grackle/testdata/paul_qr.kcl
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@ use syn::{parse_macro_input, LitStr};
|
|||||||
/// This macro takes exactly one argument: A string literal containing KCL.
|
/// This macro takes exactly one argument: A string literal containing KCL.
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
|
/// extern crate alloc;
|
||||||
/// use kcl_compile_macro::parse_kcl;
|
/// use kcl_compile_macro::parse_kcl;
|
||||||
/// let ast: kcl_lib::ast::types::Program = parse_kcl!("const y = 4");
|
/// let ast: kcl_lib::ast::types::Program = parse_kcl!("const y = 4");
|
||||||
/// ```
|
/// ```
|
||||||
@ -20,14 +21,3 @@ pub fn parse(input: TokenStream) -> TokenStream {
|
|||||||
let ast_struct = ast.bake(&Default::default());
|
let ast_struct = ast.bake(&Default::default());
|
||||||
quote!(#ast_struct).into()
|
quote!(#ast_struct).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `parse!` but read in a file.
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn parse_file(input: TokenStream) -> TokenStream {
|
|
||||||
let file_name = parse_macro_input!(input as LitStr);
|
|
||||||
let kcl_src = std::fs::read_to_string(file_name.value()).unwrap();
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|||||||
216
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
216
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
@ -7,10 +7,6 @@ name = "Inflector"
|
|||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
@ -48,26 +44,11 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android-tzdata"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_system_properties"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.81"
|
version = "1.0.80"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
|
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
]
|
]
|
||||||
@ -111,7 +92,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -122,7 +103,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -287,17 +268,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.35"
|
version = "0.4.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
|
||||||
"iana-time-zone",
|
|
||||||
"js-sys",
|
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-targets 0.52.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -344,21 +320,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crc32fast"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@ -407,7 +368,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -419,11 +380,10 @@ checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive-docs"
|
name = "derive-docs"
|
||||||
version = "0.1.11"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4e18a04fe569a325dd50743821f2605057ff5c4b48e60512270b4406907825b"
|
checksum = "834580a8bd697658876ed8c9f7727e49f01d34f5b859ca921ac5b99ffc6adf77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -431,7 +391,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_tokenstream",
|
"serde_tokenstream",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -561,7 +521,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -632,7 +592,7 @@ dependencies = [
|
|||||||
"inflections",
|
"inflections",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -779,29 +739,6 @@ dependencies = [
|
|||||||
"tokio-rustls 0.24.1",
|
"tokio-rustls 0.24.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone"
|
|
||||||
version = "0.1.60"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
|
||||||
dependencies = [
|
|
||||||
"android_system_properties",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"iana-time-zone-haiku",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone-haiku"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -870,23 +807,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kcl-lib"
|
name = "kcl-lib"
|
||||||
version = "0.1.46"
|
version = "0.1.42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"approx",
|
"approx",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bson",
|
"bson",
|
||||||
"chrono",
|
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"databake",
|
"databake",
|
||||||
"derive-docs",
|
"derive-docs",
|
||||||
@ -897,14 +833,12 @@ dependencies = [
|
|||||||
"kittycad-execution-plan-macros",
|
"kittycad-execution-plan-macros",
|
||||||
"kittycad-execution-plan-traits",
|
"kittycad-execution-plan-traits",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"mime_guess",
|
|
||||||
"parse-display 0.9.0",
|
"parse-display 0.9.0",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"ropey",
|
"ropey",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-tungstenite",
|
"tokio-tungstenite",
|
||||||
@ -915,7 +849,6 @@ dependencies = [
|
|||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winnow",
|
"winnow",
|
||||||
"zip",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -928,9 +861,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad"
|
name = "kittycad"
|
||||||
version = "0.2.60"
|
version = "0.2.54"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8aa5906d0730bd90f6b3331fe57c04951d00743169a29ee96408767b4060605"
|
checksum = "13958174d876353f429ea8230dc92fe86f164819cea2e51bbf22e01a4c2a496e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -944,7 +877,6 @@ dependencies = [
|
|||||||
"http 0.2.9",
|
"http 0.2.9",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
"mime_guess",
|
|
||||||
"parse-display 0.8.2",
|
"parse-display 0.8.2",
|
||||||
"phonenumber",
|
"phonenumber",
|
||||||
"rand",
|
"rand",
|
||||||
@ -967,13 +899,14 @@ source = "git+https://github.com/KittyCAD/modeling-api?branch=main#1e6ef9601686c
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-execution-plan-traits"
|
name = "kittycad-execution-plan-traits"
|
||||||
version = "0.1.13"
|
version = "0.1.10"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3ec8efd57b59697eb140b63c0ffe7db44fdfe5a55f14e45513411eba2280ba5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -1095,9 +1028,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.11"
|
version = "0.8.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
@ -1238,7 +1171,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"regex-syntax 0.7.5",
|
"regex-syntax 0.7.5",
|
||||||
"structmeta 0.2.0",
|
"structmeta 0.2.0",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1252,7 +1185,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"regex-syntax 0.8.2",
|
"regex-syntax 0.8.2",
|
||||||
"structmeta 0.3.0",
|
"structmeta 0.3.0",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1299,7 +1232,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1471,9 +1404,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.27"
|
version = "0.11.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.3",
|
"base64 0.21.3",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1759,7 +1692,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1793,7 +1726,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1805,7 +1738,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1843,17 +1776,6 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha2"
|
|
||||||
version = "0.10.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cpufeatures",
|
|
||||||
"digest",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@ -1925,7 +1847,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"structmeta-derive 0.2.0",
|
"structmeta-derive 0.2.0",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1937,7 +1859,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"structmeta-derive 0.3.0",
|
"structmeta-derive 0.3.0",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1948,7 +1870,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1959,7 +1881,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2003,9 +1925,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.53"
|
version = "2.0.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
|
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2026,7 +1948,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2082,7 +2004,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2155,7 +2077,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2261,7 +2183,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2290,7 +2212,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2328,7 +2250,7 @@ dependencies = [
|
|||||||
"Inflector",
|
"Inflector",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2460,9 +2382,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.92"
|
version = "0.2.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
@ -2470,24 +2392,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.92"
|
version = "0.2.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.42"
|
version = "0.4.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@ -2497,9 +2419,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.92"
|
version = "0.2.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@ -2507,22 +2429,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.92"
|
version = "0.2.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.53",
|
"syn 2.0.50",
|
||||||
"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.92"
|
version = "0.2.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-streams"
|
name = "wasm-streams"
|
||||||
@ -2539,9 +2461,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@ -2584,15 +2506,6 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
@ -2767,14 +2680,3 @@ name = "zeroize"
|
|||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zip"
|
|
||||||
version = "0.6.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"crc32fast",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|||||||
@ -351,31 +351,6 @@ impl Program {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merge two `Program`s together.
|
|
||||||
pub fn merge(self, ast_other: Program) -> Program {
|
|
||||||
let mut body_new: Vec<BodyItem> = vec![];
|
|
||||||
body_new.extend(self.body);
|
|
||||||
body_new.extend(ast_other.body);
|
|
||||||
|
|
||||||
let mut non_code_nodes_new: HashMap<usize, Vec<NonCodeNode>> = HashMap::new();
|
|
||||||
non_code_nodes_new.extend(self.non_code_meta.non_code_nodes);
|
|
||||||
non_code_nodes_new.extend(ast_other.non_code_meta.non_code_nodes);
|
|
||||||
|
|
||||||
let mut start_new: Vec<NonCodeNode> = vec![];
|
|
||||||
start_new.extend(self.non_code_meta.start);
|
|
||||||
start_new.extend(ast_other.non_code_meta.start);
|
|
||||||
|
|
||||||
Program {
|
|
||||||
start: self.start,
|
|
||||||
end: self.end + (ast_other.end - ast_other.start),
|
|
||||||
body: body_new,
|
|
||||||
non_code_meta: NonCodeMeta {
|
|
||||||
non_code_nodes: non_code_nodes_new,
|
|
||||||
start: start_new,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ValueMeta {
|
pub trait ValueMeta {
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
fn hey_from_one_of_the_devs_of_the_past_i_wish_you_a_great_day_and_maybe_gave_you_a_little_smile_as_youve_found_this = () => {
|
|
||||||
return 42
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user