Add equal-length constraints & implement UnaryExpressions (#35)
* add segLen help to lang std * adding helpers functions to sketchConstraints * update tokeniser tests because they were annoying me not being 100% * compare async lexer with sync lexer instead * add helper functions * remove unneeded nesting * update add ast modifier function for angledLine * initial equal ast modification It adds a tag to the primary line, and converts any secondary lines to angledLine, but doesn't reference the taged/primary line yet * Update fn call with refernce to previous line using segLen * add test for giveSketchFnCallTag * fix excutor bug, executing call expression in array expression * fix small issue in executor * add CallExpressions to BinaryExpressions * add unary Expressions * tweaks to unaryExpression logic * add recasting for unaryExpressions and CallExpressions in BinaryExpressions * ensure pipe substitution info is passed down to unary expressions and others * allow binary expressions in function argumentns * inital setup, new way of organising sketch fn transforms Starting with equal length * overhaul equalLength button * add equal length support for angledLine * line with one variable supports signed legLength * fix indentation when recasting long arrayExpressions in a pipeExpression * improve modifyAst consision * further modify ast tidy * equalLength transfroms far angledLineOfXLength * add transforms for line-yRelative * add equal constraint for angledLineOfYLength * quick test fix * add equal length constrain transforms for lineTo * add equal length constraints for angledLineToX * add equalLength constraints for angledLineToY * test tidy * setup new vertical-horizontal constraints * Add equal Length constraints for vertical/horizontal lines * migrate old tests, and refactor callback tag * tweaks and refactor horzVert component * fix leg len with small negative leg length
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
import { PathToNode } from './executor'
|
||||
import { Token } from './tokeniser'
|
||||
import { parseExpression } from './astMathExpressions'
|
||||
import { Range } from '../useStore'
|
||||
|
||||
type syntaxType =
|
||||
| 'Program'
|
||||
@ -21,13 +22,13 @@ type syntaxType =
|
||||
| 'PipeSubstitution'
|
||||
| 'Literal'
|
||||
| 'NoneCodeNode'
|
||||
| 'UnaryExpression'
|
||||
// | 'NumberLiteral'
|
||||
// | 'StringLiteral'
|
||||
// | 'IfStatement'
|
||||
// | 'WhileStatement'
|
||||
// | 'FunctionDeclaration'
|
||||
// | 'AssignmentExpression'
|
||||
// | 'UnaryExpression'
|
||||
// | 'Property'
|
||||
// | 'LogicalExpression'
|
||||
// | 'ConditionalExpression'
|
||||
@ -173,7 +174,7 @@ export interface CallExpression extends GeneralStatement {
|
||||
optional: boolean
|
||||
}
|
||||
|
||||
function makeCallExpression(
|
||||
export function makeCallExpression(
|
||||
tokens: Token[],
|
||||
index: number
|
||||
): {
|
||||
@ -239,6 +240,23 @@ function makeArguments(
|
||||
expression,
|
||||
])
|
||||
}
|
||||
if (
|
||||
argumentToken.token.type === 'operator' &&
|
||||
argumentToken.token.value === '-'
|
||||
) {
|
||||
const { expression, lastIndex } = makeUnaryExpression(
|
||||
tokens,
|
||||
argumentToken.index
|
||||
)
|
||||
const nextCommarOrBraceTokenIndex = nextMeaningfulToken(
|
||||
tokens,
|
||||
lastIndex
|
||||
).index
|
||||
return makeArguments(tokens, nextCommarOrBraceTokenIndex, [
|
||||
...previousArgs,
|
||||
expression,
|
||||
])
|
||||
}
|
||||
if (
|
||||
argumentToken.token.type === 'brace' &&
|
||||
argumentToken.token.value === '{'
|
||||
@ -256,8 +274,31 @@ function makeArguments(
|
||||
expression,
|
||||
])
|
||||
}
|
||||
if (
|
||||
(argumentToken.token.type === 'word' ||
|
||||
argumentToken.token.type === 'number' ||
|
||||
argumentToken.token.type === 'string') &&
|
||||
nextBraceOrCommaToken.token.type === 'operator'
|
||||
) {
|
||||
const { expression, lastIndex } = makeBinaryExpression(
|
||||
tokens,
|
||||
argumentToken.index
|
||||
)
|
||||
const nextCommarOrBraceTokenIndex = nextMeaningfulToken(
|
||||
tokens,
|
||||
lastIndex
|
||||
).index
|
||||
return makeArguments(tokens, nextCommarOrBraceTokenIndex, [
|
||||
...previousArgs,
|
||||
expression,
|
||||
])
|
||||
}
|
||||
if (!isIdentifierOrLiteral) {
|
||||
const { expression, lastIndex } = makeBinaryExpression(tokens, index)
|
||||
// I think this if statement might be dead code
|
||||
const { expression, lastIndex } = makeBinaryExpression(
|
||||
tokens,
|
||||
nextBraceOrCommaToken.index
|
||||
)
|
||||
return makeArguments(tokens, lastIndex, [...previousArgs, expression])
|
||||
}
|
||||
if (
|
||||
@ -362,15 +403,30 @@ export type Value =
|
||||
| ArrayExpression
|
||||
| ObjectExpression
|
||||
| MemberExpression
|
||||
| UnaryExpression
|
||||
|
||||
function makeValue(
|
||||
tokens: Token[],
|
||||
index: number
|
||||
): { value: Value; lastIndex: number } {
|
||||
const currentToken = tokens[index]
|
||||
const { token: nextToken } = nextMeaningfulToken(tokens, index)
|
||||
// nextToken might be empty if it's at the end of the file
|
||||
const { token: nextToken, index: nextTokenIndex } = nextMeaningfulToken(
|
||||
tokens,
|
||||
index
|
||||
)
|
||||
if (nextToken?.type === 'brace' && nextToken.value === '(') {
|
||||
const endIndex = findClosingBrace(tokens, nextTokenIndex)
|
||||
const tokenAfterCallExpression = nextMeaningfulToken(tokens, endIndex)
|
||||
if (
|
||||
tokenAfterCallExpression?.token?.type === 'operator' &&
|
||||
tokenAfterCallExpression.token.value !== '|>'
|
||||
) {
|
||||
const { expression, lastIndex } = makeBinaryExpression(tokens, index)
|
||||
return {
|
||||
value: expression,
|
||||
lastIndex,
|
||||
}
|
||||
}
|
||||
const { expression, lastIndex } = makeCallExpression(tokens, index)
|
||||
return {
|
||||
value: expression,
|
||||
@ -445,6 +501,10 @@ function makeValue(
|
||||
throw new Error('TODO - handle expression with braces')
|
||||
}
|
||||
}
|
||||
if (currentToken.type === 'operator' && currentToken.value === '-') {
|
||||
const { expression, lastIndex } = makeUnaryExpression(tokens, index)
|
||||
return { value: expression, lastIndex }
|
||||
}
|
||||
throw new Error('Expected a previous Value if statement to match')
|
||||
}
|
||||
|
||||
@ -501,12 +561,15 @@ function makeVariableDeclarators(
|
||||
}
|
||||
}
|
||||
|
||||
export type BinaryPart = Literal | Identifier | BinaryExpression
|
||||
// | CallExpression
|
||||
export type BinaryPart =
|
||||
| Literal
|
||||
| Identifier
|
||||
| BinaryExpression
|
||||
| CallExpression
|
||||
| UnaryExpression
|
||||
// | MemberExpression
|
||||
// | ArrayExpression
|
||||
// | ObjectExpression
|
||||
// | UnaryExpression
|
||||
// | LogicalExpression
|
||||
// | ConditionalExpression
|
||||
|
||||
@ -805,6 +868,22 @@ export function findEndOfBinaryExpression(
|
||||
const nextRight = nextMeaningfulToken(tokens, maybeAnotherOperator.index)
|
||||
return findEndOfBinaryExpression(tokens, nextRight.index)
|
||||
}
|
||||
if (
|
||||
currentToken.type === 'word' &&
|
||||
tokens?.[index + 1]?.type === 'brace' &&
|
||||
tokens[index + 1].value === '('
|
||||
) {
|
||||
const closingParenthesis = findClosingBrace(tokens, index + 1)
|
||||
const maybeAnotherOperator = nextMeaningfulToken(tokens, closingParenthesis)
|
||||
if (
|
||||
maybeAnotherOperator?.token?.type !== 'operator' ||
|
||||
maybeAnotherOperator?.token?.value === '|>'
|
||||
) {
|
||||
return closingParenthesis
|
||||
}
|
||||
const nextRight = nextMeaningfulToken(tokens, maybeAnotherOperator.index)
|
||||
return findEndOfBinaryExpression(tokens, nextRight.index)
|
||||
}
|
||||
const maybeOperator = nextMeaningfulToken(tokens, index)
|
||||
if (
|
||||
maybeOperator?.token?.type !== 'operator' ||
|
||||
@ -828,6 +907,34 @@ function makeBinaryExpression(
|
||||
}
|
||||
}
|
||||
|
||||
export interface UnaryExpression extends GeneralStatement {
|
||||
type: 'UnaryExpression'
|
||||
operator: '-' | '!'
|
||||
argument: BinaryPart
|
||||
}
|
||||
|
||||
function makeUnaryExpression(
|
||||
tokens: Token[],
|
||||
index: number
|
||||
): { expression: UnaryExpression; lastIndex: number } {
|
||||
const currentToken = tokens[index]
|
||||
const nextToken = nextMeaningfulToken(tokens, index)
|
||||
const { value: argument, lastIndex: argumentLastIndex } = makeValue(
|
||||
tokens,
|
||||
nextToken.index
|
||||
)
|
||||
return {
|
||||
expression: {
|
||||
type: 'UnaryExpression',
|
||||
operator: currentToken.value === '!' ? '!' : '-',
|
||||
start: currentToken.start,
|
||||
end: tokens[argumentLastIndex].end,
|
||||
argument: argument as BinaryPart,
|
||||
},
|
||||
lastIndex: argumentLastIndex,
|
||||
}
|
||||
}
|
||||
|
||||
export interface PipeExpression extends GeneralStatement {
|
||||
type: 'PipeExpression'
|
||||
body: Value[]
|
||||
@ -1478,7 +1585,7 @@ export function getNodeFromPath<T>(
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
console.error(
|
||||
`Could not find path ${pathItem} in node ${JSON.stringify(
|
||||
currentNode,
|
||||
null,
|
||||
@ -1510,7 +1617,7 @@ export function getNodeFromPathCurry(
|
||||
|
||||
export function getNodePathFromSourceRange(
|
||||
node: Program,
|
||||
sourceRange: [number, number],
|
||||
sourceRange: Range,
|
||||
previousPath: PathToNode = []
|
||||
): PathToNode {
|
||||
const [start, end] = sourceRange
|
||||
|
Reference in New Issue
Block a user