Compare commits
4 Commits
achalmers/
...
guptaarnav
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b9580b178 | |||
| 34032b6cb7 | |||
| d4ebddf75f | |||
| b7d729a4b4 |
@ -59,6 +59,7 @@ layout: manual
|
||||
* [`legAngX`](kcl/legAngX)
|
||||
* [`legAngY`](kcl/legAngY)
|
||||
* [`legLen`](kcl/legLen)
|
||||
* [`len`](kcl/len)
|
||||
* [`line`](kcl/line)
|
||||
* [`lineTo`](kcl/lineTo)
|
||||
* [`ln`](kcl/ln)
|
||||
|
||||
37
docs/kcl/len.md
Normal file
37
docs/kcl/len.md
Normal file
File diff suppressed because one or more lines are too long
4850
docs/kcl/std.json
4850
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
@ -756,17 +756,6 @@ test(`Offset plane point-and-click`, async ({
|
||||
})
|
||||
await scene.expectPixelColor([74, 74, 74], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step('Delete offset plane via feature tree selection', async () => {
|
||||
await editor.closePane()
|
||||
const operationButton = await toolbar.getFeatureTreeOperation(
|
||||
'Offset Plane',
|
||||
0
|
||||
)
|
||||
await operationButton.click({ button: 'left' })
|
||||
await page.keyboard.press('Backspace')
|
||||
await scene.expectPixelColor([50, 51, 96], testPoint, 15)
|
||||
})
|
||||
})
|
||||
|
||||
const loftPointAndClickCases = [
|
||||
@ -862,75 +851,6 @@ loftPointAndClickCases.forEach(({ shouldPreselect }) => {
|
||||
})
|
||||
await scene.expectPixelColor([89, 89, 89], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step('Delete loft via feature tree selection', async () => {
|
||||
await editor.closePane()
|
||||
const operationButton = await toolbar.getFeatureTreeOperation('Loft', 0)
|
||||
await operationButton.click({ button: 'left' })
|
||||
await page.keyboard.press('Backspace')
|
||||
await scene.expectPixelColor([254, 254, 254], testPoint, 15)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: merge with above test. Right now we're not able to delete a loft
|
||||
// right after creation via selection for some reason, so we go with a new instance
|
||||
test('Loft and offset plane deletion via selection', async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
}) => {
|
||||
const initialCode = `sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [0, 0], radius = 30 }, %)
|
||||
plane001 = offsetPlane('XZ', 50)
|
||||
sketch002 = startSketchOn(plane001)
|
||||
|> circle({ center = [0, 0], radius = 20 }, %)
|
||||
loft001 = loft([sketch001, sketch002])
|
||||
`
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 575, y: 200 }
|
||||
const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
const [clickOnSketch2] = scene.makeMouseHelpers(testPoint.x, testPoint.y + 80)
|
||||
|
||||
await test.step(`Delete loft`, async () => {
|
||||
// Check for loft
|
||||
await scene.expectPixelColor([89, 89, 89], testPoint, 15)
|
||||
await clickOnSketch1()
|
||||
await expect(page.locator('.cm-activeLine')).toHaveText(`
|
||||
|> circle({ center = [0, 0], radius = 30 }, %)
|
||||
`)
|
||||
await page.keyboard.press('Backspace')
|
||||
// Check for sketch 1
|
||||
await scene.expectPixelColor([254, 254, 254], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step('Delete sketch002', async () => {
|
||||
await page.waitForTimeout(1000)
|
||||
await clickOnSketch2()
|
||||
await expect(page.locator('.cm-activeLine')).toHaveText(`
|
||||
|> circle({ center = [0, 0], radius = 20 }, %)
|
||||
`)
|
||||
await page.keyboard.press('Backspace')
|
||||
// Check for plane001
|
||||
await scene.expectPixelColor([228, 228, 228], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step('Delete plane001', async () => {
|
||||
await page.waitForTimeout(1000)
|
||||
await clickOnSketch2()
|
||||
await expect(page.locator('.cm-activeLine')).toHaveText(`
|
||||
plane001 = offsetPlane('XZ', 50)
|
||||
`)
|
||||
await page.keyboard.press('Backspace')
|
||||
// Check for sketch 1
|
||||
await scene.expectPixelColor([254, 254, 254], testPoint, 15)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1110,102 +1030,4 @@ extrude001 = extrude(40, sketch001)
|
||||
})
|
||||
await scene.expectPixelColor([49, 49, 49], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step('Delete shell via feature tree selection', async () => {
|
||||
await editor.closePane()
|
||||
const operationButton = await toolbar.getFeatureTreeOperation('Shell', 0)
|
||||
await operationButton.click({ button: 'left' })
|
||||
await page.keyboard.press('Backspace')
|
||||
await scene.expectPixelColor([99, 99, 99], testPoint, 15)
|
||||
})
|
||||
})
|
||||
|
||||
const shellSketchOnFacesCases = [
|
||||
`sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [0, 0], radius = 100 }, %)
|
||||
|> extrude(100, %)
|
||||
|
||||
sketch002 = startSketchOn(sketch001, 'END')
|
||||
|> circle({ center = [0, 0], radius = 50 }, %)
|
||||
|> extrude(50, %)
|
||||
`,
|
||||
`sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [0, 0], radius = 100 }, %)
|
||||
extrude001 = extrude(100, sketch001)
|
||||
|
||||
sketch002 = startSketchOn(extrude001, 'END')
|
||||
|> circle({ center = [0, 0], radius = 50 }, %)
|
||||
extrude002 = extrude(50, sketch002)
|
||||
`,
|
||||
]
|
||||
shellSketchOnFacesCases.forEach((initialCode, index) => {
|
||||
const hasExtrudesInPipe = index === 0
|
||||
test(`Shell point-and-click sketch on face (extrudes in pipes: ${hasExtrudesInPipe})`, async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 550, y: 295 }
|
||||
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
const shellDeclaration = `shell001 = shell({ faces = ['end'], thickness = 5 }, ${
|
||||
hasExtrudesInPipe ? 'sketch002' : 'extrude002'
|
||||
})`
|
||||
|
||||
await test.step(`Look for the grey of the shape`, async () => {
|
||||
await toolbar.closePane('code')
|
||||
await scene.expectPixelColor([128, 128, 128], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step(`Go through the command bar flow, selecting a cap and keeping default thickness`, async () => {
|
||||
await toolbar.shellButton.click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Selection: '',
|
||||
Thickness: '',
|
||||
},
|
||||
highlightedHeaderArg: 'selection',
|
||||
commandName: 'Shell',
|
||||
})
|
||||
await clickOnCap()
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Selection: '1 cap',
|
||||
Thickness: '5',
|
||||
},
|
||||
commandName: 'Shell',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
})
|
||||
|
||||
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||
await toolbar.openPane('code')
|
||||
await editor.expectEditor.toContain(shellDeclaration)
|
||||
await editor.expectState({
|
||||
diagnostics: [],
|
||||
activeLines: [shellDeclaration],
|
||||
highlightedCode: '',
|
||||
})
|
||||
await toolbar.closePane('code')
|
||||
await scene.expectPixelColor([73, 73, 73], testPoint, 15)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@headlessui/react": "^1.7.19",
|
||||
"@headlessui/tailwindcss": "^0.2.0",
|
||||
"@kittycad/lib": "2.0.13",
|
||||
"@kittycad/lib": "2.0.12",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@lezer/lr": "^1.4.1",
|
||||
"@react-hook/resize-observer": "^2.0.1",
|
||||
|
||||
@ -368,20 +368,13 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
sortText,
|
||||
filterText,
|
||||
}) => {
|
||||
const detailText = [
|
||||
deprecated ? 'Deprecated' : undefined,
|
||||
labelDetails ? labelDetails.detail : detail,
|
||||
]
|
||||
// Don't let undefined appear.
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
const completion: Completion & {
|
||||
filterText: string
|
||||
sortText?: string
|
||||
apply: string
|
||||
} = {
|
||||
label,
|
||||
detail: detailText,
|
||||
detail: labelDetails ? labelDetails.detail : detail,
|
||||
apply: label,
|
||||
type: kind && CompletionItemKindMap[kind].toLowerCase(),
|
||||
sortText: sortText ?? label,
|
||||
@ -389,11 +382,7 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
}
|
||||
if (documentation) {
|
||||
completion.info = () => {
|
||||
const deprecatedHtml = deprecated
|
||||
? '<p><strong>Deprecated</strong></p>'
|
||||
: ''
|
||||
const htmlString =
|
||||
deprecatedHtml + formatMarkdownContents(documentation)
|
||||
const htmlString = formatMarkdownContents(documentation)
|
||||
const htmlNode = document.createElement('div')
|
||||
htmlNode.style.display = 'contents'
|
||||
htmlNode.innerHTML = htmlString
|
||||
|
||||
@ -271,7 +271,6 @@ export const ModelingMachineProvider = ({
|
||||
cmd_id: uuidv4(),
|
||||
cmd: {
|
||||
type: 'default_camera_center_to_selection',
|
||||
camera_movement: 'vantage',
|
||||
},
|
||||
})
|
||||
.catch(reportRejection)
|
||||
|
||||
@ -1149,17 +1149,11 @@ export async function deleteFromSelection(
|
||||
((selection?.artifact?.type === 'wall' ||
|
||||
selection?.artifact?.type === 'cap') &&
|
||||
varDec.node.init.type === 'PipeExpression') ||
|
||||
selection.artifact?.type === 'sweep' ||
|
||||
selection.artifact?.type === 'plane' ||
|
||||
!selection.artifact // aka expected to be a shell at this point
|
||||
selection.artifact?.type === 'sweep'
|
||||
) {
|
||||
let extrudeNameToDelete = ''
|
||||
let pathToNode: PathToNode | null = null
|
||||
if (
|
||||
selection.artifact &&
|
||||
selection.artifact.type !== 'sweep' &&
|
||||
selection.artifact.type !== 'plane'
|
||||
) {
|
||||
if (selection.artifact?.type !== 'sweep') {
|
||||
const varDecName = varDec.node.id.name
|
||||
traverse(astClone, {
|
||||
enter: (node, path) => {
|
||||
@ -1175,17 +1169,6 @@ export async function deleteFromSelection(
|
||||
pathToNode = path
|
||||
extrudeNameToDelete = dec.id.name
|
||||
}
|
||||
if (
|
||||
dec.init.type === 'CallExpression' &&
|
||||
dec.init.callee.name === 'loft' &&
|
||||
dec.init.arguments?.[0].type === 'ArrayExpression' &&
|
||||
dec.init.arguments?.[0].elements.some(
|
||||
(a) => a.type === 'Identifier' && a.name === varDecName
|
||||
)
|
||||
) {
|
||||
pathToNode = path
|
||||
extrudeNameToDelete = dec.id.name
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@ -49,27 +49,17 @@ export function addShell({
|
||||
return new Error("Couldn't find extrude")
|
||||
}
|
||||
|
||||
pathToExtrudeNode = extrudeLookupResult.pathToExtrudeNode
|
||||
// Get the sketch ref from the selection
|
||||
// TODO: this assumes the segment is piped directly from the sketch, with no intermediate `VariableDeclarator` between.
|
||||
// We must find a technique for these situations that is robust to intermediate declarations
|
||||
const extrudeNode = getNodeFromPath<VariableDeclarator>(
|
||||
const sketchNode = getNodeFromPath<VariableDeclarator>(
|
||||
modifiedAst,
|
||||
extrudeLookupResult.pathToExtrudeNode,
|
||||
graphSelection.codeRef.pathToNode,
|
||||
'VariableDeclarator'
|
||||
)
|
||||
const segmentNode = getNodeFromPath<VariableDeclarator>(
|
||||
modifiedAst,
|
||||
extrudeLookupResult.pathToSegmentNode,
|
||||
'VariableDeclarator'
|
||||
)
|
||||
if (err(extrudeNode) || err(segmentNode)) {
|
||||
return new Error("Couldn't find extrude")
|
||||
}
|
||||
if (extrudeNode.node.init.type === 'CallExpression') {
|
||||
pathToExtrudeNode = extrudeLookupResult.pathToExtrudeNode
|
||||
} else if (segmentNode.node.init.type === 'PipeExpression') {
|
||||
pathToExtrudeNode = extrudeLookupResult.pathToSegmentNode
|
||||
} else {
|
||||
return new Error("Couldn't find extrude")
|
||||
if (err(sketchNode)) {
|
||||
return sketchNode
|
||||
}
|
||||
|
||||
const selectedArtifact = graphSelection.artifact
|
||||
|
||||
@ -77,7 +77,7 @@ interface SegmentArtifactRich extends BaseArtifact {
|
||||
/** A Sweep is a more generic term for extrude, revolve, loft and sweep*/
|
||||
interface SweepArtifact extends BaseArtifact {
|
||||
type: 'sweep'
|
||||
subType: 'extrusion' | 'revolve' | 'loft'
|
||||
subType: 'extrusion' | 'revolve'
|
||||
pathId: string
|
||||
surfaceIds: Array<string>
|
||||
edgeIds: Array<string>
|
||||
@ -85,7 +85,7 @@ interface SweepArtifact extends BaseArtifact {
|
||||
}
|
||||
interface SweepArtifactRich extends BaseArtifact {
|
||||
type: 'sweep'
|
||||
subType: 'extrusion' | 'revolve' | 'loft'
|
||||
subType: 'extrusion' | 'revolve'
|
||||
path: PathArtifact
|
||||
surfaces: Array<WallArtifact | CapArtifact>
|
||||
edges: Array<SweepEdge>
|
||||
@ -398,33 +398,6 @@ export function getArtifactsToUpdate({
|
||||
artifact: { ...path, sweepId: id },
|
||||
})
|
||||
return returnArr
|
||||
} else if (
|
||||
cmd.type === 'loft' &&
|
||||
response.type === 'modeling' &&
|
||||
response.data.modeling_response.type === 'loft'
|
||||
) {
|
||||
returnArr.push({
|
||||
id,
|
||||
artifact: {
|
||||
type: 'sweep',
|
||||
subType: 'loft',
|
||||
id,
|
||||
// TODO: make sure to revisit this choice, don't think it matters for now
|
||||
pathId: cmd.section_ids[0],
|
||||
surfaceIds: [],
|
||||
edgeIds: [],
|
||||
codeRef: { range, pathToNode },
|
||||
},
|
||||
})
|
||||
for (const sectionId of cmd.section_ids) {
|
||||
const path = getArtifact(sectionId)
|
||||
if (path?.type === 'path')
|
||||
returnArr.push({
|
||||
id: sectionId,
|
||||
artifact: { ...path, sweepId: id },
|
||||
})
|
||||
}
|
||||
return returnArr
|
||||
} else if (
|
||||
cmd.type === 'solid3d_get_extrusion_face_info' &&
|
||||
response?.type === 'modeling' &&
|
||||
|
||||
@ -445,10 +445,8 @@ const setHorzVertDistanceConstraintLineCreateNode =
|
||||
])
|
||||
|
||||
const makeBinExp = (index: 0 | 1) => {
|
||||
console.error("ADAM args", args)
|
||||
const arg = getArgLiteralVal(args?.[index].expr)
|
||||
const refNum = referencedSegment?.to?.[index]
|
||||
console.error("ADAM arg and refNum:", arg, refNum)
|
||||
if (err(arg) || !isNum(refNum)) return REF_NUM_ERR
|
||||
return createBinaryExpressionWithUnary([
|
||||
createSegEnd(referenceSegName, isX),
|
||||
|
||||
@ -41,13 +41,13 @@ export default function Export() {
|
||||
export to almost any CAD software.
|
||||
</p>
|
||||
<p className="my-4">
|
||||
Our teammate Katie is working on the file format, check out{' '}
|
||||
Our teammate David is working on the file format, check out{' '}
|
||||
<a
|
||||
href="https://github.com/KhronosGroup/glTF/pull/2343"
|
||||
href="https://www.youtube.com/watch?v=8SuW0qkYCZo"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
her standards proposal on GitHub
|
||||
his talk with the Metaverse Standards Forum
|
||||
</a>
|
||||
!
|
||||
</p>
|
||||
|
||||
@ -1755,3 +1755,24 @@ mod array_elem_pop_fail {
|
||||
super::execute(TEST_NAME, false).await
|
||||
}
|
||||
}
|
||||
mod array_length {
|
||||
const TEST_NAME: &str = "array_length";
|
||||
|
||||
/// Test parsing KCL.
|
||||
#[test]
|
||||
fn parse() {
|
||||
super::parse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that parsing and unparsing KCL produces the original KCL input.
|
||||
#[test]
|
||||
fn unparse() {
|
||||
super::unparse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that KCL is executed correctly.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_execute() {
|
||||
super::execute(TEST_NAME, false).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,3 +308,40 @@ pub async fn pop(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
|
||||
inner_pop(array, &args).await
|
||||
}
|
||||
|
||||
/// Get the length of an array.
|
||||
///
|
||||
/// Returns the number of elements in an array.
|
||||
///
|
||||
/// ```no_run
|
||||
/// arr = [1, 2, 3]
|
||||
/// length = len(arr)
|
||||
/// assertEqual(length, 3, 0.00001, "The length of the array is 3")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "len",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
arg_docs = {
|
||||
array = "The array to get the length of.",
|
||||
}
|
||||
}]
|
||||
async fn inner_len(array: Vec<KclValue>, args: &Args) -> Result<KclValue, KclError> {
|
||||
Ok(KclValue::Number {
|
||||
value: array.len() as f64,
|
||||
meta: vec![args.source_range.into()],
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn len(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let val = args.get_unlabeled_kw_arg("array")?;
|
||||
let meta = vec![args.source_range];
|
||||
let KclValue::Array { value: array, meta: _ } = val else {
|
||||
let actual_type = val.human_friendly_type();
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: meta,
|
||||
message: format!("You can't get the length of a value of type {actual_type}, only an array"),
|
||||
}));
|
||||
};
|
||||
inner_len(array, &args).await
|
||||
}
|
||||
|
||||
@ -156,8 +156,5 @@ async fn inner_loft(
|
||||
.await?;
|
||||
|
||||
// Using the first sketch as the base curve, idk we might want to change this later.
|
||||
let mut sketch = sketches[0].clone();
|
||||
// Override its id with the loft id so we can get its faces later
|
||||
sketch.id = id;
|
||||
do_post_extrude(sketch, 0.0, exec_state, args).await
|
||||
do_post_extrude(sketches[0].clone(), 0.0, exec_state, args).await
|
||||
}
|
||||
|
||||
@ -108,6 +108,7 @@ lazy_static! {
|
||||
Box::new(crate::std::array::Reduce),
|
||||
Box::new(crate::std::array::Map),
|
||||
Box::new(crate::std::array::Push),
|
||||
Box::new(crate::std::array::Len),
|
||||
Box::new(crate::std::array::Pop),
|
||||
Box::new(crate::std::chamfer::Chamfer),
|
||||
Box::new(crate::std::fillet::Fillet),
|
||||
|
||||
284
src/wasm-lib/kcl/tests/array_length/artifact_commands.snap
Normal file
284
src/wasm-lib/kcl/tests/array_length/artifact_commands.snap
Normal file
@ -0,0 +1,284 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Artifact commands array_length.kcl
|
||||
---
|
||||
[
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "make_plane",
|
||||
"origin": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"x_axis": {
|
||||
"x": 1.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"y_axis": {
|
||||
"x": 0.0,
|
||||
"y": 1.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"size": 100.0,
|
||||
"clobber": false,
|
||||
"hide": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "plane_set_color",
|
||||
"plane_id": "[uuid]",
|
||||
"color": {
|
||||
"r": 0.7,
|
||||
"g": 0.28,
|
||||
"b": 0.28,
|
||||
"a": 0.4
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "make_plane",
|
||||
"origin": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"x_axis": {
|
||||
"x": 0.0,
|
||||
"y": 1.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"y_axis": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 1.0
|
||||
},
|
||||
"size": 100.0,
|
||||
"clobber": false,
|
||||
"hide": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "plane_set_color",
|
||||
"plane_id": "[uuid]",
|
||||
"color": {
|
||||
"r": 0.28,
|
||||
"g": 0.7,
|
||||
"b": 0.28,
|
||||
"a": 0.4
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "make_plane",
|
||||
"origin": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"x_axis": {
|
||||
"x": 1.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"y_axis": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 1.0
|
||||
},
|
||||
"size": 100.0,
|
||||
"clobber": false,
|
||||
"hide": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "plane_set_color",
|
||||
"plane_id": "[uuid]",
|
||||
"color": {
|
||||
"r": 0.28,
|
||||
"g": 0.28,
|
||||
"b": 0.7,
|
||||
"a": 0.4
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "make_plane",
|
||||
"origin": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"x_axis": {
|
||||
"x": -1.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"y_axis": {
|
||||
"x": 0.0,
|
||||
"y": 1.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"size": 100.0,
|
||||
"clobber": false,
|
||||
"hide": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "make_plane",
|
||||
"origin": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"x_axis": {
|
||||
"x": 0.0,
|
||||
"y": -1.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"y_axis": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 1.0
|
||||
},
|
||||
"size": 100.0,
|
||||
"clobber": false,
|
||||
"hide": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "make_plane",
|
||||
"origin": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"x_axis": {
|
||||
"x": -1.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"y_axis": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 1.0
|
||||
},
|
||||
"size": 100.0,
|
||||
"clobber": false,
|
||||
"hide": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "edge_lines_visible",
|
||||
"hidden": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "set_scene_units",
|
||||
"unit": "mm"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "object_visible",
|
||||
"object_id": "[uuid]",
|
||||
"hidden": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"command": {
|
||||
"type": "object_visible",
|
||||
"object_id": "[uuid]",
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
]
|
||||
282
src/wasm-lib/kcl/tests/array_length/ast.snap
Normal file
282
src/wasm-lib/kcl/tests/array_length/ast.snap
Normal file
@ -0,0 +1,282 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Result of parsing array_length.kcl
|
||||
---
|
||||
{
|
||||
"Ok": {
|
||||
"body": [
|
||||
{
|
||||
"declaration": {
|
||||
"end": 15,
|
||||
"id": {
|
||||
"end": 3,
|
||||
"name": "arr",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"init": {
|
||||
"elements": [
|
||||
{
|
||||
"end": 8,
|
||||
"raw": "1",
|
||||
"start": 7,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"end": 11,
|
||||
"raw": "2",
|
||||
"start": 10,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"end": 14,
|
||||
"raw": "3",
|
||||
"start": 13,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 3.0
|
||||
}
|
||||
],
|
||||
"end": 15,
|
||||
"start": 6,
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression"
|
||||
},
|
||||
"start": 0,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 15,
|
||||
"kind": "const",
|
||||
"start": 0,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
},
|
||||
{
|
||||
"declaration": {
|
||||
"end": 34,
|
||||
"id": {
|
||||
"end": 23,
|
||||
"name": "arr_len",
|
||||
"start": 16,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"init": {
|
||||
"arguments": [
|
||||
{
|
||||
"end": 33,
|
||||
"name": "arr",
|
||||
"start": 30,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 29,
|
||||
"name": "len",
|
||||
"start": 26,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 34,
|
||||
"start": 26,
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 16,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 34,
|
||||
"kind": "const",
|
||||
"start": 16,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
},
|
||||
{
|
||||
"end": 99,
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"end": 54,
|
||||
"name": "arr_len",
|
||||
"start": 47,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
{
|
||||
"end": 57,
|
||||
"raw": "3",
|
||||
"start": 56,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 3.0
|
||||
},
|
||||
{
|
||||
"end": 66,
|
||||
"raw": "0.00001",
|
||||
"start": 59,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 0.00001
|
||||
},
|
||||
{
|
||||
"end": 98,
|
||||
"raw": "\"The length of the array is 3\"",
|
||||
"start": 68,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "The length of the array is 3"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 46,
|
||||
"name": "assertEqual",
|
||||
"start": 35,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 99,
|
||||
"start": 35,
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 35,
|
||||
"type": "ExpressionStatement",
|
||||
"type": "ExpressionStatement"
|
||||
},
|
||||
{
|
||||
"declaration": {
|
||||
"end": 115,
|
||||
"id": {
|
||||
"end": 110,
|
||||
"name": "arr_empty",
|
||||
"start": 101,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"init": {
|
||||
"elements": [],
|
||||
"end": 115,
|
||||
"start": 113,
|
||||
"type": "ArrayExpression",
|
||||
"type": "ArrayExpression"
|
||||
},
|
||||
"start": 101,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 115,
|
||||
"kind": "const",
|
||||
"start": 101,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
},
|
||||
{
|
||||
"declaration": {
|
||||
"end": 142,
|
||||
"id": {
|
||||
"end": 125,
|
||||
"name": "len_empty",
|
||||
"start": 116,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"init": {
|
||||
"arguments": [
|
||||
{
|
||||
"end": 141,
|
||||
"name": "arr_empty",
|
||||
"start": 132,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 131,
|
||||
"name": "len",
|
||||
"start": 128,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 142,
|
||||
"start": 128,
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 116,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 142,
|
||||
"kind": "const",
|
||||
"start": 116,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
},
|
||||
{
|
||||
"end": 209,
|
||||
"expression": {
|
||||
"arguments": [
|
||||
{
|
||||
"end": 164,
|
||||
"name": "len_empty",
|
||||
"start": 155,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
},
|
||||
{
|
||||
"end": 167,
|
||||
"raw": "0",
|
||||
"start": 166,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"end": 176,
|
||||
"raw": "0.00001",
|
||||
"start": 169,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": 0.00001
|
||||
},
|
||||
{
|
||||
"end": 208,
|
||||
"raw": "\"The length of the array is 0\"",
|
||||
"start": 178,
|
||||
"type": "Literal",
|
||||
"type": "Literal",
|
||||
"value": "The length of the array is 0"
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 154,
|
||||
"name": "assertEqual",
|
||||
"start": 143,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 209,
|
||||
"start": 143,
|
||||
"type": "CallExpression",
|
||||
"type": "CallExpression"
|
||||
},
|
||||
"start": 143,
|
||||
"type": "ExpressionStatement",
|
||||
"type": "ExpressionStatement"
|
||||
}
|
||||
],
|
||||
"end": 210,
|
||||
"nonCodeMeta": {
|
||||
"nonCodeNodes": {
|
||||
"2": [
|
||||
{
|
||||
"end": 101,
|
||||
"start": 99,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "newLine"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"startNodes": []
|
||||
},
|
||||
"start": 0
|
||||
}
|
||||
}
|
||||
7
src/wasm-lib/kcl/tests/array_length/input.kcl
Normal file
7
src/wasm-lib/kcl/tests/array_length/input.kcl
Normal file
@ -0,0 +1,7 @@
|
||||
arr = [1, 2, 3]
|
||||
arr_len = len(arr)
|
||||
assertEqual(arr_len, 3, 0.00001, "The length of the array is 3")
|
||||
|
||||
arr_empty = []
|
||||
len_empty = len(arr_empty)
|
||||
assertEqual(len_empty, 0, 0.00001, "The length of the array is 0")
|
||||
5
src/wasm-lib/kcl/tests/array_length/ops.snap
Normal file
5
src/wasm-lib/kcl/tests/array_length/ops.snap
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Operations executed array_length.kcl
|
||||
---
|
||||
[]
|
||||
127
src/wasm-lib/kcl/tests/array_length/program_memory.snap
Normal file
127
src/wasm-lib/kcl/tests/array_length/program_memory.snap
Normal file
@ -0,0 +1,127 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
description: Program memory after executing array_length.kcl
|
||||
---
|
||||
{
|
||||
"environments": [
|
||||
{
|
||||
"bindings": {
|
||||
"HALF_TURN": {
|
||||
"type": "Number",
|
||||
"value": 180.0,
|
||||
"__meta": []
|
||||
},
|
||||
"QUARTER_TURN": {
|
||||
"type": "Number",
|
||||
"value": 90.0,
|
||||
"__meta": []
|
||||
},
|
||||
"THREE_QUARTER_TURN": {
|
||||
"type": "Number",
|
||||
"value": 270.0,
|
||||
"__meta": []
|
||||
},
|
||||
"ZERO": {
|
||||
"type": "Number",
|
||||
"value": 0.0,
|
||||
"__meta": []
|
||||
},
|
||||
"arr": {
|
||||
"type": "Array",
|
||||
"value": [
|
||||
{
|
||||
"type": "Number",
|
||||
"value": 1.0,
|
||||
"__meta": [
|
||||
{
|
||||
"sourceRange": [
|
||||
7,
|
||||
8,
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Number",
|
||||
"value": 2.0,
|
||||
"__meta": [
|
||||
{
|
||||
"sourceRange": [
|
||||
10,
|
||||
11,
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Number",
|
||||
"value": 3.0,
|
||||
"__meta": [
|
||||
{
|
||||
"sourceRange": [
|
||||
13,
|
||||
14,
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"__meta": [
|
||||
{
|
||||
"sourceRange": [
|
||||
6,
|
||||
15,
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"arr_empty": {
|
||||
"type": "Array",
|
||||
"value": [],
|
||||
"__meta": [
|
||||
{
|
||||
"sourceRange": [
|
||||
113,
|
||||
115,
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"arr_len": {
|
||||
"type": "Number",
|
||||
"value": 3.0,
|
||||
"__meta": [
|
||||
{
|
||||
"sourceRange": [
|
||||
26,
|
||||
34,
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"len_empty": {
|
||||
"type": "Number",
|
||||
"value": 0.0,
|
||||
"__meta": [
|
||||
{
|
||||
"sourceRange": [
|
||||
128,
|
||||
142,
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parent": null
|
||||
}
|
||||
],
|
||||
"currentEnv": 0,
|
||||
"return": null
|
||||
}
|
||||
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_len0.png
Normal file
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_len0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@ -1169,25 +1169,25 @@ async fn kcl_test_plumbus_fillets() {
|
||||
return sg
|
||||
}
|
||||
|
||||
fn pentagon = (len) => {
|
||||
fn pentagon = (sideLen) => {
|
||||
sg = startSketchOn('XY')
|
||||
|> startProfileAt([-len / 2, -len / 2], %)
|
||||
|> angledLine({ angle: 0, length: len }, %, $a)
|
||||
|> startProfileAt([-sideLen / 2, -sideLen / 2], %)
|
||||
|> angledLine({ angle: 0, length: sideLen }, %, $a)
|
||||
|> angledLine({
|
||||
angle: segAng(a) + 180 - 108,
|
||||
length: len
|
||||
length: sideLen
|
||||
}, %, $b)
|
||||
|> angledLine({
|
||||
angle: segAng(b) + 180 - 108,
|
||||
length: len
|
||||
length: sideLen
|
||||
}, %, $c)
|
||||
|> angledLine({
|
||||
angle: segAng(c) + 180 - 108,
|
||||
length: len
|
||||
length: sideLen
|
||||
}, %, $d)
|
||||
|> angledLine({
|
||||
angle: segAng(d) + 180 - 108,
|
||||
length: len
|
||||
length: sideLen
|
||||
}, %)
|
||||
|
||||
return sg
|
||||
@ -1653,17 +1653,17 @@ part001 = cube([0,0], 20)
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_duplicate_tags_should_error() {
|
||||
let code = r#"fn triangle = (len) => {
|
||||
let code = r#"fn triangle = (sideLen) => {
|
||||
return startSketchOn('XY')
|
||||
|> startProfileAt([-len / 2, -len / 2], %)
|
||||
|> angledLine({ angle: 0, length: len }, %, $a)
|
||||
|> startProfileAt([-sideLen / 2, -sideLen / 2], %)
|
||||
|> angledLine({ angle: 0, length: sideLen }, %, $a)
|
||||
|> angledLine({
|
||||
angle: segAng(a) + 120,
|
||||
length: len
|
||||
length: sideLen
|
||||
}, %, $b)
|
||||
|> angledLine({
|
||||
angle: segAng(b) + 120,
|
||||
length: len
|
||||
length: sideLen
|
||||
}, %, $a)
|
||||
}
|
||||
|
||||
@ -1674,7 +1674,7 @@ let p = triangle(200)
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"value already defined: KclErrorDetails { source_ranges: [SourceRange([311, 313, 0]), SourceRange([326, 339, 0])], message: "Cannot redefine `a`" }"#
|
||||
r#"value already defined: KclErrorDetails { source_ranges: [SourceRange([335, 337, 0]), SourceRange([350, 363, 0])], message: "Cannot redefine `a`" }"#
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -2010,10 +2010,10 @@
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@kittycad/lib@2.0.13":
|
||||
version "2.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-2.0.13.tgz#e20aa17847ab1359065d21bed143ea330cf545d1"
|
||||
integrity sha512-wLn6/iRVdqbRCvf6t2FhNr8No6+I6elpCEVHGUexyHLoE+1XeUS1lHeapQqcfR0pEQiwtGpcKTDfUNSlmnmaFw==
|
||||
"@kittycad/lib@2.0.12":
|
||||
version "2.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-2.0.12.tgz#517be58ee8b5f59e5c89bb5076492c960b4ef7d8"
|
||||
integrity sha512-1eXIP+JbFvWSWQe//ijBuhlnCLRUnZzNAiOf7oMI0WcRTTn8SD8A+TY+NgK6OVGG12unyTPCVXxRR4Xtm3ahLQ==
|
||||
dependencies:
|
||||
openapi-types "^12.0.0"
|
||||
ts-node "^10.9.1"
|
||||
|
||||
Reference in New Issue
Block a user