From 3c0f9b31c63d06553b605d91b79bedcf97e5f52e Mon Sep 17 00:00:00 2001 From: Asaki Yuki Date: Thu, 5 Feb 2026 13:36:33 +0700 Subject: [PATCH] refactor: temporarily remove bitwise operations --- resources/asajs.config.cjs | 2 +- src/compilers/bindings/Binary.ts | 47 ++++++++ src/compilers/bindings/Function.ts | 188 ++++++++++++++++++----------- src/compilers/bindings/Lexer.ts | 16 ++- src/compilers/bindings/Parser.ts | 113 ++--------------- src/compilers/bindings/types.ts | 4 +- src/compilers/ui/builder.ts | 2 +- src/components/UI.ts | 2 +- src/index.ts | 2 +- 9 files changed, 192 insertions(+), 184 deletions(-) create mode 100644 src/compilers/bindings/Binary.ts diff --git a/resources/asajs.config.cjs b/resources/asajs.config.cjs index 1863140..018faf9 100644 --- a/resources/asajs.config.cjs +++ b/resources/asajs.config.cjs @@ -4,7 +4,7 @@ */ export const config = { packinfo: { - name: "AsaJS - Installer Test", + name: "AsaJS", description: "Create your Minecraft JSON-UI resource packs using JavaScript.", version: [4, 0, 1], }, diff --git a/src/compilers/bindings/Binary.ts b/src/compilers/bindings/Binary.ts new file mode 100644 index 0000000..da953fd --- /dev/null +++ b/src/compilers/bindings/Binary.ts @@ -0,0 +1,47 @@ +import { RandomBindingString } from "../../components/Utils.js" +import { Binding } from "../../types/properties/value.js" +import { defaultFunctions } from "./Function.js" +import { GenBinding } from "./types.js" + +export function intToBin(input: string) { + const { abs, negabs } = defaultFunctions + + const ret = RandomBindingString(16) + const bindings: GenBinding[] = [] + + // negative bit + bindings.push({ + source: `(${input} < 0)`, + target: `${ret}0`, + }) + + return { + ret, + bindings, + } +} + +export function binToInt(input: Binding) { + const ret = RandomBindingString(16) + const bindings: GenBinding[] = [] + + const nevBind = (input + "0") as Binding + + // Is reverse to positive + bindings.push({ + source: `(-1 + ((${nevBind} = 0) * 2))`, + target: `${ret}0`, + }) + + bindings.push({ + source: `(${Array.from({ length: 31 }, ($, i) => { + return `${input}${i + 1}` + }).join(" + ")})`, + target: ret, + }) + + return { + ret, + bindings, + } +} diff --git a/src/compilers/bindings/Function.ts b/src/compilers/bindings/Function.ts index a2929f1..637b055 100644 --- a/src/compilers/bindings/Function.ts +++ b/src/compilers/bindings/Function.ts @@ -1,5 +1,5 @@ import { RandomBindingString } from "../../components/Utils.js" -import { Parser } from "./Parser.js" +import { intToBin } from "./Binary.js" import { Expression, GenBinding } from "./types.js" type Callback = (...args: Expression[]) => { @@ -13,82 +13,134 @@ function callFn(name: string, ...args: Expression[]) { return FunctionMap.get(name)!(...args) } -// Default Functions -FunctionMap.set("abs", number => { - const randomBinding = RandomBindingString(16) - return { - genBindings: [{ source: `((-1 + (${number} > 0) * 2) * ${number})`, target: randomBinding }], - value: randomBinding, - } -}) +export const defaultFunctions = { + /** + * Returns the absolute value of a number (the value without regard to whether it is positive or negative). For example, the absolute value of -5 is the same as the absolute value of 5. + * @param number + * @returns + */ + abs: number => { + const randomBinding = RandomBindingString(16) + return { + genBindings: [{ source: `((-1 + (${number} > 0) * 2) * ${number})`, target: randomBinding }], + value: randomBinding, + } + }, -FunctionMap.set("new", expression => { - const randomBinding = RandomBindingString(16) - return { - genBindings: [{ source: expression, target: randomBinding }], - value: randomBinding, - } -}) + /** + * Returns the negative absolute value of a number (the value without regard to whether it is positive or negative). For example, the absolute value of 5 is the same as the negative absolute value of -5. + * @param number + * @returns + */ + negabs: number => { + const randomBinding = RandomBindingString(16) + return { + genBindings: [{ source: `((-1 + (${number} < 0) * 2) * ${number})`, target: randomBinding }], + value: randomBinding, + } + }, -FunctionMap.set("sqrt", number => { - const rtn = RandomBindingString(16), - $1 = RandomBindingString(16), - $2 = RandomBindingString(16) + /** + * Generate a new binding for expression + * @param expression + * @returns + */ + new: expression => { + const randomBinding = RandomBindingString(16) + return { + genBindings: [{ source: expression, target: randomBinding }], + value: randomBinding, + } + }, - const { genBindings: absValue, value: absRtn } = callFn("abs", number) + /** + * Returns the square root of a number. + * @param number + * @returns + */ + sqrt: number => { + const rtn = RandomBindingString(16), + $1 = RandomBindingString(16), + $2 = RandomBindingString(16) - return { - genBindings: [ - { - source: `${number} * 100 / 2`, - target: $1, - }, - ...absValue!, - { - source: `${absRtn} > 1`, - target: $2, - }, - { - source: `(${number} < 0) * -1 + (${number} > -1) * (${$2} * ((${rtn} + ${number} / ${rtn}) / 2) + (not ${$2}) * ${rtn})`, - target: rtn, - }, - ], - value: rtn, - } -}) + const { genBindings: absValue, value: absRtn } = callFn("abs", number) -FunctionMap.set("translatable", key => { - return { - value: `'%' + ${key}`, - } -}) + return { + genBindings: [ + { + source: `${number} * 100 / 2`, + target: $1, + }, + ...absValue!, + { + source: `${absRtn} > 1`, + target: $2, + }, + { + source: `(${number} < 0) * -1 + (${number} > -1) * (${$2} * ((${rtn} + ${number} / ${rtn}) / 2) + (not ${$2}) * ${rtn})`, + target: rtn, + }, + ], + value: rtn, + } + }, -FunctionMap.set("bin", input => { - const { ret, bindings } = Parser.intToBin(input) + /** + * Return a translatable string + * @param key + * @returns + */ + translatable: key => { + return { + value: `'%' + ${key}`, + } + }, - bindings.push({ - source: `'§z' + ${Array.from({ length: 30 }, (_, i) => `${ret}${30 - i - 1}`).join(" + ")}`, - target: ret, - }) + /** + * Return a binary of int32 number in string + * @param value + * @param bait + * @returns + */ + // bin: value => { + // const {} = intToBin(value) - return { genBindings: bindings, value: ret } -}) + // return { + // value, + // } + // }, -FunctionMap.set("bind", (value, bait) => { - const ret = RandomBindingString(16) + /** + * Generate value bindings + * @param value + * @param bait + * @returns + */ + bind: (value, bait) => { + const ret = RandomBindingString(16) - if (!bait) { - throw new Error("Bait is required") - } + if (!bait) { + throw new Error("Bait is required") + } - return { - genBindings: [{ source: `((${bait} - ${bait}) + ${value})`, target: ret }], - value: ret, - } -}) + return { + genBindings: [{ source: `((${bait} - ${bait}) + ${value})`, target: ret }], + value: ret, + } + }, -FunctionMap.set("int", input => { - return { - value: input, - } -}) + /** + * Return a int of float number, because string in JSON-UI cannot read it. + * @param input + * @returns + */ + int: input => { + const ret = RandomBindingString(16) + return { + genBindings: [{ source: `${input}`, target: ret }], + value: ret, + } + }, +} satisfies Record + +Object.entries(defaultFunctions).forEach(([key, value]) => FunctionMap.set(key, value)) diff --git a/src/compilers/bindings/Lexer.ts b/src/compilers/bindings/Lexer.ts index bc47d30..3e2201f 100644 --- a/src/compilers/bindings/Lexer.ts +++ b/src/compilers/bindings/Lexer.ts @@ -73,8 +73,11 @@ export function Lexer(input: string, start: number = 0, end?: number) { if (input[index + 1] === "=") tokens.push(makeToken(input, TokenKind.OPERATOR, index++, 2)) else { if (input[index] === input[index + 1]) { - if (input[index] !== "!") tokens.push(makeToken(input, TokenKind.OPERATOR, index++, 2)) - else tokens.push(makeToken(input, TokenKind.OPERATOR, index)) + if (input[index] !== "!") { + if (input[++index] === input[index + 1]) + tokens.push(makeToken(input, TokenKind.OPERATOR, index++ - 1, 3)) + else tokens.push(makeToken(input, TokenKind.OPERATOR, index - 1, 2)) + } else tokens.push(makeToken(input, TokenKind.OPERATOR, index)) } else tokens.push(makeToken(input, TokenKind.OPERATOR, index)) } break @@ -135,6 +138,7 @@ export function Lexer(input: string, start: number = 0, end?: number) { value: `'${input.slice(start, index - 1)}'`, }, }) + index-- break } } @@ -199,12 +203,12 @@ export function Lexer(input: string, start: number = 0, end?: number) { ) throw new Error() } - tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1)) + tokens.push(makeToken(input, TokenKind.INT, 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)) + tokens.push(makeToken(input, TokenKind.INT, start, index - start + 1)) if (start + 2 === index) { console.error( `\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`, @@ -215,7 +219,7 @@ export function Lexer(input: string, start: number = 0, end?: number) { } else if (numType === "o") { index += 2 while (Checker.isOctalChar(input[index + 1])) index++ - tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1)) + tokens.push(makeToken(input, TokenKind.INT, start, index - start + 1)) if (start + 2 === index) { console.error( `\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`, @@ -239,7 +243,7 @@ export function Lexer(input: string, start: number = 0, end?: number) { while (Checker.isNumberChar(input[index + 1])) index++ } - tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1)) + tokens.push(makeToken(input, TokenKind.INT, start, index - start + 1)) } else if (Checker.isWordChar(token)) { while (Checker.isWordChar(input[index + 1])) index++ tokens.push(makeToken(input, TokenKind.WORD, start, index - start + 1)) diff --git a/src/compilers/bindings/Parser.ts b/src/compilers/bindings/Parser.ts index 5db7ab5..7461228 100644 --- a/src/compilers/bindings/Parser.ts +++ b/src/compilers/bindings/Parser.ts @@ -186,110 +186,13 @@ export class Parser { } private parseBitwiseLogicExpression(): Expression { - let left = this.parseBitwiseShiftExpression(), - current - - while ( - (current = this.at()) && - this.at()?.kind === TokenKind.OPERATOR && - ["&", "|", "^"].includes(current.value) - ) { - 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) - - if (operator.value === "&") { - this.genBindings.push( - ...Array.from({ length: 30 }, (_, i) => { - return { - source: `(${leftBin}${i} * ${rightBin}${i})`, - target: `${ret}${i}`, - } - }), - ) - } else if (operator.value === "|") { - this.genBindings.push( - ...Array.from({ length: 30 }, (_, i) => { - return { - source: `(${leftBin}${i} + ${rightBin}${i} - (${leftBin}${i} * ${rightBin}${i}))`, - target: `${ret}${i}`, - } - }), - ) - } else { - this.genBindings.push( - ...Array.from({ length: 30 }, (_, i) => { - return { - source: `(${leftBin}${i} + ${rightBin}${i} - 2 * (${leftBin}${i} * ${rightBin}${i}))`, - target: `${ret}${i}`, - } - }), - ) - } - - this.genBindings.push({ - source: `(${Array.from({ length: 30 }, (_, i) => `(${ret}${i} * ${2 ** i})`).join(" + ")})`, - target: ret, - }) - - left = ret - } - - return left + // TODO + return this.parseBitwiseShiftExpression() } private parseBitwiseShiftExpression(): Expression { - let left = this.parsePrimaryExpression(), - current - - while ( - (current = this.at()) && - this.at()?.kind === TokenKind.OPERATOR && - [">>", "<<"].includes(current.value) - ) { - 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 === "<<" ? "-" : "+" - - this.genBindings.push( - ...Array.from({ length: 30 }, (_, i) => { - return { - source: `((0 * ${left}) + ('${leftBind}' + (${i} ${op} ${right})))`, - target: `${ret}${i}`, - } - }), - ) - - this.genBindings.push({ - source: `(${Array.from({ length: 30 }, (_, i) => `(${ret}${i} * ${2 ** i})`).join(" + ")})`, - target: ret, - }) - - left = ret - } - - return left + // TODO + return this.parsePrimaryExpression() } private parsePrimaryExpression(): Expression { @@ -307,7 +210,7 @@ export class Parser { return `(${value})` } - case TokenKind.NUMBER: { + case TokenKind.INT: { const numberToken = this.eat() switch (numberToken.value[1]) { @@ -390,7 +293,7 @@ export class Parser { } default: - this.expect(TokenKind.NUMBER, "Unexpected token!") + this.expect(TokenKind.INT, "Unexpected token!") } return left.value @@ -404,7 +307,7 @@ export class Parser { const args: Expression[] = [] if (this.at().kind === TokenKind.COMMA) { - this.expect(TokenKind.NUMBER, "Unexpected token!") + this.expect(TokenKind.INT, "Unexpected token!") } if (this.at().kind !== TokenKind.CLOSE_PARENTHESIS) { @@ -413,7 +316,7 @@ export class Parser { while (this.at().kind === TokenKind.COMMA) { this.eat() if (this.at().kind === TokenKind.CLOSE_PARENTHESIS) { - this.expect(TokenKind.NUMBER, "Unexpected token!") + this.expect(TokenKind.INT, "Unexpected token!") } args.push(this.parseExpression()) } diff --git a/src/compilers/bindings/types.ts b/src/compilers/bindings/types.ts index 183f809..8b59f10 100644 --- a/src/compilers/bindings/types.ts +++ b/src/compilers/bindings/types.ts @@ -1,10 +1,12 @@ export enum TokenKind { VARIABLE, - NUMBER, STRING, TEMPLATE_STRING, WORD, + INT, + FLOAT, + OPEN_PARENTHESIS, CLOSE_PARENTHESIS, diff --git a/src/compilers/ui/builder.ts b/src/compilers/ui/builder.ts index 3803494..e06cb11 100644 --- a/src/compilers/ui/builder.ts +++ b/src/compilers/ui/builder.ts @@ -67,6 +67,7 @@ if (isBuildMode) { let first = true process.on("beforeExit", async () => { if (first) { + first = false await createBuildFolder() await buildUI() if (isLinkMode) await linkToGame() @@ -85,7 +86,6 @@ if (isBuildMode) { console.log("Install Path:", `\x1b[32m"${path.join(gamePath, await getBuildFolderName())}"\x1b[0m`) console.log("=============================================================") } - first = false }) } else if (isLinkMode) linkToGame() else if (unLinked) unlink() diff --git a/src/components/UI.ts b/src/components/UI.ts index f622d16..7deee84 100644 --- a/src/components/UI.ts +++ b/src/components/UI.ts @@ -169,7 +169,7 @@ export class UI extends Class if (this.controls.size) { obj.controls = [] - this.controls.forEach((e, key) => obj.controls.push({ [key + e[0]]: e[1] })) + this.controls.forEach((e, key) => obj.controls.push({ [key + e[0]]: FormatProperties(e[1]) })) } return obj diff --git a/src/index.ts b/src/index.ts index cd215b2..5a642f4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,4 +15,4 @@ export { ItemAuxID } from "./types/enums/Items.js" export { ArrayName, Operation } from "./types/properties/index.js" -export { Lexer } from "./compilers/bindings/Lexer.js" +export * from "./compilers/bindings/Binary.js"