@markw65/monkeyc-optimizer 1.0.25 → 1.0.28

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
@@ -285,3 +285,21 @@ More fixes found via open source projects.
285
285
 
286
286
  - Bug fix
287
287
  - estree-types was missing the returnType on FunctionDeclaration. Update to latest prettier-plugin, and fix ast.ts.
288
+
289
+ ### 1.0.26
290
+
291
+ - Bug fixes
292
+ - Use `self.` rather than `ClassName.` to qualify names that would otherwise collide with locals, since that works with both public and private variables
293
+ - Fix a bug that caused the inliner to fail to qualify certain names, even if there was a collision with an existing local variables
294
+ - Fix some name lookup issues relating to whether the lookup is done as a type or a value.
295
+
296
+ ### 1.0.27
297
+
298
+ - Bug fixes
299
+ - Update to `@markw65/prettier-plugin-monkeyc@1.0.29` to fix certain obscure comment related bugs
300
+ - When replacing a node (espcially when inlining), delete any comments contained in the old node.
301
+
302
+ ### 1.0.28
303
+
304
+ - Bug fixes
305
+ - In some circumstances, while inlining, a parameter could be substituted, and then reprocessed. During reprocessing, it would attempt to lookup the replacement symbol, and if that was a local from the calling function it would fail (since an inline function never has access to the caller's locals). Prevent the reprocessing step from happening.
package/build/api.cjs CHANGED
@@ -441,11 +441,29 @@ function inliner_shouldInline(state, func, call, context) {
441
441
  }
442
442
  return false;
443
443
  }
444
- function processInlineBody(state, func, call, root, insertedVariableDecls, params) {
444
+ // We still need to keep track of every local name that was
445
+ // already in use before we started inlining, but we don't want to
446
+ // use any of its renames. We also want to know whether a local is
447
+ // from the function being inlined, or the calling function, so
448
+ // set every element to false.
449
+ function fixupLocalsMap(state) {
450
+ if (!state.localsStack)
451
+ throw new Error("No local variable map!");
452
+ const locals = state.localsStack[state.localsStack.length - 1];
453
+ const { map } = locals;
454
+ if (!map)
455
+ throw new Error("No local variable map!");
456
+ const original = { ...map };
457
+ Object.keys(map).forEach((key) => (map[key] = false));
458
+ return original;
459
+ }
460
+ function processInlineBody(state, func, call, root, params) {
445
461
  let failed = false;
446
462
  const pre = state.pre;
447
463
  const post = state.post;
448
464
  state.inlining = true;
465
+ let insertedVariableDecls = null;
466
+ const replacements = new Set();
449
467
  try {
450
468
  state.pre = (node) => {
451
469
  if (failed)
@@ -453,19 +471,14 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
453
471
  node.start = call.start;
454
472
  node.end = call.end;
455
473
  node.loc = call.loc;
456
- if (node === insertedVariableDecls)
474
+ if (replacements.has(node))
457
475
  return false;
458
476
  const result = pre(node, state);
459
477
  if (!insertedVariableDecls && node.type === "BlockStatement") {
478
+ // the block just created a new locals map, so we don't
479
+ // need to restore it at the end.
480
+ fixupLocalsMap(state);
460
481
  const locals = state.localsStack[state.localsStack.length - 1];
461
- const { map } = locals;
462
- if (!map)
463
- throw new Error("No local variable map!");
464
- // We still need to keep track of every local name that was
465
- // already in use, but we don't want to use any of its renames.
466
- // We also want to know whether a local is from the function being
467
- // inlined, or the calling function, so set every element to false.
468
- Object.keys(map).forEach((key) => (map[key] = false));
469
482
  const declarations = func.node.params
470
483
  .map((param, i) => {
471
484
  const paramName = variableDeclarationName(param);
@@ -486,6 +499,7 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
486
499
  kind: "var",
487
500
  };
488
501
  node.body.unshift(insertedVariableDecls);
502
+ replacements.add(insertedVariableDecls);
489
503
  }
490
504
  return result;
491
505
  };
@@ -501,6 +515,8 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
501
515
  const ix = params[node.name];
502
516
  if (ix >= 0) {
503
517
  replacement = call.arguments[ix];
518
+ replacements.add(replacement);
519
+ return replacement;
504
520
  }
505
521
  break;
506
522
  }
@@ -542,6 +558,8 @@ function inliner_unused(expression, top) {
542
558
  return [];
543
559
  case "Identifier":
544
560
  return [];
561
+ case "ThisExpression":
562
+ return [];
545
563
  case "BinaryExpression":
546
564
  if (expression.operator === "as") {
547
565
  return inliner_unused(expression.left);
@@ -644,7 +662,7 @@ function inlineWithArgs(state, func, call, context) {
644
662
  const name = variableDeclarationName(param);
645
663
  return [name, argnum];
646
664
  }));
647
- if (!processInlineBody(state, func, call, body, func.node.params.length ? false : true, params)) {
665
+ if (!processInlineBody(state, func, call, body, params)) {
648
666
  return null;
649
667
  }
650
668
  inliner_diagnostic(state, call.loc, null);
@@ -676,7 +694,10 @@ function inliner_inlineFunction(state, func, call, context) {
676
694
  }
677
695
  const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
678
696
  const params = Object.fromEntries(func.node.params.map((param, i) => [variableDeclarationName(param), i]));
679
- return processInlineBody(state, func, call, retArg, true, params);
697
+ const map = fixupLocalsMap(state);
698
+ const ret = processInlineBody(state, func, call, retArg, params);
699
+ state.localsStack[state.localsStack.length - 1].map = map;
700
+ return ret;
680
701
  }
681
702
  function applyTypeIfNeeded(node) {
682
703
  if ("enumType" in node && node.enumType) {
@@ -729,6 +750,15 @@ function fixNodeScope(state, lookupNode, nodeStack) {
729
750
  return "";
730
751
  }))
731
752
  .flat();
753
+ const member = (object, property) => ({
754
+ type: "MemberExpression",
755
+ object,
756
+ property,
757
+ computed: false,
758
+ start: node.start,
759
+ end: node.end,
760
+ loc: node.loc,
761
+ });
732
762
  if (prefixes.length &&
733
763
  prefixes[0].startsWith("$.") &&
734
764
  prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
@@ -742,38 +772,32 @@ function fixNodeScope(state, lookupNode, nodeStack) {
742
772
  found = true;
743
773
  return current;
744
774
  }
745
- const object = typeof name === "string"
746
- ? {
747
- type: "Identifier",
748
- name,
749
- start: node.start,
750
- end: node.end,
751
- loc: node.loc,
752
- }
753
- : name;
754
- let root = null;
755
- let property = current;
756
- while (property.type !== "Identifier") {
757
- root = property;
758
- property = property.object;
759
- }
760
- const mb = {
761
- type: "MemberExpression",
762
- object,
763
- property,
764
- computed: false,
775
+ const object = {
776
+ type: "Identifier",
777
+ name,
765
778
  start: node.start,
766
779
  end: node.end,
767
780
  loc: node.loc,
768
781
  };
769
- if (root) {
770
- root.object = mb;
771
- }
772
- else {
773
- current = mb;
782
+ let root = null;
783
+ let property = current;
784
+ do {
785
+ root = property;
786
+ property = property.object;
787
+ } while (property.type === "MemberExpression");
788
+ if (property.type === "ThisExpression") {
789
+ root.object = object;
790
+ return root;
774
791
  }
792
+ root.object = member(object, property);
775
793
  return current;
776
- }, node);
794
+ }, member({
795
+ type: "ThisExpression",
796
+ text: "self",
797
+ start: node.start,
798
+ end: node.end,
799
+ loc: node.loc,
800
+ }, node));
777
801
  }
778
802
  return null;
779
803
  }
@@ -2213,6 +2237,7 @@ function api_collectNamespaces(ast, stateIn) {
2213
2237
  state.stack[0].node = node;
2214
2238
  break;
2215
2239
  case "TypeSpecList":
2240
+ case "TypeSpecPart":
2216
2241
  state.inType = true;
2217
2242
  break;
2218
2243
  case "ImportModule":
@@ -2454,6 +2479,11 @@ function api_collectNamespaces(ast, stateIn) {
2454
2479
  if (state.post)
2455
2480
  ret = state.post(node, state);
2456
2481
  switch (type) {
2482
+ // Don't clear inType for TypeSpecPart, since they
2483
+ // generally occur in TypeSpecLists. But do clear it for
2484
+ // SizedArrayExpression, since thats the only place they
2485
+ // happen on their own.
2486
+ case "SizedArrayExpression":
2457
2487
  case "TypeSpecList":
2458
2488
  case "TypedefDeclaration":
2459
2489
  case "EnumDeclaration":
@@ -2473,7 +2503,7 @@ function api_collectNamespaces(ast, stateIn) {
2473
2503
  }
2474
2504
  }
2475
2505
  }
2476
- if (ret === false) {
2506
+ if (ret != null) {
2477
2507
  state.removeNodeComments(node, ast);
2478
2508
  }
2479
2509
  return ret;
@@ -11165,11 +11165,29 @@ function shouldInline(state, func, call, context) {
11165
11165
  }
11166
11166
  return false;
11167
11167
  }
11168
- function processInlineBody(state, func, call, root, insertedVariableDecls, params) {
11168
+ // We still need to keep track of every local name that was
11169
+ // already in use before we started inlining, but we don't want to
11170
+ // use any of its renames. We also want to know whether a local is
11171
+ // from the function being inlined, or the calling function, so
11172
+ // set every element to false.
11173
+ function fixupLocalsMap(state) {
11174
+ if (!state.localsStack)
11175
+ throw new Error("No local variable map!");
11176
+ const locals = state.localsStack[state.localsStack.length - 1];
11177
+ const { map } = locals;
11178
+ if (!map)
11179
+ throw new Error("No local variable map!");
11180
+ const original = { ...map };
11181
+ Object.keys(map).forEach((key) => (map[key] = false));
11182
+ return original;
11183
+ }
11184
+ function processInlineBody(state, func, call, root, params) {
11169
11185
  let failed = false;
11170
11186
  const pre = state.pre;
11171
11187
  const post = state.post;
11172
11188
  state.inlining = true;
11189
+ let insertedVariableDecls = null;
11190
+ const replacements = new Set();
11173
11191
  try {
11174
11192
  state.pre = (node) => {
11175
11193
  if (failed)
@@ -11177,19 +11195,14 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
11177
11195
  node.start = call.start;
11178
11196
  node.end = call.end;
11179
11197
  node.loc = call.loc;
11180
- if (node === insertedVariableDecls)
11198
+ if (replacements.has(node))
11181
11199
  return false;
11182
11200
  const result = pre(node, state);
11183
11201
  if (!insertedVariableDecls && node.type === "BlockStatement") {
11202
+ // the block just created a new locals map, so we don't
11203
+ // need to restore it at the end.
11204
+ fixupLocalsMap(state);
11184
11205
  const locals = state.localsStack[state.localsStack.length - 1];
11185
- const { map } = locals;
11186
- if (!map)
11187
- throw new Error("No local variable map!");
11188
- // We still need to keep track of every local name that was
11189
- // already in use, but we don't want to use any of its renames.
11190
- // We also want to know whether a local is from the function being
11191
- // inlined, or the calling function, so set every element to false.
11192
- Object.keys(map).forEach((key) => (map[key] = false));
11193
11206
  const declarations = func.node.params
11194
11207
  .map((param, i) => {
11195
11208
  const paramName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
@@ -11210,6 +11223,7 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
11210
11223
  kind: "var",
11211
11224
  };
11212
11225
  node.body.unshift(insertedVariableDecls);
11226
+ replacements.add(insertedVariableDecls);
11213
11227
  }
11214
11228
  return result;
11215
11229
  };
@@ -11225,6 +11239,8 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
11225
11239
  const ix = params[node.name];
11226
11240
  if (ix >= 0) {
11227
11241
  replacement = call.arguments[ix];
11242
+ replacements.add(replacement);
11243
+ return replacement;
11228
11244
  }
11229
11245
  break;
11230
11246
  }
@@ -11266,6 +11282,8 @@ function unused(expression, top) {
11266
11282
  return [];
11267
11283
  case "Identifier":
11268
11284
  return [];
11285
+ case "ThisExpression":
11286
+ return [];
11269
11287
  case "BinaryExpression":
11270
11288
  if (expression.operator === "as") {
11271
11289
  return unused(expression.left);
@@ -11368,7 +11386,7 @@ function inlineWithArgs(state, func, call, context) {
11368
11386
  const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
11369
11387
  return [name, argnum];
11370
11388
  }));
11371
- if (!processInlineBody(state, func, call, body, func.node.params.length ? false : true, params)) {
11389
+ if (!processInlineBody(state, func, call, body, params)) {
11372
11390
  return null;
11373
11391
  }
11374
11392
  diagnostic(state, call.loc, null);
@@ -11400,7 +11418,10 @@ function inlineFunction(state, func, call, context) {
11400
11418
  }
11401
11419
  const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
11402
11420
  const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
11403
- return processInlineBody(state, func, call, retArg, true, params);
11421
+ const map = fixupLocalsMap(state);
11422
+ const ret = processInlineBody(state, func, call, retArg, params);
11423
+ state.localsStack[state.localsStack.length - 1].map = map;
11424
+ return ret;
11404
11425
  }
11405
11426
  function applyTypeIfNeeded(node) {
11406
11427
  if ("enumType" in node && node.enumType) {
@@ -11453,6 +11474,15 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11453
11474
  return "";
11454
11475
  }))
11455
11476
  .flat();
11477
+ const member = (object, property) => ({
11478
+ type: "MemberExpression",
11479
+ object,
11480
+ property,
11481
+ computed: false,
11482
+ start: node.start,
11483
+ end: node.end,
11484
+ loc: node.loc,
11485
+ });
11456
11486
  if (prefixes.length &&
11457
11487
  prefixes[0].startsWith("$.") &&
11458
11488
  prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
@@ -11466,38 +11496,32 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11466
11496
  found = true;
11467
11497
  return current;
11468
11498
  }
11469
- const object = typeof name === "string"
11470
- ? {
11471
- type: "Identifier",
11472
- name,
11473
- start: node.start,
11474
- end: node.end,
11475
- loc: node.loc,
11476
- }
11477
- : name;
11478
- let root = null;
11479
- let property = current;
11480
- while (property.type !== "Identifier") {
11481
- root = property;
11482
- property = property.object;
11483
- }
11484
- const mb = {
11485
- type: "MemberExpression",
11486
- object,
11487
- property,
11488
- computed: false,
11499
+ const object = {
11500
+ type: "Identifier",
11501
+ name,
11489
11502
  start: node.start,
11490
11503
  end: node.end,
11491
11504
  loc: node.loc,
11492
11505
  };
11493
- if (root) {
11494
- root.object = mb;
11495
- }
11496
- else {
11497
- current = mb;
11506
+ let root = null;
11507
+ let property = current;
11508
+ do {
11509
+ root = property;
11510
+ property = property.object;
11511
+ } while (property.type === "MemberExpression");
11512
+ if (property.type === "ThisExpression") {
11513
+ root.object = object;
11514
+ return root;
11498
11515
  }
11516
+ root.object = member(object, property);
11499
11517
  return current;
11500
- }, node);
11518
+ }, member({
11519
+ type: "ThisExpression",
11520
+ text: "self",
11521
+ start: node.start,
11522
+ end: node.end,
11523
+ loc: node.loc,
11524
+ }, node));
11501
11525
  }
11502
11526
  return null;
11503
11527
  }
@@ -13085,7 +13109,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
13085
13109
  // the oldest optimized file, we don't need to regenerate
13086
13110
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
13087
13111
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
13088
- if (source_time < opt_time && 1655681973607 < opt_time) {
13112
+ if (source_time < opt_time && 1655916886685 < opt_time) {
13089
13113
  return { hasTests, diagnostics: prevDiagnostics };
13090
13114
  }
13091
13115
  }
@@ -0,0 +1 @@
1
+ export declare function sizeBasedPRE(state: ProgramStateAnalysis, func: FunctionStateNode): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@markw65/monkeyc-optimizer",
3
3
  "type": "module",
4
- "version": "1.0.25",
4
+ "version": "1.0.28",
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",
@@ -37,7 +37,7 @@
37
37
  "author": "markw65",
38
38
  "license": "MIT",
39
39
  "dependencies": {
40
- "@markw65/prettier-plugin-monkeyc": "^1.0.28"
40
+ "@markw65/prettier-plugin-monkeyc": "^1.0.29"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/glob": "^7.2.0",