@markw65/monkeyc-optimizer 1.0.18 → 1.0.21
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 +46 -0
- package/build/api.cjs +275 -135
- package/build/optimizer.cjs +316 -139
- 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 +28 -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
|
|
@@ -10853,23 +10853,32 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
10853
10853
|
// determine whether decl might be changed by a function call
|
|
10854
10854
|
// or assignment during the evaluation of FunctionStateNode.
|
|
10855
10855
|
const getSafety = (decl) => {
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
if (decl.type === "VariableDeclarator") {
|
|
10860
|
-
// constants also can't change
|
|
10861
|
-
if (decl.node.kind === "const")
|
|
10856
|
+
switch (decl.type) {
|
|
10857
|
+
// enums are constant, they cant change
|
|
10858
|
+
case "EnumStringMember":
|
|
10862
10859
|
return true;
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
if (!state.stack[i] || decl.stack[i] !== state.stack[i])
|
|
10867
|
-
return false;
|
|
10868
|
-
if (state.stack[i].type === "FunctionDeclaration")
|
|
10860
|
+
case "VariableDeclarator": {
|
|
10861
|
+
// constants also can't change
|
|
10862
|
+
if (decl.node.kind === "const")
|
|
10869
10863
|
return true;
|
|
10864
|
+
// if decl is a local, it also can't be changed
|
|
10865
|
+
// by a call to another function.
|
|
10866
|
+
for (let i = 0;; i++) {
|
|
10867
|
+
if (!state.stack[i] || decl.stack[i] !== state.stack[i])
|
|
10868
|
+
return false;
|
|
10869
|
+
if (state.stack[i].type === "FunctionDeclaration")
|
|
10870
|
+
return true;
|
|
10871
|
+
}
|
|
10870
10872
|
}
|
|
10873
|
+
case "Identifier":
|
|
10874
|
+
case "BinaryExpression":
|
|
10875
|
+
// This is a parameter of the calling function.
|
|
10876
|
+
// It also can't be changed during the execution
|
|
10877
|
+
// of the inlined function
|
|
10878
|
+
return true;
|
|
10879
|
+
default:
|
|
10880
|
+
return null;
|
|
10871
10881
|
}
|
|
10872
|
-
return null;
|
|
10873
10882
|
};
|
|
10874
10883
|
const safeArgs = [];
|
|
10875
10884
|
let allSafe = true;
|
|
@@ -10983,9 +10992,26 @@ var InlineStatus;
|
|
|
10983
10992
|
InlineStatus[InlineStatus["AsExpression"] = 1] = "AsExpression";
|
|
10984
10993
|
InlineStatus[InlineStatus["AsStatement"] = 2] = "AsStatement";
|
|
10985
10994
|
})(InlineStatus || (InlineStatus = {}));
|
|
10986
|
-
function
|
|
10995
|
+
function inlineRequested(state, func) {
|
|
10996
|
+
const excludeAnnotations = (func.node.loc?.source &&
|
|
10997
|
+
state.fnMap[func.node.loc?.source]?.excludeAnnotations) ||
|
|
10998
|
+
{};
|
|
10999
|
+
if (func.node.attrs &&
|
|
11000
|
+
func.node.attrs.attributes &&
|
|
11001
|
+
func.node.attrs.attributes.elements.some((attr) => attr.type === "UnaryExpression" &&
|
|
11002
|
+
(attr.argument.name === "inline" ||
|
|
11003
|
+
(attr.argument.name.startsWith("inline_") &&
|
|
11004
|
+
(0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
|
|
11005
|
+
return true;
|
|
11006
|
+
}
|
|
11007
|
+
return false;
|
|
11008
|
+
}
|
|
11009
|
+
function shouldInline(state, func, call, context) {
|
|
11010
|
+
if (state.inlining)
|
|
11011
|
+
return false;
|
|
10987
11012
|
let autoInline = false;
|
|
10988
11013
|
let inlineAsExpression = false;
|
|
11014
|
+
const args = call.arguments;
|
|
10989
11015
|
if (func.node.body &&
|
|
10990
11016
|
func.node.body.body.length === 1 &&
|
|
10991
11017
|
func.node.body.body[0].type === "ReturnStatement" &&
|
|
@@ -10995,39 +11021,31 @@ function shouldInline(state, func, args) {
|
|
|
10995
11021
|
autoInline = inliningLooksUseful(func.node, func.node.body.body[0].argument);
|
|
10996
11022
|
}
|
|
10997
11023
|
if (autoInline === 1) {
|
|
10998
|
-
return
|
|
11024
|
+
return true;
|
|
10999
11025
|
}
|
|
11000
|
-
const
|
|
11001
|
-
|
|
11002
|
-
{
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
return
|
|
11011
|
-
? InlineStatus.AsExpression
|
|
11012
|
-
: InlineStatus.AsStatement;
|
|
11026
|
+
const requested = inlineRequested(state, func);
|
|
11027
|
+
if (autoInline || requested) {
|
|
11028
|
+
if (inlineAsExpression) {
|
|
11029
|
+
if (canInline(state, func, args)) {
|
|
11030
|
+
return true;
|
|
11031
|
+
}
|
|
11032
|
+
}
|
|
11033
|
+
if (!context && requested) {
|
|
11034
|
+
inlineDiagnostic(state, func, call, "This function can only be inlined in statement, assignment, or return contexts");
|
|
11035
|
+
}
|
|
11036
|
+
return context != null;
|
|
11013
11037
|
}
|
|
11014
|
-
return
|
|
11038
|
+
return false;
|
|
11015
11039
|
}
|
|
11016
11040
|
function processInlineBody(state, func, call, root, insertedVariableDecls, params) {
|
|
11017
|
-
|
|
11018
|
-
const safeArgs = getArgSafety(state, func, call.arguments, false);
|
|
11019
|
-
params = Object.fromEntries(func.node.params.map((param, i) => {
|
|
11020
|
-
const argnum = safeArgs === true || (safeArgs !== false && safeArgs[i] !== null)
|
|
11021
|
-
? i
|
|
11022
|
-
: -1;
|
|
11023
|
-
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
11024
|
-
return [name, argnum];
|
|
11025
|
-
}));
|
|
11026
|
-
}
|
|
11041
|
+
let failed = false;
|
|
11027
11042
|
const pre = state.pre;
|
|
11028
11043
|
const post = state.post;
|
|
11044
|
+
state.inlining = true;
|
|
11029
11045
|
try {
|
|
11030
11046
|
state.pre = (node) => {
|
|
11047
|
+
if (failed)
|
|
11048
|
+
return [];
|
|
11031
11049
|
node.start = call.start;
|
|
11032
11050
|
node.end = call.end;
|
|
11033
11051
|
node.loc = call.loc;
|
|
@@ -11039,6 +11057,11 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11039
11057
|
const { map } = locals;
|
|
11040
11058
|
if (!map)
|
|
11041
11059
|
throw new Error("No local variable map!");
|
|
11060
|
+
// We still need to keep track of every local name that was
|
|
11061
|
+
// already in use, but we don't want to use any of its renames.
|
|
11062
|
+
// We also want to know whether a local is from the function being
|
|
11063
|
+
// inlined, or the calling function, so set every element to false.
|
|
11064
|
+
Object.keys(map).forEach((key) => (map[key] = false));
|
|
11042
11065
|
const declarations = func.node.params
|
|
11043
11066
|
.map((param, i) => {
|
|
11044
11067
|
const paramName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
@@ -11063,6 +11086,8 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11063
11086
|
return result;
|
|
11064
11087
|
};
|
|
11065
11088
|
state.post = (node) => {
|
|
11089
|
+
if (failed)
|
|
11090
|
+
return post(node, state);
|
|
11066
11091
|
let replacement = null;
|
|
11067
11092
|
switch (node.type) {
|
|
11068
11093
|
case "Identifier": {
|
|
@@ -11077,26 +11102,34 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11077
11102
|
}
|
|
11078
11103
|
replacement = fixNodeScope(state, node, func.stack);
|
|
11079
11104
|
if (!replacement) {
|
|
11080
|
-
|
|
11105
|
+
failed = true;
|
|
11106
|
+
inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
|
|
11107
|
+
return post(node, state);
|
|
11081
11108
|
}
|
|
11082
11109
|
break;
|
|
11083
11110
|
}
|
|
11084
11111
|
}
|
|
11085
|
-
|
|
11112
|
+
const ret = post(replacement || node, state);
|
|
11113
|
+
return ret === false || ret ? ret : replacement;
|
|
11086
11114
|
};
|
|
11087
|
-
|
|
11088
|
-
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11115
|
+
let ret = state.traverse(root);
|
|
11116
|
+
if (failed) {
|
|
11117
|
+
return null;
|
|
11118
|
+
}
|
|
11119
|
+
if (ret === null) {
|
|
11120
|
+
ret = root;
|
|
11121
|
+
}
|
|
11122
|
+
if (!ret) {
|
|
11123
|
+
inlineDiagnostic(state, func, call, `Internal error`);
|
|
11124
|
+
return null;
|
|
11094
11125
|
}
|
|
11095
|
-
|
|
11126
|
+
inlineDiagnostic(state, func, call, null);
|
|
11127
|
+
return ret;
|
|
11096
11128
|
}
|
|
11097
11129
|
finally {
|
|
11098
11130
|
state.pre = pre;
|
|
11099
11131
|
state.post = post;
|
|
11132
|
+
delete state.inlining;
|
|
11100
11133
|
}
|
|
11101
11134
|
}
|
|
11102
11135
|
function unused(expression, top) {
|
|
@@ -11115,7 +11148,16 @@ function unused(expression, top) {
|
|
|
11115
11148
|
case "UnaryExpression":
|
|
11116
11149
|
return unused(expression.argument);
|
|
11117
11150
|
case "MemberExpression":
|
|
11118
|
-
|
|
11151
|
+
if (expression.computed) {
|
|
11152
|
+
return unused(expression.object).concat(unused(expression.property));
|
|
11153
|
+
}
|
|
11154
|
+
return unused(expression.object);
|
|
11155
|
+
case "ArrayExpression":
|
|
11156
|
+
return expression.elements.map((e) => unused(e)).flat(1);
|
|
11157
|
+
case "ObjectExpression":
|
|
11158
|
+
return expression.properties
|
|
11159
|
+
.map((p) => unused(p.key).concat(unused(p.value)))
|
|
11160
|
+
.flat(1);
|
|
11119
11161
|
}
|
|
11120
11162
|
return top
|
|
11121
11163
|
? null
|
|
@@ -11123,30 +11165,98 @@ function unused(expression, top) {
|
|
|
11123
11165
|
{
|
|
11124
11166
|
type: "ExpressionStatement",
|
|
11125
11167
|
expression,
|
|
11168
|
+
start: expression.start,
|
|
11169
|
+
end: expression.end,
|
|
11170
|
+
loc: expression.loc,
|
|
11126
11171
|
},
|
|
11127
11172
|
];
|
|
11128
11173
|
}
|
|
11129
|
-
function
|
|
11174
|
+
function diagnostic(state, loc, message) {
|
|
11175
|
+
if (!loc || !loc.source)
|
|
11176
|
+
return;
|
|
11177
|
+
const source = loc.source;
|
|
11178
|
+
if (!state.diagnostics)
|
|
11179
|
+
state.diagnostics = {};
|
|
11180
|
+
if (!(0,external_api_cjs_namespaceObject.hasProperty)(state.diagnostics, source)) {
|
|
11181
|
+
if (!message)
|
|
11182
|
+
return;
|
|
11183
|
+
state.diagnostics[source] = [];
|
|
11184
|
+
}
|
|
11185
|
+
const diags = state.diagnostics[source];
|
|
11186
|
+
let index = diags.findIndex((item) => item.loc === loc);
|
|
11187
|
+
if (message) {
|
|
11188
|
+
if (index < 0)
|
|
11189
|
+
index = diags.length;
|
|
11190
|
+
diags[index] = { type: "INFO", loc, message };
|
|
11191
|
+
}
|
|
11192
|
+
else if (index >= 0) {
|
|
11193
|
+
diags.splice(index, 1);
|
|
11194
|
+
}
|
|
11195
|
+
}
|
|
11196
|
+
function inlineDiagnostic(state, func, call, message) {
|
|
11197
|
+
if (inlineRequested(state, func)) {
|
|
11198
|
+
diagnostic(state, call.loc, message && `While inlining ${func.node.id.name}: ${message}`);
|
|
11199
|
+
}
|
|
11200
|
+
}
|
|
11201
|
+
function inlineWithArgs(state, func, call, context) {
|
|
11130
11202
|
if (!func.node || !func.node.body) {
|
|
11131
11203
|
return null;
|
|
11132
11204
|
}
|
|
11133
11205
|
let retStmtCount = 0;
|
|
11134
|
-
(
|
|
11135
|
-
|
|
11136
|
-
|
|
11137
|
-
|
|
11138
|
-
|
|
11139
|
-
|
|
11140
|
-
|
|
11206
|
+
if (context.type === "ReturnStatement") {
|
|
11207
|
+
const last = func.node.body.body.slice(-1)[0];
|
|
11208
|
+
if (!last || last.type !== "ReturnStatement") {
|
|
11209
|
+
inlineDiagnostic(state, func, call, "Function didn't end with a return statement");
|
|
11210
|
+
return null;
|
|
11211
|
+
}
|
|
11212
|
+
}
|
|
11213
|
+
else {
|
|
11214
|
+
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
|
|
11215
|
+
node.type === "ReturnStatement" && retStmtCount++;
|
|
11216
|
+
});
|
|
11217
|
+
if (retStmtCount > 1) {
|
|
11218
|
+
inlineDiagnostic(state, func, call, "Function had more than one return statement");
|
|
11219
|
+
}
|
|
11220
|
+
else if (context.type === "AssignmentExpression" && retStmtCount !== 1) {
|
|
11221
|
+
inlineDiagnostic(state, func, call, "Function did not have a return statement");
|
|
11222
|
+
return null;
|
|
11223
|
+
}
|
|
11224
|
+
if (retStmtCount === 1) {
|
|
11225
|
+
const last = func.node.body.body.slice(-1)[0];
|
|
11226
|
+
if (!last ||
|
|
11227
|
+
last.type !== "ReturnStatement" ||
|
|
11228
|
+
(context.type === "AssignmentExpression" && !last.argument)) {
|
|
11229
|
+
inlineDiagnostic(state, func, call, "There was a return statement, but not at the end of the function");
|
|
11230
|
+
return null;
|
|
11231
|
+
}
|
|
11232
|
+
}
|
|
11141
11233
|
}
|
|
11142
11234
|
const body = JSON.parse(JSON.stringify(func.node.body));
|
|
11143
|
-
|
|
11144
|
-
|
|
11235
|
+
const safeArgs = getArgSafety(state, func, call.arguments, false);
|
|
11236
|
+
const params = Object.fromEntries(func.node.params.map((param, i) => {
|
|
11237
|
+
const argnum = safeArgs === true || (safeArgs !== false && safeArgs[i] !== null)
|
|
11238
|
+
? i
|
|
11239
|
+
: -1;
|
|
11240
|
+
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
11241
|
+
return [name, argnum];
|
|
11242
|
+
}));
|
|
11243
|
+
if (!processInlineBody(state, func, call, body, func.node.params.length ? false : true, params)) {
|
|
11244
|
+
return null;
|
|
11245
|
+
}
|
|
11246
|
+
diagnostic(state, call.loc, null);
|
|
11247
|
+
if (context.type !== "ReturnStatement" && retStmtCount) {
|
|
11145
11248
|
const last = body.body[body.body.length - 1];
|
|
11146
11249
|
if (last.type != "ReturnStatement") {
|
|
11147
11250
|
throw new Error("ReturnStatement got lost!");
|
|
11148
11251
|
}
|
|
11149
|
-
if (
|
|
11252
|
+
if (context.type === "AssignmentExpression") {
|
|
11253
|
+
context.right = last.argument;
|
|
11254
|
+
body.body[body.body.length - 1] = {
|
|
11255
|
+
type: "ExpressionStatement",
|
|
11256
|
+
expression: context,
|
|
11257
|
+
};
|
|
11258
|
+
}
|
|
11259
|
+
else if (last.argument) {
|
|
11150
11260
|
const side_exprs = unused(last.argument);
|
|
11151
11261
|
body.body.splice(body.body.length - 1, 1, ...side_exprs);
|
|
11152
11262
|
}
|
|
@@ -11156,13 +11266,13 @@ function inlineWithArgs(state, func, call) {
|
|
|
11156
11266
|
}
|
|
11157
11267
|
return body;
|
|
11158
11268
|
}
|
|
11159
|
-
function inlineFunction(state, func, call,
|
|
11160
|
-
if (
|
|
11161
|
-
return inlineWithArgs(state, func, call);
|
|
11269
|
+
function inlineFunction(state, func, call, context) {
|
|
11270
|
+
if (context) {
|
|
11271
|
+
return inlineWithArgs(state, func, call, context);
|
|
11162
11272
|
}
|
|
11163
11273
|
const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
|
|
11164
11274
|
const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
|
|
11165
|
-
return processInlineBody(state, func, call, retArg, true, params)
|
|
11275
|
+
return processInlineBody(state, func, call, retArg, true, params);
|
|
11166
11276
|
}
|
|
11167
11277
|
function applyTypeIfNeeded(node) {
|
|
11168
11278
|
if ("enumType" in node && node.enumType) {
|
|
@@ -11177,13 +11287,14 @@ function applyTypeIfNeeded(node) {
|
|
|
11177
11287
|
}
|
|
11178
11288
|
function fixNodeScope(state, lookupNode, nodeStack) {
|
|
11179
11289
|
if (lookupNode.type === "Identifier") {
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11290
|
+
const locals = state.localsStack[state.localsStack.length - 1];
|
|
11291
|
+
const { map } = locals;
|
|
11292
|
+
if (!map)
|
|
11293
|
+
throw new Error("No local variable map!");
|
|
11294
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(map, lookupNode.name) && map[lookupNode.name] !== false) {
|
|
11295
|
+
// map[name] !== false means its an entry that was created during inlining
|
|
11296
|
+
// so its definitely one of our locals.
|
|
11297
|
+
return lookupNode;
|
|
11187
11298
|
}
|
|
11188
11299
|
}
|
|
11189
11300
|
const [, original] = state.lookup(lookupNode, null, nodeStack);
|
|
@@ -11400,12 +11511,12 @@ async function analyze(fnMap) {
|
|
|
11400
11511
|
shouldExclude(node) {
|
|
11401
11512
|
if ("attrs" in node &&
|
|
11402
11513
|
node.attrs &&
|
|
11403
|
-
"
|
|
11404
|
-
node.attrs.
|
|
11514
|
+
"attributes" in node.attrs &&
|
|
11515
|
+
node.attrs.attributes &&
|
|
11405
11516
|
node.loc?.source) {
|
|
11406
11517
|
const excludeAnnotations = fnMap[node.loc.source].excludeAnnotations;
|
|
11407
11518
|
if (excludeAnnotations) {
|
|
11408
|
-
return node.attrs.
|
|
11519
|
+
return node.attrs.attributes.elements.reduce((drop, attr) => {
|
|
11409
11520
|
if (attr.type != "UnaryExpression")
|
|
11410
11521
|
return drop;
|
|
11411
11522
|
if (attr.argument.type != "Identifier")
|
|
@@ -11656,13 +11767,15 @@ function optimizeNode(node) {
|
|
|
11656
11767
|
return null;
|
|
11657
11768
|
}
|
|
11658
11769
|
function evaluateFunction(func, args) {
|
|
11659
|
-
if (args && args.length != func.params.length) {
|
|
11770
|
+
if (!func.body || (args && args.length != func.params.length)) {
|
|
11660
11771
|
return false;
|
|
11661
11772
|
}
|
|
11662
11773
|
const paramValues = args &&
|
|
11663
11774
|
Object.fromEntries(func.params.map((p, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(p), args[i]]));
|
|
11664
11775
|
let ret = null;
|
|
11665
|
-
const body = args
|
|
11776
|
+
const body = args
|
|
11777
|
+
? JSON.parse(JSON.stringify(func.body))
|
|
11778
|
+
: func.body;
|
|
11666
11779
|
try {
|
|
11667
11780
|
(0,external_api_cjs_namespaceObject.traverseAst)(body, (node) => {
|
|
11668
11781
|
switch (node.type) {
|
|
@@ -11705,6 +11818,13 @@ function evaluateFunction(func, args) {
|
|
|
11705
11818
|
return false;
|
|
11706
11819
|
}
|
|
11707
11820
|
}
|
|
11821
|
+
function markFunctionCalled(state, func) {
|
|
11822
|
+
if (!(0,external_api_cjs_namespaceObject.hasProperty)(state.calledFunctions, func.id.name)) {
|
|
11823
|
+
state.calledFunctions[func.id.name] = [func];
|
|
11824
|
+
return;
|
|
11825
|
+
}
|
|
11826
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(state.calledFunctions[func.id.name], func);
|
|
11827
|
+
}
|
|
11708
11828
|
async function optimizeMonkeyC(fnMap) {
|
|
11709
11829
|
const state = {
|
|
11710
11830
|
...(await analyze(fnMap)),
|
|
@@ -11712,7 +11832,13 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11712
11832
|
exposed: {},
|
|
11713
11833
|
calledFunctions: {},
|
|
11714
11834
|
};
|
|
11715
|
-
const replace = (node
|
|
11835
|
+
const replace = (node) => {
|
|
11836
|
+
if (node === false || node === null)
|
|
11837
|
+
return node;
|
|
11838
|
+
const rep = state.traverse(node);
|
|
11839
|
+
return rep === false || rep ? rep : node;
|
|
11840
|
+
};
|
|
11841
|
+
const inPlaceReplacement = (node, obj) => {
|
|
11716
11842
|
for (const k of Object.keys(node)) {
|
|
11717
11843
|
delete node[k];
|
|
11718
11844
|
}
|
|
@@ -11737,7 +11863,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11737
11863
|
if (!obj) {
|
|
11738
11864
|
return false;
|
|
11739
11865
|
}
|
|
11740
|
-
|
|
11866
|
+
inPlaceReplacement(node, obj);
|
|
11741
11867
|
return true;
|
|
11742
11868
|
};
|
|
11743
11869
|
const topLocals = () => state.localsStack[state.localsStack.length - 1];
|
|
@@ -11753,8 +11879,8 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11753
11879
|
if ((0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, func.id.name))
|
|
11754
11880
|
return true;
|
|
11755
11881
|
if (func.attrs &&
|
|
11756
|
-
func.attrs.
|
|
11757
|
-
func.attrs.
|
|
11882
|
+
func.attrs.attributes &&
|
|
11883
|
+
func.attrs.attributes.elements.some((attr) => {
|
|
11758
11884
|
if (attr.type != "UnaryExpression")
|
|
11759
11885
|
return false;
|
|
11760
11886
|
if (attr.argument.type != "Identifier")
|
|
@@ -11863,7 +11989,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11863
11989
|
if (map) {
|
|
11864
11990
|
if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
|
|
11865
11991
|
const name = map[node.name];
|
|
11866
|
-
if (name
|
|
11992
|
+
if (typeof name === "string") {
|
|
11867
11993
|
node.name = name;
|
|
11868
11994
|
}
|
|
11869
11995
|
}
|
|
@@ -11914,10 +12040,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11914
12040
|
used = checkInherited(parent, node.id.name);
|
|
11915
12041
|
}
|
|
11916
12042
|
if (used) {
|
|
11917
|
-
|
|
11918
|
-
state.calledFunctions[node.id.name] = [];
|
|
11919
|
-
}
|
|
11920
|
-
state.calledFunctions[node.id.name].push(node);
|
|
12043
|
+
markFunctionCalled(state, node);
|
|
11921
12044
|
}
|
|
11922
12045
|
}
|
|
11923
12046
|
}
|
|
@@ -11930,8 +12053,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11930
12053
|
}
|
|
11931
12054
|
const opt = optimizeNode(node);
|
|
11932
12055
|
if (opt) {
|
|
11933
|
-
replace(
|
|
11934
|
-
return null;
|
|
12056
|
+
return replace(opt);
|
|
11935
12057
|
}
|
|
11936
12058
|
switch (node.type) {
|
|
11937
12059
|
case "ConditionalExpression":
|
|
@@ -11941,7 +12063,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11941
12063
|
const rep = node.test.value ? node.consequent : node.alternate;
|
|
11942
12064
|
if (!rep)
|
|
11943
12065
|
return false;
|
|
11944
|
-
replace(
|
|
12066
|
+
return replace(rep);
|
|
11945
12067
|
}
|
|
11946
12068
|
break;
|
|
11947
12069
|
case "WhileStatement":
|
|
@@ -11954,27 +12076,50 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11954
12076
|
return node.body;
|
|
11955
12077
|
}
|
|
11956
12078
|
break;
|
|
11957
|
-
case "
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
replace(node, ret);
|
|
12079
|
+
case "ReturnStatement":
|
|
12080
|
+
if (node.argument && node.argument.type === "CallExpression") {
|
|
12081
|
+
return replace(optimizeCall(state, node.argument, node));
|
|
11961
12082
|
}
|
|
11962
12083
|
break;
|
|
12084
|
+
case "CallExpression": {
|
|
12085
|
+
return replace(optimizeCall(state, node, null));
|
|
11963
12086
|
}
|
|
12087
|
+
case "AssignmentExpression":
|
|
12088
|
+
if (node.operator === "=" &&
|
|
12089
|
+
node.left.type === "Identifier" &&
|
|
12090
|
+
node.right.type === "Identifier" &&
|
|
12091
|
+
node.left.name === node.right.name) {
|
|
12092
|
+
return { type: "Literal", value: null, raw: "null" };
|
|
12093
|
+
}
|
|
12094
|
+
break;
|
|
11964
12095
|
case "ExpressionStatement":
|
|
11965
12096
|
if (node.expression.type === "CallExpression") {
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
12097
|
+
return replace(optimizeCall(state, node.expression, node));
|
|
12098
|
+
}
|
|
12099
|
+
else if (node.expression.type === "AssignmentExpression") {
|
|
12100
|
+
if (node.expression.right.type === "CallExpression") {
|
|
12101
|
+
let ok = false;
|
|
12102
|
+
if (node.expression.left.type === "Identifier") {
|
|
12103
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(topLocals().map, node.expression.left.type)) {
|
|
12104
|
+
ok = true;
|
|
12105
|
+
}
|
|
12106
|
+
}
|
|
12107
|
+
if (!ok && node.expression.operator == "=") {
|
|
12108
|
+
const [, result] = state.lookup(node.expression.left);
|
|
12109
|
+
ok = result != null;
|
|
12110
|
+
}
|
|
12111
|
+
if (ok) {
|
|
12112
|
+
return replace(optimizeCall(state, node.expression.right, node.expression));
|
|
11970
12113
|
}
|
|
11971
|
-
node.expression = ret;
|
|
11972
12114
|
}
|
|
11973
12115
|
}
|
|
11974
12116
|
else {
|
|
11975
12117
|
const ret = unused(node.expression, true);
|
|
11976
12118
|
if (ret) {
|
|
11977
|
-
return ret
|
|
12119
|
+
return ret
|
|
12120
|
+
.map(replace)
|
|
12121
|
+
.flat(1)
|
|
12122
|
+
.filter((s) => !!s);
|
|
11978
12123
|
}
|
|
11979
12124
|
}
|
|
11980
12125
|
break;
|
|
@@ -11984,6 +12129,11 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11984
12129
|
Object.values(fnMap).forEach((f) => {
|
|
11985
12130
|
(0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
|
|
11986
12131
|
});
|
|
12132
|
+
state.calledFunctions = {};
|
|
12133
|
+
state.exposed = {};
|
|
12134
|
+
Object.values(fnMap).forEach((f) => {
|
|
12135
|
+
(0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
|
|
12136
|
+
});
|
|
11987
12137
|
delete state.pre;
|
|
11988
12138
|
delete state.post;
|
|
11989
12139
|
const cleanup = (node) => {
|
|
@@ -12012,19 +12162,24 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12012
12162
|
if (!node.body.members.length) {
|
|
12013
12163
|
if (!node.id)
|
|
12014
12164
|
return false;
|
|
12015
|
-
if (!node.body
|
|
12165
|
+
if (!node.body.enumType) {
|
|
12016
12166
|
throw new Error("Missing enumType on optimized enum");
|
|
12017
12167
|
}
|
|
12018
|
-
|
|
12168
|
+
return {
|
|
12019
12169
|
type: "TypedefDeclaration",
|
|
12020
12170
|
id: node.id,
|
|
12021
12171
|
ts: {
|
|
12022
12172
|
type: "UnaryExpression",
|
|
12023
|
-
argument: {
|
|
12173
|
+
argument: {
|
|
12174
|
+
type: "TypeSpecList",
|
|
12175
|
+
ts: [
|
|
12176
|
+
node.body.enumType,
|
|
12177
|
+
],
|
|
12178
|
+
},
|
|
12024
12179
|
prefix: true,
|
|
12025
12180
|
operator: " as",
|
|
12026
12181
|
},
|
|
12027
|
-
}
|
|
12182
|
+
};
|
|
12028
12183
|
}
|
|
12029
12184
|
break;
|
|
12030
12185
|
case "VariableDeclaration": {
|
|
@@ -12059,9 +12214,12 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12059
12214
|
return ret;
|
|
12060
12215
|
});
|
|
12061
12216
|
});
|
|
12217
|
+
return state.diagnostics;
|
|
12062
12218
|
}
|
|
12063
|
-
function optimizeCall(state, node,
|
|
12064
|
-
const [name,
|
|
12219
|
+
function optimizeCall(state, node, context) {
|
|
12220
|
+
const [name, results] = state.lookup(node.callee);
|
|
12221
|
+
const callees = results &&
|
|
12222
|
+
results.filter((c) => c.type === "FunctionDeclaration");
|
|
12065
12223
|
if (!callees || !callees.length) {
|
|
12066
12224
|
const n = name ||
|
|
12067
12225
|
("name" in node.callee && node.callee.name) ||
|
|
@@ -12080,7 +12238,8 @@ function optimizeCall(state, node, asStatement) {
|
|
|
12080
12238
|
}
|
|
12081
12239
|
if (callees.length == 1 && callees[0].type === "FunctionDeclaration") {
|
|
12082
12240
|
const callee = callees[0].node;
|
|
12083
|
-
if (
|
|
12241
|
+
if (!context &&
|
|
12242
|
+
callee.optimizable &&
|
|
12084
12243
|
!callee.hasOverride &&
|
|
12085
12244
|
node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
|
|
12086
12245
|
const ret = evaluateFunction(callee, node.arguments);
|
|
@@ -12088,19 +12247,14 @@ function optimizeCall(state, node, asStatement) {
|
|
|
12088
12247
|
return ret;
|
|
12089
12248
|
}
|
|
12090
12249
|
}
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
(asStatement && inlineStatus === InlineStatus.AsStatement)) {
|
|
12094
|
-
const ret = inlineFunction(state, callees[0], node, inlineStatus);
|
|
12250
|
+
if (shouldInline(state, callees[0], node, context)) {
|
|
12251
|
+
const ret = inlineFunction(state, callees[0], node, context);
|
|
12095
12252
|
if (ret) {
|
|
12096
12253
|
return ret;
|
|
12097
12254
|
}
|
|
12098
12255
|
}
|
|
12099
12256
|
}
|
|
12100
|
-
|
|
12101
|
-
state.calledFunctions[name] = [];
|
|
12102
|
-
}
|
|
12103
|
-
callees.forEach((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && state.calledFunctions[name].push(c.node));
|
|
12257
|
+
callees.forEach((c) => markFunctionCalled(state, c.node));
|
|
12104
12258
|
return null;
|
|
12105
12259
|
}
|
|
12106
12260
|
|
|
@@ -12112,12 +12266,31 @@ function pragmaChecker(ast) {
|
|
|
12112
12266
|
return;
|
|
12113
12267
|
let index = -1;
|
|
12114
12268
|
let comment;
|
|
12269
|
+
let matchers;
|
|
12115
12270
|
const next = () => {
|
|
12116
12271
|
while (++index < comments.length) {
|
|
12117
12272
|
comment = comments[index];
|
|
12118
|
-
|
|
12273
|
+
let match = comment.value.match(/^\s*@match\s+(.+)/);
|
|
12274
|
+
if (!match)
|
|
12275
|
+
continue;
|
|
12276
|
+
let str = match[1];
|
|
12277
|
+
matchers = [];
|
|
12278
|
+
while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
|
|
12279
|
+
matchers.push({ quote: match[1], needle: match[2] });
|
|
12280
|
+
str = str.substring(match[0].length);
|
|
12281
|
+
if (!str.length)
|
|
12282
|
+
break;
|
|
12283
|
+
}
|
|
12284
|
+
if (!str.length)
|
|
12119
12285
|
break;
|
|
12286
|
+
if (!matchers.length) {
|
|
12287
|
+
match = str.match(/^(\S+)\s+$/);
|
|
12288
|
+
if (match) {
|
|
12289
|
+
matchers.push({ quote: '"', needle: match[1] });
|
|
12290
|
+
break;
|
|
12291
|
+
}
|
|
12120
12292
|
}
|
|
12293
|
+
throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12121
12294
|
}
|
|
12122
12295
|
};
|
|
12123
12296
|
next();
|
|
@@ -12125,29 +12298,23 @@ function pragmaChecker(ast) {
|
|
|
12125
12298
|
if (index >= comments.length)
|
|
12126
12299
|
return false;
|
|
12127
12300
|
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
12128
|
-
|
|
12129
|
-
if (!match) {
|
|
12130
|
-
throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12131
|
-
}
|
|
12301
|
+
const { quote, needle } = matchers.shift();
|
|
12132
12302
|
const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/[\r\n]/g, " ");
|
|
12133
12303
|
let found = false;
|
|
12134
|
-
|
|
12135
|
-
if (match.length == 2) {
|
|
12304
|
+
if (quote == '"') {
|
|
12136
12305
|
found = haystack.includes(needle);
|
|
12137
12306
|
}
|
|
12138
12307
|
else {
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
}
|
|
12142
|
-
else {
|
|
12143
|
-
const re = new RegExp((needle = match[2]));
|
|
12144
|
-
found = re.test(haystack);
|
|
12145
|
-
}
|
|
12308
|
+
const re = new RegExp(needle);
|
|
12309
|
+
found = re.test(haystack);
|
|
12146
12310
|
}
|
|
12147
12311
|
if (!found) {
|
|
12148
|
-
throw new Error(`Didn't find '${needle}'
|
|
12312
|
+
throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12313
|
+
}
|
|
12314
|
+
if (!matchers.length) {
|
|
12315
|
+
next();
|
|
12149
12316
|
}
|
|
12150
|
-
|
|
12317
|
+
return false;
|
|
12151
12318
|
}
|
|
12152
12319
|
return null;
|
|
12153
12320
|
});
|
|
@@ -12236,7 +12403,7 @@ async function buildOptimizedProject(product, options) {
|
|
|
12236
12403
|
config.releaseBuild = true;
|
|
12237
12404
|
}
|
|
12238
12405
|
}
|
|
12239
|
-
const { jungleFiles, program, hasTests } = await generateOptimizedProject(config);
|
|
12406
|
+
const { jungleFiles, program, hasTests, diagnostics } = await generateOptimizedProject(config);
|
|
12240
12407
|
config.jungleFiles = jungleFiles;
|
|
12241
12408
|
let bin = config.buildDir || "bin";
|
|
12242
12409
|
let name = `optimized-${program}.prg`;
|
|
@@ -12255,6 +12422,7 @@ async function buildOptimizedProject(product, options) {
|
|
|
12255
12422
|
delete config.testBuild;
|
|
12256
12423
|
return build_project(product, config).then((result) => ({
|
|
12257
12424
|
hasTests,
|
|
12425
|
+
diagnostics,
|
|
12258
12426
|
...result,
|
|
12259
12427
|
}));
|
|
12260
12428
|
}
|
|
@@ -12393,6 +12561,7 @@ async function generateOptimizedProject(options) {
|
|
|
12393
12561
|
(await checkManifest(xml, targets.map((t) => t.product)))) &&
|
|
12394
12562
|
!dropBarrels;
|
|
12395
12563
|
let hasTests = false;
|
|
12564
|
+
let diagnostics = {};
|
|
12396
12565
|
const promises = Object.keys(buildConfigs)
|
|
12397
12566
|
.sort()
|
|
12398
12567
|
.map((key) => {
|
|
@@ -12410,7 +12579,13 @@ async function generateOptimizedProject(options) {
|
|
|
12410
12579
|
e.products = products[key];
|
|
12411
12580
|
throw e;
|
|
12412
12581
|
})
|
|
12413
|
-
.then((t) =>
|
|
12582
|
+
.then((t) => {
|
|
12583
|
+
if (t.hasTests)
|
|
12584
|
+
hasTests = true;
|
|
12585
|
+
if (t.diagnostics) {
|
|
12586
|
+
diagnostics = { ...diagnostics, ...t.diagnostics };
|
|
12587
|
+
}
|
|
12588
|
+
})
|
|
12414
12589
|
: promises_namespaceObject.rm(external_path_.resolve(workspace, outputPath), {
|
|
12415
12590
|
recursive: true,
|
|
12416
12591
|
force: true,
|
|
@@ -12481,6 +12656,7 @@ async function generateOptimizedProject(options) {
|
|
|
12481
12656
|
xml,
|
|
12482
12657
|
program: external_path_.basename(external_path_.dirname(manifest)),
|
|
12483
12658
|
hasTests,
|
|
12659
|
+
diagnostics,
|
|
12484
12660
|
};
|
|
12485
12661
|
}
|
|
12486
12662
|
async function fileInfoFromConfig(workspace, output, buildConfig, extraExcludes) {
|
|
@@ -12559,7 +12735,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12559
12735
|
const actualOptimizedFiles = (await (0,external_util_cjs_namespaceObject.globa)(external_path_.join(output, "**", "*.mc"), { mark: true }))
|
|
12560
12736
|
.filter((file) => !file.endsWith("/"))
|
|
12561
12737
|
.sort();
|
|
12562
|
-
const { hasTests, ...prevOptions } = JSON.parse(await promises_namespaceObject.readFile(external_path_.join(output, "build-info.json"), "utf-8")
|
|
12738
|
+
const { hasTests, diagnostics: prevDiagnostics, ...prevOptions } = JSON.parse(await promises_namespaceObject.readFile(external_path_.join(output, "build-info.json"), "utf-8")
|
|
12563
12739
|
.catch(() => "{}"));
|
|
12564
12740
|
// check that the set of files thats actually there is the same as the
|
|
12565
12741
|
// set of files we're going to generate (in case eg a jungle file change
|
|
@@ -12577,13 +12753,13 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12577
12753
|
// the oldest optimized file, we don't need to regenerate
|
|
12578
12754
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
12579
12755
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
12580
|
-
if (source_time < opt_time &&
|
|
12581
|
-
return hasTests;
|
|
12756
|
+
if (source_time < opt_time && 1654811717108 < opt_time) {
|
|
12757
|
+
return { hasTests, diagnostics: prevDiagnostics };
|
|
12582
12758
|
}
|
|
12583
12759
|
}
|
|
12584
12760
|
await promises_namespaceObject.rm(output, { recursive: true, force: true });
|
|
12585
12761
|
await promises_namespaceObject.mkdir(output, { recursive: true });
|
|
12586
|
-
await optimizeMonkeyC(fnMap);
|
|
12762
|
+
const diagnostics = await optimizeMonkeyC(fnMap);
|
|
12587
12763
|
return Promise.all(Object.values(fnMap).map(async (info) => {
|
|
12588
12764
|
const name = info.output;
|
|
12589
12765
|
const dir = external_path_.dirname(name);
|
|
@@ -12598,9 +12774,10 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12598
12774
|
const hasTests = results.some((v) => v);
|
|
12599
12775
|
return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
|
|
12600
12776
|
hasTests,
|
|
12777
|
+
diagnostics,
|
|
12601
12778
|
...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
|
|
12602
12779
|
}))
|
|
12603
|
-
.then(() => hasTests);
|
|
12780
|
+
.then(() => ({ hasTests, diagnostics }));
|
|
12604
12781
|
});
|
|
12605
12782
|
}
|
|
12606
12783
|
async function getProjectAnalysis(targets, analysis, options) {
|