Add new query for getting available variables (#52)
* Add new query for getting available variables * use array for findAllPreviousVariables
This commit is contained in:
@ -335,12 +335,21 @@ export function sketchOnExtrudedFace(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getLastIndex = (pathToNode: PathToNode): number => {
|
export const getLastIndex = (pathToNode: PathToNode): number =>
|
||||||
|
splitPathAtLastIndex(pathToNode).index
|
||||||
|
|
||||||
|
export function splitPathAtLastIndex(pathToNode: PathToNode): {
|
||||||
|
path: PathToNode
|
||||||
|
index: number
|
||||||
|
} {
|
||||||
const last = pathToNode[pathToNode.length - 1]
|
const last = pathToNode[pathToNode.length - 1]
|
||||||
if (typeof last === 'number') {
|
if (typeof last === 'number') {
|
||||||
return last
|
return {
|
||||||
|
path: pathToNode.slice(0, -1),
|
||||||
|
index: last,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return getLastIndex(pathToNode.slice(0, -1))
|
return splitPathAtLastIndex(pathToNode.slice(0, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createLiteral(value: string | number): Literal {
|
export function createLiteral(value: string | number): Literal {
|
||||||
|
48
src/lang/queryAst.test.ts
Normal file
48
src/lang/queryAst.test.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { abstractSyntaxTree } from './abstractSyntaxTree'
|
||||||
|
import { findAllPreviousVariables } from './queryAst'
|
||||||
|
import { lexer } from './tokeniser'
|
||||||
|
import { initPromise } from './rust'
|
||||||
|
import { executor } from './executor'
|
||||||
|
|
||||||
|
beforeAll(() => initPromise)
|
||||||
|
|
||||||
|
describe('findAllPreviousVariables', () => {
|
||||||
|
it('should find all previous variables', () => {
|
||||||
|
const code = `const baseThick = 1
|
||||||
|
const armAngle = 60
|
||||||
|
|
||||||
|
const baseThickHalf = baseThick / 2
|
||||||
|
const halfArmAngle = armAngle / 2
|
||||||
|
|
||||||
|
const arrExpShouldNotBeIncluded = [1, 2, 3]
|
||||||
|
const objExpShouldNotBeIncluded = { a: 1, b: 2, c: 3 }
|
||||||
|
|
||||||
|
const part001 = startSketchAt([0, 0])
|
||||||
|
|> yLineTo(1, %)
|
||||||
|
|> xLine(3.84, %) // selection-range-7ish-before-this
|
||||||
|
|
||||||
|
const variableBelowShouldNotBeIncluded = 3
|
||||||
|
|
||||||
|
show(part001)`
|
||||||
|
const rangeStart = code.indexOf('// selection-range-7ish-before-this') - 7
|
||||||
|
const ast = abstractSyntaxTree(lexer(code))
|
||||||
|
const programMemory = executor(ast)
|
||||||
|
|
||||||
|
const { variables, bodyPath, insertIndex } = findAllPreviousVariables(
|
||||||
|
ast,
|
||||||
|
programMemory,
|
||||||
|
[rangeStart, rangeStart]
|
||||||
|
)
|
||||||
|
expect(variables).toEqual([
|
||||||
|
{ key: 'baseThick', value: 1 },
|
||||||
|
{ key: 'armAngle', value: 60 },
|
||||||
|
{ key: 'baseThickHalf', value: 0.5 },
|
||||||
|
{ key: 'halfArmAngle', value: 30 },
|
||||||
|
// no arrExpShouldNotBeIncluded, variableBelowShouldNotBeIncluded etc
|
||||||
|
])
|
||||||
|
// there are 4 number variables and 2 non-number variables before the sketch var
|
||||||
|
// ∴ the insert index should be 6
|
||||||
|
expect(insertIndex).toEqual(6)
|
||||||
|
expect(bodyPath).toEqual(['body'])
|
||||||
|
})
|
||||||
|
})
|
@ -1,6 +1,7 @@
|
|||||||
import { PathToNode } from './executor'
|
import { PathToNode, ProgramMemory } from './executor'
|
||||||
import { Range } from '../useStore'
|
import { Range } from '../useStore'
|
||||||
import { Program } from './abstractSyntaxTree'
|
import { Program } from './abstractSyntaxTree'
|
||||||
|
import { splitPathAtLastIndex } from './modifyAst'
|
||||||
|
|
||||||
export function getNodeFromPath<T>(
|
export function getNodeFromPath<T>(
|
||||||
node: Program,
|
node: Program,
|
||||||
@ -133,3 +134,43 @@ export function getNodePathFromSourceRange(
|
|||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PrevVariable<T> {
|
||||||
|
key: string
|
||||||
|
value: T
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findAllPreviousVariables(
|
||||||
|
ast: Program,
|
||||||
|
programMemory: ProgramMemory,
|
||||||
|
sourceRange: Range,
|
||||||
|
type: 'number' | 'string' = 'number'
|
||||||
|
): {
|
||||||
|
variables: PrevVariable<typeof type extends 'number' ? number : string>[]
|
||||||
|
bodyPath: PathToNode
|
||||||
|
insertIndex: number
|
||||||
|
} {
|
||||||
|
const path = getNodePathFromSourceRange(ast, sourceRange)
|
||||||
|
const { path: pathToDec } = getNodeFromPath(ast, path, 'VariableDeclaration')
|
||||||
|
const { index: insertIndex, path: bodyPath } = splitPathAtLastIndex(pathToDec)
|
||||||
|
|
||||||
|
const { node: bodyItems } = getNodeFromPath<Program['body']>(ast, bodyPath)
|
||||||
|
|
||||||
|
const variables: PrevVariable<any>[] = []
|
||||||
|
bodyItems.forEach((item) => {
|
||||||
|
if (item.type !== 'VariableDeclaration' || item.end > sourceRange[0]) return
|
||||||
|
const varName = item.declarations[0].id.name
|
||||||
|
const varValue = programMemory?.root[varName]
|
||||||
|
if (typeof varValue?.value !== type) return
|
||||||
|
variables.push({
|
||||||
|
key: varName,
|
||||||
|
value: varValue.value,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
insertIndex,
|
||||||
|
bodyPath: bodyPath,
|
||||||
|
variables,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user