idk
This commit is contained in:
parent
bc02ee786e
commit
0538b3cee2
5 changed files with 182 additions and 11 deletions
|
|
@ -10,6 +10,18 @@ export function isNumberChar(char: string) {
|
||||||
return /\d/.test(char)
|
return /\d/.test(char)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isHexChar(char: string) {
|
||||||
|
return /[0-9a-fA-F]/.test(char)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isBinaryChar(char: string) {
|
||||||
|
return /[01]/.test(char)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isOctalChar(char: string) {
|
||||||
|
return /[0-7]/.test(char)
|
||||||
|
}
|
||||||
|
|
||||||
export function isCompileBinding(input: string) {
|
export function isCompileBinding(input: string) {
|
||||||
return input.startsWith("[") && input.endsWith("]")
|
return input.startsWith("[") && input.endsWith("]")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,3 +73,22 @@ FunctionMap.set("bin", input => {
|
||||||
|
|
||||||
return { genBindings: bindings, value: ret }
|
return { genBindings: bindings, value: ret }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
FunctionMap.set("bind", (value, bait) => {
|
||||||
|
const ret = RandomBindingString(16)
|
||||||
|
|
||||||
|
if (!bait) {
|
||||||
|
throw new Error("Bait is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
genBindings: [{ source: `((${bait} - ${bait}) + ${value})`, target: ret }],
|
||||||
|
value: ret,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
FunctionMap.set("int", input => {
|
||||||
|
return {
|
||||||
|
value: input,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -188,6 +188,44 @@ export function Lexer(input: string, start: number = 0, end?: number) {
|
||||||
let start = index
|
let start = index
|
||||||
|
|
||||||
if (Checker.isNumberChar(token)) {
|
if (Checker.isNumberChar(token)) {
|
||||||
|
if (token === "0") {
|
||||||
|
const numType = input[index + 1]
|
||||||
|
if (numType === "x") {
|
||||||
|
index += 2
|
||||||
|
while (Checker.isHexChar(input[index + 1])) index++
|
||||||
|
if (start + 2 === index) {
|
||||||
|
console.error(
|
||||||
|
`\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`,
|
||||||
|
)
|
||||||
|
throw new Error()
|
||||||
|
}
|
||||||
|
tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1))
|
||||||
|
break
|
||||||
|
} else if (numType === "b") {
|
||||||
|
index += 2
|
||||||
|
while (Checker.isBinaryChar(input[index + 1])) index++
|
||||||
|
tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1))
|
||||||
|
if (start + 2 === index) {
|
||||||
|
console.error(
|
||||||
|
`\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`,
|
||||||
|
)
|
||||||
|
throw new Error()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} else if (numType === "o") {
|
||||||
|
index += 2
|
||||||
|
while (Checker.isOctalChar(input[index + 1])) index++
|
||||||
|
tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1))
|
||||||
|
if (start + 2 === index) {
|
||||||
|
console.error(
|
||||||
|
`\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`,
|
||||||
|
)
|
||||||
|
throw new Error()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (Checker.isNumberChar(input[index + 1])) index++
|
while (Checker.isNumberChar(input[index + 1])) index++
|
||||||
if (input[index + 1] === "e") {
|
if (input[index + 1] === "e") {
|
||||||
index++
|
index++
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,27 @@
|
||||||
import { Expression, GenBinding, Token, TokenKind, TSToken, TSTokenKind } from "./types.js"
|
import { Expression, GenBinding, Token, TokenKind, TSToken, TSTokenKind } from "./types.js"
|
||||||
import { BindingType } from "../../types/enums/BindingType.js"
|
import { BindingType } from "../../types/enums/BindingType.js"
|
||||||
import { Binding, BindingItem } from "../../types/properties/value.js"
|
import { BindingItem } from "../../types/properties/value.js"
|
||||||
import { FunctionMap } from "./Funtion.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"
|
||||||
|
|
||||||
export class Parser {
|
export class Parser {
|
||||||
position: number = 0
|
position: number = 0
|
||||||
tokens: Token[]
|
|
||||||
|
|
||||||
genBindings: GenBinding[] = []
|
genBindings: GenBinding[] = []
|
||||||
output: Expression
|
output: Expression
|
||||||
|
tokens: Token[]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private input: string,
|
private input: string,
|
||||||
private cache = new Map<string, unknown>(),
|
private cache = new Map<string, unknown>(),
|
||||||
|
tokens?: Token[],
|
||||||
) {
|
) {
|
||||||
this.tokens = Lexer(this.input)
|
if (tokens) {
|
||||||
|
this.tokens = tokens
|
||||||
|
tokens = undefined
|
||||||
|
} else this.tokens = Lexer(input)
|
||||||
|
|
||||||
this.output = this.parseExpression()
|
this.output = this.parseExpression()
|
||||||
|
|
||||||
if (this.at()) {
|
if (this.at()) {
|
||||||
|
|
@ -159,8 +164,22 @@ export class Parser {
|
||||||
const operator = this.eat()
|
const operator = this.eat()
|
||||||
const right = this.parsePrimaryExpression()
|
const right = this.parsePrimaryExpression()
|
||||||
|
|
||||||
if (current.value === "%") left = `(${left} - (${left} / ${right} * ${right}))`
|
if (current.value === "%") {
|
||||||
else left = `(${left} ${operator.value} ${right})`
|
const cacheStr = `expr:${left}${operator.value}${right}`
|
||||||
|
if (this.cache.has(cacheStr)) {
|
||||||
|
return (left = this.cache.get(cacheStr) as Expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ret = RandomBindingString(16)
|
||||||
|
|
||||||
|
this.genBindings.push({
|
||||||
|
source: `(${left} - (${left} / ${right} * ${right}))`,
|
||||||
|
target: ret,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.cache.set(cacheStr, ret)
|
||||||
|
left = ret
|
||||||
|
} else left = `(${left} ${operator.value} ${right})`
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
|
@ -178,8 +197,15 @@ export class Parser {
|
||||||
const operator = this.eat()
|
const operator = this.eat()
|
||||||
const right = this.parsePrimaryExpression()
|
const right = this.parsePrimaryExpression()
|
||||||
|
|
||||||
|
const cacheStr = `expr:${left}${operator.value}${right}`
|
||||||
|
if (this.cache.has(cacheStr)) {
|
||||||
|
return (left = this.cache.get(cacheStr) as Expression)
|
||||||
|
}
|
||||||
|
|
||||||
const ret = RandomBindingString(16)
|
const ret = RandomBindingString(16)
|
||||||
|
|
||||||
|
this.cache.set(cacheStr, ret)
|
||||||
|
|
||||||
const leftBin = this.intToBin(left)
|
const leftBin = this.intToBin(left)
|
||||||
const rightBin = this.intToBin(right)
|
const rightBin = this.intToBin(right)
|
||||||
|
|
||||||
|
|
@ -234,7 +260,14 @@ export class Parser {
|
||||||
) {
|
) {
|
||||||
const operator = this.eat()
|
const operator = this.eat()
|
||||||
const right = this.parsePrimaryExpression()
|
const right = this.parsePrimaryExpression()
|
||||||
|
|
||||||
|
const cacheStr = `expr:${left}${operator.value}${right}`
|
||||||
|
if (this.cache.has(cacheStr)) {
|
||||||
|
return (left = this.cache.get(cacheStr) as Expression)
|
||||||
|
}
|
||||||
const ret = RandomBindingString(16)
|
const ret = RandomBindingString(16)
|
||||||
|
this.cache.set(cacheStr, ret)
|
||||||
|
|
||||||
const leftBind = this.intToBin(left)
|
const leftBind = this.intToBin(left)
|
||||||
|
|
||||||
const op = operator.value === "<<" ? "-" : "+"
|
const op = operator.value === "<<" ? "-" : "+"
|
||||||
|
|
@ -275,9 +308,23 @@ export class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
case TokenKind.NUMBER: {
|
case TokenKind.NUMBER: {
|
||||||
const [num, exp] = (<string>this.eat().value).split("e")
|
const numberToken = this.eat()
|
||||||
|
|
||||||
|
switch (numberToken.value[1]) {
|
||||||
|
case "x":
|
||||||
|
return "" + parseInt(numberToken.value.slice(2) as string, 16)
|
||||||
|
|
||||||
|
case "o":
|
||||||
|
return "" + parseInt(numberToken.value.slice(2) as string, 8)
|
||||||
|
|
||||||
|
case "b":
|
||||||
|
return "" + parseInt(numberToken.value.slice(2) as string, 2)
|
||||||
|
|
||||||
|
default:
|
||||||
|
const [num, exp] = (<string>numberToken.value).split("e")
|
||||||
return "" + (exp ? +num * 10 ** +exp : num)
|
return "" + (exp ? +num * 10 ** +exp : num)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case TokenKind.VARIABLE:
|
case TokenKind.VARIABLE:
|
||||||
case TokenKind.STRING:
|
case TokenKind.STRING:
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ import { AnimationProperties, KeyframeAnimationProperties } from "../types/prope
|
||||||
import { Animation } from "./Animation.js"
|
import { Animation } from "./Animation.js"
|
||||||
import { SmartAnimation } from "../types/enums/SmartAnimation.js"
|
import { SmartAnimation } from "../types/enums/SmartAnimation.js"
|
||||||
import { MemoryModify } from "../compilers/Memory.js"
|
import { MemoryModify } from "../compilers/Memory.js"
|
||||||
|
import { Lexer } from "../compilers/bindings/Lexer.js"
|
||||||
|
import { Token, TokenKind, TSToken, TSTokenKind } from "../compilers/bindings/types.js"
|
||||||
|
|
||||||
type CompileBinding = `[${string}]`
|
type CompileBinding = `[${string}]`
|
||||||
|
|
||||||
|
|
@ -74,9 +76,62 @@ export function ResolveBinding(cache: Map<string, unknown>, ...bindings: Binding
|
||||||
for (const binding of bindings) {
|
for (const binding of bindings) {
|
||||||
if (binding.source_property_name) {
|
if (binding.source_property_name) {
|
||||||
if (isCompileBinding(binding.source_property_name)) {
|
if (isCompileBinding(binding.source_property_name)) {
|
||||||
const { gen, out } = new Parser(binding.source_property_name.slice(1, -1), cache).out()
|
const inputBindings = binding.source_property_name.slice(1, -1)
|
||||||
|
if (binding.source_control_name) {
|
||||||
|
// @ts-ignore
|
||||||
|
const tokensMapping = (token: Token) => {
|
||||||
|
if (token.kind === TokenKind.VARIABLE) {
|
||||||
|
const mapkey = `mapping:${binding.source_control_name}:${token.value}`
|
||||||
|
|
||||||
|
if (cache.has(mapkey)) {
|
||||||
|
return {
|
||||||
|
...token,
|
||||||
|
value: cache.get(mapkey) as string,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const ret = RandomBindingString(16)
|
||||||
|
cache.set(mapkey, ret)
|
||||||
|
|
||||||
|
result.push({
|
||||||
|
source_property_name: token.value,
|
||||||
|
source_control_name: binding.source_control_name,
|
||||||
|
target_property_name: ret,
|
||||||
|
binding_type: BindingType.VIEW,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...token,
|
||||||
|
value: ret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (token.kind === TokenKind.TEMPLATE_STRING) {
|
||||||
|
return {
|
||||||
|
...token,
|
||||||
|
// @ts-ignore
|
||||||
|
value: token.value.map((tstoken: TSToken) => {
|
||||||
|
if (tstoken.kind === TSTokenKind.STRING) return tstoken
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
...tstoken,
|
||||||
|
tokens: tstoken.tokens.map(tokensMapping),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
} else return token
|
||||||
|
}
|
||||||
|
|
||||||
|
const { gen, out } = new Parser(inputBindings, cache, Lexer(inputBindings).map(tokensMapping)).out()
|
||||||
|
|
||||||
|
delete binding.source_control_name
|
||||||
|
|
||||||
if (gen) result.push(...gen)
|
if (gen) result.push(...gen)
|
||||||
binding.source_property_name = out
|
binding.source_property_name = out
|
||||||
|
} else {
|
||||||
|
const { gen, out } = new Parser(inputBindings, cache).out()
|
||||||
|
if (gen) result.push(...gen)
|
||||||
|
binding.source_property_name = out
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.binding_type = BindingType.VIEW
|
binding.binding_type = BindingType.VIEW
|
||||||
|
|
|
||||||
Reference in a new issue