refactor: temporarily remove bitwise operations

This commit is contained in:
Asaki Yuki 2026-02-05 13:36:33 +07:00
parent 635285b8d0
commit 3c0f9b31c6
9 changed files with 192 additions and 184 deletions

View file

@ -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,
}
}

View file

@ -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<string, Callback>
Object.entries(defaultFunctions).forEach(([key, value]) => FunctionMap.set(key, value))

View file

@ -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))

View file

@ -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(<string>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(<string>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())
}

View file

@ -1,10 +1,12 @@
export enum TokenKind {
VARIABLE,
NUMBER,
STRING,
TEMPLATE_STRING,
WORD,
INT,
FLOAT,
OPEN_PARENTHESIS,
CLOSE_PARENTHESIS,

View file

@ -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()