diff --git a/src/App.tsx b/src/App.tsx index 5a40e3391..d1dcb8b7c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,6 @@ import { OrbitControls, OrthographicCamera } from '@react-three/drei' import { asyncLexer } from './lang/tokeniser' import { abstractSyntaxTree } from './lang/abstractSyntaxTree' import { executor, ExtrudeGroup, SketchGroup } from './lang/executor' -import { recast } from './lang/recast' import CodeMirror from '@uiw/react-codemirror' import { javascript } from '@codemirror/lang-javascript' import { ViewUpdate } from '@codemirror/view' diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx index 59162528c..64eddd669 100644 --- a/src/Toolbar.tsx +++ b/src/Toolbar.tsx @@ -1,6 +1,6 @@ import { useStore, toolTips } from './useStore' import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst' -import { getNodePathFromSourceRange } from './lang/abstractSyntaxTree' +import { getNodePathFromSourceRange } from './lang/queryAst' import { HorzVert } from './components/Toolbar/HorzVert' import { Equal } from './components/Toolbar/Equal' diff --git a/src/components/RenderViewerArtifacts.tsx b/src/components/RenderViewerArtifacts.tsx index 07fe8ed76..4d427c3df 100644 --- a/src/components/RenderViewerArtifacts.tsx +++ b/src/components/RenderViewerArtifacts.tsx @@ -1,10 +1,6 @@ import { useRef, useState, useEffect, useMemo } from 'react' -import { - getNodePathFromSourceRange, - getNodeFromPath, - CallExpression, - ArrayExpression, -} from '../lang/abstractSyntaxTree' +import { CallExpression, ArrayExpression } from '../lang/abstractSyntaxTree' +import { getNodePathFromSourceRange, getNodeFromPath } from '../lang/queryAst' import { changeSketchArguments } from '../lang/std/sketch' import { ExtrudeGroup, @@ -18,10 +14,9 @@ import { } from '../lang/executor' import { BufferGeometry } from 'three' import { useStore } from '../useStore' -import { isOverlap } from '../lib/utils' +import { isOverlap, roundOff } from '../lib/utils' import { Vector3, DoubleSide, Quaternion } from 'three' import { useSetCursor } from '../hooks/useSetCursor' -import { roundOff } from '../lib/utils' function MovingSphere({ geo, diff --git a/src/components/Toolbar/Equal.tsx b/src/components/Toolbar/Equal.tsx index 5daccb7cf..aee878380 100644 --- a/src/components/Toolbar/Equal.tsx +++ b/src/components/Toolbar/Equal.tsx @@ -1,11 +1,10 @@ import { useState, useEffect } from 'react' import { toolTips, useStore } from '../../useStore' +import { Value, VariableDeclarator } from '../../lang/abstractSyntaxTree' import { getNodePathFromSourceRange, getNodeFromPath, - Value, - VariableDeclarator, -} from '../../lang/abstractSyntaxTree' +} from '../../lang/queryAst' import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints' import { TransformInfo, diff --git a/src/components/Toolbar/HorzVert.tsx b/src/components/Toolbar/HorzVert.tsx index a737803d3..090ee1734 100644 --- a/src/components/Toolbar/HorzVert.tsx +++ b/src/components/Toolbar/HorzVert.tsx @@ -1,10 +1,10 @@ import { useState, useEffect } from 'react' import { toolTips, useStore } from '../../useStore' +import { Value } from '../../lang/abstractSyntaxTree' import { getNodePathFromSourceRange, getNodeFromPath, - Value, -} from '../../lang/abstractSyntaxTree' +} from '../../lang/queryAst' import { TransformInfo, getTransformInfos, diff --git a/src/lang/abstractSyntaxTree.ts b/src/lang/abstractSyntaxTree.ts index 4e2ab8f3b..4a1d3c382 100644 --- a/src/lang/abstractSyntaxTree.ts +++ b/src/lang/abstractSyntaxTree.ts @@ -123,7 +123,7 @@ function makeNoneCodeNode( return { node, lastIndex: endIndex - 1 } } -export function findEndOfNonCodeNode(tokens: Token[], index: number): number { +function findEndOfNonCodeNode(tokens: Token[], index: number): number { const currentToken = tokens[index] if (isNotCodeToken(currentToken)) { return findEndOfNonCodeNode(tokens, index + 1) @@ -1110,7 +1110,7 @@ function makeReturnStatement( export type All = Program | ExpressionStatement[] | BinaryExpression | Literal -export function nextMeaningfulToken( +function nextMeaningfulToken( tokens: Token[], index: number, offset: number = 1 @@ -1271,7 +1271,7 @@ export const abstractSyntaxTree = (tokens: Token[]): Program => { return program } -export function findNextDeclarationKeyword( +function findNextDeclarationKeyword( tokens: Token[], index: number ): { token: Token | null; index: number } { @@ -1300,7 +1300,7 @@ export function findNextDeclarationKeyword( return findNextDeclarationKeyword(tokens, nextToken.index) } -export function findNextCallExpression( +function findNextCallExpression( tokens: Token[], index: number ): { token: Token | null; index: number } { @@ -1319,7 +1319,7 @@ export function findNextCallExpression( return findNextCallExpression(tokens, nextToken.index) } -export function findNextClosingCurlyBrace( +function findNextClosingCurlyBrace( tokens: Token[], index: number ): { token: Token | null; index: number } { @@ -1447,61 +1447,6 @@ export function findClosingBrace( return findClosingBrace(tokens, index + 1, _braceCount, searchOpeningBrace) } -// function findOpeningBrace( -// tokens: Token[], -// index: number, -// _braceCount: number = 0, -// _searchClosingBrace: string = '' -// ): number { -// // should be called with the index of the opening brace -// const closingBraceMap: { [key: string]: string } = { -// ')': '(', -// '}': '{', -// ']': '[', -// } -// const currentToken = tokens[index] -// let searchClosingBrace = _searchClosingBrace - -// const isFirstCall = !searchClosingBrace && _braceCount === 0 -// if (isFirstCall) { -// searchClosingBrace = currentToken.value -// if (![')', '}', ']'].includes(searchClosingBrace)) { -// throw new Error( -// `expected to be started on a opening brace ( { [, instead found '${searchClosingBrace}'` -// ) -// } -// } - -// const foundOpeningBrace = -// _braceCount === 1 && -// currentToken.value === closingBraceMap[searchClosingBrace] -// const foundAnotherClosingBrace = currentToken.value === searchClosingBrace -// const foundAnotherOpeningBrace = -// currentToken.value === closingBraceMap[searchClosingBrace] - -// if (foundOpeningBrace) { -// return index -// } -// if (foundAnotherClosingBrace) { -// return findOpeningBrace( -// tokens, -// index - 1, -// _braceCount + 1, -// searchClosingBrace -// ) -// } -// if (foundAnotherOpeningBrace) { -// return findOpeningBrace( -// tokens, -// index - 1, -// _braceCount - 1, -// searchClosingBrace -// ) -// } -// // non-brace token, increment and continue -// return findOpeningBrace(tokens, index - 1, _braceCount, searchClosingBrace) -// } - function isCallExpression(tokens: Token[], index: number): number { const currentToken = tokens[index] const veryNextToken = tokens[index + 1] // i.e. no whitespace @@ -1551,138 +1496,6 @@ function debuggerr(tokens: Token[], indexes: number[], msg = ''): string { return debugResult } -export function getNodeFromPath( - node: Program, - path: (string | number)[], - stopAt: string = '', - returnEarly = false -): { - node: T - path: PathToNode -} { - let currentNode = node as any - let stopAtNode = null - let successfulPaths: PathToNode = [] - let pathsExplored: PathToNode = [] - for (const pathItem of path) { - try { - if (typeof currentNode[pathItem] !== 'object') - throw new Error('not an object') - currentNode = currentNode[pathItem] - successfulPaths.push(pathItem) - if (!stopAtNode) { - pathsExplored.push(pathItem) - } - if (currentNode.type === stopAt) { - // it will match the deepest node of the type - // instead of returning at the first match - stopAtNode = currentNode - if (returnEarly) { - return { - node: stopAtNode, - path: pathsExplored, - } - } - } - } catch (e) { - console.error( - `Could not find path ${pathItem} in node ${JSON.stringify( - currentNode, - null, - 2 - )}, successful path was ${successfulPaths}` - ) - } - } - return { - node: stopAtNode || currentNode, - path: pathsExplored, - } -} - -export function getNodeFromPathCurry( - node: Program, - path: (string | number)[] -): ( - stopAt: string, - returnEarly?: boolean -) => { - node: T - path: PathToNode -} { - return (stopAt: string = '', returnEarly = false) => { - return getNodeFromPath(node, path, stopAt, returnEarly) - } -} - -export function getNodePathFromSourceRange( - node: Program, - sourceRange: Range, - previousPath: PathToNode = [] -): PathToNode { - const [start, end] = sourceRange - let path: PathToNode = [...previousPath, 'body'] - const _node = { ...node } - // loop over each statement in body getting the index with a for loop - for ( - let statementIndex = 0; - statementIndex < _node.body.length; - statementIndex++ - ) { - const statement = _node.body[statementIndex] - if (statement.start <= start && statement.end >= end) { - path.push(statementIndex) - if (statement.type === 'ExpressionStatement') { - const expression = statement.expression - if (expression.start <= start && expression.end >= end) { - path.push('expression') - if (expression.type === 'CallExpression') { - const callee = expression.callee - if (callee.start <= start && callee.end >= end) { - path.push('callee') - if (callee.type === 'Identifier') { - } - } - } - } - } else if (statement.type === 'VariableDeclaration') { - const declarations = statement.declarations - - for (let decIndex = 0; decIndex < declarations.length; decIndex++) { - const declaration = declarations[decIndex] - - if (declaration.start <= start && declaration.end >= end) { - path.push('declarations') - path.push(decIndex) - const init = declaration.init - if (init.start <= start && init.end >= end) { - path.push('init') - if (init.type === 'PipeExpression') { - const body = init.body - for (let pipeIndex = 0; pipeIndex < body.length; pipeIndex++) { - const pipe = body[pipeIndex] - if (pipe.start <= start && pipe.end >= end) { - path.push('body') - path.push(pipeIndex) - } - } - } else if (init.type === 'CallExpression') { - const callee = init.callee - if (callee.start <= start && callee.end >= end) { - path.push('callee') - if (callee.type === 'Identifier') { - } - } - } - } - } - } - } - } - } - return path -} - export function isNotCodeToken(token: Token): boolean { return ( token?.type === 'whitespace' || diff --git a/src/lang/astMathExpressions.ts b/src/lang/astMathExpressions.ts index 5ad5ffb14..47713537a 100644 --- a/src/lang/astMathExpressions.ts +++ b/src/lang/astMathExpressions.ts @@ -2,10 +2,10 @@ import { BinaryExpression, Literal, Identifier, - isNotCodeToken, - findClosingBrace, CallExpression, + findClosingBrace, makeCallExpression, + isNotCodeToken, } from './abstractSyntaxTree' import { Token } from './tokeniser' diff --git a/src/lang/getNodePathFromSourceRange.test.ts b/src/lang/getNodePathFromSourceRange.test.ts index d6e8cf2cc..d522abed1 100644 --- a/src/lang/getNodePathFromSourceRange.test.ts +++ b/src/lang/getNodePathFromSourceRange.test.ts @@ -1,6 +1,6 @@ -import { getNodePathFromSourceRange } from './abstractSyntaxTree' +import { getNodePathFromSourceRange, getNodeFromPath } from './queryAst' import { lexer } from './tokeniser' -import { abstractSyntaxTree, getNodeFromPath } from './abstractSyntaxTree' +import { abstractSyntaxTree } from './abstractSyntaxTree' import { initPromise } from './rust' beforeAll(() => initPromise) diff --git a/src/lang/modifyAst.ts b/src/lang/modifyAst.ts index fc21d7aef..beaf82a5c 100644 --- a/src/lang/modifyAst.ts +++ b/src/lang/modifyAst.ts @@ -7,16 +7,15 @@ import { VariableDeclarator, ExpressionStatement, Value, - getNodeFromPath, Literal, PipeSubstitution, Identifier, ArrayExpression, ObjectExpression, - getNodePathFromSourceRange, UnaryExpression, BinaryExpression, } from './abstractSyntaxTree' +import { getNodeFromPath, getNodePathFromSourceRange } from './queryAst' import { PathToNode, ProgramMemory } from './executor' import { addTagForSketchOnFace, diff --git a/src/lang/queryAst.ts b/src/lang/queryAst.ts new file mode 100644 index 000000000..ef8c893c2 --- /dev/null +++ b/src/lang/queryAst.ts @@ -0,0 +1,135 @@ +import { PathToNode } from './executor' +import { Range } from '../useStore' +import { Program } from './abstractSyntaxTree' + +export function getNodeFromPath( + node: Program, + path: (string | number)[], + stopAt: string = '', + returnEarly = false +): { + node: T + path: PathToNode +} { + let currentNode = node as any + let stopAtNode = null + let successfulPaths: PathToNode = [] + let pathsExplored: PathToNode = [] + for (const pathItem of path) { + try { + if (typeof currentNode[pathItem] !== 'object') + throw new Error('not an object') + currentNode = currentNode[pathItem] + successfulPaths.push(pathItem) + if (!stopAtNode) { + pathsExplored.push(pathItem) + } + if (currentNode.type === stopAt) { + // it will match the deepest node of the type + // instead of returning at the first match + stopAtNode = currentNode + if (returnEarly) { + return { + node: stopAtNode, + path: pathsExplored, + } + } + } + } catch (e) { + console.error( + `Could not find path ${pathItem} in node ${JSON.stringify( + currentNode, + null, + 2 + )}, successful path was ${successfulPaths}` + ) + } + } + return { + node: stopAtNode || currentNode, + path: pathsExplored, + } +} + +export function getNodeFromPathCurry( + node: Program, + path: (string | number)[] +): ( + stopAt: string, + returnEarly?: boolean +) => { + node: T + path: PathToNode +} { + return (stopAt: string = '', returnEarly = false) => { + return getNodeFromPath(node, path, stopAt, returnEarly) + } +} + +export function getNodePathFromSourceRange( + node: Program, + sourceRange: Range, + previousPath: PathToNode = [] +): PathToNode { + const [start, end] = sourceRange + let path: PathToNode = [...previousPath, 'body'] + const _node = { ...node } + // loop over each statement in body getting the index with a for loop + for ( + let statementIndex = 0; + statementIndex < _node.body.length; + statementIndex++ + ) { + const statement = _node.body[statementIndex] + if (statement.start <= start && statement.end >= end) { + path.push(statementIndex) + if (statement.type === 'ExpressionStatement') { + const expression = statement.expression + if (expression.start <= start && expression.end >= end) { + path.push('expression') + if (expression.type === 'CallExpression') { + const callee = expression.callee + if (callee.start <= start && callee.end >= end) { + path.push('callee') + if (callee.type === 'Identifier') { + } + } + } + } + } else if (statement.type === 'VariableDeclaration') { + const declarations = statement.declarations + + for (let decIndex = 0; decIndex < declarations.length; decIndex++) { + const declaration = declarations[decIndex] + + if (declaration.start <= start && declaration.end >= end) { + path.push('declarations') + path.push(decIndex) + const init = declaration.init + if (init.start <= start && init.end >= end) { + path.push('init') + if (init.type === 'PipeExpression') { + const body = init.body + for (let pipeIndex = 0; pipeIndex < body.length; pipeIndex++) { + const pipe = body[pipeIndex] + if (pipe.start <= start && pipe.end >= end) { + path.push('body') + path.push(pipeIndex) + } + } + } else if (init.type === 'CallExpression') { + const callee = init.callee + if (callee.start <= start && callee.end >= end) { + path.push('callee') + if (callee.type === 'Identifier') { + } + } + } + } + } + } + } + } + } + return path +} diff --git a/src/lang/recast.ts b/src/lang/recast.ts index 1f940ebe8..900d0b773 100644 --- a/src/lang/recast.ts +++ b/src/lang/recast.ts @@ -1,4 +1,3 @@ -import { start } from 'repl' import { Program, BinaryExpression, diff --git a/src/lang/std/sketch.test.ts b/src/lang/std/sketch.test.ts index c28acfd8f..e330c5642 100644 --- a/src/lang/std/sketch.test.ts +++ b/src/lang/std/sketch.test.ts @@ -6,10 +6,8 @@ import { getXComponent, } from './sketch' import { lexer } from '../tokeniser' -import { - abstractSyntaxTree, - getNodePathFromSourceRange, -} from '../abstractSyntaxTree' +import { abstractSyntaxTree } from '../abstractSyntaxTree' +import { getNodePathFromSourceRange } from '../queryAst' import { recast } from '../recast' import { executor } from '../executor' import { initPromise } from '../rust' diff --git a/src/lang/std/sketch.ts b/src/lang/std/sketch.ts index 2dcb7b2f5..14f52224c 100644 --- a/src/lang/std/sketch.ts +++ b/src/lang/std/sketch.ts @@ -10,12 +10,14 @@ import { PipeExpression, CallExpression, VariableDeclarator, - getNodeFromPath, - getNodeFromPathCurry, - getNodePathFromSourceRange, Value, Literal, } from '../abstractSyntaxTree' +import { + getNodeFromPath, + getNodeFromPathCurry, + getNodePathFromSourceRange, +} from '../queryAst' import { lineGeo } from '../engine' import { GuiModes, toolTips, TooTip } from '../../useStore' import { getLastIndex } from '../modifyAst' @@ -24,7 +26,6 @@ import { SketchLineHelper, ModifyAstBase, InternalFn, - SketchCallTransfromMap, TransformCallback, } from './stdTypes' @@ -55,17 +56,6 @@ export function getCoordsFromPaths(skGroup: SketchGroup, index = 0): Coords2d { return [0, 0] } -function createCallWrapper( - a: TooTip, - val: [Value, Value] | Value, - tag?: Value -) { - return createCallExpression(a, [ - createFirstArg(a, val, tag), - createPipeSubstitution(), - ]) -} - export function createFirstArg( sketchFn: TooTip, val: Value | [Value, Value], @@ -97,34 +87,6 @@ export function createFirstArg( throw new Error('all sketch line types should have been covered') } -function tranformerDefaults( - filterOut: TooTip[] = [], - tag?: Value -): Partial { - const All: SketchCallTransfromMap = { - line: (args) => createCallWrapper('line', args, tag), - lineTo: (args) => createCallWrapper('lineTo', args, tag), - angledLine: (args) => createCallWrapper('angledLine', args, tag), - angledLineOfXLength: (args) => - createCallWrapper('angledLineOfXLength', args, tag), - angledLineOfYLength: (args) => - createCallWrapper('angledLineOfYLength', args, tag), - angledLineToX: (args) => createCallWrapper('angledLineToX', args, tag), - angledLineToY: (args) => createCallWrapper('angledLineToY', args, tag), - xLine: (args) => createCallWrapper('xLine', args[0], tag), - xLineTo: (args) => createCallWrapper('xLineTo', args[0], tag), - yLine: (args) => createCallWrapper('yLine', args[1], tag), - yLineTo: (args) => createCallWrapper('yLineTo', args[1], tag), - } - const result: Partial = {} - toolTips.forEach((key) => { - if (!filterOut.includes(key)) { - result[key] = All[key] - } - }) - return result -} - export const lineTo: SketchLineHelper = { fn: ( { sourceRange, programMemory }, @@ -567,7 +529,6 @@ export const angledLine: SketchLineHelper = { | { angle: number length: number - // name?: string tag?: string }, previousSketch: SketchGroup @@ -671,7 +632,6 @@ export const angledLineOfXLength: SketchLineHelper = { | { angle: number length: number - // name?: string tag?: string }, previousSketch: SketchGroup @@ -881,15 +841,7 @@ export const angledLineToX: SketchLineHelper = { previousSketch ) }, - add: ({ - node, - pathToNode, - to, - from, - createCallback, - replaceExisting, - // from: [number, number], - }) => { + add: ({ node, pathToNode, to, from, createCallback, replaceExisting }) => { const _node = { ...node } const { node: pipe } = getNodeFromPath( _node, @@ -926,9 +878,6 @@ export const angledLineToX: SketchLineHelper = { const xLength = roundOff(to[0], 2) const firstArg = callExpression.arguments?.[0] - // const adjustedXLength = isAngleLiteral(firstArg) - // ? Math.abs(xLength) - // : xLength // todo make work for variable angle > 180 const adjustedXLength = xLength const angleLit = createLiteral(angle) @@ -974,15 +923,7 @@ export const angledLineToY: SketchLineHelper = { previousSketch ) }, - add: ({ - node, - previousProgramMemory, - pathToNode, - to, - from, - createCallback, - replaceExisting, - }) => { + add: ({ node, pathToNode, to, from, createCallback, replaceExisting }) => { const _node = { ...node } const { node: pipe } = getNodeFromPath( _node, @@ -1019,9 +960,6 @@ export const angledLineToY: SketchLineHelper = { const xLength = roundOff(to[1], 2) const firstArg = callExpression.arguments?.[0] - // const adjustedXLength = isAngleLiteral(firstArg) - // ? Math.abs(xLength) - // : xLength // todo make work for variable angle > 180 const adjustedXLength = xLength const angleLit = createLiteral(angle) diff --git a/src/lang/std/sketchcombos.ts b/src/lang/std/sketchcombos.ts index 200e968c7..09e19b35e 100644 --- a/src/lang/std/sketchcombos.ts +++ b/src/lang/std/sketchcombos.ts @@ -3,17 +3,18 @@ import { Range, Ranges, toolTips, TooTip } from '../../useStore' import { BinaryPart, CallExpression, - getNodeFromPath, - getNodeFromPathCurry, - getNodePathFromSourceRange, Program, Value, VariableDeclarator, } from '../abstractSyntaxTree' +import { + getNodeFromPath, + getNodeFromPathCurry, + getNodePathFromSourceRange, +} from '../queryAst' import { createBinaryExpression, createCallExpression, - createIdentifier, createLiteral, createPipeSubstitution, createUnaryExpression, diff --git a/src/lang/std/std.ts b/src/lang/std/std.ts index 5fc3617c1..c2ce6e654 100644 --- a/src/lang/std/std.ts +++ b/src/lang/std/std.ts @@ -78,7 +78,9 @@ const translate: InternalFn = ( const min: InternalFn = (_, a: number, b: number): number => Math.min(a, b) const legLen: InternalFn = (_, hypotenuse: number, leg: number): number => - Math.sqrt(hypotenuse ** 2 - Math.min(Math.abs(leg), Math.abs(hypotenuse)) ** 2) + Math.sqrt( + hypotenuse ** 2 - Math.min(Math.abs(leg), Math.abs(hypotenuse)) ** 2 + ) const legAngX: InternalFn = (_, hypotenuse: number, leg: number): number => (Math.acos(Math.min(leg, hypotenuse) / hypotenuse) * 180) / Math.PI diff --git a/src/useStore.ts b/src/useStore.ts index 93718b328..4ba4d3cdb 100644 --- a/src/useStore.ts +++ b/src/useStore.ts @@ -1,11 +1,8 @@ import create from 'zustand' import { persist } from 'zustand/middleware' import { addLineHighlight, EditorView } from './editor/highlightextension' -import { - Program, - abstractSyntaxTree, - getNodeFromPath, -} from './lang/abstractSyntaxTree' +import { Program, abstractSyntaxTree } from './lang/abstractSyntaxTree' +import { getNodeFromPath } from './lang/queryAst' import { ProgramMemory, Position, PathToNode, Rotation } from './lang/executor' import { recast } from './lang/recast' import { asyncLexer } from './lang/tokeniser'