Improved math expressions (#6)

* Improved math expressions

Things are in a better state, + - / * work now for basic const var = 5 <operator> 1

Though the current method I'm using to make the ast isn't really going to work for dealing with precedence rules so some refactoring is needed going forward

* get complex math expressions working with precedence including parans

Node that identifiers are working, call expressions are not, that's a TODO
/ * % + - are working both other things like exponent and logical operators are also not working.
Recasting is the most important thing to implement next

* get recasting working for nested binary expressions

* clean up
This commit is contained in:
Kurt Hutten
2023-01-21 21:23:01 +11:00
committed by GitHub
parent d61c003f82
commit e37f68424b
8 changed files with 955 additions and 25 deletions

View File

@ -1,5 +1,6 @@
import { PathToNode } from './executor'
import { Token } from './tokeniser'
import { parseExpression } from './astMathExpressions'
type syntaxType =
| 'Program'
@ -473,8 +474,7 @@ function makeVariableDeclarators(
}
}
export type BinaryPart = Literal | Identifier
// | BinaryExpression
export type BinaryPart = Literal | Identifier | BinaryExpression
// | CallExpression
// | MemberExpression
// | ArrayExpression
@ -764,7 +764,7 @@ export interface BinaryExpression extends GeneralStatement {
function makeBinaryPart(
tokens: Token[],
index: number
): { part: BinaryPart; lastIndex: number } {
): { part: Literal | Identifier; lastIndex: number } {
const currentToken = tokens[index]
if (currentToken.type === 'word') {
const identifier = makeIdentifier(tokens, index)
@ -783,28 +783,43 @@ function makeBinaryPart(
throw new Error('Expected a previous BinaryPart if statement to match')
}
export function findEndOfBinaryExpression(
tokens: Token[],
index: number
): number {
const currentToken = tokens[index]
if (currentToken.type === 'brace' && currentToken.value === '(') {
const closingParenthesis = findClosingBrace(tokens, index)
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' ||
maybeOperator?.token?.value === '|>'
) {
return index
}
const nextRight = nextMeaningfulToken(tokens, maybeOperator.index)
return findEndOfBinaryExpression(tokens, nextRight.index)
}
function makeBinaryExpression(
tokens: Token[],
index: number
): { expression: BinaryExpression; lastIndex: number } {
const currentToken = tokens[index]
const { part: left } = makeBinaryPart(tokens, index)
const { token: operatorToken, index: operatorIndex } = nextMeaningfulToken(
tokens,
index
)
const rightToken = nextMeaningfulToken(tokens, operatorIndex)
const { part: right } = makeBinaryPart(tokens, rightToken.index)
const endIndex = findEndOfBinaryExpression(tokens, index)
const expression = parseExpression(tokens.slice(index, endIndex + 1))
return {
expression: {
type: 'BinaryExpression',
start: currentToken.start,
end: right.end,
left,
operator: operatorToken.value,
right,
},
lastIndex: rightToken.index,
expression,
lastIndex: endIndex,
}
}
@ -1296,6 +1311,61 @@ 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