@markw65/monkeyc-optimizer 1.0.36 → 1.0.38
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 +13 -1
- package/build/api.cjs +142 -17
- package/build/optimizer.cjs +167 -21
- package/build/src/inliner.d.ts +2 -1
- package/build/src/launch.d.ts +2 -0
- package/build/src/optimizer-types.d.ts +1 -0
- package/build/src/variable-renamer.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -417,6 +417,18 @@ Bug Fixes
|
|
|
417
417
|
|
|
418
418
|
### 1.0.36
|
|
419
419
|
|
|
420
|
-
- Update to [@markw65/prettier-plugin-monkeyc@1.0.
|
|
420
|
+
- Update to [@markw65/prettier-plugin-monkeyc@1.0.35](https://github.com/markw65/prettier-plugin-monkeyc#1035).
|
|
421
421
|
- Fixes [prettier-plugin-monkeyc#1](https://github.com/markw65/prettier-plugin-monkeyc/issues/1)
|
|
422
422
|
- Fixes [monkeyc-optimizer#1](https://github.com/markw65/monkeyc-optimizer/issues/1)
|
|
423
|
+
|
|
424
|
+
### 1.0.37
|
|
425
|
+
|
|
426
|
+
- Update the testing framework to launch the simulator before each test run, rather than start it once at the beginning. This is because the latest beta crashes after successfully completing.
|
|
427
|
+
- Update launchSimulator to check if the simulator is already running. This avoids lots of screen switching when the simulator is running on a separate desktop.
|
|
428
|
+
- Add optimizerVersion and extensionVersion to build-info.json.
|
|
429
|
+
|
|
430
|
+
### 1.0.38
|
|
431
|
+
|
|
432
|
+
- Allow inlining the argument to an if-statement, with the same constraints as inlining in assignment context
|
|
433
|
+
- Expand `assignment`, `declaration` and `if` contexts to include (recursively) the left operand of any binary operator, the operand of any unary operator, the `test` operand of any conditional operator or the `object` of a member-expression. So now it will inline `inlinableFunction` in:
|
|
434
|
+
- `var x = !((inlinableFunction() + 4) == 42 ? foo() : bar());`
|
package/build/api.cjs
CHANGED
|
@@ -655,8 +655,13 @@ function function_info_findCalleesForNew(lookupDefs) {
|
|
|
655
655
|
|
|
656
656
|
function variable_renamer_renameVariable(state, locals, declName) {
|
|
657
657
|
const map = locals.map;
|
|
658
|
-
if (
|
|
659
|
-
|
|
658
|
+
if (declName) {
|
|
659
|
+
if (!hasProperty(map, declName))
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
declName = "tmp";
|
|
664
|
+
}
|
|
660
665
|
let suffix = 0;
|
|
661
666
|
let node_name = declName;
|
|
662
667
|
const match = node_name.match(/^pmcr_(.*)_(\d+)$/);
|
|
@@ -711,6 +716,69 @@ function variable_renamer_renameVariable(state, locals, declName) {
|
|
|
711
716
|
|
|
712
717
|
|
|
713
718
|
|
|
719
|
+
// Note: Keep in sync with replaceInlinedSubExpression below
|
|
720
|
+
function inliner_inlinableSubExpression(expr) {
|
|
721
|
+
while (true) {
|
|
722
|
+
if (expr.type === "BinaryExpression" || expr.type === "LogicalExpression") {
|
|
723
|
+
expr = expr.left;
|
|
724
|
+
}
|
|
725
|
+
else if (expr.type === "UnaryExpression") {
|
|
726
|
+
expr = expr.argument;
|
|
727
|
+
}
|
|
728
|
+
else if (expr.type === "ConditionalExpression") {
|
|
729
|
+
expr = expr.test;
|
|
730
|
+
}
|
|
731
|
+
else if (expr.type === "MemberExpression") {
|
|
732
|
+
expr = expr.object;
|
|
733
|
+
}
|
|
734
|
+
else if (expr.type === "CallExpression") {
|
|
735
|
+
return expr;
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
return null;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
// Note: Keep in sync with inlinableSubExpression above
|
|
743
|
+
function replaceInlinedSubExpression(top, call, repl) {
|
|
744
|
+
if (top === call)
|
|
745
|
+
return repl;
|
|
746
|
+
let expr = top;
|
|
747
|
+
while (true) {
|
|
748
|
+
if (expr.type === "LogicalExpression" || expr.type === "BinaryExpression") {
|
|
749
|
+
if (expr.left === call) {
|
|
750
|
+
expr.left = repl;
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
expr = expr.left;
|
|
754
|
+
}
|
|
755
|
+
else if (expr.type === "UnaryExpression") {
|
|
756
|
+
if (expr.argument === call) {
|
|
757
|
+
expr.argument = repl;
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
expr = expr.argument;
|
|
761
|
+
}
|
|
762
|
+
else if (expr.type === "ConditionalExpression") {
|
|
763
|
+
if (expr.test === call) {
|
|
764
|
+
expr.test = repl;
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
767
|
+
expr = expr.test;
|
|
768
|
+
}
|
|
769
|
+
else if (expr.type === "MemberExpression") {
|
|
770
|
+
if (expr.object === call) {
|
|
771
|
+
expr.object = repl;
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
expr = expr.object;
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
throw new Error("Internal error: Didn't find CallExpression");
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return top;
|
|
781
|
+
}
|
|
714
782
|
function getArgSafety(state, func, args, requireAll) {
|
|
715
783
|
// determine whether decl might be changed by a function call
|
|
716
784
|
// or assignment during the evaluation of FunctionStateNode.
|
|
@@ -938,7 +1006,7 @@ function inliner_shouldInline(state, func, call, context) {
|
|
|
938
1006
|
}
|
|
939
1007
|
}
|
|
940
1008
|
if (!context && requested) {
|
|
941
|
-
inlineDiagnostic(state, func, call, "This function can only be inlined in statement, assignment, or return contexts");
|
|
1009
|
+
inlineDiagnostic(state, func, call, "This function can only be inlined in statement, assignment, if or return contexts");
|
|
942
1010
|
}
|
|
943
1011
|
return context != null;
|
|
944
1012
|
}
|
|
@@ -1198,7 +1266,8 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
1198
1266
|
inlineDiagnostic(state, func, call, "Function had more than one return statement");
|
|
1199
1267
|
}
|
|
1200
1268
|
else if ((context.type === "AssignmentExpression" ||
|
|
1201
|
-
context.type === "VariableDeclarator"
|
|
1269
|
+
context.type === "VariableDeclarator" ||
|
|
1270
|
+
context.type === "IfStatement") &&
|
|
1202
1271
|
retStmtCount !== 1) {
|
|
1203
1272
|
inlineDiagnostic(state, func, call, "Function did not have a return statement");
|
|
1204
1273
|
return null;
|
|
@@ -1208,7 +1277,8 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
1208
1277
|
if (!last ||
|
|
1209
1278
|
last.type !== "ReturnStatement" ||
|
|
1210
1279
|
((context.type === "AssignmentExpression" ||
|
|
1211
|
-
context.type === "VariableDeclarator"
|
|
1280
|
+
context.type === "VariableDeclarator" ||
|
|
1281
|
+
context.type === "IfStatement") &&
|
|
1212
1282
|
!last.argument)) {
|
|
1213
1283
|
inlineDiagnostic(state, func, call, "There was a return statement, but not at the end of the function");
|
|
1214
1284
|
return null;
|
|
@@ -1235,14 +1305,15 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
1235
1305
|
}
|
|
1236
1306
|
if (last.argument) {
|
|
1237
1307
|
if (context.type === "AssignmentExpression") {
|
|
1238
|
-
context.right = last.argument;
|
|
1308
|
+
context.right = replaceInlinedSubExpression(context.right, call, last.argument);
|
|
1239
1309
|
block.body[block.body.length - 1] = {
|
|
1240
1310
|
type: "ExpressionStatement",
|
|
1241
1311
|
expression: context,
|
|
1242
1312
|
};
|
|
1243
1313
|
}
|
|
1244
1314
|
else if (context.type === "VariableDeclarator") {
|
|
1245
|
-
const { id, init
|
|
1315
|
+
const { id, init, kind: _kind, ...rest } = context;
|
|
1316
|
+
const right = replaceInlinedSubExpression(init, call, last.argument);
|
|
1246
1317
|
block.body[block.body.length - 1] = {
|
|
1247
1318
|
...rest,
|
|
1248
1319
|
type: "ExpressionStatement",
|
|
@@ -1251,9 +1322,52 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
1251
1322
|
type: "AssignmentExpression",
|
|
1252
1323
|
operator: "=",
|
|
1253
1324
|
left: id.type === "Identifier" ? id : id.left,
|
|
1325
|
+
right,
|
|
1326
|
+
},
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
else if (context.type === "IfStatement") {
|
|
1330
|
+
// Generate a pmcr_tmp name that doesn't conflict with anything
|
|
1331
|
+
const locals = state.localsStack[state.localsStack.length - 1];
|
|
1332
|
+
const name = renameVariable(state, locals, null);
|
|
1333
|
+
locals.map[name] = true;
|
|
1334
|
+
// Replace the inlined function's return statement
|
|
1335
|
+
// with an assignment to pmcr_tmp
|
|
1336
|
+
block.body[block.body.length - 1] = {
|
|
1337
|
+
type: "ExpressionStatement",
|
|
1338
|
+
expression: {
|
|
1339
|
+
type: "AssignmentExpression",
|
|
1340
|
+
operator: "=",
|
|
1341
|
+
left: { type: "Identifier", name },
|
|
1254
1342
|
right: last.argument,
|
|
1255
1343
|
},
|
|
1256
1344
|
};
|
|
1345
|
+
// The IfStatement either has the call as its test, or as
|
|
1346
|
+
// the leftmost argument to a series of Binary/Logical expressions
|
|
1347
|
+
// Either way, replace the call with pmcr_tmp
|
|
1348
|
+
const repl = { type: "Identifier", name };
|
|
1349
|
+
context.test = replaceInlinedSubExpression(context.test, call, repl);
|
|
1350
|
+
// Wrap the inlined body so it looks like
|
|
1351
|
+
// {
|
|
1352
|
+
// var pmcr_tmp;
|
|
1353
|
+
// { /* inlined body, with assignment to pmcr_tmp */ }
|
|
1354
|
+
// if (context) {} // original if statement
|
|
1355
|
+
// }
|
|
1356
|
+
body.body = [
|
|
1357
|
+
{
|
|
1358
|
+
type: "VariableDeclaration",
|
|
1359
|
+
kind: "var",
|
|
1360
|
+
declarations: [
|
|
1361
|
+
{
|
|
1362
|
+
type: "VariableDeclarator",
|
|
1363
|
+
kind: "var",
|
|
1364
|
+
id: { type: "Identifier", name },
|
|
1365
|
+
},
|
|
1366
|
+
],
|
|
1367
|
+
},
|
|
1368
|
+
{ type: "BlockStatement", body: body.body },
|
|
1369
|
+
context,
|
|
1370
|
+
];
|
|
1257
1371
|
}
|
|
1258
1372
|
else {
|
|
1259
1373
|
const side_exprs = inliner_unused(last.argument);
|
|
@@ -1427,7 +1541,7 @@ function pragma_checker_pragmaChecker(state, ast, diagnostics) {
|
|
|
1427
1541
|
if (quote == '"') {
|
|
1428
1542
|
return haystack.includes(needle);
|
|
1429
1543
|
}
|
|
1430
|
-
const re = new RegExp(needle.replace(/@(\d+)/g, "(pre_)?$1(_\\d+)?"));
|
|
1544
|
+
const re = new RegExp(needle.replace(/@([\d\w]+)/g, "(pre_)?$1(_\\d+)?"));
|
|
1431
1545
|
return re.test(haystack);
|
|
1432
1546
|
};
|
|
1433
1547
|
next();
|
|
@@ -4048,11 +4162,18 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
4048
4162
|
return false;
|
|
4049
4163
|
return replace(rep, rep);
|
|
4050
4164
|
}
|
|
4051
|
-
else if (node.type === "IfStatement"
|
|
4052
|
-
node.alternate &&
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4165
|
+
else if (node.type === "IfStatement") {
|
|
4166
|
+
if (node.alternate &&
|
|
4167
|
+
node.alternate.type === "BlockStatement" &&
|
|
4168
|
+
!node.alternate.body.length) {
|
|
4169
|
+
delete node.alternate;
|
|
4170
|
+
}
|
|
4171
|
+
else {
|
|
4172
|
+
const call = inlinableSubExpression(node.test);
|
|
4173
|
+
if (call) {
|
|
4174
|
+
return replace(optimizeCall(state, call, node), node.test);
|
|
4175
|
+
}
|
|
4176
|
+
}
|
|
4056
4177
|
}
|
|
4057
4178
|
break;
|
|
4058
4179
|
case "WhileStatement":
|
|
@@ -4095,8 +4216,11 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
4095
4216
|
let j = 0;
|
|
4096
4217
|
while (i < node.declarations.length) {
|
|
4097
4218
|
const decl = declarations[i++];
|
|
4098
|
-
if (decl.init
|
|
4099
|
-
|
|
4219
|
+
if (!decl.init)
|
|
4220
|
+
continue;
|
|
4221
|
+
const call = inlinableSubExpression(decl.init);
|
|
4222
|
+
if (call) {
|
|
4223
|
+
const inlined = replace(optimizeCall(state, call, decl), decl.init);
|
|
4100
4224
|
if (!inlined)
|
|
4101
4225
|
continue;
|
|
4102
4226
|
if (Array.isArray(inlined) || inlined.type != "BlockStatement") {
|
|
@@ -4131,7 +4255,8 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
4131
4255
|
return replace(optimizeCall(state, node.expression, node), node.expression);
|
|
4132
4256
|
}
|
|
4133
4257
|
else if (node.expression.type === "AssignmentExpression") {
|
|
4134
|
-
|
|
4258
|
+
const call = inlinableSubExpression(node.expression.right);
|
|
4259
|
+
if (call) {
|
|
4135
4260
|
let ok = false;
|
|
4136
4261
|
if (node.expression.left.type === "Identifier") {
|
|
4137
4262
|
if (hasProperty(topLocals().map, node.expression.left.type)) {
|
|
@@ -4143,7 +4268,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
4143
4268
|
ok = !!result;
|
|
4144
4269
|
}
|
|
4145
4270
|
if (ok) {
|
|
4146
|
-
return replace(optimizeCall(state,
|
|
4271
|
+
return replace(optimizeCall(state, call, node.expression), node.expression.right);
|
|
4147
4272
|
}
|
|
4148
4273
|
}
|
|
4149
4274
|
}
|
package/build/optimizer.cjs
CHANGED
|
@@ -10956,6 +10956,8 @@ async function get_jungle(jungles, options) {
|
|
|
10956
10956
|
return result;
|
|
10957
10957
|
}
|
|
10958
10958
|
|
|
10959
|
+
;// CONCATENATED MODULE: external "net"
|
|
10960
|
+
const external_net_namespaceObject = require("net");
|
|
10959
10961
|
;// CONCATENATED MODULE: external "child_process"
|
|
10960
10962
|
const external_child_process_namespaceObject = require("child_process");
|
|
10961
10963
|
;// CONCATENATED MODULE: ./src/launch.ts
|
|
@@ -10963,10 +10965,27 @@ const external_child_process_namespaceObject = require("child_process");
|
|
|
10963
10965
|
|
|
10964
10966
|
|
|
10965
10967
|
|
|
10968
|
+
|
|
10966
10969
|
function launchSimulator() {
|
|
10967
|
-
return (
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
+
return checkIfSimulatorRunning().then((running) => running
|
|
10971
|
+
? Promise.resolve()
|
|
10972
|
+
: (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => {
|
|
10973
|
+
const child = (0,external_child_process_namespaceObject.execFile)(external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "simulator" : "connectiq"));
|
|
10974
|
+
child.unref();
|
|
10975
|
+
}));
|
|
10976
|
+
}
|
|
10977
|
+
function checkIfSimulatorRunning() {
|
|
10978
|
+
return Promise.all([1234, 1235, 1236, 1237, 1238].map(checkIfSimulatorRunningOn)).then((results) => results.some((v) => v));
|
|
10979
|
+
}
|
|
10980
|
+
function checkIfSimulatorRunningOn(port) {
|
|
10981
|
+
return new Promise((resolve) => {
|
|
10982
|
+
let listening = false;
|
|
10983
|
+
const socket = new external_net_namespaceObject.Socket();
|
|
10984
|
+
socket.on("data", (data) => (listening = data.toString().includes("A garmin device")));
|
|
10985
|
+
socket.on("error", () => resolve(false));
|
|
10986
|
+
socket.on("end", () => resolve(listening));
|
|
10987
|
+
socket.connect(port, "localhost");
|
|
10988
|
+
socket.end();
|
|
10970
10989
|
});
|
|
10971
10990
|
}
|
|
10972
10991
|
function simulateProgram(prg, device, test = false, logger) {
|
|
@@ -11351,8 +11370,13 @@ function findCalleesForNew(lookupDefs) {
|
|
|
11351
11370
|
|
|
11352
11371
|
function renameVariable(state, locals, declName) {
|
|
11353
11372
|
const map = locals.map;
|
|
11354
|
-
if (
|
|
11355
|
-
|
|
11373
|
+
if (declName) {
|
|
11374
|
+
if (!(0,external_api_cjs_namespaceObject.hasProperty)(map, declName))
|
|
11375
|
+
return null;
|
|
11376
|
+
}
|
|
11377
|
+
else {
|
|
11378
|
+
declName = "tmp";
|
|
11379
|
+
}
|
|
11356
11380
|
let suffix = 0;
|
|
11357
11381
|
let node_name = declName;
|
|
11358
11382
|
const match = node_name.match(/^pmcr_(.*)_(\d+)$/);
|
|
@@ -11407,6 +11431,69 @@ function renameVariable(state, locals, declName) {
|
|
|
11407
11431
|
|
|
11408
11432
|
|
|
11409
11433
|
|
|
11434
|
+
// Note: Keep in sync with replaceInlinedSubExpression below
|
|
11435
|
+
function inlinableSubExpression(expr) {
|
|
11436
|
+
while (true) {
|
|
11437
|
+
if (expr.type === "BinaryExpression" || expr.type === "LogicalExpression") {
|
|
11438
|
+
expr = expr.left;
|
|
11439
|
+
}
|
|
11440
|
+
else if (expr.type === "UnaryExpression") {
|
|
11441
|
+
expr = expr.argument;
|
|
11442
|
+
}
|
|
11443
|
+
else if (expr.type === "ConditionalExpression") {
|
|
11444
|
+
expr = expr.test;
|
|
11445
|
+
}
|
|
11446
|
+
else if (expr.type === "MemberExpression") {
|
|
11447
|
+
expr = expr.object;
|
|
11448
|
+
}
|
|
11449
|
+
else if (expr.type === "CallExpression") {
|
|
11450
|
+
return expr;
|
|
11451
|
+
}
|
|
11452
|
+
else {
|
|
11453
|
+
return null;
|
|
11454
|
+
}
|
|
11455
|
+
}
|
|
11456
|
+
}
|
|
11457
|
+
// Note: Keep in sync with inlinableSubExpression above
|
|
11458
|
+
function replaceInlinedSubExpression(top, call, repl) {
|
|
11459
|
+
if (top === call)
|
|
11460
|
+
return repl;
|
|
11461
|
+
let expr = top;
|
|
11462
|
+
while (true) {
|
|
11463
|
+
if (expr.type === "LogicalExpression" || expr.type === "BinaryExpression") {
|
|
11464
|
+
if (expr.left === call) {
|
|
11465
|
+
expr.left = repl;
|
|
11466
|
+
break;
|
|
11467
|
+
}
|
|
11468
|
+
expr = expr.left;
|
|
11469
|
+
}
|
|
11470
|
+
else if (expr.type === "UnaryExpression") {
|
|
11471
|
+
if (expr.argument === call) {
|
|
11472
|
+
expr.argument = repl;
|
|
11473
|
+
break;
|
|
11474
|
+
}
|
|
11475
|
+
expr = expr.argument;
|
|
11476
|
+
}
|
|
11477
|
+
else if (expr.type === "ConditionalExpression") {
|
|
11478
|
+
if (expr.test === call) {
|
|
11479
|
+
expr.test = repl;
|
|
11480
|
+
break;
|
|
11481
|
+
}
|
|
11482
|
+
expr = expr.test;
|
|
11483
|
+
}
|
|
11484
|
+
else if (expr.type === "MemberExpression") {
|
|
11485
|
+
if (expr.object === call) {
|
|
11486
|
+
expr.object = repl;
|
|
11487
|
+
break;
|
|
11488
|
+
}
|
|
11489
|
+
expr = expr.object;
|
|
11490
|
+
}
|
|
11491
|
+
else {
|
|
11492
|
+
throw new Error("Internal error: Didn't find CallExpression");
|
|
11493
|
+
}
|
|
11494
|
+
}
|
|
11495
|
+
return top;
|
|
11496
|
+
}
|
|
11410
11497
|
function getArgSafety(state, func, args, requireAll) {
|
|
11411
11498
|
// determine whether decl might be changed by a function call
|
|
11412
11499
|
// or assignment during the evaluation of FunctionStateNode.
|
|
@@ -11634,7 +11721,7 @@ function shouldInline(state, func, call, context) {
|
|
|
11634
11721
|
}
|
|
11635
11722
|
}
|
|
11636
11723
|
if (!context && requested) {
|
|
11637
|
-
inlineDiagnostic(state, func, call, "This function can only be inlined in statement, assignment, or return contexts");
|
|
11724
|
+
inlineDiagnostic(state, func, call, "This function can only be inlined in statement, assignment, if or return contexts");
|
|
11638
11725
|
}
|
|
11639
11726
|
return context != null;
|
|
11640
11727
|
}
|
|
@@ -11894,7 +11981,8 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11894
11981
|
inlineDiagnostic(state, func, call, "Function had more than one return statement");
|
|
11895
11982
|
}
|
|
11896
11983
|
else if ((context.type === "AssignmentExpression" ||
|
|
11897
|
-
context.type === "VariableDeclarator"
|
|
11984
|
+
context.type === "VariableDeclarator" ||
|
|
11985
|
+
context.type === "IfStatement") &&
|
|
11898
11986
|
retStmtCount !== 1) {
|
|
11899
11987
|
inlineDiagnostic(state, func, call, "Function did not have a return statement");
|
|
11900
11988
|
return null;
|
|
@@ -11904,7 +11992,8 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11904
11992
|
if (!last ||
|
|
11905
11993
|
last.type !== "ReturnStatement" ||
|
|
11906
11994
|
((context.type === "AssignmentExpression" ||
|
|
11907
|
-
context.type === "VariableDeclarator"
|
|
11995
|
+
context.type === "VariableDeclarator" ||
|
|
11996
|
+
context.type === "IfStatement") &&
|
|
11908
11997
|
!last.argument)) {
|
|
11909
11998
|
inlineDiagnostic(state, func, call, "There was a return statement, but not at the end of the function");
|
|
11910
11999
|
return null;
|
|
@@ -11931,14 +12020,15 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11931
12020
|
}
|
|
11932
12021
|
if (last.argument) {
|
|
11933
12022
|
if (context.type === "AssignmentExpression") {
|
|
11934
|
-
context.right = last.argument;
|
|
12023
|
+
context.right = replaceInlinedSubExpression(context.right, call, last.argument);
|
|
11935
12024
|
block.body[block.body.length - 1] = {
|
|
11936
12025
|
type: "ExpressionStatement",
|
|
11937
12026
|
expression: context,
|
|
11938
12027
|
};
|
|
11939
12028
|
}
|
|
11940
12029
|
else if (context.type === "VariableDeclarator") {
|
|
11941
|
-
const { id, init
|
|
12030
|
+
const { id, init, kind: _kind, ...rest } = context;
|
|
12031
|
+
const right = replaceInlinedSubExpression(init, call, last.argument);
|
|
11942
12032
|
block.body[block.body.length - 1] = {
|
|
11943
12033
|
...rest,
|
|
11944
12034
|
type: "ExpressionStatement",
|
|
@@ -11947,9 +12037,52 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11947
12037
|
type: "AssignmentExpression",
|
|
11948
12038
|
operator: "=",
|
|
11949
12039
|
left: id.type === "Identifier" ? id : id.left,
|
|
12040
|
+
right,
|
|
12041
|
+
},
|
|
12042
|
+
};
|
|
12043
|
+
}
|
|
12044
|
+
else if (context.type === "IfStatement") {
|
|
12045
|
+
// Generate a pmcr_tmp name that doesn't conflict with anything
|
|
12046
|
+
const locals = state.localsStack[state.localsStack.length - 1];
|
|
12047
|
+
const name = renameVariable(state, locals, null);
|
|
12048
|
+
locals.map[name] = true;
|
|
12049
|
+
// Replace the inlined function's return statement
|
|
12050
|
+
// with an assignment to pmcr_tmp
|
|
12051
|
+
block.body[block.body.length - 1] = {
|
|
12052
|
+
type: "ExpressionStatement",
|
|
12053
|
+
expression: {
|
|
12054
|
+
type: "AssignmentExpression",
|
|
12055
|
+
operator: "=",
|
|
12056
|
+
left: { type: "Identifier", name },
|
|
11950
12057
|
right: last.argument,
|
|
11951
12058
|
},
|
|
11952
12059
|
};
|
|
12060
|
+
// The IfStatement either has the call as its test, or as
|
|
12061
|
+
// the leftmost argument to a series of Binary/Logical expressions
|
|
12062
|
+
// Either way, replace the call with pmcr_tmp
|
|
12063
|
+
const repl = { type: "Identifier", name };
|
|
12064
|
+
context.test = replaceInlinedSubExpression(context.test, call, repl);
|
|
12065
|
+
// Wrap the inlined body so it looks like
|
|
12066
|
+
// {
|
|
12067
|
+
// var pmcr_tmp;
|
|
12068
|
+
// { /* inlined body, with assignment to pmcr_tmp */ }
|
|
12069
|
+
// if (context) {} // original if statement
|
|
12070
|
+
// }
|
|
12071
|
+
body.body = [
|
|
12072
|
+
{
|
|
12073
|
+
type: "VariableDeclaration",
|
|
12074
|
+
kind: "var",
|
|
12075
|
+
declarations: [
|
|
12076
|
+
{
|
|
12077
|
+
type: "VariableDeclarator",
|
|
12078
|
+
kind: "var",
|
|
12079
|
+
id: { type: "Identifier", name },
|
|
12080
|
+
},
|
|
12081
|
+
],
|
|
12082
|
+
},
|
|
12083
|
+
{ type: "BlockStatement", body: body.body },
|
|
12084
|
+
context,
|
|
12085
|
+
];
|
|
11953
12086
|
}
|
|
11954
12087
|
else {
|
|
11955
12088
|
const side_exprs = unused(last.argument);
|
|
@@ -12123,7 +12256,7 @@ function pragmaChecker(state, ast, diagnostics) {
|
|
|
12123
12256
|
if (quote == '"') {
|
|
12124
12257
|
return haystack.includes(needle);
|
|
12125
12258
|
}
|
|
12126
|
-
const re = new RegExp(needle.replace(/@(\d+)/g, "(pre_)?$1(_\\d+)?"));
|
|
12259
|
+
const re = new RegExp(needle.replace(/@([\d\w]+)/g, "(pre_)?$1(_\\d+)?"));
|
|
12127
12260
|
return re.test(haystack);
|
|
12128
12261
|
};
|
|
12129
12262
|
next();
|
|
@@ -14741,11 +14874,18 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
14741
14874
|
return false;
|
|
14742
14875
|
return replace(rep, rep);
|
|
14743
14876
|
}
|
|
14744
|
-
else if (node.type === "IfStatement"
|
|
14745
|
-
node.alternate &&
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14877
|
+
else if (node.type === "IfStatement") {
|
|
14878
|
+
if (node.alternate &&
|
|
14879
|
+
node.alternate.type === "BlockStatement" &&
|
|
14880
|
+
!node.alternate.body.length) {
|
|
14881
|
+
delete node.alternate;
|
|
14882
|
+
}
|
|
14883
|
+
else {
|
|
14884
|
+
const call = inlinableSubExpression(node.test);
|
|
14885
|
+
if (call) {
|
|
14886
|
+
return replace(optimizeCall(state, call, node), node.test);
|
|
14887
|
+
}
|
|
14888
|
+
}
|
|
14749
14889
|
}
|
|
14750
14890
|
break;
|
|
14751
14891
|
case "WhileStatement":
|
|
@@ -14788,8 +14928,11 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
14788
14928
|
let j = 0;
|
|
14789
14929
|
while (i < node.declarations.length) {
|
|
14790
14930
|
const decl = declarations[i++];
|
|
14791
|
-
if (decl.init
|
|
14792
|
-
|
|
14931
|
+
if (!decl.init)
|
|
14932
|
+
continue;
|
|
14933
|
+
const call = inlinableSubExpression(decl.init);
|
|
14934
|
+
if (call) {
|
|
14935
|
+
const inlined = replace(optimizeCall(state, call, decl), decl.init);
|
|
14793
14936
|
if (!inlined)
|
|
14794
14937
|
continue;
|
|
14795
14938
|
if (Array.isArray(inlined) || inlined.type != "BlockStatement") {
|
|
@@ -14824,7 +14967,8 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
14824
14967
|
return replace(optimizeCall(state, node.expression, node), node.expression);
|
|
14825
14968
|
}
|
|
14826
14969
|
else if (node.expression.type === "AssignmentExpression") {
|
|
14827
|
-
|
|
14970
|
+
const call = inlinableSubExpression(node.expression.right);
|
|
14971
|
+
if (call) {
|
|
14828
14972
|
let ok = false;
|
|
14829
14973
|
if (node.expression.left.type === "Identifier") {
|
|
14830
14974
|
if ((0,external_api_cjs_namespaceObject.hasProperty)(topLocals().map, node.expression.left.type)) {
|
|
@@ -14836,7 +14980,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
14836
14980
|
ok = !!result;
|
|
14837
14981
|
}
|
|
14838
14982
|
if (ok) {
|
|
14839
|
-
return replace(optimizeCall(state,
|
|
14983
|
+
return replace(optimizeCall(state, call, node.expression), node.expression.right);
|
|
14840
14984
|
}
|
|
14841
14985
|
}
|
|
14842
14986
|
}
|
|
@@ -15438,6 +15582,7 @@ const configOptionsToCheck = [
|
|
|
15438
15582
|
"ignoredSourcePaths",
|
|
15439
15583
|
"checkInvalidSymbols",
|
|
15440
15584
|
"sizeBasedPRE",
|
|
15585
|
+
"extensionVersion",
|
|
15441
15586
|
];
|
|
15442
15587
|
/**
|
|
15443
15588
|
* @param {BuildConfig} config
|
|
@@ -15489,7 +15634,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
15489
15634
|
// the oldest optimized file, we don't need to regenerate
|
|
15490
15635
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
15491
15636
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
15492
|
-
if (source_time < opt_time &&
|
|
15637
|
+
if (source_time < opt_time && 1666827670006 < opt_time) {
|
|
15493
15638
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
15494
15639
|
}
|
|
15495
15640
|
}
|
|
@@ -15514,6 +15659,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
15514
15659
|
return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
|
|
15515
15660
|
hasTests,
|
|
15516
15661
|
diagnostics,
|
|
15662
|
+
optimizerVersion: "1.0.38",
|
|
15517
15663
|
...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
|
|
15518
15664
|
}))
|
|
15519
15665
|
.then(() => ({ hasTests, diagnostics }));
|
package/build/src/inliner.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { mctree } from "@markw65/prettier-plugin-monkeyc";
|
|
2
2
|
import { FunctionStateNode, ProgramStateAnalysis, ProgramStateLive } from "./optimizer-types";
|
|
3
|
+
export declare function inlinableSubExpression(expr: mctree.Expression): mctree.SimpleCallExpression | null;
|
|
3
4
|
export declare function shouldInline(state: ProgramStateAnalysis, func: FunctionStateNode, call: mctree.CallExpression, context: InlineContext | null): boolean;
|
|
4
5
|
declare type InlineBody = mctree.BlockStatement | mctree.ExpressionStatement["expression"];
|
|
5
6
|
export declare function unused(expression: mctree.ExpressionStatement["expression"]): mctree.Statement[];
|
|
6
7
|
export declare function unused(expression: mctree.ExpressionStatement["expression"], top: true): mctree.Statement[] | null;
|
|
7
8
|
export declare function diagnostic(state: ProgramStateLive, loc: mctree.Node["loc"], message: string | null, type?: NonNullable<ProgramStateAnalysis["diagnostics"]>[string][number]["type"]): void;
|
|
8
|
-
export declare type InlineContext = mctree.ReturnStatement | mctree.AssignmentExpression | mctree.ExpressionStatement | mctree.VariableDeclarator;
|
|
9
|
+
export declare type InlineContext = mctree.ReturnStatement | mctree.IfStatement | mctree.AssignmentExpression | mctree.ExpressionStatement | mctree.VariableDeclarator;
|
|
9
10
|
export declare function inlineFunction(state: ProgramStateAnalysis, func: FunctionStateNode, call: mctree.CallExpression, context: InlineContext | null): InlineBody | null;
|
|
10
11
|
export declare function applyTypeIfNeeded(node: mctree.Node): mctree.Node;
|
|
11
12
|
export {};
|
package/build/src/launch.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { LineHandler } from "./util";
|
|
2
2
|
export declare function launchSimulator(): Promise<void>;
|
|
3
|
+
export declare function checkIfSimulatorRunning(): Promise<boolean>;
|
|
4
|
+
export declare function checkIfSimulatorRunningOn(port: number): Promise<boolean>;
|
|
3
5
|
export declare function simulateProgram(prg: string, device: string, test?: boolean, logger?: LineHandler | LineHandler[]): Promise<void>;
|
|
@@ -26,6 +26,7 @@ export declare type BuildConfig = {
|
|
|
26
26
|
checkInvalidSymbols?: DiagnosticType | "OFF";
|
|
27
27
|
sizeBasedPRE?: boolean | string;
|
|
28
28
|
prettier?: Record<string, unknown>;
|
|
29
|
+
extensionVersion?: string;
|
|
29
30
|
_cache?: {
|
|
30
31
|
barrels?: Record<string, ResolvedJungle>;
|
|
31
32
|
barrelMap?: Record<string, Record<string, ResolvedJungle>>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ProgramStateAnalysis } from "./optimizer-types";
|
|
2
|
-
export declare function renameVariable(state: ProgramStateAnalysis, locals: NonNullable<ProgramStateAnalysis["localsStack"]>[number], declName: string): string | null;
|
|
2
|
+
export declare function renameVariable(state: ProgramStateAnalysis, locals: NonNullable<ProgramStateAnalysis["localsStack"]>[number], declName: string | null): string | null;
|
package/package.json
CHANGED