From 0538b3cee2e9a21430059f21d64d7816e8045ec9 Mon Sep 17 00:00:00 2001 From: Asaki Yuki Date: Fri, 30 Jan 2026 19:42:42 +0700 Subject: [PATCH] idk --- src/compilers/bindings/Checker.ts | 12 ++++ .../bindings/{Funtion.ts => Function.ts} | 19 ++++++ src/compilers/bindings/Lexer.ts | 38 +++++++++++ src/compilers/bindings/Parser.ts | 63 ++++++++++++++++--- src/components/Utils.ts | 61 +++++++++++++++++- 5 files changed, 182 insertions(+), 11 deletions(-) rename src/compilers/bindings/{Funtion.ts => Function.ts} (84%) diff --git a/src/compilers/bindings/Checker.ts b/src/compilers/bindings/Checker.ts index 3f985ee..c0092f0 100644 --- a/src/compilers/bindings/Checker.ts +++ b/src/compilers/bindings/Checker.ts @@ -10,6 +10,18 @@ export function isNumberChar(char: string) { 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) { return input.startsWith("[") && input.endsWith("]") } diff --git a/src/compilers/bindings/Funtion.ts b/src/compilers/bindings/Function.ts similarity index 84% rename from src/compilers/bindings/Funtion.ts rename to src/compilers/bindings/Function.ts index 70cf47f..a2929f1 100644 --- a/src/compilers/bindings/Funtion.ts +++ b/src/compilers/bindings/Function.ts @@ -73,3 +73,22 @@ FunctionMap.set("bin", input => { 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, + } +}) diff --git a/src/compilers/bindings/Lexer.ts b/src/compilers/bindings/Lexer.ts index 4870e53..bc47d30 100644 --- a/src/compilers/bindings/Lexer.ts +++ b/src/compilers/bindings/Lexer.ts @@ -188,6 +188,44 @@ export function Lexer(input: string, start: number = 0, end?: number) { let start = index 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++ if (input[index + 1] === "e") { index++ diff --git a/src/compilers/bindings/Parser.ts b/src/compilers/bindings/Parser.ts index e3d7fa3..5db7ab5 100644 --- a/src/compilers/bindings/Parser.ts +++ b/src/compilers/bindings/Parser.ts @@ -1,22 +1,27 @@ import { Expression, GenBinding, Token, TokenKind, TSToken, TSTokenKind } from "./types.js" import { BindingType } from "../../types/enums/BindingType.js" -import { Binding, BindingItem } from "../../types/properties/value.js" -import { FunctionMap } from "./Funtion.js" +import { BindingItem } from "../../types/properties/value.js" +import { FunctionMap } from "./Function.js" import { Lexer } from "./Lexer.js" import { RandomBindingString } from "../../components/Utils.js" export class Parser { position: number = 0 - tokens: Token[] genBindings: GenBinding[] = [] output: Expression + tokens: Token[] constructor( private input: string, private cache = new Map(), + tokens?: Token[], ) { - this.tokens = Lexer(this.input) + if (tokens) { + this.tokens = tokens + tokens = undefined + } else this.tokens = Lexer(input) + this.output = this.parseExpression() if (this.at()) { @@ -159,8 +164,22 @@ export class Parser { const operator = this.eat() const right = this.parsePrimaryExpression() - if (current.value === "%") left = `(${left} - (${left} / ${right} * ${right}))` - else left = `(${left} ${operator.value} ${right})` + if (current.value === "%") { + 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 @@ -178,8 +197,15 @@ export class Parser { const operator = this.eat() 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) + this.cache.set(cacheStr, ret) + const leftBin = this.intToBin(left) const rightBin = this.intToBin(right) @@ -234,7 +260,14 @@ export class Parser { ) { const operator = this.eat() 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) + this.cache.set(cacheStr, ret) + const leftBind = this.intToBin(left) const op = operator.value === "<<" ? "-" : "+" @@ -275,8 +308,22 @@ export class Parser { } case TokenKind.NUMBER: { - const [num, exp] = (this.eat().value).split("e") - return "" + (exp ? +num * 10 ** +exp : num) + 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] = (numberToken.value).split("e") + return "" + (exp ? +num * 10 ** +exp : num) + } } case TokenKind.VARIABLE: diff --git a/src/components/Utils.ts b/src/components/Utils.ts index 5615e96..43c583e 100644 --- a/src/components/Utils.ts +++ b/src/components/Utils.ts @@ -38,6 +38,8 @@ import { AnimationProperties, KeyframeAnimationProperties } from "../types/prope import { Animation } from "./Animation.js" import { SmartAnimation } from "../types/enums/SmartAnimation.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}]` @@ -74,9 +76,62 @@ export function ResolveBinding(cache: Map, ...bindings: Binding for (const binding of bindings) { if (binding.source_property_name) { if (isCompileBinding(binding.source_property_name)) { - const { gen, out } = new Parser(binding.source_property_name.slice(1, -1), cache).out() - if (gen) result.push(...gen) - binding.source_property_name = 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) + 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