2023-01-06 09:29:26 +11:00
|
|
|
import {
|
|
|
|
Program,
|
|
|
|
BlockStatement,
|
|
|
|
SketchExpression,
|
|
|
|
CallExpression,
|
|
|
|
PipeExpression,
|
|
|
|
VariableDeclaration,
|
|
|
|
ExpressionStatement,
|
|
|
|
Value,
|
|
|
|
getNodeFromPath,
|
2023-01-06 12:45:34 +11:00
|
|
|
VariableDeclarator,
|
2023-01-06 09:29:26 +11:00
|
|
|
} from './abstractSyntaxTree'
|
2023-01-09 13:19:14 +11:00
|
|
|
import { PathToNode } from './executor'
|
2023-01-06 09:29:26 +11:00
|
|
|
|
|
|
|
export function addSketchTo(
|
|
|
|
node: Program,
|
|
|
|
axis: 'xy' | 'xz' | 'yz',
|
|
|
|
name = ''
|
|
|
|
): { modifiedAst: Program; id: string; pathToNode: (string | number)[] } {
|
|
|
|
const _node = { ...node }
|
|
|
|
const dumbyStartend = { start: 0, end: 0 }
|
|
|
|
const _name = name || findUniqueName(node, 'part')
|
|
|
|
const sketchBody: BlockStatement = {
|
|
|
|
type: 'BlockStatement',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: [],
|
|
|
|
}
|
|
|
|
const sketch: SketchExpression = {
|
|
|
|
type: 'SketchExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: sketchBody,
|
|
|
|
}
|
|
|
|
|
|
|
|
const rotate: CallExpression = {
|
|
|
|
type: 'CallExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: axis === 'xz' ? 'rx' : 'ry',
|
|
|
|
},
|
|
|
|
arguments: [
|
|
|
|
{
|
|
|
|
type: 'Literal',
|
|
|
|
...dumbyStartend,
|
|
|
|
value: axis === 'yz' ? 90 : 90,
|
|
|
|
raw: axis === 'yz' ? '90' : '90',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'PipeSubstitution',
|
|
|
|
...dumbyStartend,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
optional: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
const pipChain: PipeExpression = {
|
|
|
|
type: 'PipeExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: [sketch, rotate],
|
|
|
|
}
|
|
|
|
|
|
|
|
const sketchVariableDeclaration: VariableDeclaration = {
|
|
|
|
type: 'VariableDeclaration',
|
|
|
|
...dumbyStartend,
|
|
|
|
kind: 'sketch',
|
|
|
|
declarations: [
|
|
|
|
{
|
|
|
|
type: 'VariableDeclarator',
|
|
|
|
...dumbyStartend,
|
|
|
|
id: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: _name,
|
|
|
|
},
|
|
|
|
init: axis === 'xy' ? sketch : pipChain,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}
|
|
|
|
const showCallIndex = getShowIndex(_node)
|
|
|
|
let sketchIndex = showCallIndex
|
|
|
|
if (showCallIndex === -1) {
|
|
|
|
_node.body = [...node.body, sketchVariableDeclaration]
|
|
|
|
sketchIndex = _node.body.length - 1
|
|
|
|
} else {
|
|
|
|
const newBody = [...node.body]
|
|
|
|
newBody.splice(showCallIndex, 0, sketchVariableDeclaration)
|
|
|
|
_node.body = newBody
|
|
|
|
}
|
|
|
|
let pathToNode: (string | number)[] = [
|
|
|
|
'body',
|
|
|
|
sketchIndex,
|
|
|
|
'declarations',
|
|
|
|
'0',
|
|
|
|
'init',
|
|
|
|
]
|
|
|
|
if (axis !== 'xy') {
|
|
|
|
pathToNode = [...pathToNode, 'body', '0']
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: addToShow(_node, _name),
|
|
|
|
id: _name,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function findUniqueName(
|
|
|
|
ast: Program | string,
|
|
|
|
name: string,
|
2023-01-09 13:19:14 +11:00
|
|
|
pad = 3,
|
2023-01-06 09:29:26 +11:00
|
|
|
index = 1
|
|
|
|
): string {
|
|
|
|
let searchStr = ''
|
|
|
|
if (typeof ast === 'string') {
|
|
|
|
searchStr = ast
|
|
|
|
} else {
|
|
|
|
searchStr = JSON.stringify(ast)
|
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
const indexStr = `${index}`.padStart(pad, '0')
|
2023-01-06 09:29:26 +11:00
|
|
|
const newName = `${name}${indexStr}`
|
|
|
|
const isInString = searchStr.includes(newName)
|
|
|
|
if (!isInString) {
|
|
|
|
return newName
|
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
return findUniqueName(searchStr, name, pad, index + 1)
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
function addToShow(node: Program, name: string): Program {
|
|
|
|
const _node = { ...node }
|
|
|
|
const dumbyStartend = { start: 0, end: 0 }
|
|
|
|
const showCallIndex = getShowIndex(_node)
|
|
|
|
if (showCallIndex === -1) {
|
|
|
|
const showCall: CallExpression = {
|
|
|
|
type: 'CallExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: 'show',
|
|
|
|
},
|
|
|
|
optional: false,
|
|
|
|
arguments: [
|
|
|
|
{
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}
|
|
|
|
const showExpressionStatement: ExpressionStatement = {
|
|
|
|
type: 'ExpressionStatement',
|
|
|
|
...dumbyStartend,
|
|
|
|
expression: showCall,
|
|
|
|
}
|
|
|
|
_node.body = [..._node.body, showExpressionStatement]
|
|
|
|
return _node
|
|
|
|
}
|
|
|
|
const showCall = { ..._node.body[showCallIndex] } as ExpressionStatement
|
|
|
|
const showCallArgs = (showCall.expression as CallExpression).arguments
|
|
|
|
const newShowCallArgs: Value[] = [
|
|
|
|
...showCallArgs,
|
|
|
|
{
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
const newShowExpression: CallExpression = {
|
|
|
|
type: 'CallExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: 'show',
|
|
|
|
},
|
|
|
|
optional: false,
|
|
|
|
arguments: newShowCallArgs,
|
|
|
|
}
|
|
|
|
|
|
|
|
_node.body[showCallIndex] = {
|
|
|
|
...showCall,
|
|
|
|
expression: newShowExpression,
|
|
|
|
}
|
|
|
|
return _node
|
|
|
|
}
|
|
|
|
|
|
|
|
function getShowIndex(node: Program): number {
|
|
|
|
return node.body.findIndex(
|
|
|
|
(statement) =>
|
|
|
|
statement.type === 'ExpressionStatement' &&
|
|
|
|
statement.expression.type === 'CallExpression' &&
|
|
|
|
statement.expression.callee.type === 'Identifier' &&
|
|
|
|
statement.expression.callee.name === 'show'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export function addLine(
|
|
|
|
node: Program,
|
|
|
|
pathToNode: (string | number)[],
|
|
|
|
to: [number, number]
|
|
|
|
): { modifiedAst: Program; pathToNode: (string | number)[] } {
|
|
|
|
const _node = { ...node }
|
|
|
|
const dumbyStartend = { start: 0, end: 0 }
|
|
|
|
const sketchExpression = getNodeFromPath(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'SketchExpression'
|
|
|
|
) as SketchExpression
|
|
|
|
const line: ExpressionStatement = {
|
|
|
|
type: 'ExpressionStatement',
|
|
|
|
...dumbyStartend,
|
|
|
|
expression: {
|
|
|
|
type: 'CallExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: 'lineTo',
|
|
|
|
},
|
|
|
|
optional: false,
|
|
|
|
arguments: [
|
|
|
|
{
|
|
|
|
type: 'Literal',
|
|
|
|
...dumbyStartend,
|
|
|
|
value: to[0],
|
|
|
|
raw: `${to[0]}`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'Literal',
|
|
|
|
...dumbyStartend,
|
|
|
|
value: to[1],
|
|
|
|
raw: `${to[1]}`,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
const newBody = [...sketchExpression.body.body, line]
|
|
|
|
sketchExpression.body.body = newBody
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function changeArguments(
|
|
|
|
node: Program,
|
|
|
|
pathToNode: (string | number)[],
|
|
|
|
args: [number, number]
|
|
|
|
): { modifiedAst: Program; pathToNode: (string | number)[] } {
|
|
|
|
const _node = { ...node }
|
|
|
|
const dumbyStartend = { start: 0, end: 0 }
|
|
|
|
// const thePath = getNodePathFromSourceRange(_node, sourceRange)
|
|
|
|
const callExpression = getNodeFromPath(_node, pathToNode) as CallExpression
|
|
|
|
const newXArg: CallExpression['arguments'][number] =
|
|
|
|
callExpression.arguments[0].type === 'Literal'
|
|
|
|
? {
|
|
|
|
type: 'Literal',
|
|
|
|
...dumbyStartend,
|
|
|
|
value: args[0],
|
|
|
|
raw: `${args[0]}`,
|
|
|
|
}
|
|
|
|
: {
|
|
|
|
...callExpression.arguments[0],
|
|
|
|
}
|
|
|
|
const newYArg: CallExpression['arguments'][number] =
|
|
|
|
callExpression.arguments[1].type === 'Literal'
|
|
|
|
? {
|
|
|
|
type: 'Literal',
|
|
|
|
...dumbyStartend,
|
|
|
|
value: args[1],
|
|
|
|
raw: `${args[1]}`,
|
|
|
|
}
|
|
|
|
: {
|
|
|
|
...callExpression.arguments[1],
|
|
|
|
}
|
|
|
|
callExpression.arguments = [newXArg, newYArg]
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
2023-01-06 12:45:34 +11:00
|
|
|
|
|
|
|
export function extrudeSketch(
|
|
|
|
node: Program,
|
|
|
|
pathToNode: (string | number)[],
|
|
|
|
shouldPipe = true
|
|
|
|
): { modifiedAst: Program; pathToNode: (string | number)[] } {
|
|
|
|
const _node = { ...node }
|
|
|
|
const dumbyStartend = { start: 0, end: 0 }
|
|
|
|
const sketchExpression = getNodeFromPath(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'SketchExpression'
|
|
|
|
) as SketchExpression
|
|
|
|
|
|
|
|
// determine if sketchExpression is in a pipeExpression or not
|
|
|
|
const pipeExpression = getNodeFromPath(_node, pathToNode, 'PipeExpression')
|
|
|
|
const isInPipeExpression = pipeExpression.type === 'PipeExpression'
|
|
|
|
|
|
|
|
const variableDeclorator = getNodeFromPath(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
) as VariableDeclarator
|
|
|
|
|
|
|
|
const extrudeCall: CallExpression = {
|
|
|
|
type: 'CallExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: 'extrude',
|
|
|
|
},
|
|
|
|
optional: false,
|
|
|
|
arguments: [
|
|
|
|
{
|
|
|
|
type: 'Literal',
|
|
|
|
...dumbyStartend,
|
|
|
|
value: 4,
|
|
|
|
raw: '4',
|
|
|
|
},
|
|
|
|
shouldPipe
|
|
|
|
? {
|
|
|
|
type: 'PipeSubstitution',
|
|
|
|
...dumbyStartend,
|
|
|
|
}
|
|
|
|
: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: variableDeclorator.id.name,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}
|
|
|
|
if (shouldPipe) {
|
|
|
|
const pipeChain: PipeExpression = isInPipeExpression
|
|
|
|
? {
|
|
|
|
type: 'PipeExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: [...pipeExpression.body, extrudeCall],
|
|
|
|
}
|
|
|
|
: {
|
|
|
|
type: 'PipeExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: [sketchExpression, extrudeCall],
|
|
|
|
}
|
|
|
|
|
|
|
|
variableDeclorator.init = pipeChain
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const name = findUniqueName(node, 'part')
|
|
|
|
const VariableDeclaration: VariableDeclaration = {
|
|
|
|
type: 'VariableDeclaration',
|
|
|
|
...dumbyStartend,
|
|
|
|
declarations: [
|
|
|
|
{
|
|
|
|
type: 'VariableDeclarator',
|
|
|
|
...dumbyStartend,
|
|
|
|
id: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name,
|
|
|
|
},
|
|
|
|
init: extrudeCall,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
kind: 'const',
|
|
|
|
}
|
|
|
|
const showCallIndex = getShowIndex(_node)
|
|
|
|
_node.body.splice(showCallIndex, 0, VariableDeclaration)
|
|
|
|
return {
|
|
|
|
modifiedAst: addToShow(_node, name),
|
|
|
|
pathToNode: [...pathToNode.slice(0, -1), showCallIndex],
|
|
|
|
}
|
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
|
|
|
|
export function sketchOnExtrudedFace(
|
|
|
|
node: Program,
|
|
|
|
pathToNode: (string | number)[]
|
|
|
|
): { modifiedAst: Program; pathToNode: (string | number)[] } {
|
|
|
|
const _node = { ...node }
|
|
|
|
const dumbyStartend = { start: 0, end: 0 }
|
|
|
|
const newSketchName = findUniqueName(node, 'part')
|
|
|
|
const oldSketchName = getNodeFromPath(_node, pathToNode, 'VariableDeclarator')
|
|
|
|
.id.name
|
|
|
|
const expression = getNodeFromPath(_node, pathToNode, 'CallExpression') as
|
|
|
|
| VariableDeclarator
|
|
|
|
| CallExpression
|
|
|
|
const pathName =
|
|
|
|
expression.type === 'VariableDeclarator'
|
|
|
|
? expression.id.name
|
|
|
|
: findUniqueName(node, 'path', 2)
|
|
|
|
|
|
|
|
if (expression.type === 'CallExpression') {
|
|
|
|
const block = getNodeFromPath(_node, pathToNode, 'BlockStatement')
|
|
|
|
const expressionIndex = getLastIndex(pathToNode)
|
|
|
|
if (expression.callee.name !== 'lineTo')
|
|
|
|
throw new Error('expected a lineTo call')
|
|
|
|
const newExpression: VariableDeclaration = {
|
|
|
|
type: 'VariableDeclaration',
|
|
|
|
...dumbyStartend,
|
|
|
|
declarations: [
|
|
|
|
{
|
|
|
|
type: 'VariableDeclarator',
|
|
|
|
...dumbyStartend,
|
|
|
|
id: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: pathName,
|
|
|
|
},
|
|
|
|
init: expression,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
kind: 'path',
|
|
|
|
}
|
|
|
|
|
|
|
|
block.body.splice(expressionIndex, 1, newExpression)
|
|
|
|
}
|
|
|
|
|
|
|
|
// create pipe expression with a sketch block piped into a transform function
|
|
|
|
const sketchPipe: PipeExpression = {
|
|
|
|
type: 'PipeExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: [
|
|
|
|
{
|
|
|
|
type: 'SketchExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: {
|
|
|
|
type: 'BlockStatement',
|
|
|
|
...dumbyStartend,
|
|
|
|
body: [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'CallExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: 'transform',
|
|
|
|
},
|
|
|
|
optional: false,
|
|
|
|
arguments: [
|
|
|
|
{
|
|
|
|
type: 'CallExpression',
|
|
|
|
...dumbyStartend,
|
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: 'getExtrudeWallTransform',
|
|
|
|
},
|
|
|
|
optional: false,
|
|
|
|
arguments: [
|
|
|
|
{
|
|
|
|
type: 'Literal',
|
|
|
|
...dumbyStartend,
|
|
|
|
value: pathName,
|
|
|
|
raw: `'${pathName}'`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: oldSketchName,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'PipeSubstitution',
|
|
|
|
...dumbyStartend,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}
|
|
|
|
const variableDec: VariableDeclaration = {
|
|
|
|
type: 'VariableDeclaration',
|
|
|
|
...dumbyStartend,
|
|
|
|
declarations: [
|
|
|
|
{
|
|
|
|
type: 'VariableDeclarator',
|
|
|
|
...dumbyStartend,
|
|
|
|
id: {
|
|
|
|
type: 'Identifier',
|
|
|
|
...dumbyStartend,
|
|
|
|
name: newSketchName,
|
|
|
|
},
|
|
|
|
init: sketchPipe,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
kind: 'sketch',
|
|
|
|
}
|
|
|
|
|
|
|
|
const showIndex = getShowIndex(_node)
|
|
|
|
_node.body.splice(showIndex, 0, variableDec)
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: addToShow(_node, newSketchName),
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const getLastIndex = (pathToNode: PathToNode): number => {
|
|
|
|
const last = pathToNode[pathToNode.length - 1]
|
|
|
|
if (typeof last === 'number') {
|
|
|
|
return last
|
|
|
|
}
|
|
|
|
return getLastIndex(pathToNode.slice(0, -1))
|
|
|
|
}
|