@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 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.34](https://github.com/markw65/prettier-plugin-monkeyc#1034).
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 (!hasProperty(map, declName))
659
- return null;
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: _init, kind: _kind, ...rest } = context;
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
- node.alternate.type === "BlockStatement" &&
4054
- !node.alternate.body.length) {
4055
- delete node.alternate;
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 && decl.init.type === "CallExpression") {
4099
- const inlined = replace(optimizeCall(state, decl.init, decl), decl.init);
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
- if (node.expression.right.type === "CallExpression") {
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, node.expression.right, node.expression), node.expression.right);
4271
+ return replace(optimizeCall(state, call, node.expression), node.expression.right);
4147
4272
  }
4148
4273
  }
4149
4274
  }
@@ -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 (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => {
10968
- const child = (0,external_child_process_namespaceObject.execFile)(external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "simulator" : "connectiq"));
10969
- child.unref();
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 (!(0,external_api_cjs_namespaceObject.hasProperty)(map, declName))
11355
- return null;
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: _init, kind: _kind, ...rest } = context;
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
- node.alternate.type === "BlockStatement" &&
14747
- !node.alternate.body.length) {
14748
- delete node.alternate;
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 && decl.init.type === "CallExpression") {
14792
- const inlined = replace(optimizeCall(state, decl.init, decl), decl.init);
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
- if (node.expression.right.type === "CallExpression") {
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, node.expression.right, node.expression), node.expression.right);
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 && 1662763619992 < 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 }));
@@ -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 {};
@@ -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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@markw65/monkeyc-optimizer",
3
3
  "type": "module",
4
- "version": "1.0.36",
4
+ "version": "1.0.38",
5
5
  "description": "Source to source optimizer for Garmin Monkey C code",
6
6
  "main": "build/optimizer.cjs",
7
7
  "types": "build/src/optimizer.d.ts",