add binary expression
This commit is contained in:
parent
1d00af88c0
commit
246cdbb8d2
3 changed files with 62 additions and 6 deletions
|
|
@ -25,3 +25,7 @@ export function isOctalChar(char: string) {
|
||||||
export function isCompileBinding(input: string) {
|
export function isCompileBinding(input: string) {
|
||||||
return input.startsWith("[") && input.endsWith("]")
|
return input.startsWith("[") && input.endsWith("]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isHasBinding(input: string) {
|
||||||
|
return /#\w+/.test(input)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ export function Lexer(input: string, start: number = 0, end?: number) {
|
||||||
case "/":
|
case "/":
|
||||||
case "%":
|
case "%":
|
||||||
case "^":
|
case "^":
|
||||||
|
case "?":
|
||||||
|
case ":":
|
||||||
tokens.push(makeToken(input, TokenKind.OPERATOR, index))
|
tokens.push(makeToken(input, TokenKind.OPERATOR, index))
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { BindingItem } from "../../types/properties/value.js"
|
||||||
import { FunctionMap } from "./Function.js"
|
import { FunctionMap } from "./Function.js"
|
||||||
import { Lexer } from "./Lexer.js"
|
import { Lexer } from "./Lexer.js"
|
||||||
import { RandomBindingString } from "../../components/Utils.js"
|
import { RandomBindingString } from "../../components/Utils.js"
|
||||||
|
import { isHasBinding } from "./Checker.js"
|
||||||
|
|
||||||
export class Parser {
|
export class Parser {
|
||||||
position: number = 0
|
position: number = 0
|
||||||
|
|
@ -72,14 +73,63 @@ export class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseExpression(): Expression {
|
private parseExpression(): Expression {
|
||||||
return this.parseOrExpression()
|
return this.parseBinaryExpression()
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseBinaryExpression(): Expression {
|
||||||
|
let left = this.parseOrExpression(),
|
||||||
|
current
|
||||||
|
|
||||||
|
while ((current = this.at()) && current.kind === TokenKind.OPERATOR && current.value === "?") {
|
||||||
|
this.eat()
|
||||||
|
let middle = this.parseExpression(),
|
||||||
|
right: string
|
||||||
|
|
||||||
|
if ((current = this.at()) && current.kind === TokenKind.OPERATOR && current.value === ":") {
|
||||||
|
this.eat()
|
||||||
|
right = this.parseExpression()
|
||||||
|
} else this.expect(TokenKind.OPERATOR, "Unexpected token!")
|
||||||
|
|
||||||
|
let leftBind, middleBind, rightBind
|
||||||
|
|
||||||
|
if (isHasBinding(left)) {
|
||||||
|
leftBind = RandomBindingString()
|
||||||
|
this.genBindings.push({
|
||||||
|
source: `((0 + ${left}) > 0)`,
|
||||||
|
target: leftBind,
|
||||||
|
})
|
||||||
|
} else this.expect(TokenKind.WORD, "Unexpected token!")
|
||||||
|
|
||||||
|
if (isHasBinding(middle)) {
|
||||||
|
middleBind = RandomBindingString()
|
||||||
|
this.genBindings.push({
|
||||||
|
source: middle,
|
||||||
|
target: middleBind,
|
||||||
|
})
|
||||||
|
} else this.expect(TokenKind.WORD, "Unexpected token!")
|
||||||
|
|
||||||
|
if (isHasBinding(right!)) {
|
||||||
|
rightBind = RandomBindingString()
|
||||||
|
this.genBindings.push({
|
||||||
|
source: right!,
|
||||||
|
target: rightBind,
|
||||||
|
})
|
||||||
|
} else this.expect(TokenKind.WORD, "Unexpected token!")
|
||||||
|
|
||||||
|
const ifTrueExpression = `(('prefix' + ${leftBind} + ${middleBind}) - ('prefixfalse' + ${middleBind})) - 'prefixtrue')`
|
||||||
|
const ifFalseExpression = `(('prefix' + ${leftBind} + ${rightBind}) - ('prefixtrue' + ${rightBind})) - 'prefixfalse')`
|
||||||
|
|
||||||
|
return `(${ifTrueExpression} + ${ifFalseExpression})`
|
||||||
|
}
|
||||||
|
|
||||||
|
return left
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseOrExpression(): Expression {
|
private parseOrExpression(): Expression {
|
||||||
let left = this.parseAndExpression(),
|
let left = this.parseAndExpression(),
|
||||||
current
|
current
|
||||||
|
|
||||||
while ((current = this.at()) && this.at().kind === TokenKind.OPERATOR && current.value === "||") {
|
while ((current = this.at()) && current.kind === TokenKind.OPERATOR && current.value === "||") {
|
||||||
this.eat()
|
this.eat()
|
||||||
left = `(${left} or ${this.parseAndExpression()})`
|
left = `(${left} or ${this.parseAndExpression()})`
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +141,7 @@ export class Parser {
|
||||||
let left = this.parseComparisonExpression(),
|
let left = this.parseComparisonExpression(),
|
||||||
current
|
current
|
||||||
|
|
||||||
while ((current = this.at()) && this.at().kind === TokenKind.OPERATOR && current.value === "&&") {
|
while ((current = this.at()) && current.kind === TokenKind.OPERATOR && current.value === "&&") {
|
||||||
this.eat()
|
this.eat()
|
||||||
left = `(${left} and ${this.parseComparisonExpression()})`
|
left = `(${left} and ${this.parseComparisonExpression()})`
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +155,7 @@ export class Parser {
|
||||||
|
|
||||||
while (
|
while (
|
||||||
(current = this.at()) &&
|
(current = this.at()) &&
|
||||||
this.at().kind === TokenKind.OPERATOR &&
|
current.kind === TokenKind.OPERATOR &&
|
||||||
["==", ">", "<", ">=", "<=", "!="].includes(<string>current.value)
|
["==", ">", "<", ">=", "<=", "!="].includes(<string>current.value)
|
||||||
) {
|
) {
|
||||||
const operator = this.eat()
|
const operator = this.eat()
|
||||||
|
|
@ -140,7 +190,7 @@ export class Parser {
|
||||||
|
|
||||||
while (
|
while (
|
||||||
(current = this.at()) &&
|
(current = this.at()) &&
|
||||||
this.at()?.kind === TokenKind.OPERATOR &&
|
current?.kind === TokenKind.OPERATOR &&
|
||||||
["+", "-"].includes(<string>current.value)
|
["+", "-"].includes(<string>current.value)
|
||||||
) {
|
) {
|
||||||
const operator = this.eat()
|
const operator = this.eat()
|
||||||
|
|
@ -158,7 +208,7 @@ export class Parser {
|
||||||
|
|
||||||
while (
|
while (
|
||||||
(current = this.at()) &&
|
(current = this.at()) &&
|
||||||
this.at()?.kind === TokenKind.OPERATOR &&
|
current?.kind === TokenKind.OPERATOR &&
|
||||||
["*", "/", "%"].includes(<string>current.value)
|
["*", "/", "%"].includes(<string>current.value)
|
||||||
) {
|
) {
|
||||||
const operator = this.eat()
|
const operator = this.eat()
|
||||||
|
|
|
||||||
Reference in a new issue