asajs 4.0.0-indev-1 → 4.0.0-indev-3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.d.ts +26 -0
- package/dist/js/compilers/Configuration.js +20 -1
- package/dist/js/compilers/Memory.js +1 -3
- package/dist/js/compilers/bindings/Checker.js +9 -0
- package/dist/js/compilers/bindings/Function.js +71 -0
- package/dist/js/compilers/bindings/Funtion.js +30 -6
- package/dist/js/compilers/bindings/Lexer.js +49 -6
- package/dist/js/compilers/bindings/Parser.js +152 -12
- package/dist/js/compilers/ui/buildcache.js +53 -0
- package/dist/js/compilers/ui/builddata.js +4 -0
- package/dist/js/compilers/ui/builder.js +30 -9
- package/dist/js/compilers/ui/installer.js +15 -1
- package/dist/js/compilers/ui/linker.js +43 -1
- package/dist/js/compilers/ui/manifest.js +25 -1
- package/dist/js/compilers/ui/prevdata.js +8 -0
- package/dist/js/components/AnimationKeyframe.js +1 -1
- package/dist/js/components/UI.js +25 -13
- package/dist/js/components/Utils.js +100 -23
- package/dist/js/config..js +1 -0
- package/dist/js/config.js +1 -0
- package/dist/js/index.js +4 -0
- package/dist/js/types/config.js +1 -0
- package/dist/types/compilers/Configuration.d.ts +5 -1
- package/dist/types/compilers/bindings/Checker.d.ts +3 -0
- package/dist/types/compilers/bindings/Function.d.ts +7 -0
- package/dist/types/compilers/bindings/Funtion.d.ts +1 -1
- package/dist/types/compilers/bindings/Parser.d.ts +12 -3
- package/dist/types/compilers/ui/buildcache.d.ts +8 -0
- package/dist/types/compilers/ui/builddata.d.ts +1 -0
- package/dist/types/compilers/ui/installer.d.ts +1 -1
- package/dist/types/compilers/ui/linker.d.ts +4 -0
- package/dist/types/compilers/ui/manifest.d.ts +1 -1
- package/dist/types/compilers/ui/prevdata.d.ts +3 -0
- package/dist/types/components/AnimationKeyframe.d.ts +4 -4
- package/dist/types/components/UI.d.ts +9 -2
- package/dist/types/components/Utils.d.ts +17 -16
- package/dist/types/config..d.ts +2 -0
- package/dist/types/config.d.ts +13 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/types/config.d.ts +13 -0
- package/dist/types/types/enums/index.d.ts +0 -1
- package/package.json +1 -1
- package/resources/asajs.config.cjs +14 -0
package/config.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Variable } from "./src/types/properties/value.ts"
|
|
2
|
+
|
|
3
|
+
export interface Config {
|
|
4
|
+
compiler?: {
|
|
5
|
+
enabled?: boolean
|
|
6
|
+
linked?: boolean
|
|
7
|
+
}
|
|
8
|
+
packinfo?: {
|
|
9
|
+
name?: string
|
|
10
|
+
description?: string
|
|
11
|
+
version?: [number, number, number]
|
|
12
|
+
|
|
13
|
+
metadata?: {
|
|
14
|
+
authors?: string[]
|
|
15
|
+
license?: string
|
|
16
|
+
url?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
subpacks?: {
|
|
20
|
+
folder_name?: string
|
|
21
|
+
name?: string
|
|
22
|
+
memory_performance_tier?: number
|
|
23
|
+
}[]
|
|
24
|
+
}
|
|
25
|
+
global_variables?: Record<Variable, string>
|
|
26
|
+
}
|
|
@@ -1 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
if (!fs.existsSync("asajs.config.cjs")) {
|
|
4
|
+
fs.copyFileSync("node_modules/asajs/resources/asajs.config.cjs", "asajs.config.cjs");
|
|
5
|
+
}
|
|
6
|
+
if (!fs.existsSync(".gitignore")) {
|
|
7
|
+
fs.writeFileSync(".gitignore", `node_modules`, "utf-8");
|
|
8
|
+
}
|
|
9
|
+
export const config = require(path.resolve(process.cwd(), "asajs.config.cjs")).config;
|
|
10
|
+
export let isBuildMode = config.compiler?.enabled ?? false;
|
|
11
|
+
export let isLinkMode = config.compiler?.linked ?? false;
|
|
12
|
+
export let unLinked = !(config.compiler?.linked ?? true);
|
|
13
|
+
for (const arg of process.argv) {
|
|
14
|
+
if (arg === "--build")
|
|
15
|
+
isBuildMode = true;
|
|
16
|
+
if (arg === "--link")
|
|
17
|
+
isLinkMode = true;
|
|
18
|
+
else if (arg === "--unlink")
|
|
19
|
+
unLinked = true;
|
|
20
|
+
}
|
|
@@ -22,9 +22,7 @@ export class Memory extends Class {
|
|
|
22
22
|
const data = new Map();
|
|
23
23
|
Memory.files.entries().forEach(([path, { elements, namespace }]) => {
|
|
24
24
|
const record = {};
|
|
25
|
-
elements.forEach(element =>
|
|
26
|
-
record[element.name] = element;
|
|
27
|
-
});
|
|
25
|
+
elements.forEach(element => (record[element.name] = element));
|
|
28
26
|
data.set(path, {
|
|
29
27
|
namespace,
|
|
30
28
|
...record,
|
|
@@ -7,6 +7,15 @@ export function isWordChar(char) {
|
|
|
7
7
|
export function isNumberChar(char) {
|
|
8
8
|
return /\d/.test(char);
|
|
9
9
|
}
|
|
10
|
+
export function isHexChar(char) {
|
|
11
|
+
return /[0-9a-fA-F]/.test(char);
|
|
12
|
+
}
|
|
13
|
+
export function isBinaryChar(char) {
|
|
14
|
+
return /[01]/.test(char);
|
|
15
|
+
}
|
|
16
|
+
export function isOctalChar(char) {
|
|
17
|
+
return /[0-7]/.test(char);
|
|
18
|
+
}
|
|
10
19
|
export function isCompileBinding(input) {
|
|
11
20
|
return input.startsWith("[") && input.endsWith("]");
|
|
12
21
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { RandomBindingString } from "../../components/Utils.js";
|
|
2
|
+
import { Parser } from "./Parser.js";
|
|
3
|
+
export const FunctionMap = new Map();
|
|
4
|
+
function callFn(name, ...args) {
|
|
5
|
+
return FunctionMap.get(name)(...args);
|
|
6
|
+
}
|
|
7
|
+
// Default Functions
|
|
8
|
+
FunctionMap.set("abs", number => {
|
|
9
|
+
const randomBinding = RandomBindingString(16);
|
|
10
|
+
return {
|
|
11
|
+
genBindings: [{ source: `((-1 + (${number} > 0) * 2) * ${number})`, target: randomBinding }],
|
|
12
|
+
value: randomBinding,
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
FunctionMap.set("new", expression => {
|
|
16
|
+
const randomBinding = RandomBindingString(16);
|
|
17
|
+
return {
|
|
18
|
+
genBindings: [{ source: expression, target: randomBinding }],
|
|
19
|
+
value: randomBinding,
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
FunctionMap.set("sqrt", number => {
|
|
23
|
+
const rtn = RandomBindingString(16), $1 = RandomBindingString(16), $2 = RandomBindingString(16);
|
|
24
|
+
const { genBindings: absValue, value: absRtn } = callFn("abs", number);
|
|
25
|
+
return {
|
|
26
|
+
genBindings: [
|
|
27
|
+
{
|
|
28
|
+
source: `${number} * 100 / 2`,
|
|
29
|
+
target: $1,
|
|
30
|
+
},
|
|
31
|
+
...absValue,
|
|
32
|
+
{
|
|
33
|
+
source: `${absRtn} > 1`,
|
|
34
|
+
target: $2,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
source: `(${number} < 0) * -1 + (${number} > -1) * (${$2} * ((${rtn} + ${number} / ${rtn}) / 2) + (not ${$2}) * ${rtn})`,
|
|
38
|
+
target: rtn,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
value: rtn,
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
FunctionMap.set("translatable", key => {
|
|
45
|
+
return {
|
|
46
|
+
value: `'%' + ${key}`,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
FunctionMap.set("bin", input => {
|
|
50
|
+
const { ret, bindings } = Parser.intToBin(input);
|
|
51
|
+
bindings.push({
|
|
52
|
+
source: `'§z' + ${Array.from({ length: 30 }, (_, i) => `${ret}${30 - i - 1}`).join(" + ")}`,
|
|
53
|
+
target: ret,
|
|
54
|
+
});
|
|
55
|
+
return { genBindings: bindings, value: ret };
|
|
56
|
+
});
|
|
57
|
+
FunctionMap.set("bind", (value, bait) => {
|
|
58
|
+
const ret = RandomBindingString(16);
|
|
59
|
+
if (!bait) {
|
|
60
|
+
throw new Error("Bait is required");
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
genBindings: [{ source: `((${bait} - ${bait}) + ${value})`, target: ret }],
|
|
64
|
+
value: ret,
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
FunctionMap.set("int", input => {
|
|
68
|
+
return {
|
|
69
|
+
value: input,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import { RandomBindingString } from "../../components/Utils.js";
|
|
2
|
-
|
|
2
|
+
import { Parser } from "./Parser.js";
|
|
3
|
+
export const FunctionMap = new Map();
|
|
3
4
|
function callFn(name, ...args) {
|
|
4
|
-
return
|
|
5
|
+
return FunctionMap.get(name)(...args);
|
|
5
6
|
}
|
|
6
7
|
// Default Functions
|
|
7
|
-
|
|
8
|
+
FunctionMap.set("abs", number => {
|
|
8
9
|
const randomBinding = RandomBindingString(16);
|
|
9
10
|
return {
|
|
10
11
|
genBindings: [{ source: `((-1 + (${number} > 0) * 2) * ${number})`, target: randomBinding }],
|
|
11
12
|
value: randomBinding,
|
|
12
13
|
};
|
|
13
14
|
});
|
|
14
|
-
|
|
15
|
+
FunctionMap.set("new", expression => {
|
|
15
16
|
const randomBinding = RandomBindingString(16);
|
|
16
17
|
return {
|
|
17
18
|
genBindings: [{ source: expression, target: randomBinding }],
|
|
18
19
|
value: randomBinding,
|
|
19
20
|
};
|
|
20
21
|
});
|
|
21
|
-
|
|
22
|
+
FunctionMap.set("sqrt", number => {
|
|
22
23
|
const rtn = RandomBindingString(16), $1 = RandomBindingString(16), $2 = RandomBindingString(16);
|
|
23
24
|
const { genBindings: absValue, value: absRtn } = callFn("abs", number);
|
|
24
25
|
return {
|
|
@@ -40,8 +41,31 @@ FuntionMap.set("sqrt", number => {
|
|
|
40
41
|
value: rtn,
|
|
41
42
|
};
|
|
42
43
|
});
|
|
43
|
-
|
|
44
|
+
FunctionMap.set("translatable", key => {
|
|
44
45
|
return {
|
|
45
46
|
value: `'%' + ${key}`,
|
|
46
47
|
};
|
|
47
48
|
});
|
|
49
|
+
FunctionMap.set("bin", input => {
|
|
50
|
+
const { ret, bindings } = Parser.intToBin(input);
|
|
51
|
+
bindings.push({
|
|
52
|
+
source: `'§z' + ${Array.from({ length: 30 }, (_, i) => `${ret}${30 - i - 1}`).join(" + ")}`,
|
|
53
|
+
target: ret,
|
|
54
|
+
});
|
|
55
|
+
return { genBindings: bindings, value: ret };
|
|
56
|
+
});
|
|
57
|
+
FunctionMap.set("bind", (value, bait) => {
|
|
58
|
+
const ret = RandomBindingString(16);
|
|
59
|
+
if (!bait) {
|
|
60
|
+
throw new Error("Bait is required");
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
genBindings: [{ source: `((${bait} - ${bait}) + ${value})`, target: ret }],
|
|
64
|
+
value: ret,
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
FunctionMap.set("int", input => {
|
|
68
|
+
return {
|
|
69
|
+
value: input,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
@@ -39,6 +39,7 @@ export function Lexer(input, start = 0, end) {
|
|
|
39
39
|
case "*":
|
|
40
40
|
case "/":
|
|
41
41
|
case "%":
|
|
42
|
+
case "^":
|
|
42
43
|
tokens.push(makeToken(input, TokenKind.OPERATOR, index));
|
|
43
44
|
break;
|
|
44
45
|
case "(":
|
|
@@ -53,18 +54,24 @@ export function Lexer(input, start = 0, end) {
|
|
|
53
54
|
case "=":
|
|
54
55
|
if (input[index + 1] === input[index])
|
|
55
56
|
tokens.push(makeToken(input, TokenKind.OPERATOR, index++, 2));
|
|
56
|
-
else
|
|
57
|
-
|
|
58
|
-
throw new Error();
|
|
59
|
-
}
|
|
57
|
+
else
|
|
58
|
+
tokens.push(makeToken(input, TokenKind.OPERATOR, index));
|
|
60
59
|
break;
|
|
61
60
|
case "!":
|
|
62
61
|
case ">":
|
|
63
62
|
case "<":
|
|
64
63
|
if (input[index + 1] === "=")
|
|
65
64
|
tokens.push(makeToken(input, TokenKind.OPERATOR, index++, 2));
|
|
66
|
-
else
|
|
67
|
-
|
|
65
|
+
else {
|
|
66
|
+
if (input[index] === input[index + 1]) {
|
|
67
|
+
if (input[index] !== "!")
|
|
68
|
+
tokens.push(makeToken(input, TokenKind.OPERATOR, index++, 2));
|
|
69
|
+
else
|
|
70
|
+
tokens.push(makeToken(input, TokenKind.OPERATOR, index));
|
|
71
|
+
}
|
|
72
|
+
else
|
|
73
|
+
tokens.push(makeToken(input, TokenKind.OPERATOR, index));
|
|
74
|
+
}
|
|
68
75
|
break;
|
|
69
76
|
// string
|
|
70
77
|
case "'": {
|
|
@@ -168,6 +175,42 @@ export function Lexer(input, start = 0, end) {
|
|
|
168
175
|
default: {
|
|
169
176
|
let start = index;
|
|
170
177
|
if (Checker.isNumberChar(token)) {
|
|
178
|
+
if (token === "0") {
|
|
179
|
+
const numType = input[index + 1];
|
|
180
|
+
if (numType === "x") {
|
|
181
|
+
index += 2;
|
|
182
|
+
while (Checker.isHexChar(input[index + 1]))
|
|
183
|
+
index++;
|
|
184
|
+
if (start + 2 === index) {
|
|
185
|
+
console.error(`\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`);
|
|
186
|
+
throw new Error();
|
|
187
|
+
}
|
|
188
|
+
tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1));
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
else if (numType === "b") {
|
|
192
|
+
index += 2;
|
|
193
|
+
while (Checker.isBinaryChar(input[index + 1]))
|
|
194
|
+
index++;
|
|
195
|
+
tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1));
|
|
196
|
+
if (start + 2 === index) {
|
|
197
|
+
console.error(`\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`);
|
|
198
|
+
throw new Error();
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
else if (numType === "o") {
|
|
203
|
+
index += 2;
|
|
204
|
+
while (Checker.isOctalChar(input[index + 1]))
|
|
205
|
+
index++;
|
|
206
|
+
tokens.push(makeToken(input, TokenKind.NUMBER, start, index - start + 1));
|
|
207
|
+
if (start + 2 === index) {
|
|
208
|
+
console.error(`\x1b[31merror: ${input + "\n" + " ".repeat(index + 6) + "^"}\nInvalid character.\x1b[0m`);
|
|
209
|
+
throw new Error();
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
171
214
|
while (Checker.isNumberChar(input[index + 1]))
|
|
172
215
|
index++;
|
|
173
216
|
if (input[index + 1] === "e") {
|
|
@@ -1,21 +1,55 @@
|
|
|
1
1
|
import { TokenKind, TSTokenKind } from "./types.js";
|
|
2
2
|
import { BindingType } from "../../types/enums/BindingType.js";
|
|
3
|
-
import {
|
|
3
|
+
import { FunctionMap } from "./Function.js";
|
|
4
4
|
import { Lexer } from "./Lexer.js";
|
|
5
|
+
import { RandomBindingString } from "../../components/Utils.js";
|
|
5
6
|
export class Parser {
|
|
6
7
|
input;
|
|
8
|
+
cache;
|
|
7
9
|
position = 0;
|
|
8
|
-
tokens;
|
|
9
10
|
genBindings = [];
|
|
10
11
|
output;
|
|
11
|
-
|
|
12
|
+
tokens;
|
|
13
|
+
constructor(input, cache = new Map(), tokens) {
|
|
12
14
|
this.input = input;
|
|
13
|
-
this.
|
|
15
|
+
this.cache = cache;
|
|
16
|
+
if (tokens) {
|
|
17
|
+
this.tokens = tokens;
|
|
18
|
+
tokens = undefined;
|
|
19
|
+
}
|
|
20
|
+
else
|
|
21
|
+
this.tokens = Lexer(input);
|
|
14
22
|
this.output = this.parseExpression();
|
|
15
23
|
if (this.at()) {
|
|
16
24
|
this.expect(TokenKind.EOF, "Unexpected token!");
|
|
17
25
|
}
|
|
18
26
|
}
|
|
27
|
+
static intToBin(input) {
|
|
28
|
+
const bindings = [];
|
|
29
|
+
const rtn = RandomBindingString(16);
|
|
30
|
+
for (let i = 0; i < 30; i++) {
|
|
31
|
+
bindings.push({
|
|
32
|
+
source: `(${input} / ${2 ** i} - (${input} / ${2 ** (i + 1)}) * 2)`,
|
|
33
|
+
target: `${rtn}${i}`,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
ret: rtn,
|
|
38
|
+
bindings,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
intToBin(input) {
|
|
42
|
+
const inStr = `expr:${input}`;
|
|
43
|
+
if (this.cache.has(inStr)) {
|
|
44
|
+
return this.cache.get(inStr);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const { ret, bindings } = Parser.intToBin(input);
|
|
48
|
+
this.cache.set(inStr, ret);
|
|
49
|
+
this.genBindings.push(...bindings);
|
|
50
|
+
return ret;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
19
53
|
at() {
|
|
20
54
|
return this.tokens[this.position];
|
|
21
55
|
}
|
|
@@ -81,19 +115,106 @@ export class Parser {
|
|
|
81
115
|
return left;
|
|
82
116
|
}
|
|
83
117
|
parseMultiplicativeExpression() {
|
|
84
|
-
let left = this.
|
|
118
|
+
let left = this.parseBitwiseLogicExpression(), current;
|
|
85
119
|
while ((current = this.at()) &&
|
|
86
120
|
this.at()?.kind === TokenKind.OPERATOR &&
|
|
87
121
|
["*", "/", "%"].includes(current.value)) {
|
|
88
122
|
const operator = this.eat();
|
|
89
123
|
const right = this.parsePrimaryExpression();
|
|
90
|
-
if (current.value === "%")
|
|
91
|
-
|
|
124
|
+
if (current.value === "%") {
|
|
125
|
+
const cacheStr = `expr:${left}${operator.value}${right}`;
|
|
126
|
+
if (this.cache.has(cacheStr)) {
|
|
127
|
+
return (left = this.cache.get(cacheStr));
|
|
128
|
+
}
|
|
129
|
+
const ret = RandomBindingString(16);
|
|
130
|
+
this.genBindings.push({
|
|
131
|
+
source: `(${left} - (${left} / ${right} * ${right}))`,
|
|
132
|
+
target: ret,
|
|
133
|
+
});
|
|
134
|
+
this.cache.set(cacheStr, ret);
|
|
135
|
+
left = ret;
|
|
136
|
+
}
|
|
92
137
|
else
|
|
93
138
|
left = `(${left} ${operator.value} ${right})`;
|
|
94
139
|
}
|
|
95
140
|
return left;
|
|
96
141
|
}
|
|
142
|
+
parseBitwiseLogicExpression() {
|
|
143
|
+
let left = this.parseBitwiseShiftExpression(), current;
|
|
144
|
+
while ((current = this.at()) &&
|
|
145
|
+
this.at()?.kind === TokenKind.OPERATOR &&
|
|
146
|
+
["&", "|", "^"].includes(current.value)) {
|
|
147
|
+
const operator = this.eat();
|
|
148
|
+
const right = this.parsePrimaryExpression();
|
|
149
|
+
const cacheStr = `expr:${left}${operator.value}${right}`;
|
|
150
|
+
if (this.cache.has(cacheStr)) {
|
|
151
|
+
return (left = this.cache.get(cacheStr));
|
|
152
|
+
}
|
|
153
|
+
const ret = RandomBindingString(16);
|
|
154
|
+
this.cache.set(cacheStr, ret);
|
|
155
|
+
const leftBin = this.intToBin(left);
|
|
156
|
+
const rightBin = this.intToBin(right);
|
|
157
|
+
if (operator.value === "&") {
|
|
158
|
+
this.genBindings.push(...Array.from({ length: 30 }, (_, i) => {
|
|
159
|
+
return {
|
|
160
|
+
source: `(${leftBin}${i} * ${rightBin}${i})`,
|
|
161
|
+
target: `${ret}${i}`,
|
|
162
|
+
};
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
else if (operator.value === "|") {
|
|
166
|
+
this.genBindings.push(...Array.from({ length: 30 }, (_, i) => {
|
|
167
|
+
return {
|
|
168
|
+
source: `(${leftBin}${i} + ${rightBin}${i} - (${leftBin}${i} * ${rightBin}${i}))`,
|
|
169
|
+
target: `${ret}${i}`,
|
|
170
|
+
};
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.genBindings.push(...Array.from({ length: 30 }, (_, i) => {
|
|
175
|
+
return {
|
|
176
|
+
source: `(${leftBin}${i} + ${rightBin}${i} - 2 * (${leftBin}${i} * ${rightBin}${i}))`,
|
|
177
|
+
target: `${ret}${i}`,
|
|
178
|
+
};
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
this.genBindings.push({
|
|
182
|
+
source: `(${Array.from({ length: 30 }, (_, i) => `(${ret}${i} * ${2 ** i})`).join(" + ")})`,
|
|
183
|
+
target: ret,
|
|
184
|
+
});
|
|
185
|
+
left = ret;
|
|
186
|
+
}
|
|
187
|
+
return left;
|
|
188
|
+
}
|
|
189
|
+
parseBitwiseShiftExpression() {
|
|
190
|
+
let left = this.parsePrimaryExpression(), current;
|
|
191
|
+
while ((current = this.at()) &&
|
|
192
|
+
this.at()?.kind === TokenKind.OPERATOR &&
|
|
193
|
+
[">>", "<<"].includes(current.value)) {
|
|
194
|
+
const operator = this.eat();
|
|
195
|
+
const right = this.parsePrimaryExpression();
|
|
196
|
+
const cacheStr = `expr:${left}${operator.value}${right}`;
|
|
197
|
+
if (this.cache.has(cacheStr)) {
|
|
198
|
+
return (left = this.cache.get(cacheStr));
|
|
199
|
+
}
|
|
200
|
+
const ret = RandomBindingString(16);
|
|
201
|
+
this.cache.set(cacheStr, ret);
|
|
202
|
+
const leftBind = this.intToBin(left);
|
|
203
|
+
const op = operator.value === "<<" ? "-" : "+";
|
|
204
|
+
this.genBindings.push(...Array.from({ length: 30 }, (_, i) => {
|
|
205
|
+
return {
|
|
206
|
+
source: `((0 * ${left}) + ('${leftBind}' + (${i} ${op} ${right})))`,
|
|
207
|
+
target: `${ret}${i}`,
|
|
208
|
+
};
|
|
209
|
+
}));
|
|
210
|
+
this.genBindings.push({
|
|
211
|
+
source: `(${Array.from({ length: 30 }, (_, i) => `(${ret}${i} * ${2 ** i})`).join(" + ")})`,
|
|
212
|
+
target: ret,
|
|
213
|
+
});
|
|
214
|
+
left = ret;
|
|
215
|
+
}
|
|
216
|
+
return left;
|
|
217
|
+
}
|
|
97
218
|
parsePrimaryExpression() {
|
|
98
219
|
const left = this.at();
|
|
99
220
|
switch (left?.kind) {
|
|
@@ -107,8 +228,18 @@ export class Parser {
|
|
|
107
228
|
return `(${value})`;
|
|
108
229
|
}
|
|
109
230
|
case TokenKind.NUMBER: {
|
|
110
|
-
const
|
|
111
|
-
|
|
231
|
+
const numberToken = this.eat();
|
|
232
|
+
switch (numberToken.value[1]) {
|
|
233
|
+
case "x":
|
|
234
|
+
return "" + parseInt(numberToken.value.slice(2), 16);
|
|
235
|
+
case "o":
|
|
236
|
+
return "" + parseInt(numberToken.value.slice(2), 8);
|
|
237
|
+
case "b":
|
|
238
|
+
return "" + parseInt(numberToken.value.slice(2), 2);
|
|
239
|
+
default:
|
|
240
|
+
const [num, exp] = numberToken.value.split("e");
|
|
241
|
+
return "" + (exp ? +num * 10 ** +exp : num);
|
|
242
|
+
}
|
|
112
243
|
}
|
|
113
244
|
case TokenKind.VARIABLE:
|
|
114
245
|
case TokenKind.STRING:
|
|
@@ -184,7 +315,15 @@ export class Parser {
|
|
|
184
315
|
}
|
|
185
316
|
}
|
|
186
317
|
this.eat();
|
|
187
|
-
|
|
318
|
+
const inputStr = `func:${callerToken.value}(${args.join(", ")})`;
|
|
319
|
+
if (this.cache.has(inputStr)) {
|
|
320
|
+
return this.cache.get(inputStr);
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
const ret = this.functionCall(callerToken.value, ...args);
|
|
324
|
+
this.cache.set(inputStr, ret);
|
|
325
|
+
return ret;
|
|
326
|
+
}
|
|
188
327
|
}
|
|
189
328
|
else if (left?.kind === TokenKind.OPERATOR) {
|
|
190
329
|
this.warn(`Implicit string literal '${callerToken.value}'. Use quoted string ('${callerToken.value}') for clarity!`, callerToken);
|
|
@@ -198,8 +337,8 @@ export class Parser {
|
|
|
198
337
|
return callerToken.value;
|
|
199
338
|
}
|
|
200
339
|
}
|
|
201
|
-
|
|
202
|
-
const func =
|
|
340
|
+
functionCall(name, ...params) {
|
|
341
|
+
const func = FunctionMap.get(name.toLowerCase());
|
|
203
342
|
if (!func) {
|
|
204
343
|
return this.expect(TokenKind.WORD, "Function not found!");
|
|
205
344
|
}
|
|
@@ -226,6 +365,7 @@ export class Parser {
|
|
|
226
365
|
out() {
|
|
227
366
|
return {
|
|
228
367
|
out: `(${this.output})`,
|
|
368
|
+
cache: this.cache,
|
|
229
369
|
gen: this.genBindings.map(({ source, target }) => ({
|
|
230
370
|
binding_type: BindingType.VIEW,
|
|
231
371
|
source_property_name: `(${source})`,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
export class BuildCache {
|
|
3
|
+
static queue = Promise.resolve();
|
|
4
|
+
static async enqueue(task) {
|
|
5
|
+
let result;
|
|
6
|
+
this.queue = this.queue.then(async () => {
|
|
7
|
+
result = await task();
|
|
8
|
+
});
|
|
9
|
+
return this.queue.then(() => result);
|
|
10
|
+
}
|
|
11
|
+
static async get(key) {
|
|
12
|
+
return this.enqueue(async () => {
|
|
13
|
+
try {
|
|
14
|
+
return await fs.readFile("build/cache.json", "utf-8").then(data => JSON.parse(data)[key] ?? null);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
static async getWithDefault(key, defaultValue) {
|
|
22
|
+
const outVal = typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
23
|
+
return this.get(key).then(value => value ?? outVal);
|
|
24
|
+
}
|
|
25
|
+
static async getWithSetDefault(key, defaultValue) {
|
|
26
|
+
const outVal = typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
27
|
+
return this.enqueue(async () => {
|
|
28
|
+
let data = {};
|
|
29
|
+
try {
|
|
30
|
+
data = JSON.parse(await fs.readFile("build/cache.json", "utf-8"));
|
|
31
|
+
}
|
|
32
|
+
catch { }
|
|
33
|
+
if (key in data)
|
|
34
|
+
return data[key];
|
|
35
|
+
data[key] = outVal;
|
|
36
|
+
await fs.writeFile("build/cache.json", JSON.stringify(data), "utf-8");
|
|
37
|
+
return outVal;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
static async set(key, value) {
|
|
41
|
+
return this.enqueue(async () => {
|
|
42
|
+
try {
|
|
43
|
+
return fs.writeFile("build/cache.json", JSON.stringify({
|
|
44
|
+
...(await fs.readFile("build/cache.json", "utf-8").then(data => JSON.parse(data))),
|
|
45
|
+
[key]: value,
|
|
46
|
+
}), "utf-8");
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return fs.writeFile("build/cache.json", JSON.stringify({ [key]: value }), "utf-8");
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -1,22 +1,37 @@
|
|
|
1
|
-
import { isBuildMode } from "../Configuration.js";
|
|
1
|
+
import { config, isBuildMode, isLinkMode, unLinked } from "../Configuration.js";
|
|
2
2
|
import { Memory } from "../Memory.js";
|
|
3
|
-
import { createBuildFolder } from "./linker.js";
|
|
3
|
+
import { createBuildFolder, linkToGame, unlink } from "./linker.js";
|
|
4
|
+
import { genManifest } from "./manifest.js";
|
|
4
5
|
import fs from "fs/promises";
|
|
6
|
+
import { BuildCache } from "./buildcache.js";
|
|
5
7
|
async function buildUI() {
|
|
6
8
|
const build = Memory.build();
|
|
7
|
-
|
|
8
|
-
build.set("ui/ui_defs.json", {
|
|
9
|
+
build.set("ui/_ui_defs.json", {
|
|
9
10
|
ui_defs: Array.from(build.keys()),
|
|
10
11
|
});
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
if (config.global_variables)
|
|
13
|
+
build.set("ui/_global_variables.json", config.global_variables);
|
|
14
|
+
const out = await Promise.all(build.entries().map(async ([file, value]) => {
|
|
15
|
+
const outFile = `build/${file}`;
|
|
13
16
|
await fs
|
|
14
17
|
.stat(outFile.split(/\\|\//g).slice(0, -1).join("/"))
|
|
15
18
|
.catch(async () => await fs.mkdir(outFile.split(/\\|\//g).slice(0, -1).join("/"), { recursive: true }));
|
|
16
|
-
await fs.writeFile(outFile, JSON.stringify(value),
|
|
17
|
-
|
|
19
|
+
await fs.writeFile(outFile, JSON.stringify(Object.fromEntries(Object.entries(value).map(([key, value]) => {
|
|
20
|
+
const extend = value.extend;
|
|
21
|
+
return [extend ? key + String(extend) : key, value];
|
|
22
|
+
}))), "utf-8");
|
|
23
|
+
build.delete(file);
|
|
24
|
+
return file;
|
|
18
25
|
}));
|
|
19
|
-
|
|
26
|
+
await Promise.all([
|
|
27
|
+
fs.writeFile("build/manifest.json", await genManifest(), "utf-8"),
|
|
28
|
+
fs.writeFile("build/.gitignore", [...out, "manifest.json"].join("\n"), "utf-8"),
|
|
29
|
+
BuildCache.set("build-files", [...out, "manifest.json"]),
|
|
30
|
+
fs
|
|
31
|
+
.stat("build/pack_icon.png")
|
|
32
|
+
.catch(() => fs.copyFile("node_modules/asajs/resources/pack_icon.png", "build/pack_icon.png")),
|
|
33
|
+
]);
|
|
34
|
+
return out.length;
|
|
20
35
|
}
|
|
21
36
|
if (isBuildMode) {
|
|
22
37
|
let first = true;
|
|
@@ -24,7 +39,13 @@ if (isBuildMode) {
|
|
|
24
39
|
if (first) {
|
|
25
40
|
await createBuildFolder();
|
|
26
41
|
await buildUI();
|
|
42
|
+
if (isLinkMode)
|
|
43
|
+
await linkToGame();
|
|
27
44
|
}
|
|
28
45
|
first = false;
|
|
29
46
|
});
|
|
30
47
|
}
|
|
48
|
+
else if (isLinkMode)
|
|
49
|
+
linkToGame();
|
|
50
|
+
else if (unLinked)
|
|
51
|
+
unlink();
|
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import os from "os";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export function getGamedataPath() {
|
|
4
|
+
switch (os.platform()) {
|
|
5
|
+
case "win32": {
|
|
6
|
+
if (/Windows (10|11)/.test(os.version())) {
|
|
7
|
+
return path.join(process.env.APPDATA, "Minecraft Bedrock\\Users\\Shared\\games\\com.mojang");
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
default: {
|
|
11
|
+
console.error(`Your platform is not supported the install feature yet! \nYour OS version: ${os.version()}`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|