pure-dango 1.8.0
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/LICENSE.md +21 -0
- package/package.json +45 -0
- package/src/core/compiler.ts +1269 -0
- package/src/core/interpreter.ts +2042 -0
- package/src/core/parser/handlers.ts +1091 -0
- package/src/core/parser/helpers.ts +157 -0
- package/src/core/parser/main.ts +620 -0
- package/src/core/tokenizer/funnies.ts +43 -0
- package/src/core/tokenizer/tokenizer.ts +334 -0
- package/src/core/utils.ts +534 -0
- package/src/index.ts +190 -0
- package/src/runtime/errors.ts +239 -0
- package/src/runtime/globals.ts +11 -0
- package/src/runtime/libs/ai.pds +56 -0
- package/src/runtime/libs/errors.pds +74 -0
- package/src/runtime/libs/gambling.pds +93 -0
- package/src/runtime/libs/io.pds +371 -0
- package/src/runtime/libs/math.pds +86 -0
- package/src/runtime/libs/std.pds +2 -0
- package/src/runtime/libs/types.pds +1232 -0
- package/src/runtime/stdlib.ts +1483 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import {runtimeErrors, utilsErrors} from "../runtime/errors";
|
|
4
|
+
|
|
5
|
+
import {GF, isGFloat} from "./interpreter";
|
|
6
|
+
import {errorTemplate} from "../runtime/stdlib";
|
|
7
|
+
|
|
8
|
+
type RuntimeState =
|
|
9
|
+
{
|
|
10
|
+
time: number
|
|
11
|
+
}
|
|
12
|
+
type Bytecode = Array<string | number>;
|
|
13
|
+
type CacheFolder = string;
|
|
14
|
+
|
|
15
|
+
export const formatParameter = (parameter : any) : string =>
|
|
16
|
+
{
|
|
17
|
+
let result = parameter.rest ?
|
|
18
|
+
`...${parameter.name}`
|
|
19
|
+
: parameter.name;
|
|
20
|
+
|
|
21
|
+
if (parameter.default)
|
|
22
|
+
result += ` = ${generateOrigin(parameter.default, 0)}`;
|
|
23
|
+
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const functionOrigin = (node : any, padding : string) : string =>
|
|
28
|
+
{
|
|
29
|
+
const indent = padding.length;
|
|
30
|
+
const parameters = node.parameters.map(formatParameter).join(", ");
|
|
31
|
+
if (node.body.length === 0)
|
|
32
|
+
return `${padding}function ${node.name ? node.name : ""}(${parameters}) {}`;
|
|
33
|
+
|
|
34
|
+
return `${padding}function ${node.name ? node.name : ""}(${parameters}) {\n` +
|
|
35
|
+
`${node.body.map((child : any) => generateOrigin(child, indent + 4)).join("\n")}\n` +
|
|
36
|
+
`${padding}}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const binaryOrigin = (node : any, padding : string) : string =>
|
|
40
|
+
{
|
|
41
|
+
return `${padding}${generateOrigin(node.left, 0)} ${node.operator} ${generateOrigin(node.right, 0)}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const origins : Record<string, Function> = Object.freeze({
|
|
45
|
+
FunctionExpression : (node : any, padding : string) : string => functionOrigin(node, padding),
|
|
46
|
+
FunctionDeclaration : (node : any, padding : string) : string => functionOrigin(node, padding),
|
|
47
|
+
|
|
48
|
+
Literal : (node : any, padding : string) : string => `${padding}${node.value}`,
|
|
49
|
+
StringLiteral: (node: any, padding: string): string =>
|
|
50
|
+
{
|
|
51
|
+
const escaped = node.value
|
|
52
|
+
.replace(/\\/g, "\\\\")
|
|
53
|
+
.replace(/\n/g, "\\n")
|
|
54
|
+
.replace(/\t/g, "\\t")
|
|
55
|
+
.replace(/\r/g, "\\r")
|
|
56
|
+
.replace(/"/g, '\\"');
|
|
57
|
+
return `${padding}"${escaped}"`;
|
|
58
|
+
},
|
|
59
|
+
VariableReference : (node : any, padding : string) : string => `${padding}${node.value}`,
|
|
60
|
+
|
|
61
|
+
ArrayLiteral : (node : any, padding : string) : string => `${padding}[${node.elements.map((element : any) => generateOrigin(element, 0)).join(", ")}]`,
|
|
62
|
+
ArrayAccess : (node : any, padding : string) : string => `${padding}${generateOrigin(node.object, 0)}[${generateOrigin(node.index, 0)}]`,
|
|
63
|
+
ObjectLiteral : (node : any, padding : string) : string =>
|
|
64
|
+
`${padding}{\n` +
|
|
65
|
+
node.properties
|
|
66
|
+
.map((property : {key: string, value : any}) =>
|
|
67
|
+
`${property.key}: ${generateOrigin(property.value, 0)}`
|
|
68
|
+
)
|
|
69
|
+
.join(", ") +
|
|
70
|
+
`}`,
|
|
71
|
+
|
|
72
|
+
ClassDeclaration : (node : any, padding : string) : string =>
|
|
73
|
+
{
|
|
74
|
+
const methods: string = node.methods
|
|
75
|
+
.map((method: any) => {
|
|
76
|
+
const indent = padding.length + 4;
|
|
77
|
+
const pad = " ".repeat(indent);
|
|
78
|
+
|
|
79
|
+
const parameters = method.parameters.map(formatParameter).join(", "); // was node.parameters
|
|
80
|
+
|
|
81
|
+
if (method.body.length === 0)
|
|
82
|
+
return `${pad}${method.name}(${parameters}) {}`;
|
|
83
|
+
|
|
84
|
+
return `${pad}${method.name}(${parameters}) {\n` +
|
|
85
|
+
method.body.map((child: any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
86
|
+
`\n${pad}}`;
|
|
87
|
+
})
|
|
88
|
+
.join("\n\n");
|
|
89
|
+
|
|
90
|
+
const properties: string = (node.properties ?? [])
|
|
91
|
+
.slice(1)
|
|
92
|
+
.map((property: any) => {
|
|
93
|
+
const indent = padding.length + 4;
|
|
94
|
+
const pad = " ".repeat(indent);
|
|
95
|
+
|
|
96
|
+
if (property.value?.type === "FunctionExpression")
|
|
97
|
+
{
|
|
98
|
+
const parameters = property.value.parameters.map(formatParameter).join(", ");
|
|
99
|
+
if (property.value.body.length === 0)
|
|
100
|
+
return `${pad}${property.key}(${parameters}) {}`;
|
|
101
|
+
|
|
102
|
+
return `${pad}${property.key}(${parameters}) {\n` +
|
|
103
|
+
property.value.body.map((child: any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
104
|
+
`\n${pad}}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return `${pad}${property.key}: ${generateOrigin(property.value, 0)}`;
|
|
108
|
+
})
|
|
109
|
+
.join("\n\n");
|
|
110
|
+
|
|
111
|
+
return `${padding}${node.name} {\n` +
|
|
112
|
+
`${methods ? methods + "\n" : ""}` +
|
|
113
|
+
`${properties ? properties + "\n" : ""}` +
|
|
114
|
+
`${padding}}`;
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
MethodCall : (node : any, padding : string) : string =>
|
|
118
|
+
`${padding}${generateOrigin(node.object, 0)}.${node.property}(${node.args.map((a : any) => generateOrigin(a, 0)).join(", ")})`,
|
|
119
|
+
|
|
120
|
+
ClassInstantiation : (node : any, padding: string) =>
|
|
121
|
+
{
|
|
122
|
+
return `${padding}new ${node.variableName} = inst ${node.className}(${node.args.map((x : any) => generateOrigin(x, 0)).join(", ")})`
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
MemberExpression : (node : any, padding : string) : string => `${padding}${generateOrigin(node.object, 0)}.${node.property}`,
|
|
126
|
+
|
|
127
|
+
Assignment : (node : any, padding : string) : string =>
|
|
128
|
+
{
|
|
129
|
+
const isCompound : boolean =
|
|
130
|
+
(node.value.type === "BinaryExpression" || node.value.type === "LogicalExpression") &&
|
|
131
|
+
node.value.left?.type === "VariableReference" &&
|
|
132
|
+
node.value.left?.value === node.name;
|
|
133
|
+
const operator : string = isCompound ? (node.value.operator + "=") : "=";
|
|
134
|
+
const value : any = isCompound ? generateOrigin(node.value.right, 0) : generateOrigin(node.value, 0);
|
|
135
|
+
|
|
136
|
+
const target : string = typeof node.name === "string" ? node.name : generateOrigin(node.name, 0);
|
|
137
|
+
return `${padding}${target} ${operator} ${value};`;
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
NewAssignment : (node : any, padding : string) : string =>
|
|
141
|
+
{
|
|
142
|
+
const isCompound: boolean =
|
|
143
|
+
(node.value.type === "BinaryExpression" || node.value.type === "LogicalExpression") &&
|
|
144
|
+
node.value.left?.type === "VariableReference" &&
|
|
145
|
+
node.value.left?.value === node.name;
|
|
146
|
+
const operator : string = isCompound ? (node.value.operator + "=") : "=";
|
|
147
|
+
const value : any = isCompound ? generateOrigin(node.value.right, 0) : generateOrigin(node.value, 0);
|
|
148
|
+
|
|
149
|
+
const target : string = typeof node.name === "string" ? node.name : generateOrigin(node.name, 0);
|
|
150
|
+
return `${padding}new ${target} ${operator} ${value};`;
|
|
151
|
+
},
|
|
152
|
+
NewDeclaration : (node : any, padding : string) : string => `${padding}new ${node.name};`,
|
|
153
|
+
|
|
154
|
+
UnaryExpression : (node : any, padding : string) : string => `${padding}${node.value === "-u" || node.value === "+u" ? node.value[0] : node.value}${generateOrigin(node.argument, 0)}`,
|
|
155
|
+
PostfixUnaryExpression : (node : any, padding : string) : string => `${padding}${generateOrigin(node.argument, 0)}${node.operator}`,
|
|
156
|
+
BinaryExpression : (node : any, padding : string) : string => binaryOrigin(node, padding),
|
|
157
|
+
LogicalExpression : (node : any, padding : string) : string => binaryOrigin(node, padding),
|
|
158
|
+
|
|
159
|
+
IfStatement : (node : any, padding : string) : string =>
|
|
160
|
+
{
|
|
161
|
+
const indent : number = padding.length;
|
|
162
|
+
const elseBlock : string = node.else
|
|
163
|
+
? `\n${padding}else {\n` +
|
|
164
|
+
`${Array.isArray(node.else) ? generateOrigin(node.else[0], indent + 4) : generateOrigin(node.else, indent + 4)}` +
|
|
165
|
+
`\n${padding}}`
|
|
166
|
+
: "";
|
|
167
|
+
|
|
168
|
+
return `${padding}if (${generateOrigin(node.condition, 0)}) {\n` +
|
|
169
|
+
node.body.map((child : any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
170
|
+
`\n${padding}}\n` +
|
|
171
|
+
elseBlock;
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
TernaryExpression : (node : any, padding : string) : string => `${padding}${generateOrigin(node.condition, 0)} ? ${generateOrigin(node.then, 0)} : ${generateOrigin(node.else, 0)}`,
|
|
175
|
+
|
|
176
|
+
ForStatement : (node : any, padding : string) : string =>
|
|
177
|
+
{
|
|
178
|
+
const indent = padding.length;
|
|
179
|
+
|
|
180
|
+
const initial = generateOrigin(node.initial, 0)?.replace(/;$/, "") ?? "";
|
|
181
|
+
const condition = generateOrigin(node.condition, 0) ?? "";
|
|
182
|
+
const update = generateOrigin(node.update, 0)?.replace(/;$/, "") ?? "";
|
|
183
|
+
return `${padding}for (${initial}; ${condition}; ${update}) {\n` +
|
|
184
|
+
node.body.map((child : any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
185
|
+
`\n${padding}}`
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
ForInStatement : (node : any, padding : string) : string =>
|
|
189
|
+
{
|
|
190
|
+
const indent = padding.length;
|
|
191
|
+
return `${padding}for (${node.left} in ${generateOrigin(node.right, 0)}) {\n` +
|
|
192
|
+
node.body.map((child : any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
193
|
+
`\n${padding}}`;
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
ForOfStatement : (node : any, padding : string) : string =>
|
|
197
|
+
{
|
|
198
|
+
const indent = padding.length;
|
|
199
|
+
return `${padding}for (${node.left} of ${generateOrigin(node.right, 0)}) {\n` +
|
|
200
|
+
node.body.map((child : any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
201
|
+
`\n${padding}}`;
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
WhileStatement : (node : any, padding : string) : string =>
|
|
205
|
+
{
|
|
206
|
+
const indent = padding.length;
|
|
207
|
+
return `${padding}while (${generateOrigin(node.condition, 0)}) {\n` +
|
|
208
|
+
node.body.map((child : any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
209
|
+
`\n${padding}}`
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
DoWhileStatement : (node : any, padding : string) : string =>
|
|
213
|
+
{
|
|
214
|
+
const indent = padding.length;
|
|
215
|
+
return `${padding}do {\n` +
|
|
216
|
+
node.body.map((child : any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
217
|
+
`\n${padding}} while (${generateOrigin(node.condition, 0)});`;
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
TryStatement : (node : any, padding : string) : string =>
|
|
221
|
+
{
|
|
222
|
+
const indent = padding.length;
|
|
223
|
+
|
|
224
|
+
const tryBlock = node.tryBlock.map((child : any) => generateOrigin(child, indent + 4)).join("\n");
|
|
225
|
+
const catchBlock = node.catchBlock.map((child : any) => generateOrigin(child, indent + 4)).join("\n");
|
|
226
|
+
const finallyBlock = node.finallyBlock
|
|
227
|
+
? `\n${padding}finally {\n` +
|
|
228
|
+
node.finallyBlock.map((child : any) => generateOrigin(child, indent + 4)).join("\n") +
|
|
229
|
+
`\n${padding}}`
|
|
230
|
+
: "";
|
|
231
|
+
|
|
232
|
+
return `${padding}try {\n` +
|
|
233
|
+
`${tryBlock}\n` +
|
|
234
|
+
`${padding}} catch (${node.errorVariable}) {` +
|
|
235
|
+
`\n${catchBlock}\n` +
|
|
236
|
+
`${padding}}` +
|
|
237
|
+
`${finallyBlock}`;
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
SwitchStatement : (node : any, padding : string) : string =>
|
|
241
|
+
{
|
|
242
|
+
const indent = padding.length;
|
|
243
|
+
const pad = " ".repeat(indent + 4);
|
|
244
|
+
|
|
245
|
+
const cases = node.cases.map((child : any) =>
|
|
246
|
+
`${pad}case ${generateOrigin(child.test, 0)}:\n` +
|
|
247
|
+
child.consequent.map((statement: any) => generateOrigin(statement, indent + 8)).join("\n")
|
|
248
|
+
).join("\n");
|
|
249
|
+
|
|
250
|
+
const defaultCase = node.defaultCase
|
|
251
|
+
? `\n${pad}default:\n` +
|
|
252
|
+
node.defaultCase.consequent.map((statement: any) => generateOrigin(statement, indent + 8)).join("\n")
|
|
253
|
+
: "";
|
|
254
|
+
|
|
255
|
+
return `${padding}switch (${generateOrigin(node.discriminant, 0)}) {` +
|
|
256
|
+
`\n${cases}${defaultCase}\n` +
|
|
257
|
+
`${padding}}`;
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
FunctionCall : (node : any, padding : string) : string => `${padding}${node.name}(${node.args.map((argument : any) => generateOrigin(argument, 0)).join(", ")})`,
|
|
261
|
+
ReturnStatement : (node : any, padding : string) : string => `${padding}return${node.argument ? " " + generateOrigin(node.argument, 0) : ""};`,
|
|
262
|
+
|
|
263
|
+
BreakStatement : (node : any, padding : string) : string => `${padding}break;`,
|
|
264
|
+
ContinueStatement : (node : any, padding : string) : string => `${padding}continue;`,
|
|
265
|
+
|
|
266
|
+
ImportStatement : (node : any, padding : string) : string => `${padding}import "${node.path}";`
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
export const generateOrigin = (node : any, indent = 0) : string | null =>
|
|
270
|
+
{
|
|
271
|
+
if (!node)
|
|
272
|
+
return null;
|
|
273
|
+
|
|
274
|
+
const padding = " ".repeat(indent); // get the padding
|
|
275
|
+
const func = origins[node.type];
|
|
276
|
+
|
|
277
|
+
if (func)
|
|
278
|
+
return func(node, padding);
|
|
279
|
+
throw new runtimeErrors.InternalError(`No origin generator for node type "${node.type}"`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// stdlib
|
|
283
|
+
export const maxArguments = (maxLength: number, list: any[], name: string) : void =>
|
|
284
|
+
{
|
|
285
|
+
let plural = maxLength === 1 ? "argument": "arguments";
|
|
286
|
+
if (list.length > maxLength)
|
|
287
|
+
throw new utilsErrors.FunctionArgumentError(name, maxLength, plural);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export const bigIntPow = (base: bigint, exponent: bigint) : bigint | any =>
|
|
291
|
+
{
|
|
292
|
+
if (exponent < 0n)
|
|
293
|
+
return GF(base.toString()).inner.pow(GF(exponent.toString()));
|
|
294
|
+
if (exponent === 0n && base === 0n)
|
|
295
|
+
errorTemplate("bigIntPow", `0n raised to 0n can't be evaluated`);
|
|
296
|
+
if (exponent === 0n)
|
|
297
|
+
return 1n;
|
|
298
|
+
|
|
299
|
+
let result = 1n;
|
|
300
|
+
while (exponent > 0n)
|
|
301
|
+
{
|
|
302
|
+
if ((exponent & 1n) === 1n) result *= base; // use exponentiation by squaring. "(exponent & 1) === 1n" checks if the exponent is an odd number
|
|
303
|
+
base *= base;
|
|
304
|
+
exponent >>= 1n; // integer division operator
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export const typeHandler = (item: any) : string =>
|
|
311
|
+
{
|
|
312
|
+
if (item.isInstance)
|
|
313
|
+
{
|
|
314
|
+
if (item.properties["0"])
|
|
315
|
+
return format(item.properties["0"])!;
|
|
316
|
+
|
|
317
|
+
const properties = Object.entries(item.properties ?? {})
|
|
318
|
+
.filter(([key]) => key !== "0") // filter out __INIT__
|
|
319
|
+
.map(([key, value]) => ` ${key}: ${format(value)}`)
|
|
320
|
+
.join(",\n ");
|
|
321
|
+
|
|
322
|
+
const methods = Object.values(item.methods ?? {})
|
|
323
|
+
.filter((method : any) => method.name !== "constructor")
|
|
324
|
+
.map((method : any) => ` ${method.name}(${method.parameters.map((parameter: any) => parameter.name).join(", ")})`)
|
|
325
|
+
.join("\n");
|
|
326
|
+
|
|
327
|
+
const hasContent = properties || methods;
|
|
328
|
+
return hasContent
|
|
329
|
+
? `${item.class} {\n${properties ? properties + "\n" : ""}${methods ? methods + "\n" : ""}}`
|
|
330
|
+
: `${item.class} {}`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
switch (item.type)
|
|
334
|
+
{
|
|
335
|
+
case "object":
|
|
336
|
+
{
|
|
337
|
+
const entries = Object.entries(item.value).map(([key, value]) => `${key}: ${format(value)}`).join(", ");
|
|
338
|
+
return `{${entries}}`;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
case "class":
|
|
342
|
+
{
|
|
343
|
+
const methods = Object.values(item.methods ?? {})
|
|
344
|
+
.filter((method: any) => method.name !== "constructor")
|
|
345
|
+
.map((method: any) => ` ${method.name}(${method.parameters.map((p: any) => p.name).join(", ")})`)
|
|
346
|
+
.join("\n");
|
|
347
|
+
|
|
348
|
+
const properties = Object.entries(item.properties ?? {})
|
|
349
|
+
.filter(([key]) => key !== "0")
|
|
350
|
+
.map(([key, value]: [string, any]) => {
|
|
351
|
+
if (typeof value === "function" || value?.bytecode)
|
|
352
|
+
return ` ${key}(${(value.parameters ?? []).map((p: any) => p.name).join(", ")})`;
|
|
353
|
+
return ` ${key}: ${value}`;
|
|
354
|
+
})
|
|
355
|
+
.join("\n");
|
|
356
|
+
|
|
357
|
+
return `${item.name ?? "unknown"} {\n` +
|
|
358
|
+
`${methods ? methods + "\n" : ""}` +
|
|
359
|
+
`${properties ? properties + "\n" : ""}` +
|
|
360
|
+
`}`;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
default:
|
|
364
|
+
{
|
|
365
|
+
throw new runtimeErrors.InternalError(`Type of "${item}" is not implemented in typeHandler`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export const format = (item: any) : string | null =>
|
|
371
|
+
{
|
|
372
|
+
if (item === null || item === undefined)
|
|
373
|
+
return item;
|
|
374
|
+
|
|
375
|
+
if (isGFloat(item))
|
|
376
|
+
return item.inner.toString();
|
|
377
|
+
|
|
378
|
+
if (Array.isArray(item))
|
|
379
|
+
return "[" +
|
|
380
|
+
item.map(x =>
|
|
381
|
+
{
|
|
382
|
+
const formatted : any = format(x);
|
|
383
|
+
return formatted;
|
|
384
|
+
}).join(", ") + "]";
|
|
385
|
+
|
|
386
|
+
if (item.type)
|
|
387
|
+
return typeHandler(item);
|
|
388
|
+
|
|
389
|
+
if (typeof item === "object")
|
|
390
|
+
return generateOrigin(item.ast)?.replace(/\\/g, "\\\\")!;
|
|
391
|
+
|
|
392
|
+
return item;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// FON (FormatObjectNotation) is a version of format designed for console.dir()
|
|
396
|
+
export const FON = (item: any) : any =>
|
|
397
|
+
{
|
|
398
|
+
if (item === null || item === undefined)
|
|
399
|
+
return item;
|
|
400
|
+
|
|
401
|
+
if (typeof item === "number" || typeof item === "bigint")
|
|
402
|
+
return item;
|
|
403
|
+
if (isGFloat(item))
|
|
404
|
+
return item.toString();
|
|
405
|
+
if (Array.isArray(item))
|
|
406
|
+
return item.map(FON);
|
|
407
|
+
|
|
408
|
+
if (item?.type === "object")
|
|
409
|
+
{
|
|
410
|
+
const result : Record<any, any> = {};
|
|
411
|
+
for (const [key, value] of Object.entries(item.value))
|
|
412
|
+
result[key] = FON(value);
|
|
413
|
+
return result;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (item?.isInstance)
|
|
417
|
+
{
|
|
418
|
+
const inner: Record<string, any> = {};
|
|
419
|
+
for (const [key, value] of Object.entries(item.properties ?? {}))
|
|
420
|
+
{
|
|
421
|
+
if (key.startsWith("__") && key.endsWith("__"))
|
|
422
|
+
continue;
|
|
423
|
+
inner[key] = FON(value);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const wrapper: Record<string, any> = {};
|
|
427
|
+
wrapper[item.class] = inner;
|
|
428
|
+
return wrapper;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (item?.type === "class")
|
|
432
|
+
return `[class ${item.name}]`;
|
|
433
|
+
|
|
434
|
+
if (item?.bytecode)
|
|
435
|
+
return `[function ${item.name ?? "<anonymous>"}]`;
|
|
436
|
+
|
|
437
|
+
return item.toString();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export const joinStrings = (list: any[]) : string =>
|
|
441
|
+
{
|
|
442
|
+
return list.reduce((joined, item) => joined + format(item), "");
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// index
|
|
446
|
+
export const run = async (functionToRun: Function, state: RuntimeState, ...args: any[]) : Promise<any> =>
|
|
447
|
+
{
|
|
448
|
+
const start : number = performance.now();
|
|
449
|
+
const output : any = await functionToRun(...args);
|
|
450
|
+
const end : number = performance.now();
|
|
451
|
+
const duration : number = end - start;
|
|
452
|
+
|
|
453
|
+
state.time += duration;
|
|
454
|
+
|
|
455
|
+
return output;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const printResult = (name: string, value: any) : void =>
|
|
459
|
+
{
|
|
460
|
+
console.log(`${name}:`);
|
|
461
|
+
console.dir(value, {depth: null, colors: true});
|
|
462
|
+
console.log("\n");
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export const printResults = (results: object) : void =>
|
|
466
|
+
{
|
|
467
|
+
for (const [name, value] of Object.entries(results)) if (value !== null) printResult(`${name}`, value);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export const saveBytecode = (cacheFolder: CacheFolder, bytecode: Bytecode, srcFile: string, srcMTime: number) : void =>
|
|
471
|
+
{
|
|
472
|
+
const outFile = path.join(cacheFolder, path.basename(srcFile, ".pds") + ".pdbc");
|
|
473
|
+
fs.writeFileSync(
|
|
474
|
+
outFile,
|
|
475
|
+
JSON.stringify(
|
|
476
|
+
{
|
|
477
|
+
version: 1,
|
|
478
|
+
source: path.basename(srcFile),
|
|
479
|
+
bytecode,
|
|
480
|
+
mtime: srcMTime
|
|
481
|
+
},
|
|
482
|
+
null,
|
|
483
|
+
2,
|
|
484
|
+
)
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
export const loadBytecode = (cacheFolder: string, srcFile: string) : Bytecode | null =>
|
|
489
|
+
{
|
|
490
|
+
const inFile = path.join(cacheFolder, path.basename(srcFile, ".pds") + ".pdbc");
|
|
491
|
+
|
|
492
|
+
if (!fs.existsSync(inFile))
|
|
493
|
+
return null;
|
|
494
|
+
|
|
495
|
+
const data = JSON.parse(fs.readFileSync(inFile, "utf-8"));
|
|
496
|
+
const stats = fs.statSync(srcFile);
|
|
497
|
+
const srcMTime = stats.mtimeMs;
|
|
498
|
+
|
|
499
|
+
if (data.version !== 1 || data.mtime !== srcMTime)
|
|
500
|
+
{
|
|
501
|
+
console.log("recompile");
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return data.bytecode;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export const interpretEscapeCharacters = (str: string): string =>
|
|
509
|
+
{
|
|
510
|
+
return String(str).replace(
|
|
511
|
+
/\\(x[0-9a-fA-F]{1,4}|u[0-9a-fA-F]{1,4}|[0-7]{1,3}|.)/g,
|
|
512
|
+
(match, character) =>
|
|
513
|
+
{
|
|
514
|
+
if (character.startsWith('x'))
|
|
515
|
+
return String.fromCharCode(parseInt(character.slice(1), 16));
|
|
516
|
+
if (character.startsWith('u'))
|
|
517
|
+
return String.fromCharCode(parseInt(character.slice(1), 16));
|
|
518
|
+
if (/^[0-7]{1,3}$/.test(character))
|
|
519
|
+
return String.fromCharCode(parseInt(character, 8));
|
|
520
|
+
switch (character)
|
|
521
|
+
{
|
|
522
|
+
case "n": return "\n";
|
|
523
|
+
case "t": return "\t";
|
|
524
|
+
case "b": return "\b";
|
|
525
|
+
case "r": return "\r";
|
|
526
|
+
case '0': return "\0";
|
|
527
|
+
case "'": return "'";
|
|
528
|
+
case '"': return '"';
|
|
529
|
+
case "\\": return "\\";
|
|
530
|
+
default: return match;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
);
|
|
534
|
+
};
|