@markw65/monkeyc-optimizer 1.0.43 → 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 +28 -0
- package/build/api.cjs +1241 -739
- package/build/optimizer.cjs +665 -251
- package/build/sdk-util.cjs +400 -1
- package/build/src/api.d.ts +3 -2
- package/build/src/ast.d.ts +30 -1
- package/build/src/data-flow.d.ts +45 -0
- package/build/src/function-info.d.ts +2 -0
- package/build/src/inliner.d.ts +2 -2
- 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/resources.d.ts +3 -4
- package/build/src/type-flow.d.ts +4 -0
- package/build/src/util.d.ts +6 -1
- package/build/src/worker-pool.d.ts +4 -0
- package/build/src/worker-task.d.ts +29 -0
- package/build/src/xml-util.d.ts +19 -7
- package/build/util.cjs +58 -2
- package/package.json +4 -3
- package/build/src/estree-types.d.ts +0 -324
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),
|
|
@@ -524,13 +525,73 @@ function ast_getNodeValue(node) {
|
|
|
524
525
|
return [node, "Long"];
|
|
525
526
|
}
|
|
526
527
|
if (type === "string") {
|
|
527
|
-
return
|
|
528
|
+
return node.raw.startsWith("'")
|
|
529
|
+
? [node, "Char"]
|
|
530
|
+
: [node, "String"];
|
|
528
531
|
}
|
|
529
532
|
if (type === "boolean") {
|
|
530
533
|
return [node, "Boolean"];
|
|
531
534
|
}
|
|
532
535
|
throw new Error(`Literal has unknown type '${type}'`);
|
|
533
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
|
+
}
|
|
534
595
|
|
|
535
596
|
;// CONCATENATED MODULE: external "./api.cjs"
|
|
536
597
|
const external_api_cjs_namespaceObject = require("./api.cjs");
|
|
@@ -585,6 +646,8 @@ function function_info_recordCalledFuncs(func, callees) {
|
|
|
585
646
|
}
|
|
586
647
|
function function_info_functionMayModify(state, func, decl) {
|
|
587
648
|
const info = func.info;
|
|
649
|
+
if (info === false)
|
|
650
|
+
return false;
|
|
588
651
|
if (!info || info.modifiedUnknown)
|
|
589
652
|
return true;
|
|
590
653
|
if (info.resolvedDecls) {
|
|
@@ -597,7 +660,7 @@ function function_info_functionMayModify(state, func, decl) {
|
|
|
597
660
|
const visited = new Set();
|
|
598
661
|
const resolved = new Set();
|
|
599
662
|
const resolveDecls = (f) => {
|
|
600
|
-
if (visited.has(f))
|
|
663
|
+
if (f.info === false || visited.has(f))
|
|
601
664
|
return true;
|
|
602
665
|
if (!f.info)
|
|
603
666
|
return false;
|
|
@@ -659,6 +722,16 @@ function function_info_findCalleesForNew(lookupDefs) {
|
|
|
659
722
|
.flatMap(initializer)
|
|
660
723
|
.filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
|
|
661
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
|
+
}
|
|
662
735
|
|
|
663
736
|
;// CONCATENATED MODULE: ./src/optimizer-types.ts
|
|
664
737
|
var optimizer_types_StateNodeAttributes;
|
|
@@ -1622,13 +1695,17 @@ function pragma_checker_pragmaChecker(state, ast, diagnostics) {
|
|
|
1622
1695
|
if (quote == '"') {
|
|
1623
1696
|
return haystack.includes(needle);
|
|
1624
1697
|
}
|
|
1625
|
-
const re = new RegExp(needle.replace(/@([
|
|
1698
|
+
const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/\W/g, "_")}(?:_\\d+)?)`));
|
|
1626
1699
|
return re.test(haystack);
|
|
1627
1700
|
};
|
|
1628
1701
|
next();
|
|
1629
1702
|
traverseAst(ast, (node) => {
|
|
1630
|
-
if (index >= comments.length
|
|
1703
|
+
if (index >= comments.length ||
|
|
1704
|
+
node.type === "Line" ||
|
|
1705
|
+
node.type === "Block" ||
|
|
1706
|
+
node.type === "MultiLine") {
|
|
1631
1707
|
return false;
|
|
1708
|
+
}
|
|
1632
1709
|
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
1633
1710
|
const { kind, quote, needle } = matchers.shift();
|
|
1634
1711
|
if (kind === "match") {
|
|
@@ -1776,7 +1853,7 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
1776
1853
|
try {
|
|
1777
1854
|
const localState = new LocalState(func.node);
|
|
1778
1855
|
const ret = localState.curBlock;
|
|
1779
|
-
state.stack = func.stack;
|
|
1856
|
+
state.stack = [...func.stack];
|
|
1780
1857
|
const stmtStack = [func.node];
|
|
1781
1858
|
let tryActive = 0;
|
|
1782
1859
|
state.pre = (node) => {
|
|
@@ -1791,6 +1868,8 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
1791
1868
|
stmtStack.push(node);
|
|
1792
1869
|
}
|
|
1793
1870
|
switch (node.type) {
|
|
1871
|
+
case "FunctionDeclaration":
|
|
1872
|
+
return ["body"];
|
|
1794
1873
|
case "AttributeList":
|
|
1795
1874
|
return [];
|
|
1796
1875
|
case "SwitchStatement": {
|
|
@@ -2007,11 +2086,6 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
2007
2086
|
}
|
|
2008
2087
|
case "VariableDeclarator":
|
|
2009
2088
|
return ["init"];
|
|
2010
|
-
case "MemberExpression":
|
|
2011
|
-
if (!node.computed) {
|
|
2012
|
-
return ["object"];
|
|
2013
|
-
}
|
|
2014
|
-
break;
|
|
2015
2089
|
case "UnaryExpression":
|
|
2016
2090
|
if (node.operator === ":") {
|
|
2017
2091
|
return [];
|
|
@@ -2047,6 +2121,14 @@ function control_flow_buildReducedGraph(state, func, notice) {
|
|
|
2047
2121
|
case "ContinueStatement":
|
|
2048
2122
|
localState.terminal(node.type);
|
|
2049
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;
|
|
2050
2132
|
}
|
|
2051
2133
|
return null;
|
|
2052
2134
|
};
|
|
@@ -2208,142 +2290,94 @@ function getPreOrder(head) {
|
|
|
2208
2290
|
|
|
2209
2291
|
// EXTERNAL MODULE: ./node_modules/priorityqueuejs/index.js
|
|
2210
2292
|
var priorityqueuejs = __webpack_require__(2789);
|
|
2211
|
-
;// CONCATENATED MODULE: ./src/
|
|
2293
|
+
;// CONCATENATED MODULE: ./src/data-flow.ts
|
|
2212
2294
|
|
|
2213
2295
|
|
|
2214
2296
|
|
|
2215
2297
|
|
|
2216
2298
|
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
* }
|
|
2228
|
-
*
|
|
2229
|
-
* and rewrite it as
|
|
2230
|
-
*
|
|
2231
|
-
* var tmp = A.B;
|
|
2232
|
-
* switch (x) {
|
|
2233
|
-
* case 1: foo(tmp); break;
|
|
2234
|
-
* case 2: foo(C); break;
|
|
2235
|
-
* case 3: bar(tmp); break;
|
|
2236
|
-
* }
|
|
2237
|
-
*
|
|
2238
|
-
* because even though A.B wasn't used on all paths where we
|
|
2239
|
-
* inserted the temporary, we still reduced the code size.
|
|
2240
|
-
*/
|
|
2241
|
-
const logging = false;
|
|
2242
|
-
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;
|
|
2243
2309
|
switch (decl.type) {
|
|
2244
|
-
case "
|
|
2245
|
-
return decl.
|
|
2246
|
-
case "
|
|
2247
|
-
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;
|
|
2248
2316
|
default:
|
|
2249
2317
|
throw new Error(`Unexpected EventDecl type: ${decl.type}`);
|
|
2250
2318
|
}
|
|
2251
2319
|
}
|
|
2252
|
-
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;
|
|
2253
2329
|
switch (decl.type) {
|
|
2254
|
-
case "
|
|
2255
|
-
return
|
|
2256
|
-
case "
|
|
2257
|
-
return decl.name;
|
|
2330
|
+
case "BinaryExpression":
|
|
2331
|
+
return decl.left.name;
|
|
2332
|
+
case "EnumStringMember":
|
|
2333
|
+
return decl.id.name;
|
|
2258
2334
|
default:
|
|
2259
2335
|
throw new Error(`Unexpected EventDecl type: ${decl.type}`);
|
|
2260
2336
|
}
|
|
2261
2337
|
}
|
|
2262
|
-
function logAntState(s, decl) {
|
|
2263
|
-
const defs = Array.from(s.ant).reduce((defs, event) => {
|
|
2264
|
-
if (event.type === "def" || event.type === "mod")
|
|
2265
|
-
defs++;
|
|
2266
|
-
return defs;
|
|
2267
|
-
}, 0);
|
|
2268
|
-
console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
|
|
2269
|
-
console.log(` - members: ${Array.from(s.members)
|
|
2270
|
-
.map(([block, live]) => block.order + (live ? "t" : "f"))
|
|
2271
|
-
.join(", ")}`);
|
|
2272
|
-
}
|
|
2273
|
-
function logAntDecls(antDecls) {
|
|
2274
|
-
antDecls.forEach(logAntState);
|
|
2275
|
-
}
|
|
2276
|
-
function pre_sizeBasedPRE(state, func) {
|
|
2277
|
-
if (!func.node.body)
|
|
2278
|
-
return;
|
|
2279
|
-
if (!state.config ||
|
|
2280
|
-
!state.config.sizeBasedPRE ||
|
|
2281
|
-
(typeof state.config.sizeBasedPRE === "string" &&
|
|
2282
|
-
state.config.sizeBasedPRE !== func.fullName)) {
|
|
2283
|
-
return;
|
|
2284
|
-
}
|
|
2285
|
-
const { graph: head, identifiers } = buildPREGraph(state, func);
|
|
2286
|
-
const candidates = computeAttributes(state, head);
|
|
2287
|
-
if (candidates) {
|
|
2288
|
-
if (logging) {
|
|
2289
|
-
console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
|
|
2290
|
-
logAntDecls(candidates);
|
|
2291
|
-
}
|
|
2292
|
-
const nodeMap = new Map();
|
|
2293
|
-
const declMap = new Map();
|
|
2294
|
-
const variableDecl = withLoc({
|
|
2295
|
-
type: "VariableDeclaration",
|
|
2296
|
-
declarations: [],
|
|
2297
|
-
kind: "var",
|
|
2298
|
-
}, func.node.body);
|
|
2299
|
-
variableDecl.end = variableDecl.start;
|
|
2300
|
-
variableDecl.loc.end = variableDecl.loc.start;
|
|
2301
|
-
candidates.forEach((s, decl) => {
|
|
2302
|
-
let name;
|
|
2303
|
-
let i = 0;
|
|
2304
|
-
do {
|
|
2305
|
-
name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
|
|
2306
|
-
if (!identifiers.has(name)) {
|
|
2307
|
-
identifiers.add(name);
|
|
2308
|
-
break;
|
|
2309
|
-
}
|
|
2310
|
-
i++;
|
|
2311
|
-
} while (true);
|
|
2312
|
-
declMap.set(decl, name);
|
|
2313
|
-
variableDecl.declarations.push(withLoc({
|
|
2314
|
-
type: "VariableDeclarator",
|
|
2315
|
-
id: withLoc({ type: "Identifier", name }, variableDecl),
|
|
2316
|
-
kind: "var",
|
|
2317
|
-
}, variableDecl));
|
|
2318
|
-
s.ant.forEach((event) => {
|
|
2319
|
-
const events = nodeMap.get(event.node);
|
|
2320
|
-
if (!events) {
|
|
2321
|
-
nodeMap.set(event.node, [event]);
|
|
2322
|
-
}
|
|
2323
|
-
else {
|
|
2324
|
-
events.push(event);
|
|
2325
|
-
}
|
|
2326
|
-
});
|
|
2327
|
-
});
|
|
2328
|
-
applyReplacements(func.node, nodeMap, declMap);
|
|
2329
|
-
func.node.body.body.unshift(variableDecl);
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
2338
|
function unhandledExpression(node) {
|
|
2333
2339
|
throw new Error(`Unhandled expression type: ${node.type}`);
|
|
2334
2340
|
}
|
|
2335
|
-
function
|
|
2341
|
+
function data_flow_buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wantsAllRefs) {
|
|
2342
|
+
const uniqueDeclMap = new Map();
|
|
2336
2343
|
const findDecl = (node) => {
|
|
2337
2344
|
if (node.type === "Identifier" ||
|
|
2338
2345
|
(node.type === "MemberExpression" && !node.computed)) {
|
|
2339
2346
|
const [, results] = state.lookup(node);
|
|
2340
|
-
|
|
2341
|
-
results.
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
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;
|
|
2347
2381
|
}
|
|
2348
2382
|
return null;
|
|
2349
2383
|
};
|
|
@@ -2351,18 +2385,22 @@ function buildPREGraph(state, func) {
|
|
|
2351
2385
|
const identifiers = new Set();
|
|
2352
2386
|
const liveDefs = new Map();
|
|
2353
2387
|
const liveStmts = new Map();
|
|
2354
|
-
const liveDef =
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
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);
|
|
2363
2400
|
}
|
|
2364
|
-
|
|
2365
|
-
|
|
2401
|
+
: () => {
|
|
2402
|
+
/* do nothing */
|
|
2403
|
+
};
|
|
2366
2404
|
return {
|
|
2367
2405
|
identifiers,
|
|
2368
2406
|
graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
|
|
@@ -2376,7 +2414,7 @@ function buildPREGraph(state, func) {
|
|
|
2376
2414
|
}
|
|
2377
2415
|
const v = liveDefs.get(def);
|
|
2378
2416
|
if (!v || !v.has(node)) {
|
|
2379
|
-
throw new Error(`No stmt in liveDef for ${def ?
|
|
2417
|
+
throw new Error(`No stmt in liveDef for ${def ? data_flow_declFullName(def) : "null"}`);
|
|
2380
2418
|
}
|
|
2381
2419
|
v.delete(node);
|
|
2382
2420
|
if (!v.size) {
|
|
@@ -2397,7 +2435,7 @@ function buildPREGraph(state, func) {
|
|
|
2397
2435
|
case "ParenthesizedExpression":
|
|
2398
2436
|
break;
|
|
2399
2437
|
case "Literal":
|
|
2400
|
-
if (
|
|
2438
|
+
if (wantsLiteral(node)) {
|
|
2401
2439
|
const result = getNodeValue(node);
|
|
2402
2440
|
const key = result[1] +
|
|
2403
2441
|
(result[0].value === null
|
|
@@ -2419,34 +2457,40 @@ function buildPREGraph(state, func) {
|
|
|
2419
2457
|
case "Identifier":
|
|
2420
2458
|
identifiers.add(node.name);
|
|
2421
2459
|
// fall through
|
|
2422
|
-
case "MemberExpression":
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
if (
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
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
|
+
}
|
|
2440
2482
|
}
|
|
2441
|
-
return
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
decl,
|
|
2445
|
-
mayThrow,
|
|
2446
|
-
};
|
|
2447
|
-
}
|
|
2483
|
+
return false;
|
|
2484
|
+
})) {
|
|
2485
|
+
break;
|
|
2448
2486
|
}
|
|
2449
|
-
|
|
2487
|
+
return {
|
|
2488
|
+
type: "ref",
|
|
2489
|
+
node,
|
|
2490
|
+
decl: decls,
|
|
2491
|
+
mayThrow,
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2450
2494
|
case "VariableDeclarator": {
|
|
2451
2495
|
const decl = findDecl(node.id.type === "BinaryExpression" ? node.id.left : node.id);
|
|
2452
2496
|
if (decl) {
|
|
@@ -2494,8 +2538,10 @@ function buildPREGraph(state, func) {
|
|
|
2494
2538
|
}
|
|
2495
2539
|
case "CallExpression": {
|
|
2496
2540
|
liveDef(null, stmt);
|
|
2497
|
-
const [, results] = state.
|
|
2498
|
-
const callees = results
|
|
2541
|
+
const [, results] = state.lookupNonlocal(node.callee);
|
|
2542
|
+
const callees = results
|
|
2543
|
+
? findCallees(results)
|
|
2544
|
+
: findCalleesByNode(state, node.callee);
|
|
2499
2545
|
return { type: "mod", node, mayThrow, callees };
|
|
2500
2546
|
}
|
|
2501
2547
|
default:
|
|
@@ -2510,67 +2556,193 @@ function buildPREGraph(state, func) {
|
|
|
2510
2556
|
}),
|
|
2511
2557
|
};
|
|
2512
2558
|
}
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
if (a.size != b.size)
|
|
2518
|
-
return false;
|
|
2519
|
-
for (const item of a) {
|
|
2520
|
-
if (!b.has(item))
|
|
2521
|
-
return false;
|
|
2522
|
-
}
|
|
2523
|
-
return true;
|
|
2524
|
-
}
|
|
2525
|
-
function equalMap(a, b) {
|
|
2526
|
-
if (a.size != b.size)
|
|
2527
|
-
return false;
|
|
2528
|
-
for (const [item, value] of a) {
|
|
2529
|
-
if (b.get(item) !== value)
|
|
2530
|
-
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));
|
|
2531
2563
|
}
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
}
|
|
2537
|
-
function cloneAnticipatedState(as) {
|
|
2538
|
-
return {
|
|
2539
|
-
ant: cloneSet(as.ant),
|
|
2540
|
-
live: as.live,
|
|
2541
|
-
node: as.node,
|
|
2542
|
-
members: new Map(as.members),
|
|
2543
|
-
};
|
|
2544
|
-
}
|
|
2545
|
-
function mergeAnticipatedState(ae, be) {
|
|
2546
|
-
mergeSet(ae.ant, be.ant);
|
|
2547
|
-
be.members.forEach((live, block) => ae.members.set(block, live));
|
|
2548
|
-
if (be.live)
|
|
2549
|
-
ae.live = true;
|
|
2550
|
-
}
|
|
2551
|
-
function cloneAnticipatedDecls(ad) {
|
|
2552
|
-
const copy = anticipatedDecls();
|
|
2553
|
-
for (const [k, v] of ad) {
|
|
2554
|
-
if (!v.isIsolated) {
|
|
2555
|
-
copy.set(k, cloneAnticipatedState(v));
|
|
2564
|
+
enqueue(block) {
|
|
2565
|
+
if (!this.enqueued.has(block)) {
|
|
2566
|
+
this.enqueued.add(block);
|
|
2567
|
+
this.queue.enq(block);
|
|
2556
2568
|
}
|
|
2557
2569
|
}
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
if (ae) {
|
|
2566
|
-
mergeAnticipatedState(ae, v);
|
|
2567
|
-
}
|
|
2568
|
-
else {
|
|
2569
|
-
a.set(k, cloneAnticipatedState(v));
|
|
2570
|
-
}
|
|
2570
|
+
dequeue() {
|
|
2571
|
+
const block = this.queue.deq();
|
|
2572
|
+
this.enqueued.delete(block);
|
|
2573
|
+
return block;
|
|
2574
|
+
}
|
|
2575
|
+
empty() {
|
|
2576
|
+
return this.queue.isEmpty();
|
|
2571
2577
|
}
|
|
2572
2578
|
}
|
|
2573
|
-
|
|
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) {
|
|
2574
2746
|
if (a.size !== b.size)
|
|
2575
2747
|
return false;
|
|
2576
2748
|
for (const [k, ae] of a) {
|
|
@@ -2665,26 +2837,18 @@ function computeAttributes(state, head) {
|
|
|
2665
2837
|
.join(", ")}`);
|
|
2666
2838
|
if (block.events) {
|
|
2667
2839
|
block.events.forEach((event) => event.type !== "exn" &&
|
|
2668
|
-
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
|
+
: "??"}`));
|
|
2669
2845
|
}
|
|
2670
2846
|
console.log(`Succs: ${(block.succs || [])
|
|
2671
2847
|
.map((block) => block.order)
|
|
2672
2848
|
.join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
|
|
2673
2849
|
});
|
|
2674
2850
|
}
|
|
2675
|
-
const
|
|
2676
|
-
const queue = new PriorityQueue((b, a) => (a.order || 0) - (b.order || 0));
|
|
2677
|
-
const enqueue = (block) => {
|
|
2678
|
-
if (!enqueued.has(block)) {
|
|
2679
|
-
enqueued.add(block);
|
|
2680
|
-
queue.enq(block);
|
|
2681
|
-
}
|
|
2682
|
-
};
|
|
2683
|
-
const dequeue = () => {
|
|
2684
|
-
const block = queue.deq();
|
|
2685
|
-
enqueued.delete(block);
|
|
2686
|
-
return block;
|
|
2687
|
-
};
|
|
2851
|
+
const queue = new DataflowQueue();
|
|
2688
2852
|
const blockStates = [];
|
|
2689
2853
|
/*
|
|
2690
2854
|
Algorithm
|
|
@@ -2718,9 +2882,9 @@ function computeAttributes(state, head) {
|
|
|
2718
2882
|
}
|
|
2719
2883
|
return result;
|
|
2720
2884
|
};
|
|
2721
|
-
order.forEach((block) => enqueue(block));
|
|
2722
|
-
while (queue.
|
|
2723
|
-
const top = dequeue();
|
|
2885
|
+
order.forEach((block) => queue.enqueue(block));
|
|
2886
|
+
while (!queue.empty()) {
|
|
2887
|
+
const top = queue.dequeue();
|
|
2724
2888
|
if (top.order === undefined) {
|
|
2725
2889
|
throw new Error(`Unreachable block was visited!`);
|
|
2726
2890
|
}
|
|
@@ -2759,13 +2923,13 @@ function computeAttributes(state, head) {
|
|
|
2759
2923
|
break;
|
|
2760
2924
|
}
|
|
2761
2925
|
case "mod": {
|
|
2762
|
-
curState.forEach((candidates,
|
|
2763
|
-
if (decl.type === "VariableDeclarator" &&
|
|
2926
|
+
curState.forEach((candidates, decls) => {
|
|
2927
|
+
if (some(decls, (decl) => decl.type === "VariableDeclarator" &&
|
|
2764
2928
|
decl.node.kind === "var" &&
|
|
2765
2929
|
candidates.live &&
|
|
2766
2930
|
(!event.callees ||
|
|
2767
|
-
event.callees.some((callee) => functionMayModify(state, callee, decl)))) {
|
|
2768
|
-
candidates.ant.add(getMod(event,
|
|
2931
|
+
event.callees.some((callee) => functionMayModify(state, callee, decl))))) {
|
|
2932
|
+
candidates.ant.add(getMod(event, decls, candidates.node));
|
|
2769
2933
|
candidates.live = false;
|
|
2770
2934
|
}
|
|
2771
2935
|
});
|
|
@@ -2817,7 +2981,7 @@ function computeAttributes(state, head) {
|
|
|
2817
2981
|
logAntDecls(curState);
|
|
2818
2982
|
}
|
|
2819
2983
|
if (top.preds) {
|
|
2820
|
-
top.preds.forEach((pred) => enqueue(pred));
|
|
2984
|
+
top.preds.forEach((pred) => queue.enqueue(pred));
|
|
2821
2985
|
}
|
|
2822
2986
|
}
|
|
2823
2987
|
const candidateDecls = anticipatedDecls();
|
|
@@ -3572,7 +3736,7 @@ function getLiteralNode(node) {
|
|
|
3572
3736
|
case "-": {
|
|
3573
3737
|
const [arg, type] = ast_getNodeValue(node.argument);
|
|
3574
3738
|
if (type === "Number" || type === "Long") {
|
|
3575
|
-
return replacementLiteral(
|
|
3739
|
+
return replacementLiteral(node, -arg.value, type);
|
|
3576
3740
|
}
|
|
3577
3741
|
}
|
|
3578
3742
|
}
|
|
@@ -3622,8 +3786,14 @@ function isBooleanExpression(state, node) {
|
|
|
3622
3786
|
}
|
|
3623
3787
|
return false;
|
|
3624
3788
|
}
|
|
3789
|
+
function roundToFloat(value) {
|
|
3790
|
+
return new Float32Array([value])[0];
|
|
3791
|
+
}
|
|
3625
3792
|
function replacementLiteral(arg, value, type) {
|
|
3626
|
-
if (
|
|
3793
|
+
if (value === null) {
|
|
3794
|
+
type = "Null";
|
|
3795
|
+
}
|
|
3796
|
+
else if (typeof value === "boolean") {
|
|
3627
3797
|
type = "Boolean";
|
|
3628
3798
|
}
|
|
3629
3799
|
else if (type === "Number") {
|
|
@@ -3632,32 +3802,213 @@ function replacementLiteral(arg, value, type) {
|
|
|
3632
3802
|
else if (type === "Long") {
|
|
3633
3803
|
value = BigInt.asIntN(64, BigInt(value));
|
|
3634
3804
|
}
|
|
3805
|
+
else if (type === "Float") {
|
|
3806
|
+
value = roundToFloat(Number(value));
|
|
3807
|
+
}
|
|
3808
|
+
let raw = type === "String"
|
|
3809
|
+
? JSON.stringify(value)
|
|
3810
|
+
: type === "Char"
|
|
3811
|
+
? value === "'"
|
|
3812
|
+
? "'\\''"
|
|
3813
|
+
: "'" + JSON.stringify(value).slice(1, -1) + "'"
|
|
3814
|
+
: value == null
|
|
3815
|
+
? "null"
|
|
3816
|
+
: value.toString();
|
|
3817
|
+
if (type === "Long") {
|
|
3818
|
+
raw += "l";
|
|
3819
|
+
}
|
|
3820
|
+
else if (type === "Double") {
|
|
3821
|
+
raw += "d";
|
|
3822
|
+
}
|
|
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
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
const { start, end, loc } = arg;
|
|
3635
3840
|
return {
|
|
3636
|
-
|
|
3841
|
+
type: "Literal",
|
|
3637
3842
|
value,
|
|
3638
|
-
raw
|
|
3843
|
+
raw,
|
|
3844
|
+
start,
|
|
3845
|
+
end,
|
|
3846
|
+
loc,
|
|
3639
3847
|
};
|
|
3640
3848
|
}
|
|
3849
|
+
function classify(arg) {
|
|
3850
|
+
switch (arg) {
|
|
3851
|
+
case "Number":
|
|
3852
|
+
return { big: false, int: true };
|
|
3853
|
+
case "Long":
|
|
3854
|
+
return { big: true, int: true };
|
|
3855
|
+
case "Float":
|
|
3856
|
+
return { big: false, int: false };
|
|
3857
|
+
case "Double":
|
|
3858
|
+
return { big: true, int: false };
|
|
3859
|
+
}
|
|
3860
|
+
return null;
|
|
3861
|
+
}
|
|
3862
|
+
function common_arith_types(left, right) {
|
|
3863
|
+
const l = classify(left);
|
|
3864
|
+
if (!l)
|
|
3865
|
+
return null;
|
|
3866
|
+
const r = classify(right);
|
|
3867
|
+
if (!r)
|
|
3868
|
+
return null;
|
|
3869
|
+
if (l.big || r.big) {
|
|
3870
|
+
return l.int && r.int
|
|
3871
|
+
? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
|
|
3872
|
+
: ["Double", (v) => Number(v)];
|
|
3873
|
+
}
|
|
3874
|
+
else {
|
|
3875
|
+
return l.int && r.int
|
|
3876
|
+
? ["Number", (v) => BigInt.asIntN(32, BigInt(v))]
|
|
3877
|
+
: ["Float", (v) => roundToFloat(Number(v))];
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
function common_bitwise_types(left, right) {
|
|
3881
|
+
if (left === "Boolean" && right === "Boolean") {
|
|
3882
|
+
return ["Boolean", (v) => (v ? true : false)];
|
|
3883
|
+
}
|
|
3884
|
+
const l = classify(left);
|
|
3885
|
+
if (!l)
|
|
3886
|
+
return null;
|
|
3887
|
+
const r = classify(right);
|
|
3888
|
+
if (!r)
|
|
3889
|
+
return null;
|
|
3890
|
+
if (!l.int || !r.int)
|
|
3891
|
+
return null;
|
|
3892
|
+
return l.big || r.big
|
|
3893
|
+
? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
|
|
3894
|
+
: ["Number", (v) => Number(BigInt.asIntN(32, BigInt(v)))];
|
|
3895
|
+
}
|
|
3896
|
+
function plus_types(left, right) {
|
|
3897
|
+
if (left === "String" || right === "String") {
|
|
3898
|
+
// Boolean + String is an error, and
|
|
3899
|
+
// Float/Double + String is legal, but its hard to predict
|
|
3900
|
+
// the way the float will be formatted (and it won't match
|
|
3901
|
+
// what javascript would do by default)
|
|
3902
|
+
if (/Float|Double|Boolean/.test(left + right)) {
|
|
3903
|
+
return null;
|
|
3904
|
+
}
|
|
3905
|
+
return ["String", String];
|
|
3906
|
+
}
|
|
3907
|
+
if (left === "Char" || right === "Char") {
|
|
3908
|
+
if (left === right) {
|
|
3909
|
+
// adding two chars produces a string
|
|
3910
|
+
return ["String", String];
|
|
3911
|
+
}
|
|
3912
|
+
if (/Number|Long/.test(left + right)) {
|
|
3913
|
+
return ["Char", (v) => v];
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
return common_arith_types(left, right);
|
|
3917
|
+
}
|
|
3918
|
+
function shift_mod_types(left, right) {
|
|
3919
|
+
const result = common_bitwise_types(left, right);
|
|
3920
|
+
if (result && result[0] === "Boolean") {
|
|
3921
|
+
return null;
|
|
3922
|
+
}
|
|
3923
|
+
return result;
|
|
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
|
+
}
|
|
3641
3939
|
const operators = {
|
|
3642
|
-
"+":
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
"
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
"
|
|
3659
|
-
|
|
3660
|
-
|
|
3940
|
+
"+": {
|
|
3941
|
+
typeFn: plus_types,
|
|
3942
|
+
valueFn: (left, right) => typeof left === "string" && typeof right !== "string"
|
|
3943
|
+
? String.fromCharCode(left.charCodeAt(0) + Number(right))
|
|
3944
|
+
: typeof left !== "string" && typeof right === "string"
|
|
3945
|
+
? String.fromCharCode(right.charCodeAt(0) + Number(left))
|
|
3946
|
+
: left + right,
|
|
3947
|
+
},
|
|
3948
|
+
"-": {
|
|
3949
|
+
typeFn: common_arith_types,
|
|
3950
|
+
valueFn: (left, right) => left - right,
|
|
3951
|
+
},
|
|
3952
|
+
"*": {
|
|
3953
|
+
typeFn: common_arith_types,
|
|
3954
|
+
valueFn: (left, right) => left * right,
|
|
3955
|
+
},
|
|
3956
|
+
"/": {
|
|
3957
|
+
typeFn: common_arith_types,
|
|
3958
|
+
valueFn: (left, right) => left / right,
|
|
3959
|
+
},
|
|
3960
|
+
"%": {
|
|
3961
|
+
typeFn: shift_mod_types,
|
|
3962
|
+
valueFn: (left, right) => left % right,
|
|
3963
|
+
},
|
|
3964
|
+
"&": {
|
|
3965
|
+
typeFn: common_bitwise_types,
|
|
3966
|
+
valueFn: (left, right) => left & right,
|
|
3967
|
+
},
|
|
3968
|
+
"|": {
|
|
3969
|
+
typeFn: common_bitwise_types,
|
|
3970
|
+
valueFn: (left, right) => left | right,
|
|
3971
|
+
},
|
|
3972
|
+
"^": {
|
|
3973
|
+
typeFn: common_bitwise_types,
|
|
3974
|
+
valueFn: (left, right) => left ^ right,
|
|
3975
|
+
},
|
|
3976
|
+
"<<": {
|
|
3977
|
+
typeFn: shift_mod_types,
|
|
3978
|
+
valueFn: (left, right) => typeof right === "bigint"
|
|
3979
|
+
? left << right
|
|
3980
|
+
: left << right,
|
|
3981
|
+
},
|
|
3982
|
+
">>": {
|
|
3983
|
+
typeFn: shift_mod_types,
|
|
3984
|
+
valueFn: (left, right) => typeof right === "bigint"
|
|
3985
|
+
? left >> right
|
|
3986
|
+
: left >> right,
|
|
3987
|
+
},
|
|
3988
|
+
"==": {
|
|
3989
|
+
typeFn: () => ["Boolean", (v) => v],
|
|
3990
|
+
valueFn: equalsFn,
|
|
3991
|
+
},
|
|
3992
|
+
"!=": {
|
|
3993
|
+
typeFn: () => ["Boolean", (v) => v],
|
|
3994
|
+
valueFn: (left, right) => !equalsFn(left, right),
|
|
3995
|
+
},
|
|
3996
|
+
"<=": {
|
|
3997
|
+
typeFn: common_arith_types,
|
|
3998
|
+
valueFn: (left, right) => left <= right,
|
|
3999
|
+
},
|
|
4000
|
+
">=": {
|
|
4001
|
+
typeFn: common_arith_types,
|
|
4002
|
+
valueFn: (left, right) => left >= right,
|
|
4003
|
+
},
|
|
4004
|
+
"<": {
|
|
4005
|
+
typeFn: common_arith_types,
|
|
4006
|
+
valueFn: (left, right) => left < right,
|
|
4007
|
+
},
|
|
4008
|
+
">": {
|
|
4009
|
+
typeFn: common_arith_types,
|
|
4010
|
+
valueFn: (left, right) => left > right,
|
|
4011
|
+
},
|
|
3661
4012
|
as: null,
|
|
3662
4013
|
instanceof: null,
|
|
3663
4014
|
has: null,
|
|
@@ -3670,23 +4021,31 @@ function optimizeNode(state, node) {
|
|
|
3670
4021
|
break;
|
|
3671
4022
|
switch (node.operator) {
|
|
3672
4023
|
case "+":
|
|
3673
|
-
if (type === "Number" ||
|
|
4024
|
+
if (type === "Number" ||
|
|
4025
|
+
type === "Long" ||
|
|
4026
|
+
type === "Float" ||
|
|
4027
|
+
type === "Double" ||
|
|
4028
|
+
type === "Char" ||
|
|
4029
|
+
type === "String") {
|
|
3674
4030
|
return arg;
|
|
3675
4031
|
}
|
|
3676
4032
|
break;
|
|
3677
4033
|
case "-":
|
|
3678
|
-
if (type === "Number" ||
|
|
3679
|
-
|
|
4034
|
+
if (type === "Number" ||
|
|
4035
|
+
type === "Long" ||
|
|
4036
|
+
type === "Float" ||
|
|
4037
|
+
type === "Double") {
|
|
4038
|
+
return replacementLiteral(node, -arg.value, type);
|
|
3680
4039
|
}
|
|
3681
4040
|
break;
|
|
3682
4041
|
case "!":
|
|
3683
4042
|
case "~":
|
|
3684
4043
|
{
|
|
3685
4044
|
if (type === "Number" || type === "Long") {
|
|
3686
|
-
return replacementLiteral(
|
|
4045
|
+
return replacementLiteral(node, ~BigInt(arg.value), type);
|
|
3687
4046
|
}
|
|
3688
4047
|
if (type === "Boolean" && node.operator == "!") {
|
|
3689
|
-
return replacementLiteral(
|
|
4048
|
+
return replacementLiteral(node, !arg.value, type);
|
|
3690
4049
|
}
|
|
3691
4050
|
}
|
|
3692
4051
|
break;
|
|
@@ -3700,23 +4059,13 @@ function optimizeNode(state, node) {
|
|
|
3700
4059
|
const [right, right_type] = getNodeValue(node.right);
|
|
3701
4060
|
if (!left || !right)
|
|
3702
4061
|
break;
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
if (node.operator !== "==" && node.operator !== "!=") {
|
|
3708
|
-
break;
|
|
3709
|
-
}
|
|
3710
|
-
value = operators[node.operator](left.value, right.value);
|
|
3711
|
-
type = "Boolean";
|
|
3712
|
-
}
|
|
3713
|
-
else {
|
|
3714
|
-
type = left_type;
|
|
3715
|
-
value = op(BigInt(left.value), BigInt(right.value));
|
|
3716
|
-
}
|
|
4062
|
+
const type = op.typeFn(left_type, right_type);
|
|
4063
|
+
if (!type)
|
|
4064
|
+
break;
|
|
4065
|
+
const value = op.valueFn(type[1](left.value), type[1](right.value));
|
|
3717
4066
|
if (value === null)
|
|
3718
4067
|
break;
|
|
3719
|
-
return replacementLiteral(
|
|
4068
|
+
return replacementLiteral(node, value, type[0]);
|
|
3720
4069
|
}
|
|
3721
4070
|
break;
|
|
3722
4071
|
}
|
|
@@ -4169,7 +4518,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
|
|
|
4169
4518
|
if (!state.currentFunction) {
|
|
4170
4519
|
throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
|
|
4171
4520
|
}
|
|
4172
|
-
state.currentFunction.info = state.currentFunction.next_info;
|
|
4521
|
+
state.currentFunction.info = state.currentFunction.next_info || false;
|
|
4173
4522
|
delete state.currentFunction.next_info;
|
|
4174
4523
|
delete state.currentFunction;
|
|
4175
4524
|
break;
|
|
@@ -4607,6 +4956,8 @@ const external_sdk_util_cjs_namespaceObject = require("./sdk-util.cjs");
|
|
|
4607
4956
|
;// CONCATENATED MODULE: ./src/resources.ts
|
|
4608
4957
|
|
|
4609
4958
|
|
|
4959
|
+
|
|
4960
|
+
|
|
4610
4961
|
/*
|
|
4611
4962
|
* This is unavoidably ad-hoc. Garmin has arbitrary rules for how
|
|
4612
4963
|
* resources can be nested, which we need to mimic here.
|
|
@@ -4759,7 +5110,7 @@ function visit_resources(elements, parent, v) {
|
|
|
4759
5110
|
visitor.post(e);
|
|
4760
5111
|
});
|
|
4761
5112
|
}
|
|
4762
|
-
function add_resources_to_ast(ast, resources, manifestXML) {
|
|
5113
|
+
function add_resources_to_ast(state, ast, resources, manifestXML) {
|
|
4763
5114
|
const modules = {
|
|
4764
5115
|
Drawables: true,
|
|
4765
5116
|
Fonts: true,
|
|
@@ -4801,7 +5152,7 @@ function add_resources_to_ast(ast, resources, manifestXML) {
|
|
|
4801
5152
|
manifestXML.body instanceof external_sdk_util_cjs_namespaceObject.xmlUtil.Nodes) {
|
|
4802
5153
|
manifestXML.body
|
|
4803
5154
|
.children("iq:application")
|
|
4804
|
-
.elements.forEach((e) => add_one_resource(rez, e));
|
|
5155
|
+
.elements.forEach((e) => add_one_resource(state, manifestXML, rez, e));
|
|
4805
5156
|
}
|
|
4806
5157
|
const rezModules = Object.fromEntries(Object.entries(modules).map(([moduleName, isPublic]) => {
|
|
4807
5158
|
const module = makeModule(moduleName);
|
|
@@ -4817,110 +5168,152 @@ function add_resources_to_ast(ast, resources, manifestXML) {
|
|
|
4817
5168
|
if (!ast_hasProperty(rezModules, s))
|
|
4818
5169
|
return;
|
|
4819
5170
|
const module = rezModules[s];
|
|
4820
|
-
add_one_resource(module, e);
|
|
5171
|
+
add_one_resource(state, rez, module, e);
|
|
4821
5172
|
});
|
|
4822
5173
|
});
|
|
4823
5174
|
});
|
|
4824
5175
|
}
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
}
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
},
|
|
5176
|
+
const drawableSkips = {
|
|
5177
|
+
x: { center: true, left: true, right: true, start: true },
|
|
5178
|
+
y: { center: true, top: true, bottom: true, start: true },
|
|
5179
|
+
width: { fill: true },
|
|
5180
|
+
height: { fill: true },
|
|
5181
|
+
a: { fill: true },
|
|
5182
|
+
b: { fill: true },
|
|
5183
|
+
color: {},
|
|
5184
|
+
corner_radius: {},
|
|
5185
|
+
radius: {},
|
|
5186
|
+
border_width: {},
|
|
5187
|
+
border_color: {},
|
|
5188
|
+
foreground: {},
|
|
5189
|
+
background: {},
|
|
5190
|
+
font: {},
|
|
5191
|
+
justification: {},
|
|
5192
|
+
};
|
|
5193
|
+
function addPositions(base, pos) {
|
|
5194
|
+
const result = { ...base };
|
|
5195
|
+
if (pos.line > 1) {
|
|
5196
|
+
result.line += pos.line - 1;
|
|
5197
|
+
result.column = pos.column;
|
|
5198
|
+
}
|
|
5199
|
+
else {
|
|
5200
|
+
result.column += pos.column - 1;
|
|
5201
|
+
}
|
|
5202
|
+
result.offset += pos.offset;
|
|
5203
|
+
return result;
|
|
4835
5204
|
}
|
|
4836
|
-
function
|
|
4837
|
-
const
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
5205
|
+
function visit_resource_refs(state, doc, e) {
|
|
5206
|
+
const result = [];
|
|
5207
|
+
const parseArg = (name, loc, skip) => {
|
|
5208
|
+
if (name.startsWith("@")) {
|
|
5209
|
+
name = name.substring(1);
|
|
5210
|
+
loc = adjustLoc(loc, 1, 0);
|
|
4842
5211
|
}
|
|
4843
|
-
|
|
4844
|
-
|
|
5212
|
+
if (ast_hasProperty(skip, name)) {
|
|
5213
|
+
return;
|
|
4845
5214
|
}
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
}, { cur: null, offset: 0 }).cur;
|
|
4849
|
-
}
|
|
4850
|
-
function visit_resource_refs(e) {
|
|
4851
|
-
const result = [];
|
|
4852
|
-
const stringToScopedName = (element, id, dotted, l) => {
|
|
4853
|
-
const match = dotted.match(/^(@)?([\w_$]+\s*\.\s*)*[\w_$]+$/);
|
|
4854
|
-
if (!match)
|
|
5215
|
+
if (/^([-\w_$]+\s*\.\s*)*[-\w_$]+$/.test(name)) {
|
|
5216
|
+
result.push(makeScopedName(name, loc));
|
|
4855
5217
|
return;
|
|
4856
|
-
let offset = 0;
|
|
4857
|
-
if (match[1]) {
|
|
4858
|
-
offset = 1;
|
|
4859
5218
|
}
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
5219
|
+
// We wrap the expression in parentheses, so adjust
|
|
5220
|
+
// the start position by 1 character to compensate
|
|
5221
|
+
// for the opening '('
|
|
5222
|
+
const startPos = adjustLoc(loc, -1, 0).start;
|
|
5223
|
+
try {
|
|
5224
|
+
const expr = prettier_plugin_monkeyc_default().parsers.monkeyc.parse(`(${name})`, null, {
|
|
5225
|
+
filepath: loc.source || undefined,
|
|
5226
|
+
singleExpression: true,
|
|
5227
|
+
});
|
|
5228
|
+
ast_traverseAst(expr, (node) => {
|
|
5229
|
+
if (node.loc) {
|
|
5230
|
+
node.loc = {
|
|
5231
|
+
source: node.loc.source,
|
|
5232
|
+
start: addPositions(startPos, node.loc.start),
|
|
5233
|
+
end: addPositions(startPos, node.loc.end),
|
|
5234
|
+
};
|
|
5235
|
+
node.start = (node.start || 0) + startPos.offset;
|
|
5236
|
+
node.end = (node.end || 0) + startPos.offset;
|
|
5237
|
+
}
|
|
5238
|
+
});
|
|
5239
|
+
result.push(expr);
|
|
4863
5240
|
}
|
|
4864
|
-
|
|
4865
|
-
|
|
5241
|
+
catch (ex) {
|
|
5242
|
+
if (state) {
|
|
5243
|
+
const check = state.config?.checkInvalidSymbols;
|
|
5244
|
+
if (check !== "OFF" && ex instanceof Error) {
|
|
5245
|
+
const error = ex;
|
|
5246
|
+
if (error.location) {
|
|
5247
|
+
const location = {
|
|
5248
|
+
source: error.location.source,
|
|
5249
|
+
start: addPositions(startPos, error.location.start),
|
|
5250
|
+
end: addPositions(startPos, error.location.end),
|
|
5251
|
+
};
|
|
5252
|
+
inliner_diagnostic(state, location, ex.message, check || "WARNING");
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
4866
5256
|
}
|
|
4867
|
-
const dn = makeScopedName(dotted.substring(offset), adjustLoc(l, offset, 0));
|
|
4868
|
-
if (dn)
|
|
4869
|
-
result.push(dn);
|
|
4870
5257
|
};
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
if (
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
5258
|
+
const stringToScopedName = (element, id, dotted, l) => {
|
|
5259
|
+
dotted = doc.processRefs(dotted);
|
|
5260
|
+
if (dotted.startsWith("@")) {
|
|
5261
|
+
return parseArg(dotted, l);
|
|
5262
|
+
}
|
|
5263
|
+
if (/^\s*(true|false|null|NaN|(0x|#)[0-9a-f]+|[-+]?\d+%?)\s*$/i.test(dotted)) {
|
|
5264
|
+
return;
|
|
5265
|
+
}
|
|
5266
|
+
switch (element.name) {
|
|
5267
|
+
case "param":
|
|
5268
|
+
if (id === null) {
|
|
5269
|
+
parseArg(dotted, l);
|
|
5270
|
+
}
|
|
5271
|
+
return;
|
|
5272
|
+
case "drawable":
|
|
5273
|
+
if (id === "class") {
|
|
5274
|
+
parseArg(dotted, l);
|
|
5275
|
+
}
|
|
5276
|
+
return;
|
|
5277
|
+
case "shape":
|
|
5278
|
+
case "bitmap":
|
|
5279
|
+
case "drawable-list":
|
|
5280
|
+
case "text-area":
|
|
5281
|
+
case "label":
|
|
5282
|
+
if (id && ast_hasProperty(drawableSkips, id)) {
|
|
5283
|
+
parseArg(dotted, l, drawableSkips[id]);
|
|
5284
|
+
}
|
|
5285
|
+
return;
|
|
5286
|
+
case "iq:application":
|
|
5287
|
+
if (id === "entry") {
|
|
5288
|
+
parseArg(dotted, l);
|
|
4885
5289
|
}
|
|
4886
5290
|
return;
|
|
5291
|
+
default:
|
|
5292
|
+
return;
|
|
5293
|
+
}
|
|
5294
|
+
};
|
|
5295
|
+
external_sdk_util_cjs_namespaceObject.xmlUtil.visit_xml([e], {
|
|
5296
|
+
pre(node) {
|
|
5297
|
+
if (node.type !== "element")
|
|
5298
|
+
return false;
|
|
5299
|
+
Object.values(node.attr).forEach((attr) => {
|
|
5300
|
+
if (!attr || !attr.value.loc)
|
|
5301
|
+
return;
|
|
5302
|
+
const loc = adjustLoc(attr.value.loc);
|
|
5303
|
+
attr &&
|
|
5304
|
+
stringToScopedName(node, attr.name.value, attr.value.value, loc);
|
|
5305
|
+
});
|
|
5306
|
+
const content = doc.textContent(node);
|
|
5307
|
+
if (content) {
|
|
5308
|
+
stringToScopedName(node, null, content, locRange(node.children[0].loc, node.children[node.children.length - 1].loc));
|
|
5309
|
+
return false;
|
|
4887
5310
|
}
|
|
5311
|
+
return;
|
|
4888
5312
|
},
|
|
4889
5313
|
});
|
|
4890
5314
|
return result;
|
|
4891
5315
|
}
|
|
4892
|
-
function
|
|
4893
|
-
if (loc) {
|
|
4894
|
-
node.loc = loc;
|
|
4895
|
-
node.start = loc.start.offset;
|
|
4896
|
-
node.end = loc.end.offset;
|
|
4897
|
-
}
|
|
4898
|
-
return node;
|
|
4899
|
-
}
|
|
4900
|
-
function locRange(start, end) {
|
|
4901
|
-
return {
|
|
4902
|
-
source: start.source || end.source,
|
|
4903
|
-
start: start.start,
|
|
4904
|
-
end: end.end,
|
|
4905
|
-
};
|
|
4906
|
-
}
|
|
4907
|
-
function adjustLoc(loc, start = 1, end = -1) {
|
|
4908
|
-
/* Attributes are quoted, so skip the quotes */
|
|
4909
|
-
return {
|
|
4910
|
-
source: loc.source,
|
|
4911
|
-
start: {
|
|
4912
|
-
offset: loc.start.offset + start,
|
|
4913
|
-
line: loc.start.line,
|
|
4914
|
-
column: loc.start.column + start,
|
|
4915
|
-
},
|
|
4916
|
-
end: {
|
|
4917
|
-
offset: loc.end.offset + end,
|
|
4918
|
-
line: loc.end.line,
|
|
4919
|
-
column: loc.end.column + end,
|
|
4920
|
-
},
|
|
4921
|
-
};
|
|
4922
|
-
}
|
|
4923
|
-
function add_one_resource(module, e) {
|
|
5316
|
+
function add_one_resource(state, doc, module, e) {
|
|
4924
5317
|
let id;
|
|
4925
5318
|
let func;
|
|
4926
5319
|
const varDecl = () => {
|
|
@@ -4931,26 +5324,92 @@ function add_one_resource(module, e) {
|
|
|
4931
5324
|
wrap({
|
|
4932
5325
|
type: "VariableDeclarator",
|
|
4933
5326
|
kind: "var",
|
|
4934
|
-
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
|
+
},
|
|
4935
5341
|
init,
|
|
4936
|
-
}, loc),
|
|
5342
|
+
}, e.loc),
|
|
4937
5343
|
],
|
|
4938
5344
|
kind: "var",
|
|
4939
|
-
}, loc);
|
|
5345
|
+
}, e.loc);
|
|
4940
5346
|
};
|
|
4941
5347
|
const classDecl = (parent) => {
|
|
4942
5348
|
if (!id)
|
|
4943
5349
|
return null;
|
|
4944
5350
|
const loc = id.value.loc;
|
|
4945
5351
|
const items = init
|
|
4946
|
-
? [{ type: "ClassElement", item: varDecl(), loc }]
|
|
5352
|
+
? [{ type: "ClassElement", item: varDecl(), loc: e.loc }]
|
|
4947
5353
|
: [];
|
|
4948
5354
|
return {
|
|
4949
5355
|
type: "ClassDeclaration",
|
|
4950
|
-
body: { type: "ClassBody", body: items, loc },
|
|
5356
|
+
body: { type: "ClassBody", body: items, loc: e.loc },
|
|
4951
5357
|
id: makeIdentifier(id.value.value, loc),
|
|
4952
5358
|
superClass: makeScopedName(parent),
|
|
4953
|
-
loc,
|
|
5359
|
+
loc: e.loc,
|
|
5360
|
+
};
|
|
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,
|
|
4954
5413
|
};
|
|
4955
5414
|
};
|
|
4956
5415
|
switch (e.name) {
|
|
@@ -4959,13 +5418,16 @@ function add_one_resource(module, e) {
|
|
|
4959
5418
|
case "jsonData":
|
|
4960
5419
|
case "animation":
|
|
4961
5420
|
case "bitmap":
|
|
4962
|
-
case "layout":
|
|
4963
5421
|
case "drawable-list":
|
|
4964
5422
|
case "property":
|
|
4965
5423
|
case "fitField":
|
|
4966
5424
|
id = e.attr.id;
|
|
4967
5425
|
func = varDecl;
|
|
4968
5426
|
break;
|
|
5427
|
+
case "layout":
|
|
5428
|
+
id = e.attr.id;
|
|
5429
|
+
func = layoutDecl;
|
|
5430
|
+
break;
|
|
4969
5431
|
case "menu":
|
|
4970
5432
|
id = e.attr.id;
|
|
4971
5433
|
func = () => classDecl("Ui.Menu");
|
|
@@ -4992,7 +5454,7 @@ function add_one_resource(module, e) {
|
|
|
4992
5454
|
}
|
|
4993
5455
|
if (!func)
|
|
4994
5456
|
return;
|
|
4995
|
-
const elements = visit_resource_refs(e);
|
|
5457
|
+
const elements = visit_resource_refs(state, doc, e);
|
|
4996
5458
|
const init = elements.length
|
|
4997
5459
|
? { type: "ArrayExpression", elements }
|
|
4998
5460
|
: undefined;
|
|
@@ -5228,7 +5690,7 @@ async function api_getApiMapping(state, resourcesMap, manifestXML) {
|
|
|
5228
5690
|
const rezAst = state
|
|
5229
5691
|
? state.rezAst || { type: "Program", body: [] }
|
|
5230
5692
|
: ast;
|
|
5231
|
-
add_resources_to_ast(rezAst, resourcesMap, manifestXML);
|
|
5693
|
+
add_resources_to_ast(state, rezAst, resourcesMap, manifestXML);
|
|
5232
5694
|
if (state) {
|
|
5233
5695
|
state.rezAst = rezAst;
|
|
5234
5696
|
state.manifestXML = manifestXML;
|
|
@@ -5555,387 +6017,423 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
|
|
|
5555
6017
|
}
|
|
5556
6018
|
return [false, false];
|
|
5557
6019
|
}
|
|
5558
|
-
function
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
},
|
|
5573
|
-
];
|
|
5574
|
-
}
|
|
5575
|
-
if (!state.lookupRules) {
|
|
5576
|
-
const rules = state?.config?.compilerLookupRules || "DEFAULT";
|
|
5577
|
-
if (rules !== "COMPILER1" && rules !== "COMPILER2") {
|
|
5578
|
-
const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
|
|
5579
|
-
if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
|
|
5580
|
-
state.lookupRules = "COMPILER2";
|
|
5581
|
-
}
|
|
5582
|
-
else {
|
|
5583
|
-
state.lookupRules = "COMPILER1";
|
|
5584
|
-
}
|
|
5585
|
-
}
|
|
5586
|
-
}
|
|
5587
|
-
state.removeNodeComments = (node, ast) => {
|
|
5588
|
-
if (node.start && node.end && ast.comments && ast.comments.length) {
|
|
5589
|
-
let low = 0, high = ast.comments.length;
|
|
5590
|
-
while (high > low) {
|
|
5591
|
-
const mid = (low + high) >> 1;
|
|
5592
|
-
if ((ast.comments[mid].start || 0) < node.start) {
|
|
5593
|
-
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
|
+
}
|
|
5594
6034
|
}
|
|
5595
|
-
|
|
5596
|
-
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);
|
|
5597
6041
|
}
|
|
5598
6042
|
}
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
case "UnaryExpression":
|
|
5624
|
-
if (node.operator === ":" && !state.inType) {
|
|
5625
|
-
state.nextExposed[node.argument.name] = true;
|
|
5626
|
-
}
|
|
5627
|
-
break;
|
|
5628
|
-
case "AttributeList":
|
|
5629
|
-
return [];
|
|
5630
|
-
case "Program":
|
|
5631
|
-
if (state.stack.length != 1) {
|
|
5632
|
-
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 [];
|
|
5633
6067
|
}
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
case "ImportModule":
|
|
5641
|
-
case "Using": {
|
|
5642
|
-
const [parent] = state.stack.slice(-1);
|
|
5643
|
-
if (!parent.usings) {
|
|
5644
|
-
parent.usings = {};
|
|
5645
|
-
}
|
|
5646
|
-
const name = (node.type === "Using" && node.as && node.as.name) ||
|
|
5647
|
-
(node.id.type === "Identifier"
|
|
5648
|
-
? node.id.name
|
|
5649
|
-
: node.id.property.name);
|
|
5650
|
-
const using = { node };
|
|
5651
|
-
parent.usings[name] = using;
|
|
5652
|
-
if (node.type == "ImportModule") {
|
|
5653
|
-
if (!parent.imports) {
|
|
5654
|
-
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;
|
|
5655
6074
|
}
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
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;
|
|
5663
6118
|
}
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
if (parent.node === node ||
|
|
5699
|
-
(parent.type != "FunctionDeclaration" &&
|
|
5700
|
-
parent.type != "BlockStatement")) {
|
|
5701
|
-
break;
|
|
5702
|
-
}
|
|
5703
|
-
// fall through
|
|
5704
|
-
}
|
|
5705
|
-
case "ClassDeclaration":
|
|
5706
|
-
case "FunctionDeclaration":
|
|
5707
|
-
case "ModuleDeclaration": {
|
|
5708
|
-
const [parent] = state.stack.slice(-1);
|
|
5709
|
-
const name = "id" in node ? node.id && node.id.name : undefined;
|
|
5710
|
-
const fullName = state.stack
|
|
5711
|
-
.map((e) => e.name)
|
|
5712
|
-
.concat(name)
|
|
5713
|
-
.filter((e) => e != null)
|
|
5714
|
-
.join(".");
|
|
5715
|
-
const elm = {
|
|
5716
|
-
type: node.type,
|
|
5717
|
-
name,
|
|
5718
|
-
fullName,
|
|
5719
|
-
node,
|
|
5720
|
-
attributes: node.type === "BlockStatement"
|
|
5721
|
-
? 0
|
|
5722
|
-
: stateNodeAttrs(node.attrs),
|
|
5723
|
-
};
|
|
5724
|
-
state.stack.push(elm);
|
|
5725
|
-
if (name) {
|
|
5726
|
-
if (!parent.decls)
|
|
5727
|
-
parent.decls = {};
|
|
5728
|
-
if (ast_hasProperty(parent.decls, name)) {
|
|
5729
|
-
const what = node.type == "ModuleDeclaration" ? "type" : "node";
|
|
5730
|
-
const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
|
|
5731
|
-
if (e != null) {
|
|
5732
|
-
e.node = node;
|
|
5733
|
-
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")) {
|
|
5734
6153
|
break;
|
|
5735
6154
|
}
|
|
6155
|
+
// fall through
|
|
5736
6156
|
}
|
|
5737
|
-
|
|
5738
|
-
|
|
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;
|
|
5739
6211
|
}
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
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));
|
|
5745
6222
|
}
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
6223
|
+
// fall through
|
|
6224
|
+
case "TypedefDeclaration": {
|
|
6225
|
+
this.inType++;
|
|
6226
|
+
const name = node.id.name;
|
|
6227
|
+
const [parent] = this.stack.slice(-1);
|
|
5749
6228
|
if (!parent.type_decls)
|
|
5750
6229
|
parent.type_decls = {};
|
|
5751
6230
|
if (!ast_hasProperty(parent.type_decls, name)) {
|
|
5752
6231
|
parent.type_decls[name] = [];
|
|
5753
6232
|
}
|
|
5754
|
-
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;
|
|
5755
6346
|
}
|
|
5756
6347
|
}
|
|
5757
|
-
|
|
6348
|
+
if (this.pre)
|
|
6349
|
+
return this.pre(node, this);
|
|
5758
6350
|
}
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
case "EnumDeclaration": {
|
|
5762
|
-
if (!node.id) {
|
|
5763
|
-
state.inType++;
|
|
5764
|
-
break;
|
|
5765
|
-
}
|
|
5766
|
-
const [parent] = state.stack.slice(-1);
|
|
5767
|
-
const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
|
|
5768
|
-
node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
|
|
6351
|
+
catch (e) {
|
|
6352
|
+
handleException(this, node, e);
|
|
5769
6353
|
}
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
if (!ast_hasProperty(parent.type_decls, name)) {
|
|
5778
|
-
parent.type_decls[name] = [];
|
|
5779
|
-
}
|
|
5780
|
-
else if (parent.type_decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == node)) {
|
|
5781
|
-
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;
|
|
5782
6361
|
}
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
const stack = state.stackClone();
|
|
5800
|
-
node.declarations.forEach((decl) => {
|
|
5801
|
-
const name = api_variableDeclarationName(decl.id);
|
|
5802
|
-
if (!ast_hasProperty(decls, name)) {
|
|
5803
|
-
decls[name] = [];
|
|
5804
|
-
}
|
|
5805
|
-
else if (decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == decl)) {
|
|
5806
|
-
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;
|
|
5807
6378
|
}
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
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();
|
|
5820
6390
|
}
|
|
5821
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
5822
6391
|
}
|
|
5823
|
-
}
|
|
5824
|
-
|
|
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;
|
|
5825
6398
|
}
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
throw new Error(`Expected inType to be 1 at EnumStringBody. Got ${state.inType}.`);
|
|
5829
|
-
}
|
|
5830
|
-
state.inType--;
|
|
5831
|
-
const [parent] = state.stack.slice(-1);
|
|
5832
|
-
const values = parent.decls || (parent.decls = {});
|
|
5833
|
-
let prev = -1;
|
|
5834
|
-
node.members.forEach((m, i) => {
|
|
5835
|
-
if (m.type == "Identifier") {
|
|
5836
|
-
if (typeof prev === "bigint") {
|
|
5837
|
-
prev += 1n;
|
|
5838
|
-
}
|
|
5839
|
-
else {
|
|
5840
|
-
prev += 1;
|
|
5841
|
-
}
|
|
5842
|
-
m = node.members[i] = {
|
|
5843
|
-
type: "EnumStringMember",
|
|
5844
|
-
loc: m.loc,
|
|
5845
|
-
start: m.start,
|
|
5846
|
-
end: m.end,
|
|
5847
|
-
id: m,
|
|
5848
|
-
init: {
|
|
5849
|
-
type: "Literal",
|
|
5850
|
-
value: prev,
|
|
5851
|
-
raw: prev.toString() + (typeof prev === "bigint" ? "l" : ""),
|
|
5852
|
-
enumType: m.enumType,
|
|
5853
|
-
loc: m.loc,
|
|
5854
|
-
start: m.start,
|
|
5855
|
-
end: m.end,
|
|
5856
|
-
},
|
|
5857
|
-
};
|
|
5858
|
-
}
|
|
5859
|
-
const name = m.id.name;
|
|
5860
|
-
const init = getLiteralNode(m.init);
|
|
5861
|
-
if (!init) {
|
|
5862
|
-
throw new Error("Unexpected enum initializer");
|
|
5863
|
-
}
|
|
5864
|
-
if (init != m.init) {
|
|
5865
|
-
if (m.init.enumType) {
|
|
5866
|
-
init.enumType = m.init.enumType;
|
|
5867
|
-
}
|
|
5868
|
-
m.init = init;
|
|
5869
|
-
}
|
|
5870
|
-
if (init.type == "Literal" &&
|
|
5871
|
-
init.raw &&
|
|
5872
|
-
prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
|
|
5873
|
-
prev = init.value;
|
|
5874
|
-
}
|
|
5875
|
-
if (!ast_hasProperty(values, name)) {
|
|
5876
|
-
values[name] = [];
|
|
5877
|
-
}
|
|
5878
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(values[name], m);
|
|
5879
|
-
if (!ast_hasProperty(state.index, name)) {
|
|
5880
|
-
state.index[name] = [];
|
|
5881
|
-
}
|
|
5882
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
5883
|
-
});
|
|
5884
|
-
break;
|
|
6399
|
+
catch (e) {
|
|
6400
|
+
handleException(this, node, e);
|
|
5885
6401
|
}
|
|
5886
|
-
}
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
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";
|
|
5900
6429
|
}
|
|
5901
6430
|
else {
|
|
5902
|
-
|
|
5903
|
-
if (state.post)
|
|
5904
|
-
ret = state.post(node, state);
|
|
5905
|
-
switch (type) {
|
|
5906
|
-
case "TypeSpecPart":
|
|
5907
|
-
case "TypeSpecList":
|
|
5908
|
-
case "TypedefDeclaration":
|
|
5909
|
-
case "EnumDeclaration":
|
|
5910
|
-
state.inType--;
|
|
5911
|
-
break;
|
|
5912
|
-
case "EnumStringBody":
|
|
5913
|
-
state.inType++;
|
|
5914
|
-
break;
|
|
5915
|
-
}
|
|
5916
|
-
const [parent] = state.stack.slice(-1);
|
|
5917
|
-
if (parent.node === node ||
|
|
5918
|
-
// The pre function might cause node.body to be skipped,
|
|
5919
|
-
// so we need to check here, just in case.
|
|
5920
|
-
// (this actually happens with prettier-extenison-monkeyc's
|
|
5921
|
-
// findItemsByRange)
|
|
5922
|
-
(node.type === "CatchClause" && parent.node === node.body)) {
|
|
5923
|
-
delete parent.usings;
|
|
5924
|
-
delete parent.imports;
|
|
5925
|
-
if (node.type != "Program") {
|
|
5926
|
-
state.stack.pop();
|
|
5927
|
-
}
|
|
5928
|
-
}
|
|
5929
|
-
}
|
|
5930
|
-
if (ret != null) {
|
|
5931
|
-
state.removeNodeComments(node, ast);
|
|
6431
|
+
state.lookupRules = "COMPILER1";
|
|
5932
6432
|
}
|
|
5933
|
-
return ret;
|
|
5934
6433
|
}
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
});
|
|
6434
|
+
}
|
|
6435
|
+
Object.assign(state, stateFuncs());
|
|
6436
|
+
state.inType = 0;
|
|
5939
6437
|
state.traverse(ast);
|
|
5940
6438
|
if (state.inType) {
|
|
5941
6439
|
throw new Error(`inType was non-zero on exit: ${state.inType}`);
|
|
@@ -5958,8 +6456,11 @@ function api_formatAst(node, monkeyCSource = null, options = null) {
|
|
|
5958
6456
|
* should be ignored.
|
|
5959
6457
|
*/
|
|
5960
6458
|
switch (node.type) {
|
|
5961
|
-
case "Program":
|
|
5962
6459
|
case "BlockStatement":
|
|
6460
|
+
if (node.body.length)
|
|
6461
|
+
break;
|
|
6462
|
+
return "{}";
|
|
6463
|
+
case "Program":
|
|
5963
6464
|
case "ExpressionStatement":
|
|
5964
6465
|
break;
|
|
5965
6466
|
default: {
|
|
@@ -6088,15 +6589,16 @@ function api_getApiFunctionInfo(func) {
|
|
|
6088
6589
|
return invokeInfo;
|
|
6089
6590
|
}
|
|
6090
6591
|
if (!toyboxFnInfo.calledFuncs) {
|
|
6091
|
-
|
|
6092
|
-
toyboxFnInfo.calledFuncs = new Set();
|
|
6093
|
-
toyboxFnInfo.resolvedDecls = new Set();
|
|
6592
|
+
return false;
|
|
6094
6593
|
}
|
|
6095
6594
|
return toyboxFnInfo;
|
|
6096
6595
|
}
|
|
6097
6596
|
function api_markInvokeClassMethod(func) {
|
|
6098
6597
|
func.info = invokeInfo;
|
|
6099
6598
|
}
|
|
6599
|
+
function api_isLocal(v) {
|
|
6600
|
+
return v.stack[v.stack.length - 1]?.type === "BlockStatement";
|
|
6601
|
+
}
|
|
6100
6602
|
|
|
6101
6603
|
})();
|
|
6102
6604
|
|