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:
Kurt Hutten
2023-03-02 21:19:11 +11:00
committed by GitHub
parent f70f0f7bc3
commit 6446601a67
21 changed files with 2280 additions and 666 deletions

View File

@ -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