Compare commits
6 Commits
jtran/upda
...
franknoiro
Author | SHA1 | Date | |
---|---|---|---|
117e696430 | |||
c18a2223f3 | |||
c5492a7937 | |||
19a3c255c3 | |||
f93979c648 | |||
6288ab5f2f |
@ -19,11 +19,6 @@
|
||||
"plugin:jsx-a11y/recommended",
|
||||
"plugin:react-hooks/recommended"
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"no-array-constructor": "off", // This is wrong; use the @typescript-eslint one instead.
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
@ -66,7 +61,6 @@
|
||||
"jsx-a11y/click-events-have-key-events": "off",
|
||||
"jsx-a11y/no-autofocus": "off",
|
||||
"jsx-a11y/no-noninteractive-element-interactions": "off",
|
||||
"react/no-unknown-property": "error",
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
|
11
.github/ci-cd-scripts/playwright-electron.sh
vendored
@ -26,8 +26,8 @@ max_retries=1
|
||||
# Retry failed tests, doing our own retries because using inbuilt Playwright retries causes connection issues
|
||||
while [[ $retry -le $max_retries ]]; do
|
||||
if [[ -f "test-results/.last-run.json" ]]; then
|
||||
status=$(jq -r '.status' test-results/.last-run.json)
|
||||
if [[ "$status" == "failed" ]]; then
|
||||
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
|
||||
if [[ $failed_tests -gt 0 ]]; then
|
||||
echo "retried=true" >>$GITHUB_OUTPUT
|
||||
echo "run playwright with last failed tests and retry $retry"
|
||||
if [[ "$3" == *ubuntu* ]]; then
|
||||
@ -56,11 +56,10 @@ done
|
||||
echo "retried=false" >>$GITHUB_OUTPUT
|
||||
|
||||
if [[ -f "test-results/.last-run.json" ]]; then
|
||||
status=$(jq -r '.status' test-results/.last-run.json)
|
||||
if [[ "$status" == "failed" ]]; then
|
||||
# If it still fails after retries, then fail the job
|
||||
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
|
||||
if [[ $failed_tests -gt 0 ]]; then
|
||||
# If it still fails after 3 retries, then fail the job
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
7
.github/workflows/e2e-tests.yml
vendored
@ -225,7 +225,7 @@ jobs:
|
||||
uses: nick-fields/retry@v3.0.2
|
||||
with:
|
||||
shell: bash
|
||||
command: npm run test:snapshots
|
||||
command: npm run test:snapshots || true
|
||||
timeout_minutes: 5
|
||||
max_attempts: 5
|
||||
env:
|
||||
@ -285,7 +285,8 @@ jobs:
|
||||
# TODO: enable namespace-profile-windows-latest once available
|
||||
os:
|
||||
- "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
|
||||
- namespace-profile-macos-8-cores
|
||||
# TODO: renable this when macoOS runner seem more stable
|
||||
# - namespace-profile-macos-6-cores
|
||||
- windows-latest-8-cores
|
||||
shardIndex: [1, 2, 3, 4]
|
||||
shardTotal: [4]
|
||||
@ -295,7 +296,7 @@ jobs:
|
||||
isScheduled:
|
||||
- ${{ github.event_name == 'schedule' }}
|
||||
exclude:
|
||||
- os: namespace-profile-macos-8-cores
|
||||
- os: namespace-profile-macos-6-cores
|
||||
isScheduled: true
|
||||
- os: windows-latest-8-cores
|
||||
isScheduled: true
|
||||
|
@ -40,7 +40,11 @@ layout: manual
|
||||
* [`arc`](kcl/arc)
|
||||
* [`asin`](kcl/asin)
|
||||
* [`assert`](kcl/assert)
|
||||
* [`assertIs`](kcl/assertIs)
|
||||
* [`assertEqual`](kcl/assertEqual)
|
||||
* [`assertGreaterThan`](kcl/assertGreaterThan)
|
||||
* [`assertGreaterThanOrEq`](kcl/assertGreaterThanOrEq)
|
||||
* [`assertLessThan`](kcl/assertLessThan)
|
||||
* [`assertLessThanOrEq`](kcl/assertLessThanOrEq)
|
||||
* [`atan`](kcl/atan)
|
||||
* [`atan2`](kcl/atan2)
|
||||
* [`bezierCurve`](kcl/bezierCurve)
|
||||
|
@ -34,7 +34,7 @@ int(num: number): number
|
||||
|
||||
```js
|
||||
n = int(ceil(5 / 2))
|
||||
assert(n, isEqualTo = 3, error = "5/2 = 2.5, rounded up makes 3")
|
||||
assertEqual(n, 3, 0.0001, "5/2 = 2.5, rounded up makes 3")
|
||||
// Draw n cylinders.
|
||||
startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = 2)
|
||||
|
@ -21,7 +21,4 @@ once fixed in engine will just start working here with no language changes.
|
||||
- **Chamfers**: Chamfers cannot intersect, you will get an error. Only simple
|
||||
chamfer cases work currently.
|
||||
|
||||
- **Appearance**: Changing the appearance on a loft does not work.
|
||||
Changing the appearance on an imported model does not work.
|
||||
|
||||
- **CSG Booleans**: Coplanar (bodies that share a plane) unions, subtractions, and intersections are not currently supported.
|
||||
- **Appearance**: Changing the appearance on a loft does not work.
|
||||
|
@ -9,7 +9,7 @@ Extract the provided 2-dimensional sketch's profile's origin value.
|
||||
|
||||
|
||||
```js
|
||||
profileStart(profile: Sketch): [number]
|
||||
profileStart(sketch: Sketch): [number]
|
||||
```
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ profileStart(profile: Sketch): [number]
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `profile` | [`Sketch`](/docs/kcl/types/Sketch) | Profile whose start is being used | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Extract the provided 2-dimensional sketch's profile's origin's 'x' value.
|
||||
|
||||
|
||||
```js
|
||||
profileStartX(profile: Sketch): number
|
||||
profileStartX(sketch: Sketch): number
|
||||
```
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ profileStartX(profile: Sketch): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `profile` | [`Sketch`](/docs/kcl/types/Sketch) | Profile whose start is being used | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -9,7 +9,7 @@ Extract the provided 2-dimensional sketch's profile's origin's 'y' value.
|
||||
|
||||
|
||||
```js
|
||||
profileStartY(profile: Sketch): number
|
||||
profileStartY(sketch: Sketch): number
|
||||
```
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ profileStartY(profile: Sketch): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `profile` | [`Sketch`](/docs/kcl/types/Sketch) | Profile whose start is being used | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
2223
docs/kcl/std.json
@ -29,11 +29,11 @@ test.describe('Electron app header tests', () => {
|
||||
test(
|
||||
'User settings has correct shortcut',
|
||||
{ tag: '@electron' },
|
||||
async ({ page, toolbar }, testInfo) => {
|
||||
async ({ page }, testInfo) => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
// Open the user sidebar menu.
|
||||
await toolbar.userSidebarButton.click()
|
||||
await page.getByTestId('user-sidebar-toggle').click()
|
||||
|
||||
// No space after "User settings" since it's textContent.
|
||||
const text =
|
||||
|
@ -1,53 +0,0 @@
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
// test file is for testing auth functionality
|
||||
test.describe('Authentication tests', () => {
|
||||
test(
|
||||
`The user can sign out and back in`,
|
||||
{ tag: ['@electron'] },
|
||||
async ({ page, homePage, signInPage, toolbar, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.projectSection.waitFor()
|
||||
|
||||
await test.step('Click on sign out and expect sign in page', async () => {
|
||||
await toolbar.userSidebarButton.click()
|
||||
await toolbar.signOutButton.click()
|
||||
await expect(signInPage.signInButton).toBeVisible()
|
||||
})
|
||||
|
||||
await test.step('Click on sign in and cancel, click again and expect different code', async () => {
|
||||
await signInPage.signInButton.click()
|
||||
await expect(signInPage.userCode).toBeVisible()
|
||||
const firstUserCode = await signInPage.userCode.textContent()
|
||||
await signInPage.cancelSignInButton.click()
|
||||
await expect(signInPage.signInButton).toBeVisible()
|
||||
|
||||
await signInPage.signInButton.click()
|
||||
await expect(signInPage.userCode).toBeVisible()
|
||||
const secondUserCode = await signInPage.userCode.textContent()
|
||||
expect(secondUserCode).not.toEqual(firstUserCode)
|
||||
})
|
||||
|
||||
await test.step('Press back button and remain on home page', async () => {
|
||||
await page.goBack()
|
||||
await expect(homePage.projectSection).not.toBeVisible()
|
||||
await expect(signInPage.signInButton).toBeVisible()
|
||||
})
|
||||
|
||||
await test.step('Sign in, activate, and expect home page', async () => {
|
||||
await signInPage.signInButton.click()
|
||||
await expect(signInPage.userCode).toBeVisible()
|
||||
const userCode = await signInPage.userCode.textContent()
|
||||
expect(userCode).not.toBeNull()
|
||||
await signInPage.verifyAndConfirmAuth(userCode!)
|
||||
|
||||
// Longer timeout than usual here for the wait on home page
|
||||
await expect(homePage.projectSection).toBeVisible({ timeout: 10000 })
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
@ -18,7 +18,6 @@ import type { Settings } from '@rust/kcl-lib/bindings/Settings'
|
||||
import { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
|
||||
import { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
|
||||
import { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
|
||||
import { SignInPageFixture } from '@e2e/playwright/fixtures/signInPageFixture'
|
||||
import { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
|
||||
import { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
|
||||
|
||||
@ -67,7 +66,6 @@ export interface Fixtures {
|
||||
toolbar: ToolbarFixture
|
||||
scene: SceneFixture
|
||||
homePage: HomePageFixture
|
||||
signInPage: SignInPageFixture
|
||||
}
|
||||
|
||||
export class ElectronZoo {
|
||||
@ -389,9 +387,6 @@ const fixturesBasedOnProcessEnvPlatform = {
|
||||
homePage: async ({ page }: { page: Page }, use: FnUse) => {
|
||||
await use(new HomePageFixture(page))
|
||||
},
|
||||
signInPage: async ({ page }: { page: Page }, use: FnUse) => {
|
||||
await use(new SignInPageFixture(page))
|
||||
},
|
||||
}
|
||||
|
||||
if (process.env.PLATFORM === 'web') {
|
||||
|
@ -1,48 +0,0 @@
|
||||
import type { Locator, Page } from '@playwright/test'
|
||||
import { secrets } from '@e2e/playwright/secrets'
|
||||
|
||||
export class SignInPageFixture {
|
||||
public page: Page
|
||||
|
||||
signInButton!: Locator
|
||||
cancelSignInButton!: Locator
|
||||
userCode!: Locator
|
||||
|
||||
apiBaseUrl!: string
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
|
||||
this.signInButton = this.page.getByTestId('sign-in-button')
|
||||
this.cancelSignInButton = this.page.getByTestId('cancel-sign-in-button')
|
||||
this.userCode = this.page.getByTestId('sign-in-user-code')
|
||||
|
||||
// TODO: set this thru env var
|
||||
this.apiBaseUrl = 'https://api.dev.zoo.dev'
|
||||
}
|
||||
|
||||
async verifyAndConfirmAuth(userCode: string) {
|
||||
// Device flow: stolen from the tauri days
|
||||
// https://github.com/KittyCAD/modeling-app/blob/d916c7987452e480719004e6d11fd2e595c7d0eb/e2e/tauri/specs/app.spec.ts#L19
|
||||
const headers = {
|
||||
Authorization: `Bearer ${secrets.token}`,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
const verifyUrl = `${this.apiBaseUrl}/oauth2/device/verify?user_code=${userCode}`
|
||||
console.log(`GET ${verifyUrl}`)
|
||||
const vr = await fetch(verifyUrl, { headers })
|
||||
console.log(vr.status)
|
||||
|
||||
// Device flow: confirm
|
||||
const confirmUrl = `${this.apiBaseUrl}/oauth2/device/confirm`
|
||||
const data = JSON.stringify({ user_code: userCode })
|
||||
console.log(`POST ${confirmUrl} ${data}`)
|
||||
const cr = await fetch(confirmUrl, {
|
||||
headers,
|
||||
method: 'POST',
|
||||
body: data,
|
||||
})
|
||||
console.log(cr.status)
|
||||
}
|
||||
}
|
@ -46,9 +46,6 @@ export class ToolbarFixture {
|
||||
gizmo!: Locator
|
||||
gizmoDisabled!: Locator
|
||||
loadButton!: Locator
|
||||
/** User button for the user sidebar menu */
|
||||
userSidebarButton!: Locator
|
||||
signOutButton!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
@ -85,9 +82,6 @@ export class ToolbarFixture {
|
||||
// element or two different elements can represent these states.
|
||||
this.gizmo = page.getByTestId('gizmo')
|
||||
this.gizmoDisabled = page.getByTestId('gizmo-disabled')
|
||||
|
||||
this.userSidebarButton = page.getByTestId('user-sidebar-toggle')
|
||||
this.signOutButton = page.getByTestId('user-sidebar-sign-out')
|
||||
}
|
||||
|
||||
get logoLink() {
|
||||
|
@ -1,25 +1,6 @@
|
||||
import type {
|
||||
Reporter,
|
||||
TestCase,
|
||||
TestResult,
|
||||
FullResult,
|
||||
} from '@playwright/test/reporter'
|
||||
import type { Reporter, TestCase, TestResult } from '@playwright/test/reporter'
|
||||
|
||||
class MyAPIReporter implements Reporter {
|
||||
private pendingRequests: Promise<void>[] = []
|
||||
private allResults: Record<string, any>[] = []
|
||||
private blockingResults: Record<string, any>[] = []
|
||||
|
||||
async onEnd(result: FullResult): Promise<void> {
|
||||
await Promise.all(this.pendingRequests)
|
||||
if (this.allResults.length > 0 && this.blockingResults.length === 0) {
|
||||
result.status = 'passed'
|
||||
if (!process.env.CI) {
|
||||
console.error('TAB API - Marked failures as non-blocking')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTestEnd(test: TestCase, result: TestResult): void {
|
||||
if (!process.env.TAB_API_URL || !process.env.TAB_API_KEY) {
|
||||
return
|
||||
@ -39,7 +20,6 @@ class MyAPIReporter implements Reporter {
|
||||
platform: process.env.RUNNER_OS || process.platform,
|
||||
// Extra test and result data
|
||||
annotations: test.annotations.map((a) => a.type), // e.g. 'fail' or 'fixme'
|
||||
id: test.id, // computed file/test/project ID used for reruns
|
||||
retry: result.retry,
|
||||
tags: test.tags, // e.g. '@snapshot' or '@skipWin'
|
||||
// Extra environment variables
|
||||
@ -55,7 +35,7 @@ class MyAPIReporter implements Reporter {
|
||||
RUNNER_ARCH: process.env.RUNNER_ARCH || null,
|
||||
}
|
||||
|
||||
const request = (async () => {
|
||||
void (async () => {
|
||||
try {
|
||||
const response = await fetch(`${process.env.TAB_API_URL}/api/results`, {
|
||||
method: 'POST',
|
||||
@ -66,27 +46,18 @@ class MyAPIReporter implements Reporter {
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json()
|
||||
this.allResults.push(result)
|
||||
if (result.block) {
|
||||
this.blockingResults.push(result)
|
||||
}
|
||||
} else {
|
||||
const error = await response.json()
|
||||
if (!process.env.CI) {
|
||||
console.error('TAB API - Failed to send test result:', error)
|
||||
}
|
||||
if (!response.ok && !process.env.CI) {
|
||||
console.error(
|
||||
'TAB API - Failed to send test result:',
|
||||
await response.text()
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
} catch {
|
||||
if (!process.env.CI) {
|
||||
console.error('TAB API - Unable to send test result:', message)
|
||||
console.error('TAB API - Unable to send test result')
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
this.pendingRequests.push(request)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,7 +409,11 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
)
|
||||
.toBe(true)
|
||||
})
|
||||
test('Home.Help.Report a bug', async ({ tronApp, cmdBar, page }) => {
|
||||
test('Home.Help.Refresh and report a bug', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -420,8 +424,9 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const menu =
|
||||
app.applicationMenu.getMenuItemById('Help.Report a bug')
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Refresh and report a bug'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
@ -2286,7 +2291,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!menu) fail()
|
||||
})
|
||||
})
|
||||
test('Modeling.Help.Report a bug', async ({
|
||||
test('Modeling.Help.Refresh and report a bug', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
@ -2310,8 +2315,9 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu =
|
||||
app.applicationMenu.getMenuItemById('Help.Report a bug')
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Refresh and report a bug'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
|
@ -331,7 +331,6 @@ test.describe('Onboarding tests', () => {
|
||||
test('Avatar text updates depending on image load success', async ({
|
||||
context,
|
||||
page,
|
||||
toolbar,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
@ -363,7 +362,7 @@ test.describe('Onboarding tests', () => {
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// Test that the text in this step is correct
|
||||
const avatarLocator = toolbar.userSidebarButton.locator('img')
|
||||
const avatarLocator = page.getByTestId('user-sidebar-toggle').locator('img')
|
||||
const onboardingOverlayLocator = page
|
||||
.getByTestId('onboarding-content')
|
||||
.locator('div')
|
||||
@ -405,7 +404,6 @@ test.describe('Onboarding tests', () => {
|
||||
test("Avatar text doesn't mention avatar when no avatar", async ({
|
||||
context,
|
||||
page,
|
||||
toolbar,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
@ -437,7 +435,7 @@ test.describe('Onboarding tests', () => {
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// Test that the text in this step is correct
|
||||
const sidebar = toolbar.userSidebarButton
|
||||
const sidebar = page.getByTestId('user-sidebar-toggle')
|
||||
const avatar = sidebar.locator('img')
|
||||
const onboardingOverlayLocator = page
|
||||
.getByTestId('onboarding-content')
|
||||
@ -466,7 +464,6 @@ test.describe('Onboarding tests', () => {
|
||||
test('Restarting onboarding on desktop takes one attempt', async ({
|
||||
context,
|
||||
page,
|
||||
toolbar,
|
||||
tronApp,
|
||||
}) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
@ -505,7 +502,7 @@ test('Restarting onboarding on desktop takes one attempt', async ({
|
||||
.filter({ hasText: 'Tutorial Project 00' })
|
||||
const tutorialModalText = page.getByText('Welcome to Design Studio!')
|
||||
const tutorialDismissButton = page.getByRole('button', { name: 'Dismiss' })
|
||||
const userMenuButton = toolbar.userSidebarButton
|
||||
const userMenuButton = page.getByTestId('user-sidebar-toggle')
|
||||
const userMenuSettingsButton = page.getByRole('button', {
|
||||
name: 'User settings',
|
||||
})
|
||||
|
@ -400,6 +400,11 @@ test(
|
||||
await expect(page.getByText('broken-code')).toBeVisible()
|
||||
await page.getByText('broken-code').click()
|
||||
|
||||
// Gotcha: You can not use scene.settled() since the KCL code is going to fail
|
||||
await expect(
|
||||
page.getByTestId('model-state-indicator-playing')
|
||||
).toBeAttached()
|
||||
|
||||
// Gotcha: Scroll to the text content in code mirror because CodeMirror lazy loads DOM content
|
||||
await editor.scrollToText(
|
||||
"|> line(end = [0, wallMountL], tag = 'outerEdge')"
|
||||
@ -774,9 +779,7 @@ test.describe(`Project management commands`, () => {
|
||||
// Constants and locators
|
||||
const projectHomeLink = page.getByTestId('project-link')
|
||||
const commandButton = page.getByRole('button', { name: 'Commands' })
|
||||
const commandOption = page.getByRole('option', {
|
||||
name: 'rename project',
|
||||
})
|
||||
const commandOption = page.getByRole('option', { name: 'rename project' })
|
||||
const projectNameOption = page.getByRole('option', { name: projectName })
|
||||
const projectRenamedName = `untitled`
|
||||
// const projectMenuButton = page.getByTestId('project-sidebar-toggle')
|
||||
@ -836,9 +839,7 @@ test.describe(`Project management commands`, () => {
|
||||
// Constants and locators
|
||||
const projectHomeLink = page.getByTestId('project-link')
|
||||
const commandButton = page.getByRole('button', { name: 'Commands' })
|
||||
const commandOption = page.getByRole('option', {
|
||||
name: 'delete project',
|
||||
})
|
||||
const commandOption = page.getByRole('option', { name: 'delete project' })
|
||||
const projectNameOption = page.getByRole('option', { name: projectName })
|
||||
const commandWarning = page.getByText('Are you sure you want to delete?')
|
||||
const commandSubmitButton = page.getByRole('button', {
|
||||
@ -890,9 +891,7 @@ test.describe(`Project management commands`, () => {
|
||||
// Constants and locators
|
||||
const projectHomeLink = page.getByTestId('project-link')
|
||||
const commandButton = page.getByRole('button', { name: 'Commands' })
|
||||
const commandOption = page.getByRole('option', {
|
||||
name: 'rename project',
|
||||
})
|
||||
const commandOption = page.getByRole('option', { name: 'rename project' })
|
||||
const projectNameOption = page.getByRole('option', { name: projectName })
|
||||
const projectRenamedName = `untitled`
|
||||
const commandContinueButton = page.getByRole('button', {
|
||||
@ -948,9 +947,7 @@ test.describe(`Project management commands`, () => {
|
||||
// Constants and locators
|
||||
const projectHomeLink = page.getByTestId('project-link')
|
||||
const commandButton = page.getByRole('button', { name: 'Commands' })
|
||||
const commandOption = page.getByRole('option', {
|
||||
name: 'delete project',
|
||||
})
|
||||
const commandOption = page.getByRole('option', { name: 'delete project' })
|
||||
const projectNameOption = page.getByRole('option', { name: projectName })
|
||||
const commandWarning = page.getByText('Are you sure you want to delete?')
|
||||
const commandSubmitButton = page.getByRole('button', {
|
||||
@ -1965,13 +1962,13 @@ test(
|
||||
test(
|
||||
'Settings persist across restarts',
|
||||
{ tag: '@electron' },
|
||||
async ({ page, toolbar }, testInfo) => {
|
||||
async ({ page, scene, cmdBar }, testInfo) => {
|
||||
await test.step('We can change a user setting like theme', async () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
page.on('console', console.log)
|
||||
|
||||
await toolbar.userSidebarButton.click()
|
||||
await page.getByTestId('user-sidebar-toggle').click()
|
||||
|
||||
await page.getByTestId('user-settings').click()
|
||||
|
||||
@ -1998,7 +1995,7 @@ test(
|
||||
test(
|
||||
'Original project name persist after onboarding',
|
||||
{ tag: '@electron' },
|
||||
async ({ page, toolbar }, testInfo) => {
|
||||
async ({ page }, testInfo) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
@ -2010,7 +2007,7 @@ test(
|
||||
})
|
||||
|
||||
await test.step('Should go through onboarding', async () => {
|
||||
await toolbar.userSidebarButton.click()
|
||||
await page.getByTestId('user-sidebar-toggle').click()
|
||||
await page.getByTestId('user-settings').click()
|
||||
await page.getByRole('button', { name: 'Replay Onboarding' }).click()
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
/* eslint-disable jest/no-conditional-expect */
|
||||
@ -50,6 +51,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||
page,
|
||||
scene,
|
||||
}) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
await context.addInitScript((file) => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
@ -198,6 +200,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||
page,
|
||||
scene,
|
||||
}) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
const body1CapCoords = { x: 571, y: 311 }
|
||||
|
||||
await context.addInitScript((file) => {
|
||||
@ -257,6 +260,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||
page,
|
||||
scene,
|
||||
}) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
const body1CapCoords = { x: 571, y: 311 }
|
||||
const body2WallCoords = { x: 620, y: 152 }
|
||||
const [clickBody1Cap] = scene.makeMouseHelpers(
|
||||
|
@ -3295,7 +3295,7 @@ profile003 = startProfileAt([-201.08, 254.17], sketch002)
|
||||
)
|
||||
await editor.expectState({
|
||||
activeLines: [],
|
||||
diagnostics: ['`badBadBadFn`isnotdefined'],
|
||||
diagnostics: ['memoryitemkey`badBadBadFn`isnotdefined'],
|
||||
highlightedCode: '',
|
||||
})
|
||||
await expect(
|
||||
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 63 KiB |
@ -36,6 +36,7 @@ export const headerMasks = (page: Page) => [
|
||||
]
|
||||
|
||||
export const networkingMasks = (page: Page) => [
|
||||
page.getByTestId('model-state-indicator'),
|
||||
page.getByTestId('network-toggle'),
|
||||
]
|
||||
|
||||
@ -84,6 +85,12 @@ async function waitForPageLoadWithRetry(page: Page) {
|
||||
await expect(async () => {
|
||||
await page.goto('/')
|
||||
const errorMessage = 'App failed to load - 🔃 Retrying ...'
|
||||
await expect(
|
||||
page.getByTestId('model-state-indicator-playing'),
|
||||
errorMessage
|
||||
).toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'sketch Start Sketch' }),
|
||||
@ -96,6 +103,11 @@ async function waitForPageLoadWithRetry(page: Page) {
|
||||
|
||||
// lee: This needs to be replaced by scene.settled() eventually.
|
||||
async function waitForPageLoad(page: Page) {
|
||||
// wait for all spinners to be gone
|
||||
await expect(page.getByTestId('model-state-indicator-playing')).toBeVisible({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
await expect(page.getByRole('button', { name: 'Start Sketch' })).toBeEnabled({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
@ -181,6 +181,7 @@ test.describe('Testing settings', () => {
|
||||
})
|
||||
|
||||
test('Project and user settings can be reset', async ({ page, homePage }) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
const u = await getUtils(page)
|
||||
await test.step(`Setup`, async () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
@ -25,10 +25,10 @@ shelfMountingHolePlacementOffset = shelfMountingHoleDiameter * 1.5
|
||||
wallMountingHolePlacementOffset = wallMountingHoleDiameter * 1.5
|
||||
|
||||
// Add checks to ensure bracket is possible. These make sure that there is adequate distance between holes and edges.
|
||||
assert(wallMountLength, isGreaterThanOrEqual = wallMountingHoleDiameter * 3, error = "Holes not possible. Either decrease hole diameter or increase wallMountLength")
|
||||
assert(shelfMountLength, isGreaterThanOrEqual = shelfMountingHoleDiameter * 5.5, error = "wallMountLength must be longer for hole sizes to work. Either decrease mounting hole diameters or increase shelfMountLength")
|
||||
assert(width, isGreaterThanOrEqual = shelfMountingHoleDiameter * 5.5, error = "Holes not possible. Either decrease hole diameter or increase width")
|
||||
assert(width, isGreaterThanOrEqual = wallMountingHoleDiameter * 5.5, error = "Holes not possible. Either decrease hole diameter or increase width")
|
||||
assertGreaterThanOrEq(wallMountLength, wallMountingHoleDiameter * 3, "Holes not possible. Either decrease hole diameter or increase wallMountLength")
|
||||
assertGreaterThanOrEq(shelfMountLength, shelfMountingHoleDiameter * 5.5, "wallMountLength must be longer for hole sizes to work. Either decrease mounting hole diameters or increase shelfMountLength")
|
||||
assertGreaterThanOrEq(width, shelfMountingHoleDiameter * 5.5, "Holes not possible. Either decrease hole diameter or increase width")
|
||||
assertGreaterThanOrEq(width, wallMountingHoleDiameter * 5.5, "Holes not possible. Either decrease hole diameter or increase width")
|
||||
|
||||
// Create the body of the bracket
|
||||
bracketBody = startSketchOn(XZ)
|
||||
|
@ -18,7 +18,7 @@ topTotalThickness = totalThickness - (bottomThickness + baseThickness)
|
||||
nHoles = 4
|
||||
|
||||
// Add assertion so nHoles are always greater than 1
|
||||
assert(nHoles, isGreaterThan = 1, error = "nHoles must be greater than 1")
|
||||
assertGreaterThan(nHoles, 1, "nHoles must be greater than 1")
|
||||
|
||||
// Create the circular pattern for the mounting holes
|
||||
circles = startSketchOn(XY)
|
||||
|
@ -22,8 +22,8 @@ lSegments = totalLength / lbumps
|
||||
wSegments = totalWidth / wbumps
|
||||
|
||||
// Add assertions to ensure that the number of bumps are greater than 1
|
||||
assert(lbumps, isGreaterThan = 1, error = "lbumps must be greater than 1")
|
||||
assert(wbumps, isGreaterThan = 1, error = "wbumps must be greater than 1")
|
||||
assertGreaterThan(lbumps, 1, "lbumps must be greater than 1")
|
||||
assertGreaterThan(wbumps, 1, "wbumps must be greater than 1")
|
||||
|
||||
// Make the base
|
||||
base = startSketchOn(XY)
|
||||
|
20
rust/Cargo.lock
generated
@ -1792,7 +1792,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1803,7 +1803,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-derive-docs"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1822,7 +1822,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-directory-test-macro"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1831,7 +1831,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server"
|
||||
version = "0.2.63"
|
||||
version = "0.2.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1852,7 +1852,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1872,7 +1872,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.63"
|
||||
version = "0.2.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -1943,7 +1943,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.63"
|
||||
version = "0.3.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"kcl-lib",
|
||||
@ -1958,7 +1958,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper 0.14.32",
|
||||
@ -1971,7 +1971,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-to-core"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1985,7 +1985,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"bson",
|
||||
"console_error_panic_hook",
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
[package]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-api"
|
||||
rust-version = "1.76"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-directory-test-macro"
|
||||
description = "A tool for generating tests from a directory of kcl files"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.63"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
publish = false
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "kcl-language-server"
|
||||
description = "A language server for KCL."
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
version = "0.2.63"
|
||||
version = "0.2.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.63"
|
||||
version = "0.2.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -19,30 +19,6 @@ We've built a lot of tooling to make contributing to KCL easier. If you are inte
|
||||
11. Run `just redo-kcl-stdlib-docs` to generate new Markdown documentation for your function that will be used [to generate docs on our website](https://zoo.dev/docs/kcl).
|
||||
12. Create a PR in GitHub.
|
||||
|
||||
## Making a Simulation Test
|
||||
|
||||
If you have KCL code that you want to test, simulation tests are the preferred way to do that.
|
||||
|
||||
Make a new sim test. Replace `foo_bar` with the snake case name of your test. The name needs to be unique.
|
||||
|
||||
```shell
|
||||
just new-sim-test foo_bar
|
||||
```
|
||||
|
||||
It will show the commands it ran, including the path to a new file `foo_bar/input.kcl`. Edit that with your KCL. If you need additional KCL files to import, include them in this directory.
|
||||
|
||||
Then run it.
|
||||
|
||||
```shell
|
||||
just overwrite-sim-test foo_bar
|
||||
```
|
||||
|
||||
The above should create a bunch of output files in the same directory.
|
||||
|
||||
Make sure you actually look at them. Specifically, if there's an `execution_error.snap`, it means the execution failed. Depending on the test, this may be what you expect. But if it's not, delete the snap file and run it again.
|
||||
|
||||
When it looks good, commit all the files, including `input.kcl`, generated output files in the test directory, and changes to `simulation_tests.rs`.
|
||||
|
||||
## Bumping the version
|
||||
|
||||
If you bump the version of kcl-lib and push it to crates, be sure to update the repos we own that use it as well. These are:
|
||||
|
@ -4,7 +4,7 @@ const arr = [0, 0, 0, 10]
|
||||
const i = 3
|
||||
const ten = arr[i]
|
||||
|
||||
assert(ten, isEqualTo = 10, error = "oops")
|
||||
assertEqual(ten, 10, 0.000001, "oops")
|
||||
|
||||
const p = "foo"
|
||||
const obj = {
|
||||
@ -13,4 +13,4 @@ const obj = {
|
||||
}
|
||||
const one = obj[p]
|
||||
|
||||
assert(one, isEqualTo = 1, error = "oops")
|
||||
assertEqual(one, 1, 0.0000001, "oops")
|
||||
|
@ -1,25 +1,25 @@
|
||||
import identity from "identity.kcl"
|
||||
|
||||
answer = identity(42)
|
||||
assert(answer, isEqualTo = 42, error = "identity")
|
||||
assertEqual(answer, 42, 0.0001, "identity")
|
||||
|
||||
import identity as id from "identity.kcl"
|
||||
|
||||
answer43 = id(43)
|
||||
assert(answer43, isEqualTo = 43, error = "identity")
|
||||
assertEqual(answer43, 43, 0.0001, "identity")
|
||||
|
||||
import increment, decrement from "numbers.kcl"
|
||||
|
||||
answer3 = increment(2)
|
||||
assert(answer3, isEqualTo = 3, error = "increment")
|
||||
assertEqual(answer3, 3, 0.0001, "increment")
|
||||
|
||||
answer5 = decrement(6)
|
||||
assert(answer5, isEqualTo = 5, error = "decrement")
|
||||
assertEqual(answer5, 5, 0.0001, "decrement")
|
||||
|
||||
import increment as inc, decrement as dec from "numbers.kcl"
|
||||
|
||||
answer4 = inc(3)
|
||||
assert(answer4, isEqualTo = 4, error = "inc")
|
||||
assertEqual(answer4, 4, 0.0001, "inc")
|
||||
|
||||
answer6 = dec(7)
|
||||
assert(answer6, isEqualTo = 6, error = "dec")
|
||||
assertEqual(answer6, 6, 0.0001, "dec")
|
||||
|
52
rust/kcl-lib/e2e/executor/inputs/poop_chute.kcl
Normal file
@ -0,0 +1,52 @@
|
||||
wall_thickness = 0.125
|
||||
back_walls_width = 2
|
||||
front_walls_width = 2.5
|
||||
height = 5.5
|
||||
filletRadius = 0.050
|
||||
back_length = 7
|
||||
exit_height = 1
|
||||
front_length = 6
|
||||
Fx = 0.5
|
||||
Fy = 0.5
|
||||
|
||||
sketch001 = startSketchOn('-YZ')
|
||||
|> startProfileAt([back_walls_width / 2, 0], %)
|
||||
|> xLine(length = wall_thickness / 2)
|
||||
|> angledLine(angle = 45, endAbsoluteX = back_walls_width, tag = $seg01)
|
||||
|> yLine(endAbsolute = height)
|
||||
|> xLine(length = -wall_thickness)
|
||||
|> yLine(endAbsolute = segEndY(seg01))
|
||||
|> angledLine(angle = 45, endAbsoluteX = back_walls_width / 2 + wall_thickness / 2)
|
||||
|> xLine(length = -wall_thickness)
|
||||
|> angledLine(angle = 180 - 45, endAbsoluteX = wall_thickness)
|
||||
|> yLine(endAbsolute = height)
|
||||
|> xLine(endAbsolute = 0)
|
||||
|> yLine(endAbsolute = segEndY(seg01))
|
||||
|> angledLine(angle = 180 - 45, endAbsoluteY = 0)
|
||||
|> close()
|
||||
part001 = revolve({
|
||||
angle: 90,
|
||||
axis: {
|
||||
custom: {
|
||||
axis: [1.0, 0.0],
|
||||
origin: [0.0, height + .0000001]
|
||||
}
|
||||
}
|
||||
}, sketch001)
|
||||
|
||||
sketch002 = startSketchOn('-YZ')
|
||||
|> startProfileAt([back_walls_width / 2, 0], %)
|
||||
|> xLine(length = wall_thickness / 2)
|
||||
|> angledLine(angle = 45, endAbsoluteX = back_walls_width, tag = $seg02)
|
||||
|> yLine(endAbsolute = height)
|
||||
|> xLine(length = -wall_thickness)
|
||||
|> yLine(endAbsolute = segEndY(seg01))
|
||||
|> angledLine(angle = 45, endAbsoluteX = back_walls_width / 2 + wall_thickness / 2)
|
||||
|> xLine(length = -wall_thickness)
|
||||
|> angledLine(angle = 180 - 45, endAbsoluteX = wall_thickness)
|
||||
|> yLine(endAbsolute = height)
|
||||
|> xLine(endAbsolute = 0)
|
||||
|> yLine(endAbsolute = segEndY(seg02))
|
||||
|> angledLine(angle = 180 - 45, endAbsoluteY = 0)
|
||||
|> close()
|
||||
|> extrude(length = back_length - height)
|
@ -365,7 +365,7 @@ impl ProgramMemory {
|
||||
}
|
||||
|
||||
Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: format!("`{}` is not defined", var),
|
||||
message: format!("memory item key `{}` is not defined", var),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
}
|
||||
@ -486,7 +486,7 @@ impl ProgramMemory {
|
||||
}
|
||||
|
||||
Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: format!("`{}` is not defined", var),
|
||||
message: format!("memory item key `{}` is not defined", var),
|
||||
source_ranges: vec![],
|
||||
}))
|
||||
}
|
||||
|
@ -95,7 +95,8 @@ pub struct DefaultPlanes {
|
||||
pub struct TagIdentifier {
|
||||
pub value: String,
|
||||
// Multi-version representation of info about the tag. Kept ordered. The usize is the epoch at which the info
|
||||
// was written.
|
||||
// was written. Note that there might be multiple versions of tag info from the same epoch, the version with
|
||||
// the higher index will be the most recent.
|
||||
#[serde(skip)]
|
||||
pub info: Vec<(usize, TagEngineInfo)>,
|
||||
#[serde(skip)]
|
||||
@ -122,16 +123,10 @@ impl TagIdentifier {
|
||||
/// Add info from a different instance of this tag.
|
||||
pub fn merge_info(&mut self, other: &TagIdentifier) {
|
||||
assert_eq!(&self.value, &other.value);
|
||||
for (oe, ot) in &other.info {
|
||||
if let Some((e, t)) = self.info.last_mut() {
|
||||
// If there is newer info, then skip this iteration.
|
||||
if *e > *oe {
|
||||
continue;
|
||||
}
|
||||
// If we're in the same epoch, then overwrite.
|
||||
if e == oe {
|
||||
*t = ot.clone();
|
||||
continue;
|
||||
'new_info: for (oe, ot) in &other.info {
|
||||
for (e, _) in &self.info {
|
||||
if e > oe {
|
||||
continue 'new_info;
|
||||
}
|
||||
}
|
||||
self.info.push((*oe, ot.clone()));
|
||||
@ -1590,7 +1585,7 @@ const answer = returnX()"#;
|
||||
assert_eq!(
|
||||
err,
|
||||
KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "`x` is not defined".to_owned(),
|
||||
message: "memory item key `x` is not defined".to_owned(),
|
||||
source_ranges: vec![
|
||||
SourceRange::new(64, 65, ModuleId::default()),
|
||||
SourceRange::new(97, 106, ModuleId::default())
|
||||
@ -1674,7 +1669,7 @@ let shape = layer() |> patternTransform(instances = 10, transform = transform)
|
||||
assert_eq!(
|
||||
err,
|
||||
KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "`x` is not defined".to_owned(),
|
||||
message: "memory item key `x` is not defined".to_owned(),
|
||||
source_ranges: vec![SourceRange::new(80, 81, ModuleId::default())],
|
||||
}),
|
||||
);
|
||||
@ -1820,21 +1815,33 @@ const bracket = startSketchOn(XY)
|
||||
parse_execute(ast).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_bad_arg_count_std() {
|
||||
let ast = "startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> profileStartX()";
|
||||
assert!(parse_execute(ast)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.message()
|
||||
.contains("Expected a sketch argument"));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_unary_operator_not_succeeds() {
|
||||
let ast = r#"
|
||||
fn returnTrue() { return !false }
|
||||
t = true
|
||||
f = false
|
||||
notTrue = !t
|
||||
notFalse = !f
|
||||
c = !!true
|
||||
d = !returnTrue()
|
||||
fn returnTrue = () => { return !false }
|
||||
const t = true
|
||||
const f = false
|
||||
let notTrue = !t
|
||||
let notFalse = !f
|
||||
let c = !!true
|
||||
let d = !returnTrue()
|
||||
|
||||
assertIs(!false, error = "expected to pass")
|
||||
assert(!false, "expected to pass")
|
||||
|
||||
fn check = (x) => {
|
||||
assertIs(!x, error = "expected argument to be false")
|
||||
assert(!x, "expected argument to be false")
|
||||
return true
|
||||
}
|
||||
check(false)
|
||||
|
@ -1628,12 +1628,6 @@ fn function_body(i: &mut TokenSlice) -> PResult<Node<Program>> {
|
||||
}
|
||||
handle_pending_non_code!(attr);
|
||||
if attr.is_inner() {
|
||||
if !body.is_empty() {
|
||||
ParseContext::warn(CompilationError::err(
|
||||
attr.as_source_range(),
|
||||
"Named attributes should appear before any declarations or expressions.\n\nBecause named attributes apply to the whole function or module, including code written before them, it can be confusing for readers to not have these attributes at the top of code blocks.",
|
||||
));
|
||||
}
|
||||
inner_attrs.push(attr);
|
||||
} else {
|
||||
pending_attrs.push(attr);
|
||||
@ -2074,7 +2068,6 @@ fn possible_operands(i: &mut TokenSlice) -> PResult<Expr> {
|
||||
member_expression.map(Box::new).map(Expr::MemberExpression),
|
||||
literal.map(Expr::Literal),
|
||||
fn_call.map(Box::new).map(Expr::CallExpression),
|
||||
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
|
||||
name.map(Box::new).map(Expr::Name),
|
||||
binary_expr_in_parens.map(Box::new).map(Expr::BinaryExpression),
|
||||
unnecessarily_bracketed,
|
||||
@ -3255,14 +3248,6 @@ mod tests {
|
||||
assert_eq!(err.message, "Unexpected end of file. The compiler expected )");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kw_call_as_operand() {
|
||||
let tokens = crate::parsing::token::lex("f(x = 1)", ModuleId::default()).unwrap();
|
||||
let tokens = tokens.as_slice();
|
||||
let op = operand.parse(tokens).unwrap();
|
||||
println!("{op:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weird_program_just_a_pipe() {
|
||||
let tokens = crate::parsing::token::lex("|", ModuleId::default()).unwrap();
|
||||
@ -4527,15 +4512,6 @@ export fn cos(num: number(rad)): number(_) {}"#;
|
||||
assert_eq!(errs.len(), 1, "{errs:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warn_late_settings() {
|
||||
let some_program_string = r#"foo = 42
|
||||
@settings(defaultLengthUnit = mm)
|
||||
"#;
|
||||
let (_, errs) = assert_no_err(some_program_string);
|
||||
assert_eq!(errs.len(), 1, "{errs:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_decl_uom_ty() {
|
||||
let some_program_string = r#"fn foo(x: number(mm)): number(_) { return 1 }"#;
|
||||
@ -5398,7 +5374,6 @@ my14 = 4 ^ 2 - 3 ^ 2 * 2
|
||||
bar = x,
|
||||
)"#
|
||||
);
|
||||
snapshot_test!(kw_function_in_binary_op, r#"val = f(x = 1) + 1"#);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
@ -1,99 +0,0 @@
|
||||
---
|
||||
source: kcl-lib/src/parsing/parser.rs
|
||||
expression: actual
|
||||
---
|
||||
{
|
||||
"body": [
|
||||
{
|
||||
"commentStart": 0,
|
||||
"declaration": {
|
||||
"commentStart": 0,
|
||||
"end": 18,
|
||||
"id": {
|
||||
"commentStart": 0,
|
||||
"end": 3,
|
||||
"name": "val",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"init": {
|
||||
"commentStart": 6,
|
||||
"end": 18,
|
||||
"left": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 8,
|
||||
"end": 9,
|
||||
"name": "x",
|
||||
"start": 8,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 12,
|
||||
"end": 13,
|
||||
"raw": "1",
|
||||
"start": 12,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 1.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"abs_path": false,
|
||||
"commentStart": 6,
|
||||
"end": 7,
|
||||
"name": {
|
||||
"commentStart": 6,
|
||||
"end": 7,
|
||||
"name": "f",
|
||||
"start": 6,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 6,
|
||||
"type": "Name"
|
||||
},
|
||||
"commentStart": 6,
|
||||
"end": 14,
|
||||
"start": 6,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": null
|
||||
},
|
||||
"operator": "+",
|
||||
"right": {
|
||||
"commentStart": 17,
|
||||
"end": 18,
|
||||
"raw": "1",
|
||||
"start": 17,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 1.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"start": 6,
|
||||
"type": "BinaryExpression",
|
||||
"type": "BinaryExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 18,
|
||||
"kind": "const",
|
||||
"start": 0,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"commentStart": 0,
|
||||
"end": 18,
|
||||
"start": 0
|
||||
}
|
@ -2600,24 +2600,3 @@ mod import_async {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
mod loop_tag {
|
||||
const TEST_NAME: &str = "loop_tag";
|
||||
|
||||
/// Test parsing KCL.
|
||||
#[test]
|
||||
fn parse() {
|
||||
super::parse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that parsing and unparsing KCL produces the original KCL input.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn unparse() {
|
||||
super::unparse(TEST_NAME).await
|
||||
}
|
||||
|
||||
/// Test that KCL is executed correctly.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_execute() {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
|
@ -675,6 +675,28 @@ impl Args {
|
||||
Ok((sketches, sketch))
|
||||
}
|
||||
|
||||
pub(crate) fn get_sketch(&self, exec_state: &mut ExecState) -> Result<Sketch, KclError> {
|
||||
let Some(arg0) = self.args.first() else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a sketch argument".to_owned(),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
let sarg = arg0
|
||||
.value
|
||||
.coerce(&RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)
|
||||
.map_err(|_| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a sketch, found {}", arg0.value.human_friendly_type()),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?;
|
||||
match sarg {
|
||||
KclValue::Sketch { value } => Ok(*value),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_data<'a, T>(&'a self) -> Result<T, KclError>
|
||||
where
|
||||
T: FromArgs<'a>,
|
||||
@ -686,6 +708,49 @@ impl Args {
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_length_and_solid(&self, exec_state: &mut ExecState) -> Result<(TyF64, Box<Solid>), KclError> {
|
||||
let Some(arg0) = self.args.first() else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a `number(Length)` for first argument".to_owned(),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
let val0 = arg0.value.coerce(&RuntimeType::length(), exec_state).map_err(|_| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
"Expected a `number(Length)` for first argument, found {}",
|
||||
arg0.value.human_friendly_type()
|
||||
),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?;
|
||||
let data = TyF64::from_kcl_val(&val0).unwrap();
|
||||
|
||||
let Some(arg1) = self.args.get(1) else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a solid for second argument".to_owned(),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
let sarg = arg1
|
||||
.value
|
||||
.coerce(&RuntimeType::Primitive(PrimitiveType::Solid), exec_state)
|
||||
.map_err(|_| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
"Expected a solid for second argument, found {}",
|
||||
arg1.value.human_friendly_type()
|
||||
),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?;
|
||||
let solid = match sarg {
|
||||
KclValue::Solid { value } => value,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Ok((data, solid))
|
||||
}
|
||||
|
||||
pub(crate) fn get_tag_to_number_sketch(&self) -> Result<(TagIdentifier, TyF64, Sketch), KclError> {
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
@ -115,9 +115,9 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// return sumSoFar
|
||||
/// */
|
||||
///
|
||||
/// // We use `assert` to check that our `sum` function gives the
|
||||
/// // We use `assertEqual` to check that our `sum` function gives the
|
||||
/// // expected result. It's good to check your work!
|
||||
/// assert(sum([1, 2, 3]), isEqualTo = 6, tolerance = 0.1, error = "1 + 2 + 3 summed is 6")
|
||||
/// assertEqual(sum([1, 2, 3]), 6, 0.00001, "1 + 2 + 3 summed is 6")
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// // This example works just like the previous example above, but it uses
|
||||
@ -126,9 +126,9 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// arr = [1, 2, 3]
|
||||
/// sum = reduce(arr, 0, (i, result_so_far) => { return i + result_so_far })
|
||||
///
|
||||
/// // We use `assert` to check that our `sum` function gives the
|
||||
/// // We use `assertEqual` to check that our `sum` function gives the
|
||||
/// // expected result. It's good to check your work!
|
||||
/// assert(sum, isEqualTo = 6, tolerance = 0.1, error = "1 + 2 + 3 summed is 6")
|
||||
/// assertEqual(sum, 6, 0.00001, "1 + 2 + 3 summed is 6")
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// // Declare a function that sketches a decagon.
|
||||
@ -224,7 +224,7 @@ async fn call_reduce_closure(
|
||||
/// ```no_run
|
||||
/// arr = [1, 2, 3]
|
||||
/// new_arr = push(arr, 4)
|
||||
/// assert(new_arr[3], isEqualTo = 4, tolerance = 0.1, error = "4 was added to the end of the array")
|
||||
/// assertEqual(new_arr[3], 4, 0.00001, "4 was added to the end of the array")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "push",
|
||||
@ -260,9 +260,9 @@ pub async fn push(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// ```no_run
|
||||
/// arr = [1, 2, 3, 4]
|
||||
/// new_arr = pop(arr)
|
||||
/// assert(new_arr[0], isEqualTo = 1, tolerance = 0.00001, error = "1 is the first element of the array")
|
||||
/// assert(new_arr[1], isEqualTo = 2, tolerance = 0.00001, error = "2 is the second element of the array")
|
||||
/// assert(new_arr[2], isEqualTo = 3, tolerance = 0.00001, error = "3 is the third element of the array")
|
||||
/// assertEqual(new_arr[0], 1, 0.00001, "1 is the first element of the array")
|
||||
/// assertEqual(new_arr[1], 2, 0.00001, "2 is the second element of the array")
|
||||
/// assertEqual(new_arr[2], 3, 0.00001, "3 is the third element of the array")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "pop",
|
||||
|
@ -21,165 +21,135 @@ async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn assert_is(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let actual = args.get_unlabeled_kw_arg("actual")?;
|
||||
let error = args.get_kw_arg_opt("error")?;
|
||||
inner_assert_is(actual, error, &args).await?;
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Check that the provided value is true, or raise a [KclError]
|
||||
/// with the provided description.
|
||||
pub async fn assert(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let actual = args.get_unlabeled_kw_arg("actual")?;
|
||||
let gt = args.get_kw_arg_opt("isGreaterThan")?;
|
||||
let lt = args.get_kw_arg_opt("isLessThan")?;
|
||||
let gte = args.get_kw_arg_opt("isGreaterThanOrEqual")?;
|
||||
let lte = args.get_kw_arg_opt("isLessThanOrEqual")?;
|
||||
let eq = args.get_kw_arg_opt("isEqualTo")?;
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
let error = args.get_kw_arg_opt("error")?;
|
||||
inner_assert(actual, gt, lt, gte, lte, eq, tolerance, error, &args).await?;
|
||||
let (data, description): (bool, String) = args.get_data()?;
|
||||
inner_assert(data, &description, &args).await?;
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Asserts that a value is the boolean value true.
|
||||
/// ```no_run
|
||||
/// kclIsFun = true
|
||||
/// assertIs(kclIsFun)
|
||||
/// ```
|
||||
#[stdlib{
|
||||
name = "assertIs",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
actual = { docs = "Value to check. If this is the boolean value true, assert passes. Otherwise it fails." },
|
||||
error = { docs = "If the value was false, the program will terminate with this error message" },
|
||||
}
|
||||
}]
|
||||
async fn inner_assert_is(actual: bool, error: Option<String>, args: &Args) -> Result<(), KclError> {
|
||||
let error_msg = match &error {
|
||||
Some(x) => x,
|
||||
None => "should have been true, but it was not",
|
||||
};
|
||||
_assert(actual, error_msg, args).await
|
||||
}
|
||||
|
||||
/// Check a value meets some expected conditions at runtime. Program terminates with an error if conditions aren't met.
|
||||
/// If you provide multiple conditions, they will all be checked and all must be met.
|
||||
/// Check a value at runtime, and raise an error if the argument provided
|
||||
/// is false.
|
||||
///
|
||||
/// ```no_run
|
||||
/// n = 10
|
||||
/// assert(n, isEqualTo = 10)
|
||||
/// assert(n, isGreaterThanOrEqual = 0, isLessThan = 100, error = "number should be between 0 and 100")
|
||||
/// assert(1.0000000000012, isEqualTo = 1, tolerance = 0.0001, error = "number should be almost exactly 1")
|
||||
/// myVar = true
|
||||
/// assert(myVar, "should always be true")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "assert",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
actual = { docs = "Value to check. It will be compared with one of the comparison arguments." },
|
||||
is_greater_than = { docs = "Comparison argument. If given, checks the `actual` value is greater than this." },
|
||||
is_less_than = { docs = "Comparison argument. If given, checks the `actual` value is less than this." },
|
||||
is_greater_than_or_equal = { docs = "Comparison argument. If given, checks the `actual` value is greater than or equal to this." },
|
||||
is_less_than_or_equal = { docs = "Comparison argument. If given, checks the `actual` value is less than or equal to this." },
|
||||
is_equal_to = { docs = "Comparison argument. If given, checks the `actual` value is less than or equal to this.", include_in_snippet = true },
|
||||
tolerance = { docs = "If `isEqualTo` is used, this is the tolerance to allow for the comparison. This tolerance is used because KCL's number system has some floating-point imprecision when used with very large decimal places." },
|
||||
error = { docs = "If the value was false, the program will terminate with this error message" },
|
||||
}
|
||||
}]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn inner_assert(
|
||||
actual: TyF64,
|
||||
is_greater_than: Option<TyF64>,
|
||||
is_less_than: Option<TyF64>,
|
||||
is_greater_than_or_equal: Option<TyF64>,
|
||||
is_less_than_or_equal: Option<TyF64>,
|
||||
is_equal_to: Option<TyF64>,
|
||||
tolerance: Option<TyF64>,
|
||||
error: Option<String>,
|
||||
args: &Args,
|
||||
) -> Result<(), KclError> {
|
||||
// Validate the args
|
||||
let no_condition_given = [
|
||||
&is_greater_than,
|
||||
&is_less_than,
|
||||
&is_greater_than_or_equal,
|
||||
&is_less_than_or_equal,
|
||||
&is_equal_to,
|
||||
]
|
||||
.iter()
|
||||
.all(|cond| cond.is_none());
|
||||
if no_condition_given {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "You must provide at least one condition in this assert (for example, isEqualTo)".to_owned(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
if tolerance.is_some() && is_equal_to.is_none() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message:
|
||||
"The `tolerance` arg is only used with `isEqualTo`. Either remove `tolerance` or add an `isEqualTo` arg."
|
||||
.to_owned(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let suffix = if let Some(err_string) = error {
|
||||
format!(": {err_string}")
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let actual = actual.n;
|
||||
|
||||
// Run the checks.
|
||||
if let Some(exp) = is_greater_than {
|
||||
let exp = exp.n;
|
||||
_assert(
|
||||
actual > exp,
|
||||
&format!("Expected {actual} to be greater than {exp} but it wasn't{suffix}"),
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if let Some(exp) = is_less_than {
|
||||
let exp = exp.n;
|
||||
_assert(
|
||||
actual < exp,
|
||||
&format!("Expected {actual} to be less than {exp} but it wasn't{suffix}"),
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if let Some(exp) = is_greater_than_or_equal {
|
||||
let exp = exp.n;
|
||||
_assert(
|
||||
actual >= exp,
|
||||
&format!("Expected {actual} to be greater than or equal to {exp} but it wasn't{suffix}"),
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if let Some(exp) = is_less_than_or_equal {
|
||||
let exp = exp.n;
|
||||
_assert(
|
||||
actual <= exp,
|
||||
&format!("Expected {actual} to be less than or equal to {exp} but it wasn't{suffix}"),
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if let Some(exp) = is_equal_to {
|
||||
let exp = exp.n;
|
||||
let tolerance = tolerance.map(|e| e.n).unwrap_or(0.0000000001);
|
||||
_assert(
|
||||
(actual - exp).abs() < tolerance,
|
||||
&format!("Expected {actual} to be equal to {exp} but it wasn't{suffix}"),
|
||||
args,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
async fn inner_assert(data: bool, message: &str, args: &Args) -> Result<(), KclError> {
|
||||
_assert(data, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_lt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (TyF64, TyF64, String) = args.get_data()?;
|
||||
inner_assert_lt(left.n, right.n, &description, &args).await?;
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Check that a numerical value is less than to another at runtime,
|
||||
/// otherwise raise an error.
|
||||
///
|
||||
/// ```no_run
|
||||
/// assertLessThan(1, 2, "1 is less than 2")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "assertLessThan",
|
||||
}]
|
||||
async fn inner_assert_lt(left: f64, right: f64, message: &str, args: &Args) -> Result<(), KclError> {
|
||||
_assert(left < right, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_gt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (TyF64, TyF64, String) = args.get_data()?;
|
||||
inner_assert_gt(left.n, right.n, &description, &args).await?;
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Check that a numerical value equals another at runtime,
|
||||
/// otherwise raise an error.
|
||||
///
|
||||
/// ```no_run
|
||||
/// n = 1.0285
|
||||
/// o = 1.0286
|
||||
/// assertEqual(n, o, 0.01, "n is within the given tolerance for o")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "assertEqual",
|
||||
}]
|
||||
async fn inner_assert_equal(left: f64, right: f64, epsilon: f64, message: &str, args: &Args) -> Result<(), KclError> {
|
||||
if epsilon <= 0.0 {
|
||||
Err(KclError::Type(KclErrorDetails {
|
||||
message: "assertEqual epsilon must be greater than zero".to_owned(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}))
|
||||
} else if (right - left).abs() < epsilon {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(KclError::Type(KclErrorDetails {
|
||||
message: format!("assert failed because {left} != {right}: {message}"),
|
||||
source_ranges: vec![args.source_range],
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn assert_equal(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, epsilon, description): (TyF64, TyF64, TyF64, String) = args.get_data()?;
|
||||
inner_assert_equal(left.n, right.n, epsilon.n, &description, &args).await?;
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Check that a numerical value is greater than another at runtime,
|
||||
/// otherwise raise an error.
|
||||
///
|
||||
/// ```no_run
|
||||
/// assertGreaterThan(2, 1, "2 is greater than 1")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "assertGreaterThan",
|
||||
}]
|
||||
async fn inner_assert_gt(left: f64, right: f64, message: &str, args: &Args) -> Result<(), KclError> {
|
||||
_assert(left > right, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_lte(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (TyF64, TyF64, String) = args.get_data()?;
|
||||
inner_assert_lte(left.n, right.n, &description, &args).await?;
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Check that a numerical value is less than or equal to another at runtime,
|
||||
/// otherwise raise an error.
|
||||
///
|
||||
/// ```no_run
|
||||
/// assertLessThanOrEq(1, 2, "1 is less than 2")
|
||||
/// assertLessThanOrEq(1, 1, "1 is equal to 1")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "assertLessThanOrEq",
|
||||
}]
|
||||
async fn inner_assert_lte(left: f64, right: f64, message: &str, args: &Args) -> Result<(), KclError> {
|
||||
_assert(left <= right, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_gte(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (TyF64, TyF64, String) = args.get_data()?;
|
||||
inner_assert_gte(left.n, right.n, &description, &args).await?;
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Check that a numerical value is greater than or equal to another at runtime,
|
||||
/// otherwise raise an error.
|
||||
///
|
||||
/// ```no_run
|
||||
/// assertGreaterThanOrEq(2, 1, "2 is greater than 1")
|
||||
/// assertGreaterThanOrEq(1, 1, "1 is equal to 1")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "assertGreaterThanOrEq",
|
||||
}]
|
||||
async fn inner_assert_gte(left: f64, right: f64, message: &str, args: &Args) -> Result<(), KclError> {
|
||||
_assert(left >= right, message, args).await
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ pub async fn int(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
///
|
||||
/// ```no_run
|
||||
/// n = int(ceil(5/2))
|
||||
/// assert(n, isEqualTo = 3, error = "5/2 = 2.5, rounded up makes 3")
|
||||
/// assertEqual(n, 3, 0.0001, "5/2 = 2.5, rounded up makes 3")
|
||||
/// // Draw n cylinders.
|
||||
/// startSketchOn('XZ')
|
||||
/// |> circle(center = [0, 0], radius = 2 )
|
||||
|
@ -35,12 +35,12 @@ pub async fn rem(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
||||
/// If `num` is negative, the result will be too.
|
||||
///
|
||||
/// ```no_run
|
||||
/// assert(rem( 7, divisor = 4), isEqualTo = 3, error = "remainder is 3")
|
||||
/// assert(rem(-7, divisor = 4), isEqualTo = -3, error = "remainder is -3")
|
||||
/// assert(rem( 7, divisor = -4), isEqualTo = 3, error = "remainder is 3")
|
||||
/// assert(rem( 6, divisor = 2.5), isEqualTo = 1, error = "remainder is 1")
|
||||
/// assert(rem( 6.5, divisor = 2.5), isEqualTo = 1.5, error = "remainder is 1.5")
|
||||
/// assert(rem( 6.5, divisor = 2), isEqualTo = 0.5, error = "remainder is 0.5")
|
||||
/// assertEqual(rem( 7, divisor = 4), 3, 0.01, "remainder is 3" )
|
||||
/// assertEqual(rem(-7, divisor = 4), -3, 0.01, "remainder is -3")
|
||||
/// assertEqual(rem( 7, divisor = -4), 3, 0.01, "remainder is 3" )
|
||||
/// assertEqual(rem( 6, divisor = 2.5), 1, 0.01, "remainder is 1" )
|
||||
/// assertEqual(rem( 6.5, divisor = 2.5), 1.5, 0.01, "remainder is 1.5" )
|
||||
/// assertEqual(rem( 6.5, divisor = 2), 0.5, 0.01, "remainder is 0.5" )
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "rem",
|
||||
|
@ -135,7 +135,11 @@ lazy_static! {
|
||||
Box::new(crate::std::units::FromCm),
|
||||
Box::new(crate::std::units::FromYd),
|
||||
Box::new(crate::std::assert::Assert),
|
||||
Box::new(crate::std::assert::AssertIs),
|
||||
Box::new(crate::std::assert::AssertEqual),
|
||||
Box::new(crate::std::assert::AssertLessThan),
|
||||
Box::new(crate::std::assert::AssertGreaterThan),
|
||||
Box::new(crate::std::assert::AssertLessThanOrEq),
|
||||
Box::new(crate::std::assert::AssertGreaterThanOrEq),
|
||||
Box::new(crate::std::transform::Scale),
|
||||
Box::new(crate::std::transform::Translate),
|
||||
Box::new(crate::std::transform::Rotate),
|
||||
|
@ -247,10 +247,9 @@ async fn inner_shell(
|
||||
|
||||
/// Make the inside of a 3D object hollow.
|
||||
pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let solid = args.get_unlabeled_kw_arg_typed("solid", &RuntimeType::solid(), exec_state)?;
|
||||
let thickness: TyF64 = args.get_kw_arg_typed("thickness", &RuntimeType::length(), exec_state)?;
|
||||
let (thickness, solid) = args.get_length_and_solid(exec_state)?;
|
||||
|
||||
let value = inner_hollow(solid, thickness, exec_state, args).await?;
|
||||
let value = inner_hollow(thickness, solid, exec_state, args).await?;
|
||||
Ok(KclValue::Solid { value })
|
||||
}
|
||||
|
||||
@ -268,7 +267,7 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> line(end = [-24, 0])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 6)
|
||||
/// |> hollow(thickness = 0.25)
|
||||
/// |> hollow (0.25, %)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
@ -280,7 +279,7 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> line(end = [-24, 0])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 6)
|
||||
/// |> hollow(thickness = 0.5)
|
||||
/// |> hollow (0.5, %)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
@ -302,21 +301,15 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// |> circle( center = [size / 2, -size / 2], radius = 25 )
|
||||
/// |> extrude(length = 50)
|
||||
///
|
||||
/// hollow(case, thickness = 0.5)
|
||||
/// hollow(0.5, case)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "hollow",
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
solid = { docs = "Which solid to shell out" },
|
||||
thickness = {docs = "The thickness of the shell" },
|
||||
}
|
||||
}]
|
||||
async fn inner_hollow(
|
||||
solid: Box<Solid>,
|
||||
thickness: TyF64,
|
||||
solid: Box<Solid>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
|
@ -1454,7 +1454,7 @@ pub(crate) async fn inner_start_profile_at(
|
||||
|
||||
/// Returns the X component of the sketch profile start point.
|
||||
pub async fn profile_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch: Sketch = args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::sketch(), exec_state)?;
|
||||
let sketch: Sketch = args.get_sketch(exec_state)?;
|
||||
let ty = sketch.units.into();
|
||||
let x = inner_profile_start_x(sketch)?;
|
||||
Ok(args.make_user_val_from_f64_with_type(TyF64::new(x, ty)))
|
||||
@ -1471,20 +1471,15 @@ pub async fn profile_start_x(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// |> angledLine(angle = 30, endAbsoluteX = profileStartX(%))
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "profileStartX",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
profile = {docs = "Profile whose start is being used"},
|
||||
}
|
||||
name = "profileStartX"
|
||||
}]
|
||||
pub(crate) fn inner_profile_start_x(profile: Sketch) -> Result<f64, KclError> {
|
||||
Ok(profile.start.to[0])
|
||||
pub(crate) fn inner_profile_start_x(sketch: Sketch) -> Result<f64, KclError> {
|
||||
Ok(sketch.start.to[0])
|
||||
}
|
||||
|
||||
/// Returns the Y component of the sketch profile start point.
|
||||
pub async fn profile_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch: Sketch = args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::sketch(), exec_state)?;
|
||||
let sketch: Sketch = args.get_sketch(exec_state)?;
|
||||
let ty = sketch.units.into();
|
||||
let x = inner_profile_start_y(sketch)?;
|
||||
Ok(args.make_user_val_from_f64_with_type(TyF64::new(x, ty)))
|
||||
@ -1500,20 +1495,15 @@ pub async fn profile_start_y(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
/// |> angledLine(angle = 30, endAbsoluteY = profileStartY(%))
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "profileStartY",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
profile = {docs = "Profile whose start is being used"},
|
||||
}
|
||||
name = "profileStartY"
|
||||
}]
|
||||
pub(crate) fn inner_profile_start_y(profile: Sketch) -> Result<f64, KclError> {
|
||||
Ok(profile.start.to[1])
|
||||
pub(crate) fn inner_profile_start_y(sketch: Sketch) -> Result<f64, KclError> {
|
||||
Ok(sketch.start.to[1])
|
||||
}
|
||||
|
||||
/// Returns the sketch profile start point.
|
||||
pub async fn profile_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch: Sketch = args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::sketch(), exec_state)?;
|
||||
let sketch: Sketch = args.get_sketch(exec_state)?;
|
||||
let ty = sketch.units.into();
|
||||
let point = inner_profile_start(sketch)?;
|
||||
Ok(KclValue::from_point2d(point, ty, args.into()))
|
||||
@ -1532,15 +1522,10 @@ pub async fn profile_start(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
/// |> extrude(length = 20)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "profileStart",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
profile = {docs = "Profile whose start is being used"},
|
||||
}
|
||||
name = "profileStart"
|
||||
}]
|
||||
pub(crate) fn inner_profile_start(profile: Sketch) -> Result<[f64; 2], KclError> {
|
||||
Ok(profile.start.to)
|
||||
pub(crate) fn inner_profile_start(sketch: Sketch) -> Result<[f64; 2], KclError> {
|
||||
Ok(sketch.start.to)
|
||||
}
|
||||
|
||||
/// Close the current sketch.
|
||||
|
@ -2798,45 +2798,53 @@ description: Result of parsing add_lots.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": "x",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "3660",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 3660.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "3660",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 3660.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"Big sum\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "Big sum"
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0.1",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.1,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"Big sum\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "Big sum"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
@ -2846,7 +2854,7 @@ description: Result of parsing add_lots.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "assert",
|
||||
"name": "assertEqual",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -2857,24 +2865,8 @@ description: Result of parsing add_lots.kcl
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "x",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
}
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
|
@ -4,4 +4,4 @@ fn f(i) {
|
||||
|
||||
x = f(0) + f(1) + f(2) + f(3) + f(4) + f(5) + f(6) + f(7) + f(8) + f(9) + f(10) + f(11) + f(12) + f(13) + f(14) + f(15) + f(16) + f(17) + f(18) + f(19) + f(20) + f(21) + f(22) + f(23) + f(24) + f(25) + f(26) + f(27) + f(28) + f(29) + f(30) + f(31) + f(32) + f(33) + f(34) + f(35) + f(36) + f(37) + f(38) + f(39) + f(40) + f(41) + f(42) + f(43) + f(44) + f(45) + f(46) + f(47) + f(48) + f(49) + f(50) + f(51) + f(52) + f(53) + f(54) + f(55) + f(56) + f(57) + f(58) + f(59) + f(60)
|
||||
|
||||
assert(x, isEqualTo = 3660, error = "Big sum")
|
||||
assertEqual(x, 3660, 0.1, "Big sum")
|
||||
|
@ -8,4 +8,4 @@ fn f(i) {
|
||||
|
||||
x = f(0) + f(1) + f(2) + f(3) + f(4) + f(5) + f(6) + f(7) + f(8) + f(9) + f(10) + f(11) + f(12) + f(13) + f(14) + f(15) + f(16) + f(17) + f(18) + f(19) + f(20) + f(21) + f(22) + f(23) + f(24) + f(25) + f(26) + f(27) + f(28) + f(29) + f(30) + f(31) + f(32) + f(33) + f(34) + f(35) + f(36) + f(37) + f(38) + f(39) + f(40) + f(41) + f(42) + f(43) + f(44) + f(45) + f(46) + f(47) + f(48) + f(49) + f(50) + f(51) + f(52) + f(53) + f(54) + f(55) + f(56) + f(57) + f(58) + f(59) + f(60)
|
||||
|
||||
assert(x, isEqualTo = 3660, error = "Big sum")
|
||||
assertEqual(x, 3660, 0.1, "Big sum")
|
||||
|
@ -260,180 +260,34 @@ description: Result of parsing array_elem_pop.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"object": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": "new_arr1",
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"property": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "1",
|
||||
"raw": "0",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 1.0,
|
||||
"value": 0.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"element 0 should not have changed\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "element 0 should not have changed"
|
||||
}
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "assert",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name"
|
||||
},
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"object": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "new_arr1",
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"property": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
"type": "ExpressionStatement"
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "2",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 2.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"element 1 should not have changed\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "element 1 should not have changed"
|
||||
}
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "assert",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name"
|
||||
},
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"object": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "new_arr1",
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"property": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "1",
|
||||
@ -445,10 +299,48 @@ description: Result of parsing array_elem_pop.kcl
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0.00001",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.00001,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"element 0 should not have changed\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "element 0 should not have changed"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "assertEqual",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
}
|
||||
"type": "Name"
|
||||
},
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
@ -460,15 +352,18 @@ description: Result of parsing array_elem_pop.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"object": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": "new_arr1",
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"property": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "1",
|
||||
@ -479,26 +374,43 @@ description: Result of parsing array_elem_pop.kcl
|
||||
"value": 1.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "2",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 2.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"element 0 should not have changed\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "element 0 should not have changed"
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0.00001",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.00001,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"element 1 should not have changed\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "element 1 should not have changed"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
@ -508,7 +420,7 @@ description: Result of parsing array_elem_pop.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "assert",
|
||||
"name": "assertEqual",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -519,36 +431,100 @@ description: Result of parsing array_elem_pop.kcl
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"object": {
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
"type": "ExpressionStatement"
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"name": "new_arr2",
|
||||
"object": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "new_arr2",
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"property": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
},
|
||||
"property": {
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0",
|
||||
"raw": "1",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.0,
|
||||
"value": 1.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0.00001",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.00001,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"element 0 should not have changed\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "element 0 should not have changed"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "assertEqual",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
}
|
||||
"type": "Name"
|
||||
},
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
|
@ -2,6 +2,6 @@ arr = [1, 2, 3]
|
||||
new_arr1 = pop(arr)
|
||||
new_arr2 = pop(new_arr1)
|
||||
new_arr3 = pop(new_arr2)
|
||||
assert(new_arr1[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assert(new_arr1[1], isEqualTo = 2, error = "element 1 should not have changed")
|
||||
assert(new_arr2[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assertEqual(new_arr1[0], 1, 0.00001, "element 0 should not have changed")
|
||||
assertEqual(new_arr1[1], 2, 0.00001, "element 1 should not have changed")
|
||||
assertEqual(new_arr2[0], 1, 0.00001, "element 0 should not have changed")
|
||||
|
@ -6,6 +6,6 @@ arr = [1, 2, 3]
|
||||
new_arr1 = pop(arr)
|
||||
new_arr2 = pop(new_arr1)
|
||||
new_arr3 = pop(new_arr2)
|
||||
assert(new_arr1[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assert(new_arr1[1], isEqualTo = 2, error = "element 1 should not have changed")
|
||||
assert(new_arr2[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assertEqual(new_arr1[0], 1, 0.00001, "element 0 should not have changed")
|
||||
assertEqual(new_arr1[1], 2, 0.00001, "element 1 should not have changed")
|
||||
assertEqual(new_arr2[0], 1, 0.00001, "element 0 should not have changed")
|
||||
|
@ -1,12 +1,12 @@
|
||||
arr = [1, 2, 3]
|
||||
new_arr1 = push(arr, 4)
|
||||
new_arr2 = push(new_arr1, 5)
|
||||
assert(new_arr1[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assert(new_arr1[1], isEqualTo = 2, error = "element 1 should not have changed")
|
||||
assert(new_arr1[2], isEqualTo = 3, error = "element 2 should not have changed")
|
||||
assert(new_arr1[3], isEqualTo = 4, error = "4 was added to the end of the array")
|
||||
assert(new_arr2[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assert(new_arr2[1], isEqualTo = 2, error = "element 1 should not have changed")
|
||||
assert(new_arr2[2], isEqualTo = 3, error = "element 2 should not have changed")
|
||||
assert(new_arr2[3], isEqualTo = 4, error = "4 was added to the end of the array")
|
||||
assert(new_arr2[4], isEqualTo = 5, error = "5 was added to the end of the array")
|
||||
assertEqual(new_arr1[0], 1, 0.00001, "element 0 should not have changed")
|
||||
assertEqual(new_arr1[1], 2, 0.00001, "element 1 should not have changed")
|
||||
assertEqual(new_arr1[2], 3, 0.00001, "element 2 should not have changed")
|
||||
assertEqual(new_arr1[3], 4, 0.00001, "4 was added to the end of the array")
|
||||
assertEqual(new_arr2[0], 1, 0.00001, "element 0 should not have changed")
|
||||
assertEqual(new_arr2[1], 2, 0.00001, "element 1 should not have changed")
|
||||
assertEqual(new_arr2[2], 3, 0.00001, "element 2 should not have changed")
|
||||
assertEqual(new_arr2[3], 4, 0.00001, "4 was added to the end of the array")
|
||||
assertEqual(new_arr2[4], 5, 0.00001, "5 was added to the end of the array")
|
||||
|
@ -5,12 +5,12 @@ description: Result of unparsing array_elem_push.kcl
|
||||
arr = [1, 2, 3]
|
||||
new_arr1 = push(arr, 4)
|
||||
new_arr2 = push(new_arr1, 5)
|
||||
assert(new_arr1[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assert(new_arr1[1], isEqualTo = 2, error = "element 1 should not have changed")
|
||||
assert(new_arr1[2], isEqualTo = 3, error = "element 2 should not have changed")
|
||||
assert(new_arr1[3], isEqualTo = 4, error = "4 was added to the end of the array")
|
||||
assert(new_arr2[0], isEqualTo = 1, error = "element 0 should not have changed")
|
||||
assert(new_arr2[1], isEqualTo = 2, error = "element 1 should not have changed")
|
||||
assert(new_arr2[2], isEqualTo = 3, error = "element 2 should not have changed")
|
||||
assert(new_arr2[3], isEqualTo = 4, error = "4 was added to the end of the array")
|
||||
assert(new_arr2[4], isEqualTo = 5, error = "5 was added to the end of the array")
|
||||
assertEqual(new_arr1[0], 1, 0.00001, "element 0 should not have changed")
|
||||
assertEqual(new_arr1[1], 2, 0.00001, "element 1 should not have changed")
|
||||
assertEqual(new_arr1[2], 3, 0.00001, "element 2 should not have changed")
|
||||
assertEqual(new_arr1[3], 4, 0.00001, "4 was added to the end of the array")
|
||||
assertEqual(new_arr2[0], 1, 0.00001, "element 0 should not have changed")
|
||||
assertEqual(new_arr2[1], 2, 0.00001, "element 1 should not have changed")
|
||||
assertEqual(new_arr2[2], 3, 0.00001, "element 2 should not have changed")
|
||||
assertEqual(new_arr2[3], 4, 0.00001, "4 was added to the end of the array")
|
||||
assertEqual(new_arr2[4], 5, 0.00001, "5 was added to the end of the array")
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Error from executing array_elem_push_fail.kcl
|
||||
---
|
||||
KCL UndefinedValue error
|
||||
|
@ -1,17 +1,17 @@
|
||||
r1 = [0..4]
|
||||
assert(r1[4], isEqualTo = 4, error = "last element is included")
|
||||
assertEqual(r1[4], 4, 0.00001, "last element is included")
|
||||
|
||||
four = 4
|
||||
zero = 0
|
||||
r2 = [zero..four]
|
||||
assert(r2[4], isEqualTo = 4, error = "last element is included")
|
||||
assertEqual(r2[4], 4, 0.00001, "last element is included")
|
||||
|
||||
five = int(four + 1)
|
||||
r3 = [zero..five]
|
||||
assert(r3[4], isEqualTo = 4, error = "second-to-last element is included")
|
||||
assert(r3[5], isEqualTo = 5, error = "last element is included")
|
||||
assertEqual(r3[4], 4, 0.00001, "second-to-last element is included")
|
||||
assertEqual(r3[5], 5, 0.00001, "last element is included")
|
||||
|
||||
r4 = [int(zero + 1) .. int(five - 1)]
|
||||
assert(r4[0], isEqualTo = 1, error = "first element is 1")
|
||||
assert(r4[2], isEqualTo = 3, error = "second-to-last element is 3")
|
||||
assert(r4[3], isEqualTo = 4, error = "last element is 4")
|
||||
assertEqual(r4[0], 1, 0.00001, "first element is 1")
|
||||
assertEqual(r4[2], 3, 0.00001, "second-to-last element is 3")
|
||||
assertEqual(r4[3], 4, 0.00001, "last element is 4")
|
||||
|
@ -3,19 +3,19 @@ source: kcl-lib/src/simulation_tests.rs
|
||||
description: Result of unparsing array_range_expr.kcl
|
||||
---
|
||||
r1 = [0..4]
|
||||
assert(r1[4], isEqualTo = 4, error = "last element is included")
|
||||
assertEqual(r1[4], 4, 0.00001, "last element is included")
|
||||
|
||||
four = 4
|
||||
zero = 0
|
||||
r2 = [zero..four]
|
||||
assert(r2[4], isEqualTo = 4, error = "last element is included")
|
||||
assertEqual(r2[4], 4, 0.00001, "last element is included")
|
||||
|
||||
five = int(four + 1)
|
||||
r3 = [zero..five]
|
||||
assert(r3[4], isEqualTo = 4, error = "second-to-last element is included")
|
||||
assert(r3[5], isEqualTo = 5, error = "last element is included")
|
||||
assertEqual(r3[4], 4, 0.00001, "second-to-last element is included")
|
||||
assertEqual(r3[5], 5, 0.00001, "last element is included")
|
||||
|
||||
r4 = [int(zero + 1) .. int(five - 1)]
|
||||
assert(r4[0], isEqualTo = 1, error = "first element is 1")
|
||||
assert(r4[2], isEqualTo = 3, error = "second-to-last element is 3")
|
||||
assert(r4[3], isEqualTo = 4, error = "last element is 4")
|
||||
assertEqual(r4[0], 1, 0.00001, "first element is 1")
|
||||
assertEqual(r4[2], 3, 0.00001, "second-to-last element is 3")
|
||||
assertEqual(r4[3], 4, 0.00001, "last element is 4")
|
||||
|
@ -96,53 +96,73 @@ description: Result of parsing array_range_negative_expr.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"object": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": "xs",
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"argument": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "5",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 5.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"property": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"operator": "-",
|
||||
"raw": "0",
|
||||
"start": 0,
|
||||
"type": "UnaryExpression",
|
||||
"type": "UnaryExpression"
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
},
|
||||
{
|
||||
"argument": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "5",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 5.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"operator": "-",
|
||||
"start": 0,
|
||||
"type": "UnaryExpression",
|
||||
"type": "UnaryExpression"
|
||||
},
|
||||
{
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0.001",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.001,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"first element is -5\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "first element is -5"
|
||||
}
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"first element is -5\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "first element is -5"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
@ -152,7 +172,7 @@ description: Result of parsing array_range_negative_expr.kcl
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "assert",
|
||||
"name": "assertEqual",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
@ -163,36 +183,8 @@ description: Result of parsing array_range_negative_expr.kcl
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"commentStart": 0,
|
||||
"computed": false,
|
||||
"end": 0,
|
||||
"object": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "xs",
|
||||
"start": 0,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
"property": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "0",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": {
|
||||
"value": 0.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "MemberExpression",
|
||||
"type": "MemberExpression"
|
||||
}
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
|
@ -1,2 +1,2 @@
|
||||
xs = [int(-5) .. 5]
|
||||
assert(xs[0], isEqualTo = -5, error = "first element is -5")
|
||||
assertEqual(xs[0], -5, 0.001, "first element is -5")
|
||||
|
@ -3,4 +3,4 @@ source: kcl-lib/src/simulation_tests.rs
|
||||
description: Result of unparsing array_range_negative_expr.kcl
|
||||
---
|
||||
xs = [int(-5) .. 5]
|
||||
assert(xs[0], isEqualTo = -5, error = "first element is -5")
|
||||
assertEqual(xs[0], -5, 0.001, "first element is -5")
|
||||
|
@ -156,15 +156,26 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"left": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "a",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
},
|
||||
"arg": {
|
||||
"operator": "==",
|
||||
"right": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "2",
|
||||
@ -175,26 +186,19 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"value": 2.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "BinaryExpression",
|
||||
"type": "BinaryExpression"
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"right branch of and is false makes the whole expression false\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "right branch of and is false makes the whole expression false"
|
||||
}
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"right branch of and is false makes the whole expression false\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "right branch of and is false makes the whole expression false"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
@ -215,24 +219,8 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "a",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
}
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
@ -389,15 +377,26 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"left": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "b",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
},
|
||||
"arg": {
|
||||
"operator": "==",
|
||||
"right": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "2",
|
||||
@ -408,26 +407,19 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"value": 2.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "BinaryExpression",
|
||||
"type": "BinaryExpression"
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"left branch of and is false makes the whole expression false\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "left branch of and is false makes the whole expression false"
|
||||
}
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"left branch of and is false makes the whole expression false\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "left branch of and is false makes the whole expression false"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
@ -448,24 +440,8 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "b",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
}
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
@ -622,15 +598,26 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"left": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "c",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
},
|
||||
"arg": {
|
||||
"operator": "==",
|
||||
"right": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "1",
|
||||
@ -641,26 +628,19 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"value": 1.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "BinaryExpression",
|
||||
"type": "BinaryExpression"
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"both branches of and are true makes the whole expression true\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "both branches of and are true makes the whole expression true"
|
||||
}
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"both branches of and are true makes the whole expression true\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "both branches of and are true makes the whole expression true"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
@ -681,24 +661,8 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "c",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
}
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
@ -855,15 +819,26 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"left": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "isEqualTo",
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "d",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
},
|
||||
"arg": {
|
||||
"operator": "==",
|
||||
"right": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "2",
|
||||
@ -874,26 +849,19 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"value": 2.0,
|
||||
"suffix": "None"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start": 0,
|
||||
"type": "BinaryExpression",
|
||||
"type": "BinaryExpression"
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "error",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"arg": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"both branches of and are false makes the whole expression false\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "both branches of and are false makes the whole expression false"
|
||||
}
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"raw": "\"both branches of and are false makes the whole expression false\"",
|
||||
"start": 0,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "both branches of and are false makes the whole expression false"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
@ -914,24 +882,8 @@ description: Result of parsing boolean_logical_and.kcl
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"start": 0,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": {
|
||||
"abs_path": false,
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": {
|
||||
"commentStart": 0,
|
||||
"end": 0,
|
||||
"name": "d",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"path": [],
|
||||
"start": 0,
|
||||
"type": "Name",
|
||||
"type": "Name"
|
||||
}
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "ExpressionStatement",
|
||||
|
@ -4,7 +4,7 @@ a = if aa {
|
||||
} else {
|
||||
2
|
||||
}
|
||||
assert(a, isEqualTo = 2, error = "right branch of and is false makes the whole expression false")
|
||||
assert(a == 2, "right branch of and is false makes the whole expression false")
|
||||
|
||||
bb = false & true
|
||||
b = if bb {
|
||||
@ -12,7 +12,7 @@ b = if bb {
|
||||
} else {
|
||||
2
|
||||
}
|
||||
assert(b, isEqualTo = 2, error = "left branch of and is false makes the whole expression false")
|
||||
assert(b == 2, "left branch of and is false makes the whole expression false")
|
||||
|
||||
cc = true & true
|
||||
c = if cc {
|
||||
@ -20,7 +20,7 @@ c = if cc {
|
||||
} else {
|
||||
2
|
||||
}
|
||||
assert(c, isEqualTo = 1, error = "both branches of and are true makes the whole expression true")
|
||||
assert(c == 1, "both branches of and are true makes the whole expression true")
|
||||
|
||||
dd = false & false
|
||||
d = if dd {
|
||||
@ -28,4 +28,4 @@ d = if dd {
|
||||
} else {
|
||||
2
|
||||
}
|
||||
assert(d, isEqualTo = 2, error = "both branches of and are false makes the whole expression false")
|
||||
assert(d == 2, "both branches of and are false makes the whole expression false")
|
||||
|