@markw65/monkeyc-optimizer 1.0.17 → 1.0.20
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 +42 -0
- package/build/api.cjs +240 -98
- package/build/optimizer.cjs +281 -111
- package/build/src/inliner.d.ts +3 -2
- package/build/src/launch.d.ts +2 -1
- package/build/src/mc-rewrite.d.ts +8 -1
- package/build/src/optimizer.d.ts +27 -2
- package/build/src/util.d.ts +2 -3
- package/package.json +2 -2
package/build/optimizer.cjs
CHANGED
|
@@ -10784,11 +10784,11 @@ function launchSimulator() {
|
|
|
10784
10784
|
child.unref();
|
|
10785
10785
|
});
|
|
10786
10786
|
}
|
|
10787
|
-
function simulateProgram(prg, device, test) {
|
|
10787
|
+
function simulateProgram(prg, device, test = false, logger) {
|
|
10788
10788
|
const args = [prg, device];
|
|
10789
10789
|
if (test)
|
|
10790
10790
|
args.push("-t");
|
|
10791
|
-
return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, (line) => console.log(line)).then(() => { }));
|
|
10791
|
+
return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, logger || ((line) => console.log(line))).then(() => { }));
|
|
10792
10792
|
}
|
|
10793
10793
|
|
|
10794
10794
|
;// CONCATENATED MODULE: ./src/variable-renamer.ts
|
|
@@ -10902,7 +10902,7 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
10902
10902
|
})) {
|
|
10903
10903
|
return false;
|
|
10904
10904
|
}
|
|
10905
|
-
if (allSafe)
|
|
10905
|
+
if (allSafe && requireAll)
|
|
10906
10906
|
return true;
|
|
10907
10907
|
let callSeen = false;
|
|
10908
10908
|
let ok = true;
|
|
@@ -10925,10 +10925,16 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
10925
10925
|
.map(([key]) => key);
|
|
10926
10926
|
}, (node) => {
|
|
10927
10927
|
switch (node.type) {
|
|
10928
|
+
case "AssignmentExpression":
|
|
10929
|
+
case "UpdateExpression": {
|
|
10930
|
+
const v = node.type == "UpdateExpression" ? node.argument : node.left;
|
|
10931
|
+
if (v.type === "Identifier" && (0,external_api_cjs_namespaceObject.hasProperty)(params, v.name)) {
|
|
10932
|
+
safeArgs[params[v.name]] = null;
|
|
10933
|
+
}
|
|
10934
|
+
}
|
|
10935
|
+
// fall through
|
|
10928
10936
|
case "CallExpression":
|
|
10929
10937
|
case "NewExpression":
|
|
10930
|
-
case "AssignmentExpression":
|
|
10931
|
-
case "UpdateExpression":
|
|
10932
10938
|
callSeen = true;
|
|
10933
10939
|
break;
|
|
10934
10940
|
case "Identifier":
|
|
@@ -10977,9 +10983,24 @@ var InlineStatus;
|
|
|
10977
10983
|
InlineStatus[InlineStatus["AsExpression"] = 1] = "AsExpression";
|
|
10978
10984
|
InlineStatus[InlineStatus["AsStatement"] = 2] = "AsStatement";
|
|
10979
10985
|
})(InlineStatus || (InlineStatus = {}));
|
|
10980
|
-
function
|
|
10986
|
+
function inlineRequested(state, func) {
|
|
10987
|
+
const excludeAnnotations = (func.node.loc?.source &&
|
|
10988
|
+
state.fnMap[func.node.loc?.source]?.excludeAnnotations) ||
|
|
10989
|
+
{};
|
|
10990
|
+
if (func.node.attrs &&
|
|
10991
|
+
func.node.attrs.attrs &&
|
|
10992
|
+
func.node.attrs.attrs.some((attr) => attr.type === "UnaryExpression" &&
|
|
10993
|
+
(attr.argument.name === "inline" ||
|
|
10994
|
+
(attr.argument.name.startsWith("inline_") &&
|
|
10995
|
+
(0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
|
|
10996
|
+
return true;
|
|
10997
|
+
}
|
|
10998
|
+
return false;
|
|
10999
|
+
}
|
|
11000
|
+
function shouldInline(state, func, call, context) {
|
|
10981
11001
|
let autoInline = false;
|
|
10982
11002
|
let inlineAsExpression = false;
|
|
11003
|
+
const args = call.arguments;
|
|
10983
11004
|
if (func.node.body &&
|
|
10984
11005
|
func.node.body.body.length === 1 &&
|
|
10985
11006
|
func.node.body.body[0].type === "ReturnStatement" &&
|
|
@@ -10989,39 +11010,30 @@ function shouldInline(state, func, args) {
|
|
|
10989
11010
|
autoInline = inliningLooksUseful(func.node, func.node.body.body[0].argument);
|
|
10990
11011
|
}
|
|
10991
11012
|
if (autoInline === 1) {
|
|
10992
|
-
return
|
|
11013
|
+
return true;
|
|
10993
11014
|
}
|
|
10994
|
-
const
|
|
10995
|
-
|
|
10996
|
-
{
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
return
|
|
11005
|
-
? InlineStatus.AsExpression
|
|
11006
|
-
: InlineStatus.AsStatement;
|
|
11015
|
+
const requested = inlineRequested(state, func);
|
|
11016
|
+
if (autoInline || requested) {
|
|
11017
|
+
if (inlineAsExpression) {
|
|
11018
|
+
if (canInline(state, func, args)) {
|
|
11019
|
+
return true;
|
|
11020
|
+
}
|
|
11021
|
+
}
|
|
11022
|
+
if (!context && requested) {
|
|
11023
|
+
inlineDiagnostic(state, func, call, "This function can only be inlined in statement, assignment, or return contexts");
|
|
11024
|
+
}
|
|
11025
|
+
return context != null;
|
|
11007
11026
|
}
|
|
11008
|
-
return
|
|
11027
|
+
return false;
|
|
11009
11028
|
}
|
|
11010
11029
|
function processInlineBody(state, func, call, root, insertedVariableDecls, params) {
|
|
11011
|
-
|
|
11012
|
-
const safeArgs = getArgSafety(state, func, call.arguments, false);
|
|
11013
|
-
params = Object.fromEntries(func.node.params.map((param, i) => {
|
|
11014
|
-
const argnum = safeArgs === true || (safeArgs !== false && safeArgs[i] !== null)
|
|
11015
|
-
? i
|
|
11016
|
-
: -1;
|
|
11017
|
-
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
11018
|
-
return [name, argnum];
|
|
11019
|
-
}));
|
|
11020
|
-
}
|
|
11030
|
+
let failed = false;
|
|
11021
11031
|
const pre = state.pre;
|
|
11022
11032
|
const post = state.post;
|
|
11023
11033
|
try {
|
|
11024
11034
|
state.pre = (node) => {
|
|
11035
|
+
if (failed)
|
|
11036
|
+
return [];
|
|
11025
11037
|
node.start = call.start;
|
|
11026
11038
|
node.end = call.end;
|
|
11027
11039
|
node.loc = call.loc;
|
|
@@ -11033,6 +11045,11 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11033
11045
|
const { map } = locals;
|
|
11034
11046
|
if (!map)
|
|
11035
11047
|
throw new Error("No local variable map!");
|
|
11048
|
+
// We still need to keep track of every local name that was
|
|
11049
|
+
// already in use, but we don't want to use any of its renames.
|
|
11050
|
+
// We also want to know whether a local is from the function being
|
|
11051
|
+
// inlined, or the calling function, so set every element to false.
|
|
11052
|
+
Object.keys(map).forEach((key) => (map[key] = false));
|
|
11036
11053
|
const declarations = func.node.params
|
|
11037
11054
|
.map((param, i) => {
|
|
11038
11055
|
const paramName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
@@ -11057,6 +11074,8 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11057
11074
|
return result;
|
|
11058
11075
|
};
|
|
11059
11076
|
state.post = (node) => {
|
|
11077
|
+
if (failed)
|
|
11078
|
+
return null;
|
|
11060
11079
|
let replacement = null;
|
|
11061
11080
|
switch (node.type) {
|
|
11062
11081
|
case "Identifier": {
|
|
@@ -11071,22 +11090,28 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11071
11090
|
}
|
|
11072
11091
|
replacement = fixNodeScope(state, node, func.stack);
|
|
11073
11092
|
if (!replacement) {
|
|
11074
|
-
|
|
11093
|
+
failed = true;
|
|
11094
|
+
inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
|
|
11095
|
+
return null;
|
|
11075
11096
|
}
|
|
11076
11097
|
break;
|
|
11077
11098
|
}
|
|
11078
11099
|
}
|
|
11079
11100
|
return post(replacement || node, state) || replacement;
|
|
11080
11101
|
};
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
}
|
|
11102
|
+
let ret = state.traverse(root);
|
|
11103
|
+
if (failed) {
|
|
11104
|
+
return null;
|
|
11105
|
+
}
|
|
11106
|
+
if (ret === null) {
|
|
11107
|
+
ret = root;
|
|
11088
11108
|
}
|
|
11089
|
-
|
|
11109
|
+
if (!ret) {
|
|
11110
|
+
inlineDiagnostic(state, func, call, `Internal error`);
|
|
11111
|
+
return null;
|
|
11112
|
+
}
|
|
11113
|
+
inlineDiagnostic(state, func, call, null);
|
|
11114
|
+
return ret;
|
|
11090
11115
|
}
|
|
11091
11116
|
finally {
|
|
11092
11117
|
state.pre = pre;
|
|
@@ -11109,7 +11134,16 @@ function unused(expression, top) {
|
|
|
11109
11134
|
case "UnaryExpression":
|
|
11110
11135
|
return unused(expression.argument);
|
|
11111
11136
|
case "MemberExpression":
|
|
11112
|
-
|
|
11137
|
+
if (expression.computed) {
|
|
11138
|
+
return unused(expression.object).concat(unused(expression.property));
|
|
11139
|
+
}
|
|
11140
|
+
return unused(expression.object);
|
|
11141
|
+
case "ArrayExpression":
|
|
11142
|
+
return expression.elements.map((e) => unused(e)).flat(1);
|
|
11143
|
+
case "ObjectExpression":
|
|
11144
|
+
return expression.properties
|
|
11145
|
+
.map((p) => unused(p.key).concat(unused(p.value)))
|
|
11146
|
+
.flat(1);
|
|
11113
11147
|
}
|
|
11114
11148
|
return top
|
|
11115
11149
|
? null
|
|
@@ -11117,30 +11151,98 @@ function unused(expression, top) {
|
|
|
11117
11151
|
{
|
|
11118
11152
|
type: "ExpressionStatement",
|
|
11119
11153
|
expression,
|
|
11154
|
+
start: expression.start,
|
|
11155
|
+
end: expression.end,
|
|
11156
|
+
loc: expression.loc,
|
|
11120
11157
|
},
|
|
11121
11158
|
];
|
|
11122
11159
|
}
|
|
11123
|
-
function
|
|
11160
|
+
function diagnostic(state, loc, message) {
|
|
11161
|
+
if (!loc || !loc.source)
|
|
11162
|
+
return;
|
|
11163
|
+
const source = loc.source;
|
|
11164
|
+
if (!state.diagnostics)
|
|
11165
|
+
state.diagnostics = {};
|
|
11166
|
+
if (!(0,external_api_cjs_namespaceObject.hasProperty)(state.diagnostics, source)) {
|
|
11167
|
+
if (!message)
|
|
11168
|
+
return;
|
|
11169
|
+
state.diagnostics[source] = [];
|
|
11170
|
+
}
|
|
11171
|
+
const diags = state.diagnostics[source];
|
|
11172
|
+
let index = diags.findIndex((item) => item.loc === loc);
|
|
11173
|
+
if (message) {
|
|
11174
|
+
if (index < 0)
|
|
11175
|
+
index = diags.length;
|
|
11176
|
+
diags[index] = { type: "INFO", loc, message };
|
|
11177
|
+
}
|
|
11178
|
+
else if (index >= 0) {
|
|
11179
|
+
diags.splice(index, 1);
|
|
11180
|
+
}
|
|
11181
|
+
}
|
|
11182
|
+
function inlineDiagnostic(state, func, call, message) {
|
|
11183
|
+
if (inlineRequested(state, func)) {
|
|
11184
|
+
diagnostic(state, call.loc, message && `While inlining ${func.node.id.name}: ${message}`);
|
|
11185
|
+
}
|
|
11186
|
+
}
|
|
11187
|
+
function inlineWithArgs(state, func, call, context) {
|
|
11124
11188
|
if (!func.node || !func.node.body) {
|
|
11125
11189
|
return null;
|
|
11126
11190
|
}
|
|
11127
11191
|
let retStmtCount = 0;
|
|
11128
|
-
(
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11192
|
+
if (context.type === "ReturnStatement") {
|
|
11193
|
+
const last = func.node.body.body.slice(-1)[0];
|
|
11194
|
+
if (!last || last.type !== "ReturnStatement") {
|
|
11195
|
+
inlineDiagnostic(state, func, call, "Function didn't end with a return statement");
|
|
11196
|
+
return null;
|
|
11197
|
+
}
|
|
11198
|
+
}
|
|
11199
|
+
else {
|
|
11200
|
+
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
|
|
11201
|
+
node.type === "ReturnStatement" && retStmtCount++;
|
|
11202
|
+
});
|
|
11203
|
+
if (retStmtCount > 1) {
|
|
11204
|
+
inlineDiagnostic(state, func, call, "Function had more than one return statement");
|
|
11205
|
+
}
|
|
11206
|
+
else if (context.type === "AssignmentExpression" && retStmtCount !== 1) {
|
|
11207
|
+
inlineDiagnostic(state, func, call, "Function did not have a return statement");
|
|
11208
|
+
return null;
|
|
11209
|
+
}
|
|
11210
|
+
if (retStmtCount === 1) {
|
|
11211
|
+
const last = func.node.body.body.slice(-1)[0];
|
|
11212
|
+
if (!last ||
|
|
11213
|
+
last.type !== "ReturnStatement" ||
|
|
11214
|
+
(context.type === "AssignmentExpression" && !last.argument)) {
|
|
11215
|
+
inlineDiagnostic(state, func, call, "There was a return statement, but not at the end of the function");
|
|
11216
|
+
return null;
|
|
11217
|
+
}
|
|
11218
|
+
}
|
|
11135
11219
|
}
|
|
11136
11220
|
const body = JSON.parse(JSON.stringify(func.node.body));
|
|
11137
|
-
|
|
11138
|
-
|
|
11221
|
+
const safeArgs = getArgSafety(state, func, call.arguments, false);
|
|
11222
|
+
const params = Object.fromEntries(func.node.params.map((param, i) => {
|
|
11223
|
+
const argnum = safeArgs === true || (safeArgs !== false && safeArgs[i] !== null)
|
|
11224
|
+
? i
|
|
11225
|
+
: -1;
|
|
11226
|
+
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
11227
|
+
return [name, argnum];
|
|
11228
|
+
}));
|
|
11229
|
+
if (!processInlineBody(state, func, call, body, func.node.params.length ? false : true, params)) {
|
|
11230
|
+
return null;
|
|
11231
|
+
}
|
|
11232
|
+
diagnostic(state, call.loc, null);
|
|
11233
|
+
if (context.type !== "ReturnStatement" && retStmtCount) {
|
|
11139
11234
|
const last = body.body[body.body.length - 1];
|
|
11140
11235
|
if (last.type != "ReturnStatement") {
|
|
11141
11236
|
throw new Error("ReturnStatement got lost!");
|
|
11142
11237
|
}
|
|
11143
|
-
if (
|
|
11238
|
+
if (context.type === "AssignmentExpression") {
|
|
11239
|
+
context.right = last.argument;
|
|
11240
|
+
body.body[body.body.length - 1] = {
|
|
11241
|
+
type: "ExpressionStatement",
|
|
11242
|
+
expression: context,
|
|
11243
|
+
};
|
|
11244
|
+
}
|
|
11245
|
+
else if (last.argument) {
|
|
11144
11246
|
const side_exprs = unused(last.argument);
|
|
11145
11247
|
body.body.splice(body.body.length - 1, 1, ...side_exprs);
|
|
11146
11248
|
}
|
|
@@ -11150,13 +11252,13 @@ function inlineWithArgs(state, func, call) {
|
|
|
11150
11252
|
}
|
|
11151
11253
|
return body;
|
|
11152
11254
|
}
|
|
11153
|
-
function inlineFunction(state, func, call,
|
|
11154
|
-
if (
|
|
11155
|
-
return inlineWithArgs(state, func, call);
|
|
11255
|
+
function inlineFunction(state, func, call, context) {
|
|
11256
|
+
if (context) {
|
|
11257
|
+
return inlineWithArgs(state, func, call, context);
|
|
11156
11258
|
}
|
|
11157
11259
|
const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
|
|
11158
11260
|
const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
|
|
11159
|
-
return processInlineBody(state, func, call, retArg, true, params)
|
|
11261
|
+
return processInlineBody(state, func, call, retArg, true, params);
|
|
11160
11262
|
}
|
|
11161
11263
|
function applyTypeIfNeeded(node) {
|
|
11162
11264
|
if ("enumType" in node && node.enumType) {
|
|
@@ -11171,13 +11273,14 @@ function applyTypeIfNeeded(node) {
|
|
|
11171
11273
|
}
|
|
11172
11274
|
function fixNodeScope(state, lookupNode, nodeStack) {
|
|
11173
11275
|
if (lookupNode.type === "Identifier") {
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11276
|
+
const locals = state.localsStack[state.localsStack.length - 1];
|
|
11277
|
+
const { map } = locals;
|
|
11278
|
+
if (!map)
|
|
11279
|
+
throw new Error("No local variable map!");
|
|
11280
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(map, lookupNode.name) && map[lookupNode.name] !== false) {
|
|
11281
|
+
// map[name] !== false means its an entry that was created during inlining
|
|
11282
|
+
// so its definitely one of our locals.
|
|
11283
|
+
return lookupNode;
|
|
11181
11284
|
}
|
|
11182
11285
|
}
|
|
11183
11286
|
const [, original] = state.lookup(lookupNode, null, nodeStack);
|
|
@@ -11650,13 +11753,15 @@ function optimizeNode(node) {
|
|
|
11650
11753
|
return null;
|
|
11651
11754
|
}
|
|
11652
11755
|
function evaluateFunction(func, args) {
|
|
11653
|
-
if (args && args.length != func.params.length) {
|
|
11756
|
+
if (!func.body || (args && args.length != func.params.length)) {
|
|
11654
11757
|
return false;
|
|
11655
11758
|
}
|
|
11656
11759
|
const paramValues = args &&
|
|
11657
11760
|
Object.fromEntries(func.params.map((p, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(p), args[i]]));
|
|
11658
11761
|
let ret = null;
|
|
11659
|
-
const body = args
|
|
11762
|
+
const body = args
|
|
11763
|
+
? JSON.parse(JSON.stringify(func.body))
|
|
11764
|
+
: func.body;
|
|
11660
11765
|
try {
|
|
11661
11766
|
(0,external_api_cjs_namespaceObject.traverseAst)(body, (node) => {
|
|
11662
11767
|
switch (node.type) {
|
|
@@ -11699,6 +11804,13 @@ function evaluateFunction(func, args) {
|
|
|
11699
11804
|
return false;
|
|
11700
11805
|
}
|
|
11701
11806
|
}
|
|
11807
|
+
function markFunctionCalled(state, func) {
|
|
11808
|
+
if (!(0,external_api_cjs_namespaceObject.hasProperty)(state.calledFunctions, func.id.name)) {
|
|
11809
|
+
state.calledFunctions[func.id.name] = [func];
|
|
11810
|
+
return;
|
|
11811
|
+
}
|
|
11812
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(state.calledFunctions[func.id.name], func);
|
|
11813
|
+
}
|
|
11702
11814
|
async function optimizeMonkeyC(fnMap) {
|
|
11703
11815
|
const state = {
|
|
11704
11816
|
...(await analyze(fnMap)),
|
|
@@ -11857,7 +11969,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11857
11969
|
if (map) {
|
|
11858
11970
|
if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
|
|
11859
11971
|
const name = map[node.name];
|
|
11860
|
-
if (name
|
|
11972
|
+
if (typeof name === "string") {
|
|
11861
11973
|
node.name = name;
|
|
11862
11974
|
}
|
|
11863
11975
|
}
|
|
@@ -11908,10 +12020,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11908
12020
|
used = checkInherited(parent, node.id.name);
|
|
11909
12021
|
}
|
|
11910
12022
|
if (used) {
|
|
11911
|
-
|
|
11912
|
-
state.calledFunctions[node.id.name] = [];
|
|
11913
|
-
}
|
|
11914
|
-
state.calledFunctions[node.id.name].push(node);
|
|
12023
|
+
markFunctionCalled(state, node);
|
|
11915
12024
|
}
|
|
11916
12025
|
}
|
|
11917
12026
|
}
|
|
@@ -11948,27 +12057,61 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11948
12057
|
return node.body;
|
|
11949
12058
|
}
|
|
11950
12059
|
break;
|
|
12060
|
+
case "ReturnStatement":
|
|
12061
|
+
if (node.argument && node.argument.type === "CallExpression") {
|
|
12062
|
+
return optimizeCall(state, node.argument, node);
|
|
12063
|
+
}
|
|
12064
|
+
break;
|
|
11951
12065
|
case "CallExpression": {
|
|
11952
|
-
const ret = optimizeCall(state, node,
|
|
12066
|
+
const ret = optimizeCall(state, node, null);
|
|
11953
12067
|
if (ret) {
|
|
11954
12068
|
replace(node, ret);
|
|
11955
12069
|
}
|
|
11956
12070
|
break;
|
|
11957
12071
|
}
|
|
12072
|
+
case "AssignmentExpression":
|
|
12073
|
+
if (node.operator === "=" &&
|
|
12074
|
+
node.left.type === "Identifier" &&
|
|
12075
|
+
node.right.type === "Identifier" &&
|
|
12076
|
+
node.left.name === node.right.name) {
|
|
12077
|
+
return { type: "Literal", value: null, raw: "null" };
|
|
12078
|
+
}
|
|
12079
|
+
break;
|
|
11958
12080
|
case "ExpressionStatement":
|
|
11959
12081
|
if (node.expression.type === "CallExpression") {
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
12082
|
+
return optimizeCall(state, node.expression, node);
|
|
12083
|
+
}
|
|
12084
|
+
else if (node.expression.type === "AssignmentExpression") {
|
|
12085
|
+
if (node.expression.right.type === "CallExpression") {
|
|
12086
|
+
let ok = false;
|
|
12087
|
+
if (node.expression.left.type === "Identifier") {
|
|
12088
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(topLocals().map, node.expression.left.type)) {
|
|
12089
|
+
ok = true;
|
|
12090
|
+
}
|
|
12091
|
+
}
|
|
12092
|
+
if (!ok && node.expression.operator == "=") {
|
|
12093
|
+
const [, result] = state.lookup(node.expression.left);
|
|
12094
|
+
ok = result != null;
|
|
12095
|
+
}
|
|
12096
|
+
if (ok) {
|
|
12097
|
+
const ret = optimizeCall(state, node.expression.right, node.expression);
|
|
12098
|
+
if (ret && ret.type === "BlockStatement") {
|
|
12099
|
+
const r2 = state.traverse(ret);
|
|
12100
|
+
return r2 === false || r2 ? r2 : ret;
|
|
12101
|
+
}
|
|
11964
12102
|
}
|
|
11965
|
-
node.expression = ret;
|
|
11966
12103
|
}
|
|
11967
12104
|
}
|
|
11968
12105
|
else {
|
|
11969
12106
|
const ret = unused(node.expression, true);
|
|
11970
12107
|
if (ret) {
|
|
11971
|
-
return ret
|
|
12108
|
+
return ret
|
|
12109
|
+
.map((s) => {
|
|
12110
|
+
const r2 = state.traverse(s);
|
|
12111
|
+
return r2 === false || r2 ? r2 : s;
|
|
12112
|
+
})
|
|
12113
|
+
.flat(1)
|
|
12114
|
+
.filter((s) => s !== false);
|
|
11972
12115
|
}
|
|
11973
12116
|
}
|
|
11974
12117
|
break;
|
|
@@ -11978,6 +12121,11 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11978
12121
|
Object.values(fnMap).forEach((f) => {
|
|
11979
12122
|
(0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
|
|
11980
12123
|
});
|
|
12124
|
+
state.calledFunctions = {};
|
|
12125
|
+
state.exposed = {};
|
|
12126
|
+
Object.values(fnMap).forEach((f) => {
|
|
12127
|
+
(0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
|
|
12128
|
+
});
|
|
11981
12129
|
delete state.pre;
|
|
11982
12130
|
delete state.post;
|
|
11983
12131
|
const cleanup = (node) => {
|
|
@@ -12053,9 +12201,12 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12053
12201
|
return ret;
|
|
12054
12202
|
});
|
|
12055
12203
|
});
|
|
12204
|
+
return state.diagnostics;
|
|
12056
12205
|
}
|
|
12057
|
-
function optimizeCall(state, node,
|
|
12058
|
-
const [name,
|
|
12206
|
+
function optimizeCall(state, node, context) {
|
|
12207
|
+
const [name, results] = state.lookup(node.callee);
|
|
12208
|
+
const callees = results &&
|
|
12209
|
+
results.filter((c) => c.type === "FunctionDeclaration");
|
|
12059
12210
|
if (!callees || !callees.length) {
|
|
12060
12211
|
const n = name ||
|
|
12061
12212
|
("name" in node.callee && node.callee.name) ||
|
|
@@ -12074,7 +12225,8 @@ function optimizeCall(state, node, asStatement) {
|
|
|
12074
12225
|
}
|
|
12075
12226
|
if (callees.length == 1 && callees[0].type === "FunctionDeclaration") {
|
|
12076
12227
|
const callee = callees[0].node;
|
|
12077
|
-
if (
|
|
12228
|
+
if (!context &&
|
|
12229
|
+
callee.optimizable &&
|
|
12078
12230
|
!callee.hasOverride &&
|
|
12079
12231
|
node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
|
|
12080
12232
|
const ret = evaluateFunction(callee, node.arguments);
|
|
@@ -12082,19 +12234,14 @@ function optimizeCall(state, node, asStatement) {
|
|
|
12082
12234
|
return ret;
|
|
12083
12235
|
}
|
|
12084
12236
|
}
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
(asStatement && inlineStatus === InlineStatus.AsStatement)) {
|
|
12088
|
-
const ret = inlineFunction(state, callees[0], node, inlineStatus);
|
|
12237
|
+
if (shouldInline(state, callees[0], node, context)) {
|
|
12238
|
+
const ret = inlineFunction(state, callees[0], node, context);
|
|
12089
12239
|
if (ret) {
|
|
12090
12240
|
return ret;
|
|
12091
12241
|
}
|
|
12092
12242
|
}
|
|
12093
12243
|
}
|
|
12094
|
-
|
|
12095
|
-
state.calledFunctions[name] = [];
|
|
12096
|
-
}
|
|
12097
|
-
callees.forEach((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && state.calledFunctions[name].push(c.node));
|
|
12244
|
+
callees.forEach((c) => markFunctionCalled(state, c.node));
|
|
12098
12245
|
return null;
|
|
12099
12246
|
}
|
|
12100
12247
|
|
|
@@ -12106,12 +12253,31 @@ function pragmaChecker(ast) {
|
|
|
12106
12253
|
return;
|
|
12107
12254
|
let index = -1;
|
|
12108
12255
|
let comment;
|
|
12256
|
+
let matchers;
|
|
12109
12257
|
const next = () => {
|
|
12110
12258
|
while (++index < comments.length) {
|
|
12111
12259
|
comment = comments[index];
|
|
12112
|
-
|
|
12260
|
+
let match = comment.value.match(/^\s*@match\s+(.+)/);
|
|
12261
|
+
if (!match)
|
|
12262
|
+
continue;
|
|
12263
|
+
let str = match[1];
|
|
12264
|
+
matchers = [];
|
|
12265
|
+
while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
|
|
12266
|
+
matchers.push({ quote: match[1], needle: match[2] });
|
|
12267
|
+
str = str.substring(match[0].length);
|
|
12268
|
+
if (!str.length)
|
|
12269
|
+
break;
|
|
12270
|
+
}
|
|
12271
|
+
if (!str.length)
|
|
12113
12272
|
break;
|
|
12273
|
+
if (!matchers.length) {
|
|
12274
|
+
match = str.match(/^(\S+)\s+$/);
|
|
12275
|
+
if (match) {
|
|
12276
|
+
matchers.push({ quote: '"', needle: match[1] });
|
|
12277
|
+
break;
|
|
12278
|
+
}
|
|
12114
12279
|
}
|
|
12280
|
+
throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12115
12281
|
}
|
|
12116
12282
|
};
|
|
12117
12283
|
next();
|
|
@@ -12119,29 +12285,23 @@ function pragmaChecker(ast) {
|
|
|
12119
12285
|
if (index >= comments.length)
|
|
12120
12286
|
return false;
|
|
12121
12287
|
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
12122
|
-
|
|
12123
|
-
if (!match) {
|
|
12124
|
-
throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12125
|
-
}
|
|
12288
|
+
const { quote, needle } = matchers.shift();
|
|
12126
12289
|
const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/[\r\n]/g, " ");
|
|
12127
12290
|
let found = false;
|
|
12128
|
-
|
|
12129
|
-
if (match.length == 2) {
|
|
12291
|
+
if (quote == '"') {
|
|
12130
12292
|
found = haystack.includes(needle);
|
|
12131
12293
|
}
|
|
12132
12294
|
else {
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
}
|
|
12136
|
-
else {
|
|
12137
|
-
const re = new RegExp((needle = match[2]));
|
|
12138
|
-
found = re.test(haystack);
|
|
12139
|
-
}
|
|
12295
|
+
const re = new RegExp(needle);
|
|
12296
|
+
found = re.test(haystack);
|
|
12140
12297
|
}
|
|
12141
12298
|
if (!found) {
|
|
12142
|
-
throw new Error(`Didn't find '${needle}'
|
|
12299
|
+
throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12300
|
+
}
|
|
12301
|
+
if (!matchers.length) {
|
|
12302
|
+
next();
|
|
12143
12303
|
}
|
|
12144
|
-
|
|
12304
|
+
return false;
|
|
12145
12305
|
}
|
|
12146
12306
|
return null;
|
|
12147
12307
|
});
|
|
@@ -12230,7 +12390,7 @@ async function buildOptimizedProject(product, options) {
|
|
|
12230
12390
|
config.releaseBuild = true;
|
|
12231
12391
|
}
|
|
12232
12392
|
}
|
|
12233
|
-
const { jungleFiles, program, hasTests } = await generateOptimizedProject(config);
|
|
12393
|
+
const { jungleFiles, program, hasTests, diagnostics } = await generateOptimizedProject(config);
|
|
12234
12394
|
config.jungleFiles = jungleFiles;
|
|
12235
12395
|
let bin = config.buildDir || "bin";
|
|
12236
12396
|
let name = `optimized-${program}.prg`;
|
|
@@ -12249,6 +12409,7 @@ async function buildOptimizedProject(product, options) {
|
|
|
12249
12409
|
delete config.testBuild;
|
|
12250
12410
|
return build_project(product, config).then((result) => ({
|
|
12251
12411
|
hasTests,
|
|
12412
|
+
diagnostics,
|
|
12252
12413
|
...result,
|
|
12253
12414
|
}));
|
|
12254
12415
|
}
|
|
@@ -12387,6 +12548,7 @@ async function generateOptimizedProject(options) {
|
|
|
12387
12548
|
(await checkManifest(xml, targets.map((t) => t.product)))) &&
|
|
12388
12549
|
!dropBarrels;
|
|
12389
12550
|
let hasTests = false;
|
|
12551
|
+
let diagnostics = {};
|
|
12390
12552
|
const promises = Object.keys(buildConfigs)
|
|
12391
12553
|
.sort()
|
|
12392
12554
|
.map((key) => {
|
|
@@ -12404,7 +12566,13 @@ async function generateOptimizedProject(options) {
|
|
|
12404
12566
|
e.products = products[key];
|
|
12405
12567
|
throw e;
|
|
12406
12568
|
})
|
|
12407
|
-
.then((t) =>
|
|
12569
|
+
.then((t) => {
|
|
12570
|
+
if (t.hasTests)
|
|
12571
|
+
hasTests = true;
|
|
12572
|
+
if (t.diagnostics) {
|
|
12573
|
+
diagnostics = { ...diagnostics, ...t.diagnostics };
|
|
12574
|
+
}
|
|
12575
|
+
})
|
|
12408
12576
|
: promises_namespaceObject.rm(external_path_.resolve(workspace, outputPath), {
|
|
12409
12577
|
recursive: true,
|
|
12410
12578
|
force: true,
|
|
@@ -12475,6 +12643,7 @@ async function generateOptimizedProject(options) {
|
|
|
12475
12643
|
xml,
|
|
12476
12644
|
program: external_path_.basename(external_path_.dirname(manifest)),
|
|
12477
12645
|
hasTests,
|
|
12646
|
+
diagnostics,
|
|
12478
12647
|
};
|
|
12479
12648
|
}
|
|
12480
12649
|
async function fileInfoFromConfig(workspace, output, buildConfig, extraExcludes) {
|
|
@@ -12553,7 +12722,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12553
12722
|
const actualOptimizedFiles = (await (0,external_util_cjs_namespaceObject.globa)(external_path_.join(output, "**", "*.mc"), { mark: true }))
|
|
12554
12723
|
.filter((file) => !file.endsWith("/"))
|
|
12555
12724
|
.sort();
|
|
12556
|
-
const { hasTests, ...prevOptions } = JSON.parse(await promises_namespaceObject.readFile(external_path_.join(output, "build-info.json"), "utf-8")
|
|
12725
|
+
const { hasTests, diagnostics: prevDiagnostics, ...prevOptions } = JSON.parse(await promises_namespaceObject.readFile(external_path_.join(output, "build-info.json"), "utf-8")
|
|
12557
12726
|
.catch(() => "{}"));
|
|
12558
12727
|
// check that the set of files thats actually there is the same as the
|
|
12559
12728
|
// set of files we're going to generate (in case eg a jungle file change
|
|
@@ -12571,13 +12740,13 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12571
12740
|
// the oldest optimized file, we don't need to regenerate
|
|
12572
12741
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
12573
12742
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
12574
|
-
if (source_time < opt_time &&
|
|
12575
|
-
return hasTests;
|
|
12743
|
+
if (source_time < opt_time && 1654708837029 < opt_time) {
|
|
12744
|
+
return { hasTests, diagnostics: prevDiagnostics };
|
|
12576
12745
|
}
|
|
12577
12746
|
}
|
|
12578
12747
|
await promises_namespaceObject.rm(output, { recursive: true, force: true });
|
|
12579
12748
|
await promises_namespaceObject.mkdir(output, { recursive: true });
|
|
12580
|
-
await optimizeMonkeyC(fnMap);
|
|
12749
|
+
const diagnostics = await optimizeMonkeyC(fnMap);
|
|
12581
12750
|
return Promise.all(Object.values(fnMap).map(async (info) => {
|
|
12582
12751
|
const name = info.output;
|
|
12583
12752
|
const dir = external_path_.dirname(name);
|
|
@@ -12592,9 +12761,10 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12592
12761
|
const hasTests = results.some((v) => v);
|
|
12593
12762
|
return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
|
|
12594
12763
|
hasTests,
|
|
12764
|
+
diagnostics,
|
|
12595
12765
|
...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
|
|
12596
12766
|
}))
|
|
12597
|
-
.then(() => hasTests);
|
|
12767
|
+
.then(() => ({ hasTests, diagnostics }));
|
|
12598
12768
|
});
|
|
12599
12769
|
}
|
|
12600
12770
|
async function getProjectAnalysis(targets, analysis, options) {
|