@markw65/monkeyc-optimizer 1.0.44 → 1.0.45
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/README.md +18 -0
- package/build/api.cjs +905 -668
- package/build/optimizer.cjs +465 -214
- package/build/sdk-util.cjs +58 -0
- package/build/src/api.d.ts +3 -2
- package/build/src/ast.d.ts +26 -0
- package/build/src/data-flow.d.ts +45 -0
- package/build/src/function-info.d.ts +2 -0
- package/build/src/interp-binary.d.ts +4 -0
- package/build/src/interp-call.d.ts +3 -0
- package/build/src/interp.d.ts +23 -0
- package/build/src/jungles.d.ts +2 -1
- package/build/src/manifest.d.ts +1 -0
- package/build/src/mc-types.d.ts +166 -0
- package/build/src/optimizer-types.d.ts +12 -3
- package/build/src/pre.d.ts +1 -1
- package/build/src/projects.d.ts +2 -1
- package/build/src/type-flow.d.ts +4 -0
- package/build/src/util.d.ts +6 -1
- package/build/util.cjs +58 -2
- package/package.json +4 -3
package/build/api.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
0 && (module.exports = {checkCompilerVersion,collectNamespaces,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,hasProperty,isLookupCandidate,isStateNode,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
|
|
1
|
+
0 && (module.exports = {checkCompilerVersion,collectNamespaces,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,hasProperty,isLocal,isLookupCandidate,isStateNode,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
|
|
2
2
|
/******/ (() => { // webpackBootstrap
|
|
3
3
|
/******/ var __webpack_modules__ = ({
|
|
4
4
|
|
|
@@ -265,6 +265,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
265
265
|
"getApiFunctionInfo": () => (/* binding */ api_getApiFunctionInfo),
|
|
266
266
|
"getApiMapping": () => (/* binding */ api_getApiMapping),
|
|
267
267
|
"hasProperty": () => (/* reexport */ ast_hasProperty),
|
|
268
|
+
"isLocal": () => (/* binding */ api_isLocal),
|
|
268
269
|
"isLookupCandidate": () => (/* binding */ api_isLookupCandidate),
|
|
269
270
|
"isStateNode": () => (/* binding */ api_isStateNode),
|
|
270
271
|
"markInvokeClassMethod": () => (/* binding */ api_markInvokeClassMethod),
|
|
@@ -533,6 +534,64 @@ function ast_getNodeValue(node) {
|
|
|
533
534
|
}
|
|
534
535
|
throw new Error(`Literal has unknown type '${type}'`);
|
|
535
536
|
}
|
|
537
|
+
function wrap(node, loc) {
|
|
538
|
+
if (loc) {
|
|
539
|
+
node.loc = loc;
|
|
540
|
+
node.start = loc.start.offset;
|
|
541
|
+
node.end = loc.end.offset;
|
|
542
|
+
}
|
|
543
|
+
return node;
|
|
544
|
+
}
|
|
545
|
+
function locRange(start, end) {
|
|
546
|
+
return {
|
|
547
|
+
source: start.source || end.source,
|
|
548
|
+
start: start.start,
|
|
549
|
+
end: end.end,
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function adjustLoc(loc, start = 1, end = -1) {
|
|
553
|
+
return {
|
|
554
|
+
source: loc.source,
|
|
555
|
+
start: {
|
|
556
|
+
offset: loc.start.offset + start,
|
|
557
|
+
line: loc.start.line,
|
|
558
|
+
column: loc.start.column + start,
|
|
559
|
+
},
|
|
560
|
+
end: {
|
|
561
|
+
offset: loc.end.offset + end,
|
|
562
|
+
line: loc.end.line,
|
|
563
|
+
column: loc.end.column + end,
|
|
564
|
+
},
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function makeIdentifier(name, loc) {
|
|
568
|
+
return wrap({ type: "Identifier", name }, loc);
|
|
569
|
+
}
|
|
570
|
+
function makeMemberExpression(object, property) {
|
|
571
|
+
return wrap({
|
|
572
|
+
type: "MemberExpression",
|
|
573
|
+
object,
|
|
574
|
+
property,
|
|
575
|
+
computed: false,
|
|
576
|
+
}, object.loc && locRange(object.loc, property.loc));
|
|
577
|
+
}
|
|
578
|
+
function makeScopedName(dotted, l) {
|
|
579
|
+
const loc = l && adjustLoc(l, 0, l.start.offset - l.end.offset);
|
|
580
|
+
const result = dotted.split(/\s*\.\s*/).reduce(({ cur, offset }, next) => {
|
|
581
|
+
const id = makeIdentifier(next, loc && adjustLoc(loc, offset, offset + next.length));
|
|
582
|
+
if (!cur) {
|
|
583
|
+
cur = id;
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
cur = makeMemberExpression(cur, id);
|
|
587
|
+
}
|
|
588
|
+
offset += next.length + 1;
|
|
589
|
+
return { cur, offset };
|
|
590
|
+
}, { cur: null, offset: 0 }).cur;
|
|
591
|
+
if (!result)
|
|
592
|
+
throw new Error("Failed to make a ScopedName");
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
536
595
|
|
|
537
596
|
;// CONCATENATED MODULE: external "./api.cjs"
|
|
538
597
|
const external_api_cjs_namespaceObject = require("./api.cjs");
|
|
@@ -587,6 +646,8 @@ function function_info_recordCalledFuncs(func, callees) {
|
|
|
587
646
|
}
|
|
588
647
|
function function_info_functionMayModify(state, func, decl) {
|
|
589
648
|
const info = func.info;
|
|
649
|
+
if (info === false)
|
|
650
|
+
return false;
|
|
590
651
|
if (!info || info.modifiedUnknown)
|
|
591
652
|
return true;
|
|
592
653
|
if (info.resolvedDecls) {
|
|
@@ -599,7 +660,7 @@ function function_info_functionMayModify(state, func, decl) {
|
|
|
599
660
|
const visited = new Set();
|
|
600
661
|
const resolved = new Set();
|
|
601
662
|
const resolveDecls = (f) => {
|
|
602
|
-
if (visited.has(f))
|
|
663
|
+
if (f.info === false || visited.has(f))
|
|
603
664
|
return true;
|
|
604
665
|
if (!f.info)
|
|
605
666
|
return false;
|
|
@@ -661,6 +722,16 @@ function function_info_findCalleesForNew(lookupDefs) {
|
|
|
661
722
|
.flatMap(initializer)
|
|
662
723
|
.filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
|
|
663
724
|
}
|
|
725
|
+
function function_info_findCalleesByNode(state, callee) {
|
|
726
|
+
const name = callee.type === "Identifier"
|
|
727
|
+
? callee.name
|
|
728
|
+
: callee.type === "MemberExpression" && !callee.computed
|
|
729
|
+
? callee.property.name
|
|
730
|
+
: null;
|
|
731
|
+
if (!name)
|
|
732
|
+
return null;
|
|
733
|
+
return ((hasProperty(state.allFunctions, name) && state.allFunctions[name]) || null);
|
|
734
|
+
}
|
|
664
735
|
|
|
665
736
|
;// CONCATENATED MODULE: ./src/optimizer-types.ts
|
|
666
737
|
var optimizer_types_StateNodeAttributes;
|
|
@@ -1624,13 +1695,17 @@ function pragma_checker_pragmaChecker(state, ast, diagnostics) {
|
|
|
1624
1695
|
if (quote == '"') {
|
|
1625
1696
|
return haystack.includes(needle);
|
|
1626
1697
|
}
|
|
1627
|
-
const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/
|
|
1698
|
+
const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/\W/g, "_")}(?:_\\d+)?)`));
|
|
1628
1699
|
return re.test(haystack);
|
|
1629
1700
|
};
|
|
1630
1701
|
next();
|
|
1631
1702
|
traverseAst(ast, (node) => {
|
|
1632
|
-
if (index >= comments.length
|
|
1703
|
+
if (index >= comments.length ||
|
|
1704
|
+
node.type === "Line" ||
|
|
1705
|
+
node.type === "Block" ||
|
|
1706
|
+
node.type === "MultiLine") {
|
|
1633
1707
|
return false;
|
|
1708
|
+
}
|
|
1634
1709
|
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
1635
1710
|
const { kind, quote, needle } = matchers.shift();
|
|
1636
1711
|
if (kind === "match") {
|
|
@@ -1778,7 +1853,7 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
1778
1853
|
try {
|
|
1779
1854
|
const localState = new LocalState(func.node);
|
|
1780
1855
|
const ret = localState.curBlock;
|
|
1781
|
-
state.stack = func.stack;
|
|
1856
|
+
state.stack = [...func.stack];
|
|
1782
1857
|
const stmtStack = [func.node];
|
|
1783
1858
|
let tryActive = 0;
|
|
1784
1859
|
state.pre = (node) => {
|
|
@@ -1793,6 +1868,8 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
1793
1868
|
stmtStack.push(node);
|
|
1794
1869
|
}
|
|
1795
1870
|
switch (node.type) {
|
|
1871
|
+
case "FunctionDeclaration":
|
|
1872
|
+
return ["body"];
|
|
1796
1873
|
case "AttributeList":
|
|
1797
1874
|
return [];
|
|
1798
1875
|
case "SwitchStatement": {
|
|
@@ -2009,11 +2086,6 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
2009
2086
|
}
|
|
2010
2087
|
case "VariableDeclarator":
|
|
2011
2088
|
return ["init"];
|
|
2012
|
-
case "MemberExpression":
|
|
2013
|
-
if (!node.computed) {
|
|
2014
|
-
return ["object"];
|
|
2015
|
-
}
|
|
2016
|
-
break;
|
|
2017
2089
|
case "UnaryExpression":
|
|
2018
2090
|
if (node.operator === ":") {
|
|
2019
2091
|
return [];
|
|
@@ -2049,6 +2121,14 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
2049
2121
|
case "ContinueStatement":
|
|
2050
2122
|
localState.terminal(node.type);
|
|
2051
2123
|
return [];
|
|
2124
|
+
case "CallExpression":
|
|
2125
|
+
if (node.callee.type === "Identifier") {
|
|
2126
|
+
const extra = state.stack.splice(func.stack.length);
|
|
2127
|
+
state.traverse(node.callee);
|
|
2128
|
+
state.stack.push(...extra);
|
|
2129
|
+
return ["arguments"];
|
|
2130
|
+
}
|
|
2131
|
+
break;
|
|
2052
2132
|
}
|
|
2053
2133
|
return null;
|
|
2054
2134
|
};
|
|
@@ -2210,142 +2290,94 @@ function getPreOrder(head) {
|
|
|
2210
2290
|
|
|
2211
2291
|
// EXTERNAL MODULE: ./node_modules/priorityqueuejs/index.js
|
|
2212
2292
|
var priorityqueuejs = __webpack_require__(2789);
|
|
2213
|
-
;// CONCATENATED MODULE: ./src/
|
|
2293
|
+
;// CONCATENATED MODULE: ./src/data-flow.ts
|
|
2214
2294
|
|
|
2215
2295
|
|
|
2216
2296
|
|
|
2217
2297
|
|
|
2218
2298
|
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
* }
|
|
2230
|
-
*
|
|
2231
|
-
* and rewrite it as
|
|
2232
|
-
*
|
|
2233
|
-
* var tmp = A.B;
|
|
2234
|
-
* switch (x) {
|
|
2235
|
-
* case 1: foo(tmp); break;
|
|
2236
|
-
* case 2: foo(C); break;
|
|
2237
|
-
* case 3: bar(tmp); break;
|
|
2238
|
-
* }
|
|
2239
|
-
*
|
|
2240
|
-
* because even though A.B wasn't used on all paths where we
|
|
2241
|
-
* inserted the temporary, we still reduced the code size.
|
|
2242
|
-
*/
|
|
2243
|
-
const logging = false;
|
|
2244
|
-
function declFullName(decl) {
|
|
2299
|
+
|
|
2300
|
+
function data_flow_declFullName(decl) {
|
|
2301
|
+
if (Array.isArray(decl)) {
|
|
2302
|
+
decl = decl[0];
|
|
2303
|
+
}
|
|
2304
|
+
if (decl.type === "Literal") {
|
|
2305
|
+
return decl.raw || decl.value?.toString() || "null";
|
|
2306
|
+
}
|
|
2307
|
+
if (isStateNode(decl))
|
|
2308
|
+
return decl.fullName;
|
|
2245
2309
|
switch (decl.type) {
|
|
2246
|
-
case "
|
|
2247
|
-
return decl.
|
|
2248
|
-
case "
|
|
2249
|
-
return decl.
|
|
2310
|
+
case "BinaryExpression":
|
|
2311
|
+
return decl.left.name;
|
|
2312
|
+
case "EnumStringMember":
|
|
2313
|
+
return decl.init
|
|
2314
|
+
? `${decl.id.name}:${formatAst(decl.init)}`
|
|
2315
|
+
: decl.id.name;
|
|
2250
2316
|
default:
|
|
2251
2317
|
throw new Error(`Unexpected EventDecl type: ${decl.type}`);
|
|
2252
2318
|
}
|
|
2253
2319
|
}
|
|
2254
|
-
function
|
|
2320
|
+
function data_flow_declName(decl) {
|
|
2321
|
+
if (Array.isArray(decl)) {
|
|
2322
|
+
decl = decl[0];
|
|
2323
|
+
}
|
|
2324
|
+
if (decl.type === "Literal") {
|
|
2325
|
+
return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
|
|
2326
|
+
}
|
|
2327
|
+
if (isStateNode(decl))
|
|
2328
|
+
return decl.name;
|
|
2255
2329
|
switch (decl.type) {
|
|
2256
|
-
case "
|
|
2257
|
-
return
|
|
2258
|
-
case "
|
|
2259
|
-
return decl.name;
|
|
2330
|
+
case "BinaryExpression":
|
|
2331
|
+
return decl.left.name;
|
|
2332
|
+
case "EnumStringMember":
|
|
2333
|
+
return decl.id.name;
|
|
2260
2334
|
default:
|
|
2261
2335
|
throw new Error(`Unexpected EventDecl type: ${decl.type}`);
|
|
2262
2336
|
}
|
|
2263
2337
|
}
|
|
2264
|
-
function logAntState(s, decl) {
|
|
2265
|
-
const defs = Array.from(s.ant).reduce((defs, event) => {
|
|
2266
|
-
if (event.type === "def" || event.type === "mod")
|
|
2267
|
-
defs++;
|
|
2268
|
-
return defs;
|
|
2269
|
-
}, 0);
|
|
2270
|
-
console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
|
|
2271
|
-
console.log(` - members: ${Array.from(s.members)
|
|
2272
|
-
.map(([block, live]) => block.order + (live ? "t" : "f"))
|
|
2273
|
-
.join(", ")}`);
|
|
2274
|
-
}
|
|
2275
|
-
function logAntDecls(antDecls) {
|
|
2276
|
-
antDecls.forEach(logAntState);
|
|
2277
|
-
}
|
|
2278
|
-
function pre_sizeBasedPRE(state, func) {
|
|
2279
|
-
if (!func.node.body)
|
|
2280
|
-
return;
|
|
2281
|
-
if (!state.config ||
|
|
2282
|
-
!state.config.sizeBasedPRE ||
|
|
2283
|
-
(typeof state.config.sizeBasedPRE === "string" &&
|
|
2284
|
-
state.config.sizeBasedPRE !== func.fullName)) {
|
|
2285
|
-
return;
|
|
2286
|
-
}
|
|
2287
|
-
const { graph: head, identifiers } = buildPREGraph(state, func);
|
|
2288
|
-
const candidates = computeAttributes(state, head);
|
|
2289
|
-
if (candidates) {
|
|
2290
|
-
if (logging) {
|
|
2291
|
-
console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
|
|
2292
|
-
logAntDecls(candidates);
|
|
2293
|
-
}
|
|
2294
|
-
const nodeMap = new Map();
|
|
2295
|
-
const declMap = new Map();
|
|
2296
|
-
const variableDecl = withLoc({
|
|
2297
|
-
type: "VariableDeclaration",
|
|
2298
|
-
declarations: [],
|
|
2299
|
-
kind: "var",
|
|
2300
|
-
}, func.node.body);
|
|
2301
|
-
variableDecl.end = variableDecl.start;
|
|
2302
|
-
variableDecl.loc.end = variableDecl.loc.start;
|
|
2303
|
-
candidates.forEach((s, decl) => {
|
|
2304
|
-
let name;
|
|
2305
|
-
let i = 0;
|
|
2306
|
-
do {
|
|
2307
|
-
name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
|
|
2308
|
-
if (!identifiers.has(name)) {
|
|
2309
|
-
identifiers.add(name);
|
|
2310
|
-
break;
|
|
2311
|
-
}
|
|
2312
|
-
i++;
|
|
2313
|
-
} while (true);
|
|
2314
|
-
declMap.set(decl, name);
|
|
2315
|
-
variableDecl.declarations.push(withLoc({
|
|
2316
|
-
type: "VariableDeclarator",
|
|
2317
|
-
id: withLoc({ type: "Identifier", name }, variableDecl),
|
|
2318
|
-
kind: "var",
|
|
2319
|
-
}, variableDecl));
|
|
2320
|
-
s.ant.forEach((event) => {
|
|
2321
|
-
const events = nodeMap.get(event.node);
|
|
2322
|
-
if (!events) {
|
|
2323
|
-
nodeMap.set(event.node, [event]);
|
|
2324
|
-
}
|
|
2325
|
-
else {
|
|
2326
|
-
events.push(event);
|
|
2327
|
-
}
|
|
2328
|
-
});
|
|
2329
|
-
});
|
|
2330
|
-
applyReplacements(func.node, nodeMap, declMap);
|
|
2331
|
-
func.node.body.body.unshift(variableDecl);
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
2338
|
function unhandledExpression(node) {
|
|
2335
2339
|
throw new Error(`Unhandled expression type: ${node.type}`);
|
|
2336
2340
|
}
|
|
2337
|
-
function
|
|
2341
|
+
function data_flow_buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wantsAllRefs) {
|
|
2342
|
+
const uniqueDeclMap = new Map();
|
|
2338
2343
|
const findDecl = (node) => {
|
|
2339
2344
|
if (node.type === "Identifier" ||
|
|
2340
2345
|
(node.type === "MemberExpression" && !node.computed)) {
|
|
2341
2346
|
const [, results] = state.lookup(node);
|
|
2342
|
-
|
|
2343
|
-
results.
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2347
|
+
const decls = (results &&
|
|
2348
|
+
results.reduce((decls, result) => result.results.reduce((decls, result) => {
|
|
2349
|
+
if (!wantsAllRefs &&
|
|
2350
|
+
(result.type !== "VariableDeclarator" || isLocal(result))) {
|
|
2351
|
+
return decls;
|
|
2352
|
+
}
|
|
2353
|
+
if (!decls)
|
|
2354
|
+
return result;
|
|
2355
|
+
if (Array.isArray(decls)) {
|
|
2356
|
+
decls.push(result);
|
|
2357
|
+
return decls;
|
|
2358
|
+
}
|
|
2359
|
+
else {
|
|
2360
|
+
return [decls, result];
|
|
2361
|
+
}
|
|
2362
|
+
}, decls), null)) ||
|
|
2363
|
+
null;
|
|
2364
|
+
if (!Array.isArray(decls))
|
|
2365
|
+
return decls;
|
|
2366
|
+
// We use EventDecl as a Map key, so we need to
|
|
2367
|
+
// uniquify it. Note that from any given function,
|
|
2368
|
+
// if state.lookup finds a set of non locals, it will
|
|
2369
|
+
// always find the same set, so we can use the first
|
|
2370
|
+
// such as the unique identifier.
|
|
2371
|
+
const canon = uniqueDeclMap.get(decls[0]);
|
|
2372
|
+
if (!canon) {
|
|
2373
|
+
uniqueDeclMap.set(decls[0], decls);
|
|
2374
|
+
return decls;
|
|
2375
|
+
}
|
|
2376
|
+
if (canon.length != decls.length ||
|
|
2377
|
+
!canon.every((v, i) => v === decls[i])) {
|
|
2378
|
+
throw new Error(`Canonical representation of ${data_flow_declFullName(canon)} did not match`);
|
|
2379
|
+
}
|
|
2380
|
+
return canon;
|
|
2349
2381
|
}
|
|
2350
2382
|
return null;
|
|
2351
2383
|
};
|
|
@@ -2353,18 +2385,22 @@ function buildPREGraph(state, func) {
|
|
|
2353
2385
|
const identifiers = new Set();
|
|
2354
2386
|
const liveDefs = new Map();
|
|
2355
2387
|
const liveStmts = new Map();
|
|
2356
|
-
const liveDef =
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2388
|
+
const liveDef = trackInsertionPoints
|
|
2389
|
+
? (def, stmt) => {
|
|
2390
|
+
let curNodes = liveDefs.get(def);
|
|
2391
|
+
if (!curNodes) {
|
|
2392
|
+
liveDefs.set(def, (curNodes = new Set()));
|
|
2393
|
+
}
|
|
2394
|
+
curNodes.add(stmt);
|
|
2395
|
+
let defs = liveStmts.get(stmt);
|
|
2396
|
+
if (!defs) {
|
|
2397
|
+
liveStmts.set(stmt, (defs = new Map()));
|
|
2398
|
+
}
|
|
2399
|
+
defs.set(def, (defs.get(def) || 0) + 1);
|
|
2365
2400
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2401
|
+
: () => {
|
|
2402
|
+
/* do nothing */
|
|
2403
|
+
};
|
|
2368
2404
|
return {
|
|
2369
2405
|
identifiers,
|
|
2370
2406
|
graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
|
|
@@ -2378,7 +2414,7 @@ function buildPREGraph(state, func) {
|
|
|
2378
2414
|
}
|
|
2379
2415
|
const v = liveDefs.get(def);
|
|
2380
2416
|
if (!v || !v.has(node)) {
|
|
2381
|
-
throw new Error(`No stmt in liveDef for ${def ?
|
|
2417
|
+
throw new Error(`No stmt in liveDef for ${def ? data_flow_declFullName(def) : "null"}`);
|
|
2382
2418
|
}
|
|
2383
2419
|
v.delete(node);
|
|
2384
2420
|
if (!v.size) {
|
|
@@ -2399,7 +2435,7 @@ function buildPREGraph(state, func) {
|
|
|
2399
2435
|
case "ParenthesizedExpression":
|
|
2400
2436
|
break;
|
|
2401
2437
|
case "Literal":
|
|
2402
|
-
if (
|
|
2438
|
+
if (wantsLiteral(node)) {
|
|
2403
2439
|
const result = getNodeValue(node);
|
|
2404
2440
|
const key = result[1] +
|
|
2405
2441
|
(result[0].value === null
|
|
@@ -2421,34 +2457,40 @@ function buildPREGraph(state, func) {
|
|
|
2421
2457
|
case "Identifier":
|
|
2422
2458
|
identifiers.add(node.name);
|
|
2423
2459
|
// fall through
|
|
2424
|
-
case "MemberExpression":
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
if (
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2460
|
+
case "MemberExpression": {
|
|
2461
|
+
const decls = findDecl(node);
|
|
2462
|
+
if (!decls)
|
|
2463
|
+
break;
|
|
2464
|
+
if (trackInsertionPoints &&
|
|
2465
|
+
some(decls, (decl) => {
|
|
2466
|
+
if (decl.type === "VariableDeclarator") {
|
|
2467
|
+
const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
|
|
2468
|
+
liveDefs.get(decl);
|
|
2469
|
+
if (defStmts) {
|
|
2470
|
+
return true;
|
|
2471
|
+
/*
|
|
2472
|
+
// hold off on this for now. we need to communicate
|
|
2473
|
+
// which defs need to be fixed, which involves yet-another
|
|
2474
|
+
// table.
|
|
2475
|
+
|
|
2476
|
+
if (defStmts.size !== 1) break;
|
|
2477
|
+
const fixable = isFixableStmt([...defStmts][0]);
|
|
2478
|
+
if (fixable === false) break;
|
|
2479
|
+
cost += fixable;
|
|
2480
|
+
*/
|
|
2481
|
+
}
|
|
2442
2482
|
}
|
|
2443
|
-
return
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
decl,
|
|
2447
|
-
mayThrow,
|
|
2448
|
-
};
|
|
2449
|
-
}
|
|
2483
|
+
return false;
|
|
2484
|
+
})) {
|
|
2485
|
+
break;
|
|
2450
2486
|
}
|
|
2451
|
-
|
|
2487
|
+
return {
|
|
2488
|
+
type: "ref",
|
|
2489
|
+
node,
|
|
2490
|
+
decl: decls,
|
|
2491
|
+
mayThrow,
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2452
2494
|
case "VariableDeclarator": {
|
|
2453
2495
|
const decl = findDecl(node.id.type === "BinaryExpression" ? node.id.left : node.id);
|
|
2454
2496
|
if (decl) {
|
|
@@ -2496,8 +2538,10 @@ function buildPREGraph(state, func) {
|
|
|
2496
2538
|
}
|
|
2497
2539
|
case "CallExpression": {
|
|
2498
2540
|
liveDef(null, stmt);
|
|
2499
|
-
const [, results] = state.
|
|
2500
|
-
const callees = results
|
|
2541
|
+
const [, results] = state.lookupNonlocal(node.callee);
|
|
2542
|
+
const callees = results
|
|
2543
|
+
? findCallees(results)
|
|
2544
|
+
: findCalleesByNode(state, node.callee);
|
|
2501
2545
|
return { type: "mod", node, mayThrow, callees };
|
|
2502
2546
|
}
|
|
2503
2547
|
default:
|
|
@@ -2512,67 +2556,193 @@ function buildPREGraph(state, func) {
|
|
|
2512
2556
|
}),
|
|
2513
2557
|
};
|
|
2514
2558
|
}
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
if (a.size != b.size)
|
|
2520
|
-
return false;
|
|
2521
|
-
for (const item of a) {
|
|
2522
|
-
if (!b.has(item))
|
|
2523
|
-
return false;
|
|
2524
|
-
}
|
|
2525
|
-
return true;
|
|
2526
|
-
}
|
|
2527
|
-
function equalMap(a, b) {
|
|
2528
|
-
if (a.size != b.size)
|
|
2529
|
-
return false;
|
|
2530
|
-
for (const [item, value] of a) {
|
|
2531
|
-
if (b.get(item) !== value)
|
|
2532
|
-
return false;
|
|
2559
|
+
class data_flow_DataflowQueue {
|
|
2560
|
+
constructor() {
|
|
2561
|
+
this.enqueued = new Set();
|
|
2562
|
+
this.queue = new PriorityQueue((b, a) => (a.order || 0) - (b.order || 0));
|
|
2533
2563
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
}
|
|
2539
|
-
function cloneAnticipatedState(as) {
|
|
2540
|
-
return {
|
|
2541
|
-
ant: cloneSet(as.ant),
|
|
2542
|
-
live: as.live,
|
|
2543
|
-
node: as.node,
|
|
2544
|
-
members: new Map(as.members),
|
|
2545
|
-
};
|
|
2546
|
-
}
|
|
2547
|
-
function mergeAnticipatedState(ae, be) {
|
|
2548
|
-
mergeSet(ae.ant, be.ant);
|
|
2549
|
-
be.members.forEach((live, block) => ae.members.set(block, live));
|
|
2550
|
-
if (be.live)
|
|
2551
|
-
ae.live = true;
|
|
2552
|
-
}
|
|
2553
|
-
function cloneAnticipatedDecls(ad) {
|
|
2554
|
-
const copy = anticipatedDecls();
|
|
2555
|
-
for (const [k, v] of ad) {
|
|
2556
|
-
if (!v.isIsolated) {
|
|
2557
|
-
copy.set(k, cloneAnticipatedState(v));
|
|
2564
|
+
enqueue(block) {
|
|
2565
|
+
if (!this.enqueued.has(block)) {
|
|
2566
|
+
this.enqueued.add(block);
|
|
2567
|
+
this.queue.enq(block);
|
|
2558
2568
|
}
|
|
2559
2569
|
}
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
if (ae) {
|
|
2568
|
-
mergeAnticipatedState(ae, v);
|
|
2569
|
-
}
|
|
2570
|
-
else {
|
|
2571
|
-
a.set(k, cloneAnticipatedState(v));
|
|
2572
|
-
}
|
|
2570
|
+
dequeue() {
|
|
2571
|
+
const block = this.queue.deq();
|
|
2572
|
+
this.enqueued.delete(block);
|
|
2573
|
+
return block;
|
|
2574
|
+
}
|
|
2575
|
+
empty() {
|
|
2576
|
+
return this.queue.isEmpty();
|
|
2573
2577
|
}
|
|
2574
2578
|
}
|
|
2575
|
-
|
|
2579
|
+
|
|
2580
|
+
;// CONCATENATED MODULE: ./src/pre.ts
|
|
2581
|
+
|
|
2582
|
+
|
|
2583
|
+
|
|
2584
|
+
|
|
2585
|
+
|
|
2586
|
+
|
|
2587
|
+
/**
|
|
2588
|
+
* This implements a pseudo Partial Redundancy Elimination
|
|
2589
|
+
* pass. It isn't quite like traditional PRE because we're
|
|
2590
|
+
* aiming to minimize size, not dynamic instructions. So
|
|
2591
|
+
* for us, its worthwhile to take something like:
|
|
2592
|
+
*
|
|
2593
|
+
* switch (x) {
|
|
2594
|
+
* case 1: foo(A.B); break;
|
|
2595
|
+
* case 2: foo(C); break;
|
|
2596
|
+
* case 3: bar(A.B); break;
|
|
2597
|
+
* }
|
|
2598
|
+
*
|
|
2599
|
+
* and rewrite it as
|
|
2600
|
+
*
|
|
2601
|
+
* var tmp = A.B;
|
|
2602
|
+
* switch (x) {
|
|
2603
|
+
* case 1: foo(tmp); break;
|
|
2604
|
+
* case 2: foo(C); break;
|
|
2605
|
+
* case 3: bar(tmp); break;
|
|
2606
|
+
* }
|
|
2607
|
+
*
|
|
2608
|
+
* because even though A.B wasn't used on all paths where we
|
|
2609
|
+
* inserted the temporary, we still reduced the code size.
|
|
2610
|
+
*/
|
|
2611
|
+
const logging = false;
|
|
2612
|
+
function logAntState(s, decl) {
|
|
2613
|
+
const defs = Array.from(s.ant).reduce((defs, event) => {
|
|
2614
|
+
if (event.type === "def" || event.type === "mod")
|
|
2615
|
+
defs++;
|
|
2616
|
+
return defs;
|
|
2617
|
+
}, 0);
|
|
2618
|
+
console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
|
|
2619
|
+
console.log(` - members: ${Array.from(s.members)
|
|
2620
|
+
.map(([block, live]) => block.order + (live ? "t" : "f"))
|
|
2621
|
+
.join(", ")}`);
|
|
2622
|
+
}
|
|
2623
|
+
function logAntDecls(antDecls) {
|
|
2624
|
+
antDecls.forEach(logAntState);
|
|
2625
|
+
}
|
|
2626
|
+
function pre_sizeBasedPRE(state, func) {
|
|
2627
|
+
if (!func.node.body)
|
|
2628
|
+
return;
|
|
2629
|
+
if (!state.config ||
|
|
2630
|
+
!state.config.sizeBasedPRE ||
|
|
2631
|
+
(typeof state.config.sizeBasedPRE === "string" &&
|
|
2632
|
+
state.config.sizeBasedPRE !== func.fullName)) {
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
const { graph: head, identifiers } = buildPREGraph(state, func);
|
|
2636
|
+
const candidates = computeAttributes(state, head);
|
|
2637
|
+
if (candidates) {
|
|
2638
|
+
if (logging) {
|
|
2639
|
+
console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
|
|
2640
|
+
logAntDecls(candidates);
|
|
2641
|
+
}
|
|
2642
|
+
const nodeMap = new Map();
|
|
2643
|
+
const declMap = new Map();
|
|
2644
|
+
const variableDecl = withLoc({
|
|
2645
|
+
type: "VariableDeclaration",
|
|
2646
|
+
declarations: [],
|
|
2647
|
+
kind: "var",
|
|
2648
|
+
}, func.node.body);
|
|
2649
|
+
variableDecl.end = variableDecl.start;
|
|
2650
|
+
variableDecl.loc.end = variableDecl.loc.start;
|
|
2651
|
+
candidates.forEach((s, decl) => {
|
|
2652
|
+
let name;
|
|
2653
|
+
let i = 0;
|
|
2654
|
+
do {
|
|
2655
|
+
name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
|
|
2656
|
+
if (!identifiers.has(name)) {
|
|
2657
|
+
identifiers.add(name);
|
|
2658
|
+
break;
|
|
2659
|
+
}
|
|
2660
|
+
i++;
|
|
2661
|
+
} while (true);
|
|
2662
|
+
declMap.set(decl, name);
|
|
2663
|
+
variableDecl.declarations.push(withLoc({
|
|
2664
|
+
type: "VariableDeclarator",
|
|
2665
|
+
id: withLoc({ type: "Identifier", name }, variableDecl),
|
|
2666
|
+
kind: "var",
|
|
2667
|
+
}, variableDecl));
|
|
2668
|
+
s.ant.forEach((event) => {
|
|
2669
|
+
const events = nodeMap.get(event.node);
|
|
2670
|
+
if (!events) {
|
|
2671
|
+
nodeMap.set(event.node, [event]);
|
|
2672
|
+
}
|
|
2673
|
+
else {
|
|
2674
|
+
events.push(event);
|
|
2675
|
+
}
|
|
2676
|
+
});
|
|
2677
|
+
});
|
|
2678
|
+
applyReplacements(func.node, nodeMap, declMap);
|
|
2679
|
+
func.node.body.body.unshift(variableDecl);
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
function buildPREGraph(state, func) {
|
|
2683
|
+
return buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
|
|
2684
|
+
}
|
|
2685
|
+
function anticipatedDecls() {
|
|
2686
|
+
return new Map();
|
|
2687
|
+
}
|
|
2688
|
+
function equalSet(a, b) {
|
|
2689
|
+
if (a.size != b.size)
|
|
2690
|
+
return false;
|
|
2691
|
+
for (const item of a) {
|
|
2692
|
+
if (!b.has(item))
|
|
2693
|
+
return false;
|
|
2694
|
+
}
|
|
2695
|
+
return true;
|
|
2696
|
+
}
|
|
2697
|
+
function equalMap(a, b) {
|
|
2698
|
+
if (a.size != b.size)
|
|
2699
|
+
return false;
|
|
2700
|
+
for (const [item, value] of a) {
|
|
2701
|
+
if (b.get(item) !== value)
|
|
2702
|
+
return false;
|
|
2703
|
+
}
|
|
2704
|
+
return true;
|
|
2705
|
+
}
|
|
2706
|
+
function anticipatedState(node, events) {
|
|
2707
|
+
return { ant: events || new Set(), live: true, node, members: new Map() };
|
|
2708
|
+
}
|
|
2709
|
+
function cloneAnticipatedState(as) {
|
|
2710
|
+
return {
|
|
2711
|
+
ant: cloneSet(as.ant),
|
|
2712
|
+
live: as.live,
|
|
2713
|
+
node: as.node,
|
|
2714
|
+
members: new Map(as.members),
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
function mergeAnticipatedState(ae, be) {
|
|
2718
|
+
mergeSet(ae.ant, be.ant);
|
|
2719
|
+
be.members.forEach((live, block) => ae.members.set(block, live));
|
|
2720
|
+
if (be.live)
|
|
2721
|
+
ae.live = true;
|
|
2722
|
+
}
|
|
2723
|
+
function cloneAnticipatedDecls(ad) {
|
|
2724
|
+
const copy = anticipatedDecls();
|
|
2725
|
+
for (const [k, v] of ad) {
|
|
2726
|
+
if (!v.isIsolated) {
|
|
2727
|
+
copy.set(k, cloneAnticipatedState(v));
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
return copy;
|
|
2731
|
+
}
|
|
2732
|
+
function mergeAnticipatedDecls(a, b) {
|
|
2733
|
+
for (const [k, v] of b) {
|
|
2734
|
+
if (v.isIsolated)
|
|
2735
|
+
continue;
|
|
2736
|
+
const ae = a.get(k);
|
|
2737
|
+
if (ae) {
|
|
2738
|
+
mergeAnticipatedState(ae, v);
|
|
2739
|
+
}
|
|
2740
|
+
else {
|
|
2741
|
+
a.set(k, cloneAnticipatedState(v));
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
function equalStates(a, b) {
|
|
2576
2746
|
if (a.size !== b.size)
|
|
2577
2747
|
return false;
|
|
2578
2748
|
for (const [k, ae] of a) {
|
|
@@ -2667,26 +2837,18 @@ function computeAttributes(state, head) {
|
|
|
2667
2837
|
.join(", ")}`);
|
|
2668
2838
|
if (block.events) {
|
|
2669
2839
|
block.events.forEach((event) => event.type !== "exn" &&
|
|
2670
|
-
console.log(` ${event.type}: ${event.decl
|
|
2840
|
+
console.log(` ${event.type}: ${event.decl
|
|
2841
|
+
? declFullName(event.decl)
|
|
2842
|
+
: event.node
|
|
2843
|
+
? formatAst(event.node)
|
|
2844
|
+
: "??"}`));
|
|
2671
2845
|
}
|
|
2672
2846
|
console.log(`Succs: ${(block.succs || [])
|
|
2673
2847
|
.map((block) => block.order)
|
|
2674
2848
|
.join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
|
|
2675
2849
|
});
|
|
2676
2850
|
}
|
|
2677
|
-
const
|
|
2678
|
-
const queue = new PriorityQueue((b, a) => (a.order || 0) - (b.order || 0));
|
|
2679
|
-
const enqueue = (block) => {
|
|
2680
|
-
if (!enqueued.has(block)) {
|
|
2681
|
-
enqueued.add(block);
|
|
2682
|
-
queue.enq(block);
|
|
2683
|
-
}
|
|
2684
|
-
};
|
|
2685
|
-
const dequeue = () => {
|
|
2686
|
-
const block = queue.deq();
|
|
2687
|
-
enqueued.delete(block);
|
|
2688
|
-
return block;
|
|
2689
|
-
};
|
|
2851
|
+
const queue = new DataflowQueue();
|
|
2690
2852
|
const blockStates = [];
|
|
2691
2853
|
/*
|
|
2692
2854
|
Algorithm
|
|
@@ -2720,9 +2882,9 @@ function computeAttributes(state, head) {
|
|
|
2720
2882
|
}
|
|
2721
2883
|
return result;
|
|
2722
2884
|
};
|
|
2723
|
-
order.forEach((block) => enqueue(block));
|
|
2724
|
-
while (queue.
|
|
2725
|
-
const top = dequeue();
|
|
2885
|
+
order.forEach((block) => queue.enqueue(block));
|
|
2886
|
+
while (!queue.empty()) {
|
|
2887
|
+
const top = queue.dequeue();
|
|
2726
2888
|
if (top.order === undefined) {
|
|
2727
2889
|
throw new Error(`Unreachable block was visited!`);
|
|
2728
2890
|
}
|
|
@@ -2761,13 +2923,13 @@ function computeAttributes(state, head) {
|
|
|
2761
2923
|
break;
|
|
2762
2924
|
}
|
|
2763
2925
|
case "mod": {
|
|
2764
|
-
curState.forEach((candidates,
|
|
2765
|
-
if (decl.type === "VariableDeclarator" &&
|
|
2926
|
+
curState.forEach((candidates, decls) => {
|
|
2927
|
+
if (some(decls, (decl) => decl.type === "VariableDeclarator" &&
|
|
2766
2928
|
decl.node.kind === "var" &&
|
|
2767
2929
|
candidates.live &&
|
|
2768
2930
|
(!event.callees ||
|
|
2769
|
-
event.callees.some((callee) => functionMayModify(state, callee, decl)))) {
|
|
2770
|
-
candidates.ant.add(getMod(event,
|
|
2931
|
+
event.callees.some((callee) => functionMayModify(state, callee, decl))))) {
|
|
2932
|
+
candidates.ant.add(getMod(event, decls, candidates.node));
|
|
2771
2933
|
candidates.live = false;
|
|
2772
2934
|
}
|
|
2773
2935
|
});
|
|
@@ -2819,7 +2981,7 @@ function computeAttributes(state, head) {
|
|
|
2819
2981
|
logAntDecls(curState);
|
|
2820
2982
|
}
|
|
2821
2983
|
if (top.preds) {
|
|
2822
|
-
top.preds.forEach((pred) => enqueue(pred));
|
|
2984
|
+
top.preds.forEach((pred) => queue.enqueue(pred));
|
|
2823
2985
|
}
|
|
2824
2986
|
}
|
|
2825
2987
|
const candidateDecls = anticipatedDecls();
|
|
@@ -3658,8 +3820,21 @@ function replacementLiteral(arg, value, type) {
|
|
|
3658
3820
|
else if (type === "Double") {
|
|
3659
3821
|
raw += "d";
|
|
3660
3822
|
}
|
|
3661
|
-
else if (type === "Float"
|
|
3662
|
-
raw
|
|
3823
|
+
else if (type === "Float") {
|
|
3824
|
+
if (prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
|
|
3825
|
+
raw += "f";
|
|
3826
|
+
}
|
|
3827
|
+
else {
|
|
3828
|
+
const match = raw.match(/^(-)?(\d*)\.(\d+)(e\d+)?/);
|
|
3829
|
+
if (match && match[2].length + match[3].length > 9) {
|
|
3830
|
+
for (let l = 9 - match[2].length; l > 0; l--) {
|
|
3831
|
+
const s = `${match[1] || ""}${match[2]}.${match[3].substring(0, l)}${match[4] || ""}`;
|
|
3832
|
+
if (value !== roundToFloat(parseFloat(s)))
|
|
3833
|
+
break;
|
|
3834
|
+
raw = s;
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3663
3838
|
}
|
|
3664
3839
|
const { start, end, loc } = arg;
|
|
3665
3840
|
return {
|
|
@@ -3747,6 +3922,20 @@ function shift_mod_types(left, right) {
|
|
|
3747
3922
|
}
|
|
3748
3923
|
return result;
|
|
3749
3924
|
}
|
|
3925
|
+
function equalsFn(left, right) {
|
|
3926
|
+
const lt = typeof left;
|
|
3927
|
+
const rt = typeof right;
|
|
3928
|
+
return lt === "string" || rt === "string"
|
|
3929
|
+
? // two string literals will compare unequal, becuase string
|
|
3930
|
+
// equality is object equality.
|
|
3931
|
+
false
|
|
3932
|
+
: (lt === "number" || lt === "bigint") &&
|
|
3933
|
+
(rt === "number" || rt === "bigint")
|
|
3934
|
+
? // numeric types are compared for value equality
|
|
3935
|
+
left == right
|
|
3936
|
+
: // otherwise types and values must match
|
|
3937
|
+
left === right;
|
|
3938
|
+
}
|
|
3750
3939
|
const operators = {
|
|
3751
3940
|
"+": {
|
|
3752
3941
|
typeFn: plus_types,
|
|
@@ -3798,14 +3987,11 @@ const operators = {
|
|
|
3798
3987
|
},
|
|
3799
3988
|
"==": {
|
|
3800
3989
|
typeFn: () => ["Boolean", (v) => v],
|
|
3801
|
-
valueFn:
|
|
3802
|
-
// two string literals will compare unequal, becuase string
|
|
3803
|
-
// equality is object equality.
|
|
3804
|
-
typeof left === "string" ? false : left === right,
|
|
3990
|
+
valueFn: equalsFn,
|
|
3805
3991
|
},
|
|
3806
3992
|
"!=": {
|
|
3807
3993
|
typeFn: () => ["Boolean", (v) => v],
|
|
3808
|
-
valueFn: (left, right) =>
|
|
3994
|
+
valueFn: (left, right) => !equalsFn(left, right),
|
|
3809
3995
|
},
|
|
3810
3996
|
"<=": {
|
|
3811
3997
|
typeFn: common_arith_types,
|
|
@@ -4332,7 +4518,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
|
|
|
4332
4518
|
if (!state.currentFunction) {
|
|
4333
4519
|
throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
|
|
4334
4520
|
}
|
|
4335
|
-
state.currentFunction.info = state.currentFunction.next_info;
|
|
4521
|
+
state.currentFunction.info = state.currentFunction.next_info || false;
|
|
4336
4522
|
delete state.currentFunction.next_info;
|
|
4337
4523
|
delete state.currentFunction;
|
|
4338
4524
|
break;
|
|
@@ -4987,31 +5173,6 @@ function add_resources_to_ast(state, ast, resources, manifestXML) {
|
|
|
4987
5173
|
});
|
|
4988
5174
|
});
|
|
4989
5175
|
}
|
|
4990
|
-
function makeIdentifier(name, loc) {
|
|
4991
|
-
return wrap({ type: "Identifier", name }, loc);
|
|
4992
|
-
}
|
|
4993
|
-
function makeMemberExpression(object, property) {
|
|
4994
|
-
return wrap({
|
|
4995
|
-
type: "MemberExpression",
|
|
4996
|
-
object,
|
|
4997
|
-
property,
|
|
4998
|
-
computed: false,
|
|
4999
|
-
}, object.loc && locRange(object.loc, property.loc));
|
|
5000
|
-
}
|
|
5001
|
-
function makeScopedName(dotted, l) {
|
|
5002
|
-
const loc = l && adjustLoc(l, 0, l.start.offset - l.end.offset);
|
|
5003
|
-
return dotted.split(/\s*\.\s*/).reduce(({ cur, offset }, next) => {
|
|
5004
|
-
const id = makeIdentifier(next, loc && adjustLoc(loc, offset, offset + next.length));
|
|
5005
|
-
if (!cur) {
|
|
5006
|
-
cur = id;
|
|
5007
|
-
}
|
|
5008
|
-
else {
|
|
5009
|
-
cur = makeMemberExpression(cur, id);
|
|
5010
|
-
}
|
|
5011
|
-
offset += next.length + 1;
|
|
5012
|
-
return { cur, offset };
|
|
5013
|
-
}, { cur: null, offset: 0 }).cur;
|
|
5014
|
-
}
|
|
5015
5176
|
const drawableSkips = {
|
|
5016
5177
|
x: { center: true, left: true, right: true, start: true },
|
|
5017
5178
|
y: { center: true, top: true, bottom: true, start: true },
|
|
@@ -5051,10 +5212,8 @@ function visit_resource_refs(state, doc, e) {
|
|
|
5051
5212
|
if (ast_hasProperty(skip, name)) {
|
|
5052
5213
|
return;
|
|
5053
5214
|
}
|
|
5054
|
-
if (/^([
|
|
5055
|
-
|
|
5056
|
-
if (dn)
|
|
5057
|
-
result.push(dn);
|
|
5215
|
+
if (/^([-\w_$]+\s*\.\s*)*[-\w_$]+$/.test(name)) {
|
|
5216
|
+
result.push(makeScopedName(name, loc));
|
|
5058
5217
|
return;
|
|
5059
5218
|
}
|
|
5060
5219
|
// We wrap the expression in parentheses, so adjust
|
|
@@ -5154,37 +5313,6 @@ function visit_resource_refs(state, doc, e) {
|
|
|
5154
5313
|
});
|
|
5155
5314
|
return result;
|
|
5156
5315
|
}
|
|
5157
|
-
function wrap(node, loc) {
|
|
5158
|
-
if (loc) {
|
|
5159
|
-
node.loc = loc;
|
|
5160
|
-
node.start = loc.start.offset;
|
|
5161
|
-
node.end = loc.end.offset;
|
|
5162
|
-
}
|
|
5163
|
-
return node;
|
|
5164
|
-
}
|
|
5165
|
-
function locRange(start, end) {
|
|
5166
|
-
return {
|
|
5167
|
-
source: start.source || end.source,
|
|
5168
|
-
start: start.start,
|
|
5169
|
-
end: end.end,
|
|
5170
|
-
};
|
|
5171
|
-
}
|
|
5172
|
-
function adjustLoc(loc, start = 1, end = -1) {
|
|
5173
|
-
/* Attributes are quoted, so skip the quotes */
|
|
5174
|
-
return {
|
|
5175
|
-
source: loc.source,
|
|
5176
|
-
start: {
|
|
5177
|
-
offset: loc.start.offset + start,
|
|
5178
|
-
line: loc.start.line,
|
|
5179
|
-
column: loc.start.column + start,
|
|
5180
|
-
},
|
|
5181
|
-
end: {
|
|
5182
|
-
offset: loc.end.offset + end,
|
|
5183
|
-
line: loc.end.line,
|
|
5184
|
-
column: loc.end.column + end,
|
|
5185
|
-
},
|
|
5186
|
-
};
|
|
5187
|
-
}
|
|
5188
5316
|
function add_one_resource(state, doc, module, e) {
|
|
5189
5317
|
let id;
|
|
5190
5318
|
let func;
|
|
@@ -5196,7 +5324,20 @@ function add_one_resource(state, doc, module, e) {
|
|
|
5196
5324
|
wrap({
|
|
5197
5325
|
type: "VariableDeclarator",
|
|
5198
5326
|
kind: "var",
|
|
5199
|
-
id:
|
|
5327
|
+
id: {
|
|
5328
|
+
type: "BinaryExpression",
|
|
5329
|
+
operator: "as",
|
|
5330
|
+
left: makeIdentifier(id ? id.value.value : "*invalid*", loc),
|
|
5331
|
+
right: {
|
|
5332
|
+
type: "TypeSpecList",
|
|
5333
|
+
ts: [
|
|
5334
|
+
{
|
|
5335
|
+
type: "TypeSpecPart",
|
|
5336
|
+
name: makeIdentifier("Symbol"),
|
|
5337
|
+
},
|
|
5338
|
+
],
|
|
5339
|
+
},
|
|
5340
|
+
},
|
|
5200
5341
|
init,
|
|
5201
5342
|
}, e.loc),
|
|
5202
5343
|
],
|
|
@@ -5218,19 +5359,75 @@ function add_one_resource(state, doc, module, e) {
|
|
|
5218
5359
|
loc: e.loc,
|
|
5219
5360
|
};
|
|
5220
5361
|
};
|
|
5362
|
+
const layoutDecl = () => {
|
|
5363
|
+
if (!id)
|
|
5364
|
+
return null;
|
|
5365
|
+
const loc = id.value.loc;
|
|
5366
|
+
const items = init ? [varDecl()] : [];
|
|
5367
|
+
return {
|
|
5368
|
+
type: "FunctionDeclaration",
|
|
5369
|
+
body: { type: "BlockStatement", body: items, loc: e.loc },
|
|
5370
|
+
id: makeIdentifier(id.value.value, loc),
|
|
5371
|
+
params: [
|
|
5372
|
+
{
|
|
5373
|
+
type: "BinaryExpression",
|
|
5374
|
+
operator: "as",
|
|
5375
|
+
left: makeIdentifier("dc"),
|
|
5376
|
+
right: {
|
|
5377
|
+
type: "TypeSpecList",
|
|
5378
|
+
ts: [
|
|
5379
|
+
{
|
|
5380
|
+
type: "TypeSpecPart",
|
|
5381
|
+
name: makeScopedName("Graphics.Dc"),
|
|
5382
|
+
},
|
|
5383
|
+
],
|
|
5384
|
+
},
|
|
5385
|
+
},
|
|
5386
|
+
],
|
|
5387
|
+
returnType: {
|
|
5388
|
+
type: "UnaryExpression",
|
|
5389
|
+
operator: " as",
|
|
5390
|
+
prefix: true,
|
|
5391
|
+
argument: {
|
|
5392
|
+
type: "TypeSpecList",
|
|
5393
|
+
ts: [
|
|
5394
|
+
{
|
|
5395
|
+
type: "TypeSpecPart",
|
|
5396
|
+
name: makeScopedName("$.Toybox.Lang.Array"),
|
|
5397
|
+
generics: [
|
|
5398
|
+
{
|
|
5399
|
+
type: "TypeSpecList",
|
|
5400
|
+
ts: [
|
|
5401
|
+
{
|
|
5402
|
+
type: "TypeSpecPart",
|
|
5403
|
+
name: makeScopedName("$.Toybox.WatchUi.Drawable"),
|
|
5404
|
+
},
|
|
5405
|
+
],
|
|
5406
|
+
},
|
|
5407
|
+
],
|
|
5408
|
+
},
|
|
5409
|
+
],
|
|
5410
|
+
},
|
|
5411
|
+
},
|
|
5412
|
+
loc: e.loc,
|
|
5413
|
+
};
|
|
5414
|
+
};
|
|
5221
5415
|
switch (e.name) {
|
|
5222
5416
|
case "font":
|
|
5223
5417
|
case "string":
|
|
5224
5418
|
case "jsonData":
|
|
5225
5419
|
case "animation":
|
|
5226
5420
|
case "bitmap":
|
|
5227
|
-
case "layout":
|
|
5228
5421
|
case "drawable-list":
|
|
5229
5422
|
case "property":
|
|
5230
5423
|
case "fitField":
|
|
5231
5424
|
id = e.attr.id;
|
|
5232
5425
|
func = varDecl;
|
|
5233
5426
|
break;
|
|
5427
|
+
case "layout":
|
|
5428
|
+
id = e.attr.id;
|
|
5429
|
+
func = layoutDecl;
|
|
5430
|
+
break;
|
|
5234
5431
|
case "menu":
|
|
5235
5432
|
id = e.attr.id;
|
|
5236
5433
|
func = () => classDecl("Ui.Menu");
|
|
@@ -5820,387 +6017,423 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
|
|
|
5820
6017
|
}
|
|
5821
6018
|
return [false, false];
|
|
5822
6019
|
}
|
|
5823
|
-
function
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
},
|
|
5838
|
-
];
|
|
5839
|
-
}
|
|
5840
|
-
if (!state.lookupRules) {
|
|
5841
|
-
const rules = state?.config?.compilerLookupRules || "DEFAULT";
|
|
5842
|
-
if (rules !== "COMPILER1" && rules !== "COMPILER2") {
|
|
5843
|
-
const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
|
|
5844
|
-
if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
|
|
5845
|
-
state.lookupRules = "COMPILER2";
|
|
5846
|
-
}
|
|
5847
|
-
else {
|
|
5848
|
-
state.lookupRules = "COMPILER1";
|
|
5849
|
-
}
|
|
5850
|
-
}
|
|
5851
|
-
}
|
|
5852
|
-
state.removeNodeComments = (node, ast) => {
|
|
5853
|
-
if (node.start && node.end && ast.comments && ast.comments.length) {
|
|
5854
|
-
let low = 0, high = ast.comments.length;
|
|
5855
|
-
while (high > low) {
|
|
5856
|
-
const mid = (low + high) >> 1;
|
|
5857
|
-
if ((ast.comments[mid].start || 0) < node.start) {
|
|
5858
|
-
low = mid + 1;
|
|
6020
|
+
function stateFuncs() {
|
|
6021
|
+
let currentEnum = null;
|
|
6022
|
+
return {
|
|
6023
|
+
removeNodeComments(node, ast) {
|
|
6024
|
+
if (node.start && node.end && ast.comments && ast.comments.length) {
|
|
6025
|
+
let low = 0, high = ast.comments.length;
|
|
6026
|
+
while (high > low) {
|
|
6027
|
+
const mid = (low + high) >> 1;
|
|
6028
|
+
if ((ast.comments[mid].start || 0) < node.start) {
|
|
6029
|
+
low = mid + 1;
|
|
6030
|
+
}
|
|
6031
|
+
else {
|
|
6032
|
+
high = mid;
|
|
6033
|
+
}
|
|
5859
6034
|
}
|
|
5860
|
-
|
|
5861
|
-
high
|
|
6035
|
+
while (high < ast.comments.length &&
|
|
6036
|
+
(ast.comments[high].end || 0) < node.end) {
|
|
6037
|
+
high++;
|
|
6038
|
+
}
|
|
6039
|
+
if (high > low) {
|
|
6040
|
+
ast.comments.splice(low, high - low);
|
|
5862
6041
|
}
|
|
5863
6042
|
}
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
case "UnaryExpression":
|
|
5889
|
-
if (node.operator === ":" && !state.inType) {
|
|
5890
|
-
state.nextExposed[node.argument.name] = true;
|
|
5891
|
-
}
|
|
5892
|
-
break;
|
|
5893
|
-
case "AttributeList":
|
|
5894
|
-
return [];
|
|
5895
|
-
case "Program":
|
|
5896
|
-
if (state.stack.length != 1) {
|
|
5897
|
-
throw new Error("Unexpected stack length for Program node");
|
|
6043
|
+
},
|
|
6044
|
+
lookup(node, name, stack) {
|
|
6045
|
+
return lookup(this, this.inType ? "type_decls" : "decls", node, name, stack);
|
|
6046
|
+
},
|
|
6047
|
+
lookupNonlocal(node, name, stack) {
|
|
6048
|
+
return lookup(this, "decls", node, name, stack, true);
|
|
6049
|
+
},
|
|
6050
|
+
lookupValue(node, name, stack) {
|
|
6051
|
+
return lookup(this, "decls", node, name, stack);
|
|
6052
|
+
},
|
|
6053
|
+
lookupType(node, name, stack) {
|
|
6054
|
+
return lookup(this, "type_decls", node, name, stack);
|
|
6055
|
+
},
|
|
6056
|
+
stackClone() {
|
|
6057
|
+
return this.stack.map((elm) => elm.type === "ModuleDeclaration" || elm.type === "Program"
|
|
6058
|
+
? { ...elm }
|
|
6059
|
+
: elm);
|
|
6060
|
+
},
|
|
6061
|
+
traverse(root) {
|
|
6062
|
+
return ast_traverseAst(root, (node) => {
|
|
6063
|
+
try {
|
|
6064
|
+
if (this.shouldExclude && this.shouldExclude(node)) {
|
|
6065
|
+
// don't visit any children, but do call post
|
|
6066
|
+
return [];
|
|
5898
6067
|
}
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
case "ImportModule":
|
|
5906
|
-
case "Using": {
|
|
5907
|
-
const [parent] = state.stack.slice(-1);
|
|
5908
|
-
if (!parent.usings) {
|
|
5909
|
-
parent.usings = {};
|
|
5910
|
-
}
|
|
5911
|
-
const name = (node.type === "Using" && node.as && node.as.name) ||
|
|
5912
|
-
(node.id.type === "Identifier"
|
|
5913
|
-
? node.id.name
|
|
5914
|
-
: node.id.property.name);
|
|
5915
|
-
const using = { node };
|
|
5916
|
-
parent.usings[name] = using;
|
|
5917
|
-
if (node.type == "ImportModule") {
|
|
5918
|
-
if (!parent.imports) {
|
|
5919
|
-
parent.imports = [using];
|
|
6068
|
+
switch (node.type) {
|
|
6069
|
+
case "MemberExpression": {
|
|
6070
|
+
if (api_isLookupCandidate(node)) {
|
|
6071
|
+
return (this.pre && this.pre(node, this)) || ["object"];
|
|
6072
|
+
}
|
|
6073
|
+
break;
|
|
5920
6074
|
}
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
6075
|
+
case "UnaryExpression":
|
|
6076
|
+
if (node.operator === ":" && !this.inType) {
|
|
6077
|
+
this.nextExposed[node.argument.name] = true;
|
|
6078
|
+
}
|
|
6079
|
+
break;
|
|
6080
|
+
case "AttributeList":
|
|
6081
|
+
return [];
|
|
6082
|
+
case "Program":
|
|
6083
|
+
if (this.stack.length != 1) {
|
|
6084
|
+
throw new Error("Unexpected stack length for Program node");
|
|
6085
|
+
}
|
|
6086
|
+
this.stack[0].node = node;
|
|
6087
|
+
break;
|
|
6088
|
+
case "TypeSpecList":
|
|
6089
|
+
case "TypeSpecPart":
|
|
6090
|
+
this.inType++;
|
|
6091
|
+
break;
|
|
6092
|
+
case "ImportModule":
|
|
6093
|
+
case "Using": {
|
|
6094
|
+
const [parent] = this.stack.slice(-1);
|
|
6095
|
+
if (!parent.usings) {
|
|
6096
|
+
parent.usings = {};
|
|
6097
|
+
}
|
|
6098
|
+
const name = (node.type === "Using" && node.as && node.as.name) ||
|
|
6099
|
+
(node.id.type === "Identifier"
|
|
6100
|
+
? node.id.name
|
|
6101
|
+
: node.id.property.name);
|
|
6102
|
+
const using = { node };
|
|
6103
|
+
parent.usings[name] = using;
|
|
6104
|
+
if (node.type == "ImportModule") {
|
|
6105
|
+
if (!parent.imports) {
|
|
6106
|
+
parent.imports = [using];
|
|
6107
|
+
}
|
|
6108
|
+
else {
|
|
6109
|
+
const index = parent.imports.findIndex((using) => (using.node.id.type === "Identifier"
|
|
6110
|
+
? using.node.id.name
|
|
6111
|
+
: using.node.id.property.name) === name);
|
|
6112
|
+
if (index >= 0)
|
|
6113
|
+
parent.imports.splice(index, 1);
|
|
6114
|
+
parent.imports.push(using);
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
break;
|
|
5928
6118
|
}
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
if (parent.node === node ||
|
|
5964
|
-
(parent.type != "FunctionDeclaration" &&
|
|
5965
|
-
parent.type != "BlockStatement")) {
|
|
5966
|
-
break;
|
|
5967
|
-
}
|
|
5968
|
-
// fall through
|
|
5969
|
-
}
|
|
5970
|
-
case "ClassDeclaration":
|
|
5971
|
-
case "FunctionDeclaration":
|
|
5972
|
-
case "ModuleDeclaration": {
|
|
5973
|
-
const [parent] = state.stack.slice(-1);
|
|
5974
|
-
const name = "id" in node ? node.id && node.id.name : undefined;
|
|
5975
|
-
const fullName = state.stack
|
|
5976
|
-
.map((e) => e.name)
|
|
5977
|
-
.concat(name)
|
|
5978
|
-
.filter((e) => e != null)
|
|
5979
|
-
.join(".");
|
|
5980
|
-
const elm = {
|
|
5981
|
-
type: node.type,
|
|
5982
|
-
name,
|
|
5983
|
-
fullName,
|
|
5984
|
-
node,
|
|
5985
|
-
attributes: node.type === "BlockStatement"
|
|
5986
|
-
? 0
|
|
5987
|
-
: stateNodeAttrs(node.attrs),
|
|
5988
|
-
};
|
|
5989
|
-
state.stack.push(elm);
|
|
5990
|
-
if (name) {
|
|
5991
|
-
if (!parent.decls)
|
|
5992
|
-
parent.decls = {};
|
|
5993
|
-
if (ast_hasProperty(parent.decls, name)) {
|
|
5994
|
-
const what = node.type == "ModuleDeclaration" ? "type" : "node";
|
|
5995
|
-
const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
|
|
5996
|
-
if (e != null) {
|
|
5997
|
-
e.node = node;
|
|
5998
|
-
state.stack.splice(-1, 1, e);
|
|
6119
|
+
case "CatchClause":
|
|
6120
|
+
if (node.param) {
|
|
6121
|
+
const [parent] = this.stack.slice(-1);
|
|
6122
|
+
if (!parent.decls)
|
|
6123
|
+
parent.decls = {};
|
|
6124
|
+
const id = node.param.type === "Identifier"
|
|
6125
|
+
? node.param
|
|
6126
|
+
: node.param.left;
|
|
6127
|
+
this.stack.push({
|
|
6128
|
+
type: "BlockStatement",
|
|
6129
|
+
fullName: undefined,
|
|
6130
|
+
name: undefined,
|
|
6131
|
+
node: node.body,
|
|
6132
|
+
decls: { [id.name]: [id] },
|
|
6133
|
+
attributes: 0,
|
|
6134
|
+
});
|
|
6135
|
+
}
|
|
6136
|
+
break;
|
|
6137
|
+
case "ForStatement":
|
|
6138
|
+
if (node.init && node.init.type === "VariableDeclaration") {
|
|
6139
|
+
this.stack.push({
|
|
6140
|
+
type: "BlockStatement",
|
|
6141
|
+
fullName: undefined,
|
|
6142
|
+
name: undefined,
|
|
6143
|
+
node: node,
|
|
6144
|
+
attributes: 0,
|
|
6145
|
+
});
|
|
6146
|
+
}
|
|
6147
|
+
break;
|
|
6148
|
+
case "BlockStatement": {
|
|
6149
|
+
const [parent] = this.stack.slice(-1);
|
|
6150
|
+
if (parent.node === node ||
|
|
6151
|
+
(parent.type != "FunctionDeclaration" &&
|
|
6152
|
+
parent.type != "BlockStatement")) {
|
|
5999
6153
|
break;
|
|
6000
6154
|
}
|
|
6155
|
+
// fall through
|
|
6001
6156
|
}
|
|
6002
|
-
|
|
6003
|
-
|
|
6157
|
+
case "ClassDeclaration":
|
|
6158
|
+
case "FunctionDeclaration":
|
|
6159
|
+
case "ModuleDeclaration": {
|
|
6160
|
+
const [parent] = this.stack.slice(-1);
|
|
6161
|
+
const name = "id" in node ? node.id && node.id.name : undefined;
|
|
6162
|
+
const fullName = this.stack
|
|
6163
|
+
.map((e) => e.name)
|
|
6164
|
+
.concat(name)
|
|
6165
|
+
.filter((e) => e != null)
|
|
6166
|
+
.join(".");
|
|
6167
|
+
const elm = {
|
|
6168
|
+
type: node.type,
|
|
6169
|
+
name,
|
|
6170
|
+
fullName,
|
|
6171
|
+
node,
|
|
6172
|
+
attributes: node.type === "BlockStatement"
|
|
6173
|
+
? 0
|
|
6174
|
+
: stateNodeAttrs(node.attrs),
|
|
6175
|
+
};
|
|
6176
|
+
this.stack.push(elm);
|
|
6177
|
+
if (name) {
|
|
6178
|
+
if (!parent.decls)
|
|
6179
|
+
parent.decls = {};
|
|
6180
|
+
if (ast_hasProperty(parent.decls, name)) {
|
|
6181
|
+
const what = node.type == "ModuleDeclaration" ? "type" : "node";
|
|
6182
|
+
const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
|
|
6183
|
+
if (e != null) {
|
|
6184
|
+
e.node = node;
|
|
6185
|
+
this.stack.splice(-1, 1, e);
|
|
6186
|
+
break;
|
|
6187
|
+
}
|
|
6188
|
+
}
|
|
6189
|
+
else {
|
|
6190
|
+
parent.decls[name] = [];
|
|
6191
|
+
}
|
|
6192
|
+
if (node.type === "FunctionDeclaration" &&
|
|
6193
|
+
node.params &&
|
|
6194
|
+
node.params.length) {
|
|
6195
|
+
const decls = (elm.decls = {});
|
|
6196
|
+
node.params.forEach((p) => (decls[api_variableDeclarationName(p)] = [p]));
|
|
6197
|
+
}
|
|
6198
|
+
parent.decls[name].push(elm);
|
|
6199
|
+
if (node.type == "ModuleDeclaration" ||
|
|
6200
|
+
node.type == "ClassDeclaration") {
|
|
6201
|
+
if (!parent.type_decls)
|
|
6202
|
+
parent.type_decls = {};
|
|
6203
|
+
if (!ast_hasProperty(parent.type_decls, name)) {
|
|
6204
|
+
parent.type_decls[name] = [];
|
|
6205
|
+
}
|
|
6206
|
+
parent.type_decls[name].push(elm);
|
|
6207
|
+
}
|
|
6208
|
+
break;
|
|
6209
|
+
}
|
|
6210
|
+
break;
|
|
6004
6211
|
}
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6212
|
+
// an EnumDeclaration doesn't create a scope, but
|
|
6213
|
+
// it does create a type (if it has a name)
|
|
6214
|
+
case "EnumDeclaration": {
|
|
6215
|
+
if (!node.id) {
|
|
6216
|
+
this.inType++;
|
|
6217
|
+
break;
|
|
6218
|
+
}
|
|
6219
|
+
const [parent] = this.stack.slice(-1);
|
|
6220
|
+
const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
|
|
6221
|
+
node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
|
|
6010
6222
|
}
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6223
|
+
// fall through
|
|
6224
|
+
case "TypedefDeclaration": {
|
|
6225
|
+
this.inType++;
|
|
6226
|
+
const name = node.id.name;
|
|
6227
|
+
const [parent] = this.stack.slice(-1);
|
|
6014
6228
|
if (!parent.type_decls)
|
|
6015
6229
|
parent.type_decls = {};
|
|
6016
6230
|
if (!ast_hasProperty(parent.type_decls, name)) {
|
|
6017
6231
|
parent.type_decls[name] = [];
|
|
6018
6232
|
}
|
|
6019
|
-
parent.type_decls[name].
|
|
6233
|
+
else if (parent.type_decls[name].find((n) => (api_isStateNode(n) ? n.node : n) === node)) {
|
|
6234
|
+
break;
|
|
6235
|
+
}
|
|
6236
|
+
const decl = {
|
|
6237
|
+
type: node.type,
|
|
6238
|
+
node,
|
|
6239
|
+
name,
|
|
6240
|
+
fullName: parent.fullName + "." + name,
|
|
6241
|
+
attributes: stateNodeAttrs(node.attrs),
|
|
6242
|
+
stack: this.stack.slice(),
|
|
6243
|
+
};
|
|
6244
|
+
parent.type_decls[name].push(decl);
|
|
6245
|
+
if (decl.type === "EnumDeclaration") {
|
|
6246
|
+
currentEnum = decl;
|
|
6247
|
+
}
|
|
6248
|
+
break;
|
|
6249
|
+
}
|
|
6250
|
+
case "VariableDeclaration": {
|
|
6251
|
+
const [parent] = this.stack.slice(-1);
|
|
6252
|
+
if (!parent.decls)
|
|
6253
|
+
parent.decls = {};
|
|
6254
|
+
const decls = parent.decls;
|
|
6255
|
+
const stack = this.stackClone();
|
|
6256
|
+
node.declarations.forEach((decl) => {
|
|
6257
|
+
const name = api_variableDeclarationName(decl.id);
|
|
6258
|
+
if (!ast_hasProperty(decls, name)) {
|
|
6259
|
+
decls[name] = [];
|
|
6260
|
+
}
|
|
6261
|
+
else if (decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == decl)) {
|
|
6262
|
+
return;
|
|
6263
|
+
}
|
|
6264
|
+
decl.kind = node.kind;
|
|
6265
|
+
decls[name].push({
|
|
6266
|
+
type: "VariableDeclarator",
|
|
6267
|
+
node: decl,
|
|
6268
|
+
name,
|
|
6269
|
+
fullName: parent.fullName + "." + name,
|
|
6270
|
+
stack,
|
|
6271
|
+
attributes: stateNodeAttrs(node.attrs),
|
|
6272
|
+
});
|
|
6273
|
+
if (node.kind == "const") {
|
|
6274
|
+
if (!ast_hasProperty(this.index, name)) {
|
|
6275
|
+
this.index[name] = [];
|
|
6276
|
+
}
|
|
6277
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(this.index[name], parent);
|
|
6278
|
+
}
|
|
6279
|
+
});
|
|
6280
|
+
break;
|
|
6281
|
+
}
|
|
6282
|
+
case "EnumStringBody": {
|
|
6283
|
+
if (this.inType !== 1) {
|
|
6284
|
+
throw new Error(`Expected inType to be 1 at EnumStringBody. Got ${this.inType}.`);
|
|
6285
|
+
}
|
|
6286
|
+
this.inType--;
|
|
6287
|
+
const [parent] = this.stack.slice(-1);
|
|
6288
|
+
const values = parent.decls || (parent.decls = {});
|
|
6289
|
+
let prev = -1;
|
|
6290
|
+
node.members.forEach((m, i) => {
|
|
6291
|
+
if (m.type == "Identifier") {
|
|
6292
|
+
if (typeof prev === "bigint") {
|
|
6293
|
+
prev += 1n;
|
|
6294
|
+
}
|
|
6295
|
+
else {
|
|
6296
|
+
prev += 1;
|
|
6297
|
+
}
|
|
6298
|
+
m = node.members[i] = {
|
|
6299
|
+
type: "EnumStringMember",
|
|
6300
|
+
loc: m.loc,
|
|
6301
|
+
start: m.start,
|
|
6302
|
+
end: m.end,
|
|
6303
|
+
id: m,
|
|
6304
|
+
init: {
|
|
6305
|
+
type: "Literal",
|
|
6306
|
+
value: prev,
|
|
6307
|
+
raw: prev.toString() +
|
|
6308
|
+
(typeof prev === "bigint" ? "l" : ""),
|
|
6309
|
+
enumType: m.enumType,
|
|
6310
|
+
loc: m.loc,
|
|
6311
|
+
start: m.start,
|
|
6312
|
+
end: m.end,
|
|
6313
|
+
},
|
|
6314
|
+
};
|
|
6315
|
+
}
|
|
6316
|
+
const name = m.id.name;
|
|
6317
|
+
const init = getLiteralNode(m.init);
|
|
6318
|
+
if (!init) {
|
|
6319
|
+
throw new Error("Unexpected enum initializer");
|
|
6320
|
+
}
|
|
6321
|
+
if (init != m.init) {
|
|
6322
|
+
if (m.init.enumType) {
|
|
6323
|
+
init.enumType = m.init.enumType;
|
|
6324
|
+
}
|
|
6325
|
+
m.init = init;
|
|
6326
|
+
}
|
|
6327
|
+
if (init.type == "Literal" &&
|
|
6328
|
+
init.raw &&
|
|
6329
|
+
prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
|
|
6330
|
+
prev = init.value;
|
|
6331
|
+
}
|
|
6332
|
+
if (!ast_hasProperty(values, name)) {
|
|
6333
|
+
values[name] = [];
|
|
6334
|
+
}
|
|
6335
|
+
if ((0,external_util_cjs_namespaceObject.pushUnique)(values[name], m) && currentEnum) {
|
|
6336
|
+
if (!this.enumMap)
|
|
6337
|
+
this.enumMap = new Map();
|
|
6338
|
+
this.enumMap.set(m, currentEnum);
|
|
6339
|
+
}
|
|
6340
|
+
if (!ast_hasProperty(this.index, name)) {
|
|
6341
|
+
this.index[name] = [];
|
|
6342
|
+
}
|
|
6343
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(this.index[name], parent);
|
|
6344
|
+
});
|
|
6345
|
+
break;
|
|
6020
6346
|
}
|
|
6021
6347
|
}
|
|
6022
|
-
|
|
6348
|
+
if (this.pre)
|
|
6349
|
+
return this.pre(node, this);
|
|
6023
6350
|
}
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
case "EnumDeclaration": {
|
|
6027
|
-
if (!node.id) {
|
|
6028
|
-
state.inType++;
|
|
6029
|
-
break;
|
|
6030
|
-
}
|
|
6031
|
-
const [parent] = state.stack.slice(-1);
|
|
6032
|
-
const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
|
|
6033
|
-
node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
|
|
6351
|
+
catch (e) {
|
|
6352
|
+
handleException(this, node, e);
|
|
6034
6353
|
}
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
if (!ast_hasProperty(parent.type_decls, name)) {
|
|
6043
|
-
parent.type_decls[name] = [];
|
|
6044
|
-
}
|
|
6045
|
-
else if (parent.type_decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == node)) {
|
|
6046
|
-
break;
|
|
6354
|
+
return null;
|
|
6355
|
+
}, (node) => {
|
|
6356
|
+
try {
|
|
6357
|
+
let ret;
|
|
6358
|
+
if (this.shouldExclude && this.shouldExclude(node)) {
|
|
6359
|
+
// delete the node.
|
|
6360
|
+
ret = false;
|
|
6047
6361
|
}
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
const stack = state.stackClone();
|
|
6065
|
-
node.declarations.forEach((decl) => {
|
|
6066
|
-
const name = api_variableDeclarationName(decl.id);
|
|
6067
|
-
if (!ast_hasProperty(decls, name)) {
|
|
6068
|
-
decls[name] = [];
|
|
6069
|
-
}
|
|
6070
|
-
else if (decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == decl)) {
|
|
6071
|
-
return;
|
|
6362
|
+
else {
|
|
6363
|
+
const type = node.type;
|
|
6364
|
+
if (this.post)
|
|
6365
|
+
ret = this.post(node, this);
|
|
6366
|
+
switch (type) {
|
|
6367
|
+
case "EnumDeclaration":
|
|
6368
|
+
currentEnum = null;
|
|
6369
|
+
// fall through
|
|
6370
|
+
case "TypeSpecPart":
|
|
6371
|
+
case "TypeSpecList":
|
|
6372
|
+
case "TypedefDeclaration":
|
|
6373
|
+
this.inType--;
|
|
6374
|
+
break;
|
|
6375
|
+
case "EnumStringBody":
|
|
6376
|
+
this.inType++;
|
|
6377
|
+
break;
|
|
6072
6378
|
}
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
state.index[name] = [];
|
|
6379
|
+
const [parent] = this.stack.slice(-1);
|
|
6380
|
+
if (parent.node === node ||
|
|
6381
|
+
// The pre function might cause node.body to be skipped,
|
|
6382
|
+
// so we need to check here, just in case.
|
|
6383
|
+
// (this actually happens with prettier-extenison-monkeyc's
|
|
6384
|
+
// findItemsByRange)
|
|
6385
|
+
(node.type === "CatchClause" && parent.node === node.body)) {
|
|
6386
|
+
delete parent.usings;
|
|
6387
|
+
delete parent.imports;
|
|
6388
|
+
if (node.type != "Program") {
|
|
6389
|
+
this.stack.pop();
|
|
6085
6390
|
}
|
|
6086
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
6087
6391
|
}
|
|
6088
|
-
}
|
|
6089
|
-
|
|
6392
|
+
}
|
|
6393
|
+
if (ret != null && node.loc && node.loc.source && this.fnMap) {
|
|
6394
|
+
const fnInfo = this.fnMap[node.loc.source];
|
|
6395
|
+
fnInfo && fnInfo.ast && this.removeNodeComments(node, fnInfo.ast);
|
|
6396
|
+
}
|
|
6397
|
+
return ret;
|
|
6090
6398
|
}
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
throw new Error(`Expected inType to be 1 at EnumStringBody. Got ${state.inType}.`);
|
|
6094
|
-
}
|
|
6095
|
-
state.inType--;
|
|
6096
|
-
const [parent] = state.stack.slice(-1);
|
|
6097
|
-
const values = parent.decls || (parent.decls = {});
|
|
6098
|
-
let prev = -1;
|
|
6099
|
-
node.members.forEach((m, i) => {
|
|
6100
|
-
if (m.type == "Identifier") {
|
|
6101
|
-
if (typeof prev === "bigint") {
|
|
6102
|
-
prev += 1n;
|
|
6103
|
-
}
|
|
6104
|
-
else {
|
|
6105
|
-
prev += 1;
|
|
6106
|
-
}
|
|
6107
|
-
m = node.members[i] = {
|
|
6108
|
-
type: "EnumStringMember",
|
|
6109
|
-
loc: m.loc,
|
|
6110
|
-
start: m.start,
|
|
6111
|
-
end: m.end,
|
|
6112
|
-
id: m,
|
|
6113
|
-
init: {
|
|
6114
|
-
type: "Literal",
|
|
6115
|
-
value: prev,
|
|
6116
|
-
raw: prev.toString() + (typeof prev === "bigint" ? "l" : ""),
|
|
6117
|
-
enumType: m.enumType,
|
|
6118
|
-
loc: m.loc,
|
|
6119
|
-
start: m.start,
|
|
6120
|
-
end: m.end,
|
|
6121
|
-
},
|
|
6122
|
-
};
|
|
6123
|
-
}
|
|
6124
|
-
const name = m.id.name;
|
|
6125
|
-
const init = getLiteralNode(m.init);
|
|
6126
|
-
if (!init) {
|
|
6127
|
-
throw new Error("Unexpected enum initializer");
|
|
6128
|
-
}
|
|
6129
|
-
if (init != m.init) {
|
|
6130
|
-
if (m.init.enumType) {
|
|
6131
|
-
init.enumType = m.init.enumType;
|
|
6132
|
-
}
|
|
6133
|
-
m.init = init;
|
|
6134
|
-
}
|
|
6135
|
-
if (init.type == "Literal" &&
|
|
6136
|
-
init.raw &&
|
|
6137
|
-
prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
|
|
6138
|
-
prev = init.value;
|
|
6139
|
-
}
|
|
6140
|
-
if (!ast_hasProperty(values, name)) {
|
|
6141
|
-
values[name] = [];
|
|
6142
|
-
}
|
|
6143
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(values[name], m);
|
|
6144
|
-
if (!ast_hasProperty(state.index, name)) {
|
|
6145
|
-
state.index[name] = [];
|
|
6146
|
-
}
|
|
6147
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
6148
|
-
});
|
|
6149
|
-
break;
|
|
6399
|
+
catch (e) {
|
|
6400
|
+
handleException(this, node, e);
|
|
6150
6401
|
}
|
|
6151
|
-
}
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6402
|
+
});
|
|
6403
|
+
},
|
|
6404
|
+
};
|
|
6405
|
+
}
|
|
6406
|
+
function api_collectNamespaces(ast, stateIn) {
|
|
6407
|
+
const state = (stateIn || {});
|
|
6408
|
+
if (!state.nextExposed)
|
|
6409
|
+
state.nextExposed = {};
|
|
6410
|
+
if (!state.index)
|
|
6411
|
+
state.index = {};
|
|
6412
|
+
if (!state.stack) {
|
|
6413
|
+
state.stack = [
|
|
6414
|
+
{
|
|
6415
|
+
type: "Program",
|
|
6416
|
+
name: "$",
|
|
6417
|
+
fullName: "$",
|
|
6418
|
+
node: undefined,
|
|
6419
|
+
attributes: 0,
|
|
6420
|
+
},
|
|
6421
|
+
];
|
|
6422
|
+
}
|
|
6423
|
+
if (!state.lookupRules) {
|
|
6424
|
+
const rules = state?.config?.compilerLookupRules || "DEFAULT";
|
|
6425
|
+
if (rules !== "COMPILER1" && rules !== "COMPILER2") {
|
|
6426
|
+
const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
|
|
6427
|
+
if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
|
|
6428
|
+
state.lookupRules = "COMPILER2";
|
|
6165
6429
|
}
|
|
6166
6430
|
else {
|
|
6167
|
-
|
|
6168
|
-
if (state.post)
|
|
6169
|
-
ret = state.post(node, state);
|
|
6170
|
-
switch (type) {
|
|
6171
|
-
case "TypeSpecPart":
|
|
6172
|
-
case "TypeSpecList":
|
|
6173
|
-
case "TypedefDeclaration":
|
|
6174
|
-
case "EnumDeclaration":
|
|
6175
|
-
state.inType--;
|
|
6176
|
-
break;
|
|
6177
|
-
case "EnumStringBody":
|
|
6178
|
-
state.inType++;
|
|
6179
|
-
break;
|
|
6180
|
-
}
|
|
6181
|
-
const [parent] = state.stack.slice(-1);
|
|
6182
|
-
if (parent.node === node ||
|
|
6183
|
-
// The pre function might cause node.body to be skipped,
|
|
6184
|
-
// so we need to check here, just in case.
|
|
6185
|
-
// (this actually happens with prettier-extenison-monkeyc's
|
|
6186
|
-
// findItemsByRange)
|
|
6187
|
-
(node.type === "CatchClause" && parent.node === node.body)) {
|
|
6188
|
-
delete parent.usings;
|
|
6189
|
-
delete parent.imports;
|
|
6190
|
-
if (node.type != "Program") {
|
|
6191
|
-
state.stack.pop();
|
|
6192
|
-
}
|
|
6193
|
-
}
|
|
6194
|
-
}
|
|
6195
|
-
if (ret != null) {
|
|
6196
|
-
state.removeNodeComments(node, ast);
|
|
6431
|
+
state.lookupRules = "COMPILER1";
|
|
6197
6432
|
}
|
|
6198
|
-
return ret;
|
|
6199
|
-
}
|
|
6200
|
-
catch (e) {
|
|
6201
|
-
handleException(state, node, e);
|
|
6202
6433
|
}
|
|
6203
|
-
}
|
|
6434
|
+
}
|
|
6435
|
+
Object.assign(state, stateFuncs());
|
|
6436
|
+
state.inType = 0;
|
|
6204
6437
|
state.traverse(ast);
|
|
6205
6438
|
if (state.inType) {
|
|
6206
6439
|
throw new Error(`inType was non-zero on exit: ${state.inType}`);
|
|
@@ -6223,8 +6456,11 @@ function api_formatAst(node, monkeyCSource = null, options = null) {
|
|
|
6223
6456
|
* should be ignored.
|
|
6224
6457
|
*/
|
|
6225
6458
|
switch (node.type) {
|
|
6226
|
-
case "Program":
|
|
6227
6459
|
case "BlockStatement":
|
|
6460
|
+
if (node.body.length)
|
|
6461
|
+
break;
|
|
6462
|
+
return "{}";
|
|
6463
|
+
case "Program":
|
|
6228
6464
|
case "ExpressionStatement":
|
|
6229
6465
|
break;
|
|
6230
6466
|
default: {
|
|
@@ -6353,15 +6589,16 @@ function api_getApiFunctionInfo(func) {
|
|
|
6353
6589
|
return invokeInfo;
|
|
6354
6590
|
}
|
|
6355
6591
|
if (!toyboxFnInfo.calledFuncs) {
|
|
6356
|
-
|
|
6357
|
-
toyboxFnInfo.calledFuncs = new Set();
|
|
6358
|
-
toyboxFnInfo.resolvedDecls = new Set();
|
|
6592
|
+
return false;
|
|
6359
6593
|
}
|
|
6360
6594
|
return toyboxFnInfo;
|
|
6361
6595
|
}
|
|
6362
6596
|
function api_markInvokeClassMethod(func) {
|
|
6363
6597
|
func.info = invokeInfo;
|
|
6364
6598
|
}
|
|
6599
|
+
function api_isLocal(v) {
|
|
6600
|
+
return v.stack[v.stack.length - 1]?.type === "BlockStatement";
|
|
6601
|
+
}
|
|
6365
6602
|
|
|
6366
6603
|
})();
|
|
6367
6604
|
|