@markw65/monkeyc-optimizer 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/build/api.cjs +65 -27
- package/build/optimizer.cjs +4329 -1361
- package/build/sdk-util.cjs +7 -4
- package/build/src/api.d.ts +8 -4
- package/build/src/ast.d.ts +1 -1
- package/build/src/control-flow.d.ts +2 -1
- package/build/src/data-flow.d.ts +68 -4
- package/build/src/mc-rewrite.d.ts +1 -8
- package/build/src/optimizer-types.d.ts +22 -10
- package/build/src/optimizer.d.ts +2 -16
- package/build/src/projects.d.ts +1 -1
- package/build/src/type-flow/could-be.d.ts +1 -0
- package/build/src/type-flow/dead-store.d.ts +5 -0
- package/build/src/type-flow/interp-call.d.ts +15 -3
- package/build/src/type-flow/interp.d.ts +7 -1
- package/build/src/type-flow/optimize.d.ts +1 -0
- package/build/src/type-flow/type-flow-util.d.ts +16 -0
- package/build/src/type-flow/types.d.ts +41 -39
- package/build/src/type-flow/union-type.d.ts +1 -0
- package/build/src/type-flow.d.ts +11 -2
- package/build/src/unused-exprs.d.ts +1 -1
- package/build/src/util.d.ts +3 -2
- package/build/src/worker-task.d.ts +2 -16
- package/build/util.cjs +10 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -578,3 +578,37 @@ Bug Fixes
|
|
|
578
578
|
### 1.1.1
|
|
579
579
|
|
|
580
580
|
- Fix the package spec to include the new .d.ts files
|
|
581
|
+
|
|
582
|
+
### 1.1.2
|
|
583
|
+
|
|
584
|
+
- Fix a couple of edge cases when constant folding == and !=
|
|
585
|
+
- Optimize `<boolean> && false`, and `<boolean> || true`, when `<boolean>` has no side effects
|
|
586
|
+
- Better optimization of inlined function bodies
|
|
587
|
+
- Analyze constants with casts to help with constant propagation
|
|
588
|
+
- Ignore widening casts (eg a cast that is given a `Number` and converts it to `Number or String`)
|
|
589
|
+
- More accurate deletion of unused constants. Sometimes a constant that was unused after the optimization phase ended, was still considered used because of references that were eventually deleted.
|
|
590
|
+
|
|
591
|
+
### 1.1.3
|
|
592
|
+
|
|
593
|
+
- Tweaks and fixes
|
|
594
|
+
|
|
595
|
+
- Update to [@markw65/prettier-plugin-monkeyc@1.0.42](https://github.com/markw65/prettier-plugin-monkeyc#1042)
|
|
596
|
+
- Fixed an issue that cause inlining in return context to be too conservative
|
|
597
|
+
- Update inliner to keep a stack of locations, so that error messages can show exactly where an error occurred, even in the presence of inlining.
|
|
598
|
+
- Update diagnostic api to optionally include a uri to more detailing information.
|
|
599
|
+
|
|
600
|
+
- Type Analysis
|
|
601
|
+
|
|
602
|
+
- Track type info through branch conditions, so that in `if (x != null) { A } else { B }`, the type checker knows that x is not null in A, and it is null in B.
|
|
603
|
+
- Added checkers for return types, call arguments, assignments and variable declarations.
|
|
604
|
+
- Automatically infer Array and Dictionary types
|
|
605
|
+
- Track equivalencies, and use them for various optimizations.
|
|
606
|
+
- Add support for "strong" and "weak" type checking.
|
|
607
|
+
- Add type analysis to getProgramAnalysis.
|
|
608
|
+
|
|
609
|
+
- Optimizations
|
|
610
|
+
- Eliminate self-assignments (eg `x = x;`, but also `x = a; y = a; ... y = x;`).
|
|
611
|
+
- Eliminate dead stores.
|
|
612
|
+
- Replace more expensive accesses by less expensive ones.
|
|
613
|
+
- Delete empty else blocks.
|
|
614
|
+
- Delete if statements with empty body and no else.
|
package/build/api.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
0 && (module.exports = {checkCompilerVersion,collectNamespaces,diagnostic,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,getSuperClasses,hasProperty,isLocal,isLookupCandidate,isStateNode,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
|
|
1
|
+
0 && (module.exports = {checkCompilerVersion,collectNamespaces,diagnostic,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,getSuperClasses,hasProperty,isLocal,isLookupCandidate,isStateNode,lookupNext,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
|
|
2
2
|
/******/ (() => { // webpackBootstrap
|
|
3
3
|
/******/ "use strict";
|
|
4
4
|
/******/ var __webpack_modules__ = ({
|
|
@@ -113,7 +113,7 @@ function isMCTreeNode(node) {
|
|
|
113
113
|
* - if post returns false, the node it was called on is
|
|
114
114
|
* removed.
|
|
115
115
|
*/
|
|
116
|
-
function traverseAst(node, pre, post) {
|
|
116
|
+
function traverseAst(node, pre, post, parent) {
|
|
117
117
|
const nodes = pre && pre(node);
|
|
118
118
|
if (nodes === false)
|
|
119
119
|
return;
|
|
@@ -128,7 +128,7 @@ function traverseAst(node, pre, post) {
|
|
|
128
128
|
const values = value;
|
|
129
129
|
const deletions = values.reduce((state, obj, i) => {
|
|
130
130
|
if (isMCTreeNode(obj)) {
|
|
131
|
-
const repl = traverseAst(obj, pre, post);
|
|
131
|
+
const repl = traverseAst(obj, pre, post, node);
|
|
132
132
|
if (repl === false) {
|
|
133
133
|
if (!state)
|
|
134
134
|
state = {};
|
|
@@ -147,7 +147,7 @@ function traverseAst(node, pre, post) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
else if (isMCTreeNode(value)) {
|
|
150
|
-
let repl = traverseAst(value, pre, post);
|
|
150
|
+
let repl = traverseAst(value, pre, post, node);
|
|
151
151
|
if (repl === false) {
|
|
152
152
|
delete node[key];
|
|
153
153
|
}
|
|
@@ -167,7 +167,7 @@ function traverseAst(node, pre, post) {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
return post && post(node);
|
|
170
|
+
return post && post(node, parent);
|
|
171
171
|
}
|
|
172
172
|
function isStatement(node) {
|
|
173
173
|
return hasProperty(mctreeTypeInfo[node.type], "stmt");
|
|
@@ -212,6 +212,9 @@ function withLoc(node, start, end) {
|
|
|
212
212
|
}
|
|
213
213
|
function withLocDeep(node, start, end, inplace) {
|
|
214
214
|
node = withLoc(inplace ? node : { ...node }, start, end);
|
|
215
|
+
if (!inplace && node.origins) {
|
|
216
|
+
node.origins = [...node.origins];
|
|
217
|
+
}
|
|
215
218
|
for (const key of mctreeTypeInfo[node.type].keys) {
|
|
216
219
|
const value = node[key];
|
|
217
220
|
if (!value)
|
|
@@ -546,6 +549,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
546
549
|
"isLocal": () => (/* binding */ isLocal),
|
|
547
550
|
"isLookupCandidate": () => (/* binding */ isLookupCandidate),
|
|
548
551
|
"isStateNode": () => (/* binding */ isStateNode),
|
|
552
|
+
"lookupNext": () => (/* binding */ lookupNext),
|
|
549
553
|
"markInvokeClassMethod": () => (/* binding */ markInvokeClassMethod),
|
|
550
554
|
"parseSdkVersion": () => (/* binding */ parseSdkVersion),
|
|
551
555
|
"sameLookupResult": () => (/* binding */ sameLookupResult),
|
|
@@ -869,7 +873,7 @@ function visit_resource_refs(state, doc, e) {
|
|
|
869
873
|
start: addPositions(startPos, error.location.start),
|
|
870
874
|
end: addPositions(startPos, error.location.end),
|
|
871
875
|
};
|
|
872
|
-
(0,external_api_cjs_.diagnostic)(state, location, ex.message, check || "WARNING");
|
|
876
|
+
(0,external_api_cjs_.diagnostic)(state, { type: "Identifier", loc: location, name: "" }, ex.message, check || "WARNING");
|
|
873
877
|
}
|
|
874
878
|
}
|
|
875
879
|
}
|
|
@@ -1458,6 +1462,22 @@ function isLookupCandidate(node) {
|
|
|
1458
1462
|
node.property.argument
|
|
1459
1463
|
: node.property.type === "Identifier" && node.property;
|
|
1460
1464
|
}
|
|
1465
|
+
function lookupNext(state, results, decls, property) {
|
|
1466
|
+
return results.reduce((current, lookupDef) => {
|
|
1467
|
+
const items = lookupDef.results
|
|
1468
|
+
.map((module) => {
|
|
1469
|
+
if (!isStateNode(module)) {
|
|
1470
|
+
return null;
|
|
1471
|
+
}
|
|
1472
|
+
const res = checkOne(state, module, decls, property);
|
|
1473
|
+
return res ? { parent: module, results: res } : null;
|
|
1474
|
+
})
|
|
1475
|
+
.filter((r) => r != null);
|
|
1476
|
+
if (!items.length)
|
|
1477
|
+
return current;
|
|
1478
|
+
return current ? current.concat(items) : items;
|
|
1479
|
+
}, null);
|
|
1480
|
+
}
|
|
1461
1481
|
/**
|
|
1462
1482
|
*
|
|
1463
1483
|
* @param state - The ProgramState
|
|
@@ -1491,20 +1511,7 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
|
|
|
1491
1511
|
break;
|
|
1492
1512
|
if (!results)
|
|
1493
1513
|
return [null, null];
|
|
1494
|
-
result =
|
|
1495
|
-
const items = lookupDef.results
|
|
1496
|
-
.map((module) => {
|
|
1497
|
-
if (!isStateNode(module)) {
|
|
1498
|
-
return null;
|
|
1499
|
-
}
|
|
1500
|
-
const res = checkOne(state, module, decls, property);
|
|
1501
|
-
return res ? { parent: module, results: res } : null;
|
|
1502
|
-
})
|
|
1503
|
-
.filter((r) => r != null);
|
|
1504
|
-
if (!items.length)
|
|
1505
|
-
return current;
|
|
1506
|
-
return current ? current.concat(items) : items;
|
|
1507
|
-
}, null);
|
|
1514
|
+
result = lookupNext(state, results, decls, property);
|
|
1508
1515
|
if (!result &&
|
|
1509
1516
|
results.some((ld) => ld.results.some((sn) => sn.type === "VariableDeclarator" ||
|
|
1510
1517
|
sn.type === "Identifier" ||
|
|
@@ -1610,7 +1617,7 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
|
|
|
1610
1617
|
if (imports) {
|
|
1611
1618
|
if (imports.length > 1) {
|
|
1612
1619
|
if (state.config?.checkInvalidSymbols !== "OFF") {
|
|
1613
|
-
diagnostic(state, node
|
|
1620
|
+
diagnostic(state, node, `${formatAst(node)} is ambiguous and exists in multiple imported modules [${imports
|
|
1614
1621
|
.map(({ name }) => name)
|
|
1615
1622
|
.join(", ")}]`, state.config?.checkInvalidSymbols || "WARNING");
|
|
1616
1623
|
}
|
|
@@ -1623,7 +1630,10 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
|
|
|
1623
1630
|
if (imports.length == 1) {
|
|
1624
1631
|
if (decls !== "type_decls") {
|
|
1625
1632
|
if (state.config?.checkCompilerLookupRules !== "OFF") {
|
|
1626
|
-
diagnostic(state, node
|
|
1633
|
+
diagnostic(state, node, `${formatAst(node)} will only be found when compiled with compiler2 at -O1 or above`, state.config?.checkCompilerLookupRules || "WARNING", {
|
|
1634
|
+
uri: "https://github.com/markw65/monkeyc-optimizer/wiki/Compiler1-vs-Compiler2-lookup-rules",
|
|
1635
|
+
message: "more info",
|
|
1636
|
+
});
|
|
1627
1637
|
}
|
|
1628
1638
|
else if (state.lookupRules === "COMPILER1") {
|
|
1629
1639
|
return [null, null];
|
|
@@ -1688,7 +1698,7 @@ function stateFuncs() {
|
|
|
1688
1698
|
switch (node.type) {
|
|
1689
1699
|
case "MemberExpression": {
|
|
1690
1700
|
if (isLookupCandidate(node)) {
|
|
1691
|
-
return (this.pre && this.pre(node, this))
|
|
1701
|
+
return (this.pre && this.pre(node, this)) ?? ["object"];
|
|
1692
1702
|
}
|
|
1693
1703
|
break;
|
|
1694
1704
|
}
|
|
@@ -2157,7 +2167,7 @@ function findUsing(state, stack, using) {
|
|
|
2157
2167
|
return using.module;
|
|
2158
2168
|
}
|
|
2159
2169
|
if (state.config?.checkInvalidSymbols !== "OFF") {
|
|
2160
|
-
diagnostic(state, using.node.id
|
|
2170
|
+
diagnostic(state, using.node.id, `Unable to resolve import of ${formatAst(using.node.id)}`, state.config?.checkInvalidSymbols || "WARNING");
|
|
2161
2171
|
}
|
|
2162
2172
|
return null;
|
|
2163
2173
|
}
|
|
@@ -2216,7 +2226,8 @@ function markInvokeClassMethod(state, func) {
|
|
|
2216
2226
|
function isLocal(v) {
|
|
2217
2227
|
return v.stack[v.stack.length - 1]?.type === "BlockStatement";
|
|
2218
2228
|
}
|
|
2219
|
-
function diagnostic(state,
|
|
2229
|
+
function diagnostic(state, node, message, type = "INFO", extra) {
|
|
2230
|
+
const loc = node.loc;
|
|
2220
2231
|
if (!loc || !loc.source)
|
|
2221
2232
|
return;
|
|
2222
2233
|
const source = loc.source;
|
|
@@ -2228,11 +2239,38 @@ function diagnostic(state, loc, message, type = "INFO") {
|
|
|
2228
2239
|
state.diagnostics[source] = [];
|
|
2229
2240
|
}
|
|
2230
2241
|
const diags = state.diagnostics[source];
|
|
2231
|
-
let index = diags.findIndex((item) => item.loc === loc
|
|
2242
|
+
let index = diags.findIndex((item) => item.loc.start.offset === loc.start.offset &&
|
|
2243
|
+
item.loc.end.offset === loc.end.offset &&
|
|
2244
|
+
(!item.related
|
|
2245
|
+
? !node.origins
|
|
2246
|
+
: item.related.length === node.origins?.length &&
|
|
2247
|
+
item.related.every((r, i) => r.loc.start.offset === node.origins[i].loc.start.offset &&
|
|
2248
|
+
r.loc.end.offset === node.origins[i].loc.end.offset &&
|
|
2249
|
+
r.loc.source === node.origins[i].loc.source)));
|
|
2232
2250
|
if (message) {
|
|
2233
2251
|
if (index < 0)
|
|
2234
2252
|
index = diags.length;
|
|
2235
|
-
|
|
2253
|
+
const diag = {
|
|
2254
|
+
type,
|
|
2255
|
+
loc,
|
|
2256
|
+
message,
|
|
2257
|
+
};
|
|
2258
|
+
if (extra) {
|
|
2259
|
+
diag.extra = extra;
|
|
2260
|
+
}
|
|
2261
|
+
if (node.origins) {
|
|
2262
|
+
diag.related = [];
|
|
2263
|
+
const related = diag.related;
|
|
2264
|
+
node.origins.forEach((origin) => {
|
|
2265
|
+
if (origin.loc.source) {
|
|
2266
|
+
related.push({
|
|
2267
|
+
loc: origin.loc,
|
|
2268
|
+
message: `inlined from ${origin.func}`,
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2273
|
+
diags[index] = diag;
|
|
2236
2274
|
}
|
|
2237
2275
|
else if (index >= 0) {
|
|
2238
2276
|
diags.splice(index, 1);
|