Fix test 'yRelative to horizontal distance'

Fixes:
 - Make a lineTo helper
 - Fix pathToNode to go through the labeled arg .arg property
This commit is contained in:
Adam Chalmers
2025-01-09 15:55:01 -06:00
committed by Nick Cameron
parent cd28a4a9a1
commit ecec739632
8 changed files with 215 additions and 111 deletions

View File

@ -191,7 +191,8 @@ function moreNodePathFromSourceRange(
const arg = args[argIndex].arg const arg = args[argIndex].arg
if (arg.start <= start && arg.end >= end) { if (arg.start <= start && arg.end >= end) {
path.push(['arguments', 'CallExpressionKw']) path.push(['arguments', 'CallExpressionKw'])
path.push([argIndex, 'index']) path.push([argIndex, 'arg index'])
path.push(['arg', 'LabeledArg -> Arg'])
return moreNodePathFromSourceRange(arg, sourceRange, path) return moreNodePathFromSourceRange(arg, sourceRange, path)
} }
} }

View File

@ -65,7 +65,7 @@ import { perpendicularDistance } from 'sketch-helpers'
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator' import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
import { EdgeCutInfo } from 'machines/modelingMachine' import { EdgeCutInfo } from 'machines/modelingMachine'
import { Node } from 'wasm-lib/kcl/bindings/Node' import { Node } from 'wasm-lib/kcl/bindings/Node'
import { findKwArg, findKwArgAny } from 'lang/util' import { findKwArg, findKwArgAny, findKwArgAnyIndex } from 'lang/util'
export const ARG_TAG = 'tag' export const ARG_TAG = 'tag'
const ARG_END = 'end' const ARG_END = 'end'
@ -191,14 +191,37 @@ const commonConstraintInfoHelper = (
([_, nodeName]) => nodeName === 'PipeExpression' ([_, nodeName]) => nodeName === 'PipeExpression'
) )
const pathToBase = pathToNode.slice(0, pipeExpressionIndex + 2) const pathToBase = pathToNode.slice(0, pipeExpressionIndex + 2)
const pathToArrayExpression: PathToNode = [ const argIndex = (() => {
switch (callExp.type) {
case 'CallExpression':
return 0
case 'CallExpressionKw':
return findKwArgAnyIndex([ARG_END, ARG_END_ABSOLUTE], callExp)
}
})()
if (argIndex === undefined) {
return []
}
// Construct the pathToNode.
const pathToArrayExpression: PathToNode = (() => {
const isKw = callExp.type === 'CallExpressionKw'
let path: PathToNode = [
...pathToBase, ...pathToBase,
['arguments', callExp.type], ['arguments', callExp.type],
[0, 'index'], [argIndex, 'index'],
]
if (isKw) {
path.push(['arg', 'LabeledArg -> Arg'])
}
path.push(
isArr isArr
? ['elements', 'ArrayExpression'] ? ['elements', 'ArrayExpression']
: ['properties', 'ObjectExpression'], : ['properties', 'ObjectExpression']
] )
return path
})()
const pathToFirstArg: PathToNode = isArr const pathToFirstArg: PathToNode = isArr
? [...pathToArrayExpression, [0, 'index']] ? [...pathToArrayExpression, [0, 'index']]
: [ : [
@ -328,92 +351,6 @@ function getTagKwArg(): SketchLineHelperKw['getTag'] {
} }
} }
export const lineTo: SketchLineHelper = {
add: ({ node, pathToNode, segmentInput, replaceExistingCallback }) => {
if (segmentInput.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR
const to = segmentInput.to
const _node = { ...node }
const nodeMeta = getNodeFromPath<PipeExpression>(
_node,
pathToNode,
'PipeExpression'
)
if (err(nodeMeta)) return nodeMeta
const { node: pipe } = nodeMeta
const newVals: [Expr, Expr] = [
createLiteral(roundOff(to[0], 2)),
createLiteral(roundOff(to[1], 2)),
]
const newLine = createCallExpression('lineTo', [
createArrayExpression(newVals),
createPipeSubstitution(),
])
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
if (replaceExistingCallback) {
const result = replaceExistingCallback([
{
type: 'arrayItem',
index: 0,
argType: 'xAbsolute',
expr: createLiteral(roundOff(to[0], 2)),
},
{
type: 'arrayItem',
index: 1,
argType: 'yAbsolute',
expr: createLiteral(roundOff(to[1], 2)),
},
])
if (err(result)) return result
const { callExp, valueUsedInTransform } = result
pipe.body[callIndex] = callExp
return {
modifiedAst: _node,
pathToNode,
valueUsedInTransform: valueUsedInTransform,
}
} else {
pipe.body = [...pipe.body, newLine]
}
return {
modifiedAst: _node,
pathToNode,
}
},
updateArgs: ({ node, pathToNode, input }) => {
if (input.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR
const { to } = input
const _node = { ...node }
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
if (err(nodeMeta)) return nodeMeta
const { node: callExpression } = nodeMeta
const toArrExp = createArrayExpression([
createLiteral(to[0]),
createLiteral(to[1]),
])
mutateArrExp(callExpression.arguments?.[0], toArrExp) ||
mutateObjExpProp(callExpression.arguments?.[0], toArrExp, 'to')
return {
modifiedAst: _node,
pathToNode,
}
},
getTag: getTag(),
addTag: addTag(),
getConstraintInfo: (callExp, ...args) =>
commonConstraintInfoHelper(
callExp,
['xAbsolute', 'yAbsolute'],
'lineTo',
[{ arrayInput: 0 }, { arrayInput: 1 }],
...args
),
}
export const line: SketchLineHelperKw = { export const line: SketchLineHelperKw = {
add: ({ add: ({
node, node,
@ -552,6 +489,154 @@ export const line: SketchLineHelperKw = {
), ),
} }
export const lineTo: SketchLineHelperKw = {
add: ({
node,
previousProgramMemory,
pathToNode,
segmentInput,
replaceExistingCallback,
spliceBetween,
}) => {
if (segmentInput.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR
const to = segmentInput.to
const _node = { ...node }
const nodeMeta = getNodeFromPath<PipeExpression | CallExpressionKw>(
_node,
pathToNode,
'PipeExpression'
)
if (err(nodeMeta)) return nodeMeta
const { node: pipe } = nodeMeta
const nodeMeta2 = getNodeFromPath<VariableDeclarator>(
_node,
pathToNode,
'VariableDeclarator'
)
if (err(nodeMeta2)) return nodeMeta2
const { node: varDec } = nodeMeta2
const newXVal = createLiteral(roundOff(to[0], 2))
const newYVal = createLiteral(roundOff(to[1], 2))
if (
spliceBetween &&
!replaceExistingCallback &&
pipe.type === 'PipeExpression'
) {
const callExp = createCallExpressionStdLibKw(
'line',
createPipeSubstitution(),
[
createLabeledArg(
ARG_END_ABSOLUTE,
createArrayExpression([newXVal, newYVal])
),
]
)
const pathToNodeIndex = pathToNode.findIndex(
(x) => x[1] === 'PipeExpression'
)
const pipeIndex = pathToNode[pathToNodeIndex + 1][0]
if (typeof pipeIndex === 'undefined' || typeof pipeIndex === 'string') {
return new Error('pipeIndex is undefined')
}
pipe.body = [
...pipe.body.slice(0, pipeIndex),
callExp,
...pipe.body.slice(pipeIndex),
]
return {
modifiedAst: _node,
pathToNode,
}
}
if (replaceExistingCallback && pipe.type !== 'CallExpressionKw') {
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
const result = replaceExistingCallback([
{
type: 'arrayItem',
index: 0,
argType: 'xRelative',
expr: newXVal,
},
{
type: 'arrayItem',
index: 1,
argType: 'yRelative',
expr: newYVal,
},
])
if (err(result)) return result
const { callExp, valueUsedInTransform } = result
pipe.body[callIndex] = callExp
return {
modifiedAst: _node,
pathToNode: [...pathToNode],
valueUsedInTransform,
}
}
const callExp = createCallExpressionStdLibKw(
'line',
createPipeSubstitution(),
[
createLabeledArg(
ARG_END_ABSOLUTE,
createArrayExpression([newXVal, newYVal])
),
]
)
if (pipe.type === 'PipeExpression') {
pipe.body = [...pipe.body, callExp]
return {
modifiedAst: _node,
pathToNode: [
...pathToNode,
['body', 'PipeExpression'],
[pipe.body.length - 1, 'CallExpressionKw'],
],
}
} else {
varDec.init = createPipeExpression([varDec.init, callExp])
}
return {
modifiedAst: _node,
pathToNode,
}
},
updateArgs: ({ node, pathToNode, input }) => {
if (input.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR
const { to, from } = input
const _node = { ...node }
const nodeMeta = getNodeFromPath<CallExpressionKw>(_node, pathToNode)
if (err(nodeMeta)) return nodeMeta
const { node: callExpression } = nodeMeta
const toArrExp = createArrayExpression([
createLiteral(roundOff(to[0] - from[0], 2)),
createLiteral(roundOff(to[1] - from[1], 2)),
])
mutateKwArg(ARG_END_ABSOLUTE, callExpression, toArrExp)
return {
modifiedAst: _node,
pathToNode,
}
},
getTag: getTagKwArg(),
addTag: addTag(),
getConstraintInfo: (callExp, ...args) =>
commonConstraintInfoHelper(
callExp,
['xRelative', 'yRelative'],
'line',
[{ arrayInput: 0 }, { arrayInput: 1 }],
...args
),
}
export const xLineTo: SketchLineHelper = { export const xLineTo: SketchLineHelper = {
add: ({ node, pathToNode, segmentInput, replaceExistingCallback }) => { add: ({ node, pathToNode, segmentInput, replaceExistingCallback }) => {
if (segmentInput.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR if (segmentInput.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR
@ -1903,6 +1988,7 @@ export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = {
export const sketchLineHelperMapKw: { [key: string]: SketchLineHelperKw } = { export const sketchLineHelperMapKw: { [key: string]: SketchLineHelperKw } = {
line, line,
lineTo,
} as const } as const
export function changeSketchArguments( export function changeSketchArguments(
@ -1966,7 +2052,7 @@ export function getConstraintInfoKw(
pathToNode: PathToNode pathToNode: PathToNode
): ConstrainInfo[] { ): ConstrainInfo[] {
const fnName = callExpression?.callee?.name || '' const fnName = callExpression?.callee?.name || ''
if (!(fnName in sketchLineHelperMap)) return [] if (!(fnName in sketchLineHelperMapKw)) return []
return sketchLineHelperMapKw[fnName].getConstraintInfo( return sketchLineHelperMapKw[fnName].getConstraintInfo(
callExpression, callExpression,
code, code,
@ -2124,7 +2210,10 @@ export function replaceSketchLine({
} }
const _node = { ...node } const _node = { ...node }
const { add } = sketchLineHelperMap[fnName] const { add } =
sketchLineHelperMap[fnName] === undefined
? sketchLineHelperMapKw[fnName]
: sketchLineHelperMap[fnName]
const addRetVal = add({ const addRetVal = add({
node: _node, node: _node,
previousProgramMemory: programMemory, previousProgramMemory: programMemory,

View File

@ -28,10 +28,7 @@ export function getSketchSegmentFromPathToNode(
// TODO: once pathToNode is stored on program memory as part of execution, // TODO: once pathToNode is stored on program memory as part of execution,
// we can check if the pathToNode matches the pathToNode of the sketch. // we can check if the pathToNode matches the pathToNode of the sketch.
// For now we fall back to the sourceRange // For now we fall back to the sourceRange
const nodeMeta = getNodeFromPath<Node<Expr> | Node<LabeledArg>>( const nodeMeta = getNodeFromPath<Node<Expr> | LabeledArg>(ast, pathToNode)
ast,
pathToNode
)
if (err(nodeMeta)) return nodeMeta if (err(nodeMeta)) return nodeMeta
const _node = nodeMeta.node const _node = nodeMeta.node

View File

@ -513,10 +513,10 @@ part001 = startSketchOn('XY')
['// base selection', '// xRelative'], ['// base selection', '// xRelative'],
'setVertDistance' 'setVertDistance'
) )
expect(expectedCode).toContain(`|> lineTo([ expect(expectedCode).toContain(`|> line(%, endAbsolute = [
lastSegX(%) + myVar, lastSegX(%) + myVar,
segEndY(seg01) + 2.93 segEndY(seg01) + 2.93
], %) // xRelative`) ]) // xRelative`)
}) })
it('testing for yRelative to horizontal distance', async () => { it('testing for yRelative to horizontal distance', async () => {
const expectedCode = await helperThing( const expectedCode = await helperThing(
@ -524,10 +524,11 @@ part001 = startSketchOn('XY')
['// base selection', '// yRelative'], ['// base selection', '// yRelative'],
'setHorzDistance' 'setHorzDistance'
) )
expect(expectedCode).toContain(`|> lineTo([ // ADAM here
expect(expectedCode).toContain(`|> line(%, endAbsolute = [
segEndX(seg01) + 2.6, segEndX(seg01) + 2.6,
lastSegY(%) + myVar lastSegY(%) + myVar
], %) // yRelative`) ]) // yRelative`)
}) })
}) })
}) })

View File

@ -1871,7 +1871,7 @@ export function transformAstSketchLines({
return return
} }
} }
const segMeta = getSketchSegmentFromPathToNode(sketch, ast, _pathToNode) const segMeta = getSketchSegmentFromPathToNode(sketch, ast, _pathToNode) // ADAM: HERE
if (err(segMeta)) return segMeta if (err(segMeta)) return segMeta
const seg = segMeta.segment const seg = segMeta.segment
@ -1932,9 +1932,12 @@ export function transformAstSketchLines({
if ('graphSelections' in selectionRanges) { if ('graphSelections' in selectionRanges) {
// If the processing of any of the selections failed, return the first error // If the processing of any of the selections failed, return the first error
const maybeProcessErrors = selectionRanges.graphSelections const maybeProcessErrors = selectionRanges.graphSelections
.map(({ codeRef }, index) => .map(({ codeRef }, index) => {
processSelection(getNodePathFromSourceRange(node, codeRef.range), index) return processSelection(
getNodePathFromSourceRange(node, codeRef.range),
index
) )
})
.filter(err) .filter(err)
if (maybeProcessErrors.length) return maybeProcessErrors[0] if (maybeProcessErrors.length) return maybeProcessErrors[0]

View File

@ -64,7 +64,7 @@ export type SegmentInputs = StraightSegmentInput | ArcSegmentInput
* @property referencedSegment - An optional path to a referenced segment. * @property referencedSegment - An optional path to a referenced segment.
* @property spliceBetween=false - Defaults to false. Normal behavior is to add a new callExpression to the end of the pipeExpression. * @property spliceBetween=false - Defaults to false. Normal behavior is to add a new callExpression to the end of the pipeExpression.
*/ */
interface addCall extends ModifyAstBase { export interface addCall extends ModifyAstBase {
segmentInput: SegmentInputs segmentInput: SegmentInputs
replaceExistingCallback?: ( replaceExistingCallback?: (
rawArgs: RawArgs rawArgs: RawArgs

View File

@ -95,3 +95,15 @@ export function findKwArgAny(
return labels.includes(arg.label.name) return labels.includes(arg.label.name)
})?.arg })?.arg
} }
/**
Search the keyword arguments from a call for an argument with one of these labels.
*/
export function findKwArgAnyIndex(
labels: string[],
call: CallExpressionKw
): number | undefined {
return call.arguments.findIndex((arg) => {
return labels.includes(arg.label.name)
})
}

View File

@ -1,6 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"baseUrl": "src", "baseUrl": "src",
"noErrorTruncation": true,
"paths": { "paths": {
"@kittycad/codemirror-lsp-client": [ "@kittycad/codemirror-lsp-client": [
"../packages/codemirror-lsp-client/src/index.ts" "../packages/codemirror-lsp-client/src/index.ts"