@ -1,4 +1,4 @@
|
|||||||
import { parse, recast, initPromise } from './wasm'
|
import { parse, recast, initPromise, PathToNode } from './wasm'
|
||||||
import {
|
import {
|
||||||
findAllPreviousVariables,
|
findAllPreviousVariables,
|
||||||
isNodeSafeToReplace,
|
isNodeSafeToReplace,
|
||||||
@ -9,6 +9,7 @@ import {
|
|||||||
findUsesOfTagInPipe,
|
findUsesOfTagInPipe,
|
||||||
hasSketchPipeBeenExtruded,
|
hasSketchPipeBeenExtruded,
|
||||||
hasExtrudableGeometry,
|
hasExtrudableGeometry,
|
||||||
|
traverse,
|
||||||
} from './queryAst'
|
} from './queryAst'
|
||||||
import { enginelessExecutor } from '../lib/testHelpers'
|
import { enginelessExecutor } from '../lib/testHelpers'
|
||||||
import {
|
import {
|
||||||
@ -538,3 +539,53 @@ const extrude001 = extrude(10, sketch001)
|
|||||||
expect(extrudable).toBeFalsy()
|
expect(extrudable).toBeFalsy()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe.only('Testing traverse and pathToNode', () => {
|
||||||
|
it.each([
|
||||||
|
['basic', '2.73'],
|
||||||
|
[
|
||||||
|
'very nested, array, object, callExpression, array, memberExpression',
|
||||||
|
'.yo',
|
||||||
|
],
|
||||||
|
])('testing %s', async (testName, literalOfInterest) => {
|
||||||
|
const code = `const myVar = 5
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([3.29, 7.86], %)
|
||||||
|
|> line([2.48, 2.44], %)
|
||||||
|
|> line([-3.86, -2.73], %)
|
||||||
|
|> line([-17.67, 0.85], %)
|
||||||
|
|> close(%)
|
||||||
|
const bing = { yo: 55 }
|
||||||
|
const myNestedVar = [
|
||||||
|
{
|
||||||
|
prop: line([bing.yo, 21], sketch001)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`
|
||||||
|
const ast = parse(code)
|
||||||
|
if (err(ast)) throw ast
|
||||||
|
let pathToNode: PathToNode = []
|
||||||
|
traverse(ast, {
|
||||||
|
enter: (node, path) => {
|
||||||
|
if (
|
||||||
|
node.type === 'Literal' &&
|
||||||
|
String(node.value) === literalOfInterest
|
||||||
|
) {
|
||||||
|
pathToNode = path
|
||||||
|
} else if (
|
||||||
|
node.type === 'Identifier' &&
|
||||||
|
literalOfInterest.includes(node.name)
|
||||||
|
) {
|
||||||
|
pathToNode = path
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const literalIndex = code.indexOf(literalOfInterest)
|
||||||
|
const pathToNode2 = getNodePathFromSourceRange(ast, [
|
||||||
|
literalIndex + 2,
|
||||||
|
literalIndex + 2,
|
||||||
|
])
|
||||||
|
expect(pathToNode).toEqual(pathToNode2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -270,6 +270,18 @@ function moreNodePathFromSourceRange(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_node.type === 'MemberExpression' && isInRange) {
|
||||||
|
const { object, property } = _node
|
||||||
|
if (object.start <= start && object.end >= end) {
|
||||||
|
path.push(['object', 'MemberExpression'])
|
||||||
|
return moreNodePathFromSourceRange(object, sourceRange, path)
|
||||||
|
}
|
||||||
|
if (property.start <= start && property.end >= end) {
|
||||||
|
path.push(['property', 'MemberExpression'])
|
||||||
|
return moreNodePathFromSourceRange(property, sourceRange, path)
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
if (_node.type === 'PipeSubstitution' && isInRange) return path
|
if (_node.type === 'PipeSubstitution' && isInRange) return path
|
||||||
console.error('not implemented: ' + node.type)
|
console.error('not implemented: ' + node.type)
|
||||||
return path
|
return path
|
||||||
@ -307,48 +319,87 @@ type KCLNode =
|
|||||||
| ReturnStatement
|
| ReturnStatement
|
||||||
|
|
||||||
export function traverse(
|
export function traverse(
|
||||||
node: KCLNode,
|
node: KCLNode | Program,
|
||||||
option: {
|
option: {
|
||||||
enter?: (node: KCLNode) => void
|
enter?: (node: KCLNode, pathToNode: PathToNode) => void
|
||||||
leave?: (node: KCLNode) => void
|
leave?: (node: KCLNode) => void
|
||||||
}
|
},
|
||||||
|
pathToNode: PathToNode = []
|
||||||
) {
|
) {
|
||||||
option?.enter?.(node)
|
const _node = node as KCLNode
|
||||||
const _traverse = (node: KCLNode) => traverse(node, option)
|
option?.enter?.(_node, pathToNode)
|
||||||
|
const _traverse = (node: KCLNode, pathToNode: PathToNode) =>
|
||||||
|
traverse(node, option, pathToNode)
|
||||||
|
|
||||||
if (node.type === 'VariableDeclaration') {
|
if (_node.type === 'VariableDeclaration') {
|
||||||
node.declarations.forEach(_traverse)
|
_node.declarations.forEach((declaration, index) =>
|
||||||
} else if (node.type === 'VariableDeclarator') {
|
_traverse(declaration, [
|
||||||
_traverse(node.init)
|
...pathToNode,
|
||||||
} else if (node.type === 'PipeExpression') {
|
['declarations', 'VariableDeclaration'],
|
||||||
node.body.forEach(_traverse)
|
[index, 'index'],
|
||||||
} else if (node.type === 'CallExpression') {
|
])
|
||||||
_traverse(node.callee)
|
)
|
||||||
node.arguments.forEach(_traverse)
|
} else if (_node.type === 'VariableDeclarator') {
|
||||||
} else if (node.type === 'BinaryExpression') {
|
_traverse(_node.init, [...pathToNode, ['init', '']])
|
||||||
_traverse(node.left)
|
} else if (_node.type === 'PipeExpression') {
|
||||||
_traverse(node.right)
|
_node.body.forEach((expression, index) =>
|
||||||
} else if (node.type === 'Identifier') {
|
_traverse(expression, [
|
||||||
|
...pathToNode,
|
||||||
|
['body', 'PipeExpression'],
|
||||||
|
[index, 'index'],
|
||||||
|
])
|
||||||
|
)
|
||||||
|
} else if (_node.type === 'CallExpression') {
|
||||||
|
_traverse(_node.callee, [...pathToNode, ['callee', 'CallExpression']])
|
||||||
|
_node.arguments.forEach((arg, index) =>
|
||||||
|
_traverse(arg, [
|
||||||
|
...pathToNode,
|
||||||
|
['arguments', 'CallExpression'],
|
||||||
|
[index, 'index'],
|
||||||
|
])
|
||||||
|
)
|
||||||
|
} else if (_node.type === 'BinaryExpression') {
|
||||||
|
_traverse(_node.left, [...pathToNode, ['left', 'BinaryExpression']])
|
||||||
|
_traverse(_node.right, [...pathToNode, ['right', 'BinaryExpression']])
|
||||||
|
} else if (_node.type === 'Identifier') {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else if (node.type === 'Literal') {
|
} else if (_node.type === 'Literal') {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else if (node.type === 'ArrayExpression') {
|
} else if (_node.type === 'ArrayExpression') {
|
||||||
node.elements.forEach(_traverse)
|
_node.elements.forEach((el, index) =>
|
||||||
} else if (node.type === 'ObjectExpression') {
|
_traverse(el, [
|
||||||
node.properties.forEach(({ key, value }) => {
|
...pathToNode,
|
||||||
_traverse(key)
|
['elements', 'ArrayExpression'],
|
||||||
_traverse(value)
|
[index, 'index'],
|
||||||
|
])
|
||||||
|
)
|
||||||
|
} else if (_node.type === 'ObjectExpression') {
|
||||||
|
_node.properties.forEach(({ key, value }, index) => {
|
||||||
|
_traverse(key, [
|
||||||
|
...pathToNode,
|
||||||
|
['properties', 'ObjectExpression'],
|
||||||
|
[index, 'index'],
|
||||||
|
['key', 'Property'],
|
||||||
|
])
|
||||||
|
_traverse(value, [
|
||||||
|
...pathToNode,
|
||||||
|
['properties', 'ObjectExpression'],
|
||||||
|
[index, 'index'],
|
||||||
|
['value', 'Property'],
|
||||||
|
])
|
||||||
})
|
})
|
||||||
} else if (node.type === 'UnaryExpression') {
|
} else if (_node.type === 'UnaryExpression') {
|
||||||
_traverse(node.argument)
|
_traverse(_node.argument, [...pathToNode, ['argument', 'UnaryExpression']])
|
||||||
} else if (node.type === 'MemberExpression') {
|
} else if (_node.type === 'MemberExpression') {
|
||||||
// hmm this smell
|
// hmm this smell
|
||||||
_traverse(node.object)
|
_traverse(_node.object, [...pathToNode, ['object', 'MemberExpression']])
|
||||||
_traverse(node.property)
|
_traverse(_node.property, [...pathToNode, ['property', 'MemberExpression']])
|
||||||
} else if ('body' in node && Array.isArray(node.body)) {
|
} else if ('body' in _node && Array.isArray(_node.body)) {
|
||||||
node.body.forEach(_traverse)
|
_node.body.forEach((expression, index) =>
|
||||||
|
_traverse(expression, [...pathToNode, ['body', ''], [index, 'index']])
|
||||||
|
)
|
||||||
}
|
}
|
||||||
option?.leave?.(node)
|
option?.leave?.(_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PrevVariable<T> {
|
export interface PrevVariable<T> {
|
||||||
|
Reference in New Issue
Block a user