@markw65/monkeyc-optimizer 1.0.26 → 1.0.29

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/build/api.cjs CHANGED
@@ -1,8 +1,211 @@
1
1
  0 && (module.exports = {collectNamespaces,findUsingForNode,formatAst,getApiMapping,hasProperty,isStateNode,sameLookupResult,traverseAst,variableDeclarationName,visitReferences});
2
2
  /******/ (() => { // webpackBootstrap
3
- /******/ "use strict";
4
- /******/ // The require scope
5
- /******/ var __webpack_require__ = {};
3
+ /******/ var __webpack_modules__ = ({
4
+
5
+ /***/ 2789:
6
+ /***/ ((module) => {
7
+
8
+ /**
9
+ * Expose `PriorityQueue`.
10
+ */
11
+ module.exports = PriorityQueue;
12
+
13
+ /**
14
+ * Initializes a new empty `PriorityQueue` with the given `comparator(a, b)`
15
+ * function, uses `.DEFAULT_COMPARATOR()` when no function is provided.
16
+ *
17
+ * The comparator function must return a positive number when `a > b`, 0 when
18
+ * `a == b` and a negative number when `a < b`.
19
+ *
20
+ * @param {Function}
21
+ * @return {PriorityQueue}
22
+ * @api public
23
+ */
24
+ function PriorityQueue(comparator) {
25
+ this._comparator = comparator || PriorityQueue.DEFAULT_COMPARATOR;
26
+ this._elements = [];
27
+ }
28
+
29
+ /**
30
+ * Compares `a` and `b`, when `a > b` it returns a positive number, when
31
+ * it returns 0 and when `a < b` it returns a negative number.
32
+ *
33
+ * @param {String|Number} a
34
+ * @param {String|Number} b
35
+ * @return {Number}
36
+ * @api public
37
+ */
38
+ PriorityQueue.DEFAULT_COMPARATOR = function(a, b) {
39
+ if (typeof a === 'number' && typeof b === 'number') {
40
+ return a - b;
41
+ } else {
42
+ a = a.toString();
43
+ b = b.toString();
44
+
45
+ if (a == b) return 0;
46
+
47
+ return (a > b) ? 1 : -1;
48
+ }
49
+ };
50
+
51
+ /**
52
+ * Returns whether the priority queue is empty or not.
53
+ *
54
+ * @return {Boolean}
55
+ * @api public
56
+ */
57
+ PriorityQueue.prototype.isEmpty = function() {
58
+ return this.size() === 0;
59
+ };
60
+
61
+ /**
62
+ * Peeks at the top element of the priority queue.
63
+ *
64
+ * @return {Object}
65
+ * @throws {Error} when the queue is empty.
66
+ * @api public
67
+ */
68
+ PriorityQueue.prototype.peek = function() {
69
+ if (this.isEmpty()) throw new Error('PriorityQueue is empty');
70
+
71
+ return this._elements[0];
72
+ };
73
+
74
+ /**
75
+ * Dequeues the top element of the priority queue.
76
+ *
77
+ * @return {Object}
78
+ * @throws {Error} when the queue is empty.
79
+ * @api public
80
+ */
81
+ PriorityQueue.prototype.deq = function() {
82
+ var first = this.peek();
83
+ var last = this._elements.pop();
84
+ var size = this.size();
85
+
86
+ if (size === 0) return first;
87
+
88
+ this._elements[0] = last;
89
+ var current = 0;
90
+
91
+ while (current < size) {
92
+ var largest = current;
93
+ var left = (2 * current) + 1;
94
+ var right = (2 * current) + 2;
95
+
96
+ if (left < size && this._compare(left, largest) >= 0) {
97
+ largest = left;
98
+ }
99
+
100
+ if (right < size && this._compare(right, largest) >= 0) {
101
+ largest = right;
102
+ }
103
+
104
+ if (largest === current) break;
105
+
106
+ this._swap(largest, current);
107
+ current = largest;
108
+ }
109
+
110
+ return first;
111
+ };
112
+
113
+ /**
114
+ * Enqueues the `element` at the priority queue and returns its new size.
115
+ *
116
+ * @param {Object} element
117
+ * @return {Number}
118
+ * @api public
119
+ */
120
+ PriorityQueue.prototype.enq = function(element) {
121
+ var size = this._elements.push(element);
122
+ var current = size - 1;
123
+
124
+ while (current > 0) {
125
+ var parent = Math.floor((current - 1) / 2);
126
+
127
+ if (this._compare(current, parent) <= 0) break;
128
+
129
+ this._swap(parent, current);
130
+ current = parent;
131
+ }
132
+
133
+ return size;
134
+ };
135
+
136
+ /**
137
+ * Returns the size of the priority queue.
138
+ *
139
+ * @return {Number}
140
+ * @api public
141
+ */
142
+ PriorityQueue.prototype.size = function() {
143
+ return this._elements.length;
144
+ };
145
+
146
+ /**
147
+ * Iterates over queue elements
148
+ *
149
+ * @param {Function} fn
150
+ */
151
+ PriorityQueue.prototype.forEach = function(fn) {
152
+ return this._elements.forEach(fn);
153
+ };
154
+
155
+ /**
156
+ * Compares the values at position `a` and `b` in the priority queue using its
157
+ * comparator function.
158
+ *
159
+ * @param {Number} a
160
+ * @param {Number} b
161
+ * @return {Number}
162
+ * @api private
163
+ */
164
+ PriorityQueue.prototype._compare = function(a, b) {
165
+ return this._comparator(this._elements[a], this._elements[b]);
166
+ };
167
+
168
+ /**
169
+ * Swaps the values at position `a` and `b` in the priority queue.
170
+ *
171
+ * @param {Number} a
172
+ * @param {Number} b
173
+ * @api private
174
+ */
175
+ PriorityQueue.prototype._swap = function(a, b) {
176
+ var aux = this._elements[a];
177
+ this._elements[a] = this._elements[b];
178
+ this._elements[b] = aux;
179
+ };
180
+
181
+
182
+ /***/ })
183
+
184
+ /******/ });
185
+ /************************************************************************/
186
+ /******/ // The module cache
187
+ /******/ var __webpack_module_cache__ = {};
188
+ /******/
189
+ /******/ // The require function
190
+ /******/ function __webpack_require__(moduleId) {
191
+ /******/ // Check if module is in cache
192
+ /******/ var cachedModule = __webpack_module_cache__[moduleId];
193
+ /******/ if (cachedModule !== undefined) {
194
+ /******/ return cachedModule.exports;
195
+ /******/ }
196
+ /******/ // Create a new module (and put it into the cache)
197
+ /******/ var module = __webpack_module_cache__[moduleId] = {
198
+ /******/ // no module.id needed
199
+ /******/ // no module.loaded needed
200
+ /******/ exports: {}
201
+ /******/ };
202
+ /******/
203
+ /******/ // Execute the module function
204
+ /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
205
+ /******/
206
+ /******/ // Return the exports of the module
207
+ /******/ return module.exports;
208
+ /******/ }
6
209
  /******/
7
210
  /************************************************************************/
8
211
  /******/ /* webpack/runtime/compat get default export */
@@ -47,6 +250,9 @@
47
250
  /******/
48
251
  /************************************************************************/
49
252
  var __webpack_exports__ = {};
253
+ // This entry need to be wrapped in an IIFE because it need to be in strict mode.
254
+ (() => {
255
+ "use strict";
50
256
  // ESM COMPAT FLAG
51
257
  __webpack_require__.r(__webpack_exports__);
52
258
 
@@ -56,7 +262,7 @@ __webpack_require__.d(__webpack_exports__, {
56
262
  "findUsingForNode": () => (/* binding */ findUsingForNode),
57
263
  "formatAst": () => (/* binding */ api_formatAst),
58
264
  "getApiMapping": () => (/* binding */ api_getApiMapping),
59
- "hasProperty": () => (/* binding */ api_hasProperty),
265
+ "hasProperty": () => (/* reexport */ ast_hasProperty),
60
266
  "isStateNode": () => (/* binding */ api_isStateNode),
61
267
  "sameLookupResult": () => (/* binding */ api_sameLookupResult),
62
268
  "traverseAst": () => (/* reexport */ ast_traverseAst),
@@ -86,62 +292,68 @@ function _check(x) {
86
292
  x = y;
87
293
  }
88
294
  const mctreeTypeInfo = {
89
- ArrayExpression: ["elements"],
90
- AssignmentExpression: ["left", "right"],
91
- AttributeList: ["attributes"],
92
- Attributes: ["elements"],
93
- BinaryExpression: ["left", "right"],
94
- Block: [],
95
- BlockStatement: ["body", "innerComments"],
96
- BreakStatement: [],
97
- CallExpression: ["callee", "arguments"],
98
- CatchClause: ["param", "body"],
99
- CatchClauses: ["catches"],
100
- ClassBody: ["body"],
101
- ClassDeclaration: ["attrs", "id", "superClass", "body"],
102
- ClassElement: ["item"],
103
- ConditionalExpression: ["test", "consequent", "alternate"],
104
- ContinueStatement: [],
105
- DoWhileStatement: ["body", "test"],
106
- EnumDeclaration: ["attrs", "id", "body"],
107
- EnumStringBody: ["members"],
108
- EnumStringMember: ["id", "init"],
109
- ExpressionStatement: ["expression"],
110
- ForStatement: ["init", "test", "body", "update"],
111
- FunctionDeclaration: ["attrs", "id", "params", "returnType", "body"],
112
- Identifier: [],
113
- IfStatement: ["test", "consequent", "alternate"],
114
- ImportModule: ["id"],
115
- InstanceOfCase: ["id"],
116
- Line: [],
117
- Literal: [],
118
- LogicalExpression: ["left", "right"],
119
- MemberExpression: ["object", "property"],
120
- MethodDefinition: ["params", "returnType"],
121
- ModuleDeclaration: ["attrs", "id", "body"],
122
- MultiLine: [],
123
- NewExpression: ["callee", "arguments"],
124
- ObjectExpression: ["properties"],
125
- ParenthesizedExpression: ["expression"],
126
- Program: ["body", "comments"],
127
- Property: ["key", "value"],
128
- ReturnStatement: ["argument"],
129
- SequenceExpression: ["expressions"],
130
- SizedArrayExpression: ["size", "ts"],
131
- SwitchCase: ["test", "consequent"],
132
- SwitchStatement: ["discriminant", "cases"],
133
- ThisExpression: [],
134
- ThrowStatement: ["argument"],
135
- TryStatement: ["block", "handler", "finalizer"],
136
- TypedefDeclaration: ["attrs", "id", "ts"],
137
- TypeSpecList: ["ts"],
138
- TypeSpecPart: ["name", "body", "callspec", "generics"],
139
- UnaryExpression: ["argument"],
140
- UpdateExpression: ["argument"],
141
- Using: ["id", "as"],
142
- VariableDeclaration: ["attrs", "declarations"],
143
- VariableDeclarator: ["id", "init"],
144
- WhileStatement: ["test", "body"],
295
+ ArrayExpression: { keys: ["elements"], expr: true },
296
+ AssignmentExpression: { keys: ["left", "right"], expr: true },
297
+ AttributeList: { keys: ["attributes"] },
298
+ Attributes: { keys: ["elements"] },
299
+ BinaryExpression: { keys: ["left", "right"], expr: true },
300
+ Block: { keys: [] },
301
+ BlockStatement: { keys: ["body", "innerComments"], stmt: true },
302
+ BreakStatement: { keys: [], stmt: true },
303
+ CallExpression: { keys: ["callee", "arguments"], expr: true },
304
+ CatchClause: { keys: ["param", "body"] },
305
+ CatchClauses: { keys: ["catches"] },
306
+ ClassBody: { keys: ["body"] },
307
+ ClassDeclaration: { keys: ["attrs", "id", "superClass", "body"], stmt: true },
308
+ ClassElement: { keys: ["item"] },
309
+ ConditionalExpression: {
310
+ keys: ["test", "consequent", "alternate"],
311
+ expr: true,
312
+ },
313
+ ContinueStatement: { keys: [], stmt: true },
314
+ DoWhileStatement: { keys: ["body", "test"], stmt: true },
315
+ EnumDeclaration: { keys: ["attrs", "id", "body"], stmt: true },
316
+ EnumStringBody: { keys: ["members"] },
317
+ EnumStringMember: { keys: ["id", "init"] },
318
+ ExpressionStatement: { keys: ["expression"], stmt: true },
319
+ ForStatement: { keys: ["init", "test", "body", "update"], stmt: true },
320
+ FunctionDeclaration: {
321
+ keys: ["attrs", "id", "params", "returnType", "body"],
322
+ stmt: true,
323
+ },
324
+ Identifier: { keys: [], expr: true },
325
+ IfStatement: { keys: ["test", "consequent", "alternate"], stmt: true },
326
+ ImportModule: { keys: ["id"] },
327
+ InstanceOfCase: { keys: ["id"] },
328
+ Line: { keys: [] },
329
+ Literal: { keys: [], expr: true },
330
+ LogicalExpression: { keys: ["left", "right"], expr: true },
331
+ MemberExpression: { keys: ["object", "property"], expr: true },
332
+ MethodDefinition: { keys: ["params", "returnType"] },
333
+ ModuleDeclaration: { keys: ["attrs", "id", "body"], stmt: true },
334
+ MultiLine: { keys: [] },
335
+ NewExpression: { keys: ["callee", "arguments"], expr: true },
336
+ ObjectExpression: { keys: ["properties"], expr: true },
337
+ ParenthesizedExpression: { keys: ["expression"], expr: true },
338
+ Program: { keys: ["body", "comments"] },
339
+ Property: { keys: ["key", "value"] },
340
+ ReturnStatement: { keys: ["argument"], stmt: true },
341
+ SequenceExpression: { keys: ["expressions"], expr: true },
342
+ SizedArrayExpression: { keys: ["size", "ts"], expr: true },
343
+ SwitchCase: { keys: ["test", "consequent"] },
344
+ SwitchStatement: { keys: ["discriminant", "cases"], stmt: true },
345
+ ThisExpression: { keys: [], expr: true },
346
+ ThrowStatement: { keys: ["argument"], stmt: true },
347
+ TryStatement: { keys: ["block", "handler", "finalizer"], stmt: true },
348
+ TypedefDeclaration: { keys: ["attrs", "id", "ts"], stmt: true },
349
+ TypeSpecList: { keys: ["ts"] },
350
+ TypeSpecPart: { keys: ["name", "body", "callspec", "generics"] },
351
+ UnaryExpression: { keys: ["argument"], expr: true },
352
+ UpdateExpression: { keys: ["argument"], expr: true },
353
+ Using: { keys: ["id", "as"] },
354
+ VariableDeclaration: { keys: ["attrs", "declarations"], stmt: true },
355
+ VariableDeclarator: { keys: ["id", "init"] },
356
+ WhileStatement: { keys: ["test", "body"], stmt: true },
145
357
  };
146
358
  function isMCTreeNode(node) {
147
359
  return node ? typeof node === "object" && "type" in node : false;
@@ -166,7 +378,7 @@ function ast_traverseAst(node, pre, post) {
166
378
  if (!mctreeTypeInfo[node.type]) {
167
379
  throw new Error("what?");
168
380
  }
169
- for (const key of nodes || mctreeTypeInfo[node.type]) {
381
+ for (const key of nodes || mctreeTypeInfo[node.type].keys) {
170
382
  const value = node[key];
171
383
  if (!value)
172
384
  continue;
@@ -193,13 +405,21 @@ function ast_traverseAst(node, pre, post) {
193
405
  }
194
406
  }
195
407
  else if (isMCTreeNode(value)) {
196
- const repl = ast_traverseAst(value, pre, post);
408
+ let repl = ast_traverseAst(value, pre, post);
197
409
  if (repl === false) {
198
410
  delete node[key];
199
411
  }
200
412
  else if (repl != null) {
201
413
  if (Array.isArray(repl)) {
202
- throw new Error("Array returned by traverseAst in Node context");
414
+ if (ast_isStatement(value) && repl.every((s) => ast_isStatement(s))) {
415
+ repl = ast_withLoc({
416
+ type: "BlockStatement",
417
+ body: repl,
418
+ }, repl[0], repl[repl.length - 1]);
419
+ }
420
+ else {
421
+ throw new Error("Array returned by traverseAst in Node context");
422
+ }
203
423
  }
204
424
  node[key] = repl;
205
425
  }
@@ -207,6 +427,55 @@ function ast_traverseAst(node, pre, post) {
207
427
  }
208
428
  return post && post(node);
209
429
  }
430
+ function ast_isStatement(node) {
431
+ return ast_hasProperty(mctreeTypeInfo[node.type], "stmt");
432
+ }
433
+ function ast_isExpression(node) {
434
+ return ast_hasProperty(mctreeTypeInfo[node.type], "expr");
435
+ }
436
+ function ast_mayThrow(node) {
437
+ switch (node.type) {
438
+ case "BinaryExpression":
439
+ case "CallExpression":
440
+ case "ConditionalExpression":
441
+ case "LogicalExpression":
442
+ case "NewExpression":
443
+ case "ThrowStatement":
444
+ case "UnaryExpression":
445
+ case "UpdateExpression":
446
+ return true;
447
+ default:
448
+ return false;
449
+ }
450
+ }
451
+ function ast_hasProperty(obj, prop) {
452
+ return obj ? Object.prototype.hasOwnProperty.call(obj, prop) : false;
453
+ }
454
+ function ast_withLoc(node, start, end) {
455
+ if (start && start.loc) {
456
+ node.start = start.start;
457
+ if (!node.end)
458
+ node.end = start.end;
459
+ node.loc = { ...(node.loc || start.loc), start: start.loc.start };
460
+ }
461
+ if (end && end.loc) {
462
+ node.end = end.end;
463
+ node.loc = { ...(node.loc || end.loc), end: end.loc.end };
464
+ }
465
+ return node;
466
+ }
467
+ function ast_withLocDeep(node, start, end) {
468
+ node = ast_withLoc({ ...node }, start, end);
469
+ for (const key of mctreeTypeInfo[node.type].keys) {
470
+ const value = node[key];
471
+ if (!value)
472
+ continue;
473
+ const fix = (v) => isMCTreeNode(v) ? ast_withLocDeep(v, start, end) : v;
474
+ const repl = Array.isArray(value) ? value.map(fix) : fix(value);
475
+ node[key] = repl;
476
+ }
477
+ return node;
478
+ }
210
479
 
211
480
  ;// CONCATENATED MODULE: external "./api.cjs"
212
481
  const external_api_cjs_namespaceObject = require("./api.cjs");
@@ -463,6 +732,7 @@ function processInlineBody(state, func, call, root, params) {
463
732
  const post = state.post;
464
733
  state.inlining = true;
465
734
  let insertedVariableDecls = null;
735
+ const replacements = new Set();
466
736
  try {
467
737
  state.pre = (node) => {
468
738
  if (failed)
@@ -470,7 +740,7 @@ function processInlineBody(state, func, call, root, params) {
470
740
  node.start = call.start;
471
741
  node.end = call.end;
472
742
  node.loc = call.loc;
473
- if (node === insertedVariableDecls)
743
+ if (replacements.has(node))
474
744
  return false;
475
745
  const result = pre(node, state);
476
746
  if (!insertedVariableDecls && node.type === "BlockStatement") {
@@ -498,6 +768,7 @@ function processInlineBody(state, func, call, root, params) {
498
768
  kind: "var",
499
769
  };
500
770
  node.body.unshift(insertedVariableDecls);
771
+ replacements.add(insertedVariableDecls);
501
772
  }
502
773
  return result;
503
774
  };
@@ -512,7 +783,9 @@ function processInlineBody(state, func, call, root, params) {
512
783
  if (hasProperty(params, node.name)) {
513
784
  const ix = params[node.name];
514
785
  if (ix >= 0) {
515
- replacement = call.arguments[ix];
786
+ replacement = { ...call.arguments[ix] };
787
+ replacements.add(replacement);
788
+ return replacement;
516
789
  }
517
790
  break;
518
791
  }
@@ -549,6 +822,10 @@ function processInlineBody(state, func, call, root, params) {
549
822
  }
550
823
  }
551
824
  function inliner_unused(expression, top) {
825
+ const estmt = (expression) => withLoc({
826
+ type: "ExpressionStatement",
827
+ expression,
828
+ }, expression);
552
829
  switch (expression.type) {
553
830
  case "Literal":
554
831
  return [];
@@ -560,9 +837,50 @@ function inliner_unused(expression, top) {
560
837
  if (expression.operator === "as") {
561
838
  return inliner_unused(expression.left);
562
839
  }
563
- // fall through
564
- case "LogicalExpression":
565
840
  return inliner_unused(expression.left).concat(inliner_unused(expression.right));
841
+ case "LogicalExpression": {
842
+ const right = inliner_unused(expression.right);
843
+ if (!right.length)
844
+ return inliner_unused(expression.left);
845
+ const consequent = withLoc({
846
+ type: "BlockStatement",
847
+ body: [estmt(expression.right)],
848
+ }, expression.right);
849
+ let alternate;
850
+ if (expression.operator == "||") {
851
+ alternate = { ...consequent };
852
+ consequent.body = [];
853
+ }
854
+ return [
855
+ withLoc({
856
+ type: "IfStatement",
857
+ test: expression.left,
858
+ consequent,
859
+ alternate,
860
+ }, expression),
861
+ ];
862
+ }
863
+ case "ConditionalExpression": {
864
+ const consequentExprs = inliner_unused(expression.consequent);
865
+ const alternateExprs = inliner_unused(expression.alternate);
866
+ if (!consequentExprs.length && !alternateExprs.length) {
867
+ return inliner_unused(expression.test);
868
+ }
869
+ return [
870
+ withLoc({
871
+ type: "IfStatement",
872
+ test: expression.test,
873
+ consequent: withLoc({
874
+ type: "BlockStatement",
875
+ body: consequentExprs,
876
+ }, expression.consequent),
877
+ alternate: withLoc({
878
+ type: "BlockStatement",
879
+ body: alternateExprs,
880
+ }, expression.alternate),
881
+ }, expression),
882
+ ];
883
+ }
566
884
  case "UnaryExpression":
567
885
  return inliner_unused(expression.argument);
568
886
  case "MemberExpression":
@@ -577,17 +895,7 @@ function inliner_unused(expression, top) {
577
895
  .map((p) => inliner_unused(p.key).concat(inliner_unused(p.value)))
578
896
  .flat(1);
579
897
  }
580
- return top
581
- ? null
582
- : [
583
- {
584
- type: "ExpressionStatement",
585
- expression,
586
- start: expression.start,
587
- end: expression.end,
588
- loc: expression.loc,
589
- },
590
- ];
898
+ return top ? null : [estmt(expression)];
591
899
  }
592
900
  function inliner_diagnostic(state, loc, message, type = "INFO") {
593
901
  if (!loc || !loc.source)
@@ -635,7 +943,9 @@ function inlineWithArgs(state, func, call, context) {
635
943
  if (retStmtCount > 1) {
636
944
  inlineDiagnostic(state, func, call, "Function had more than one return statement");
637
945
  }
638
- else if (context.type === "AssignmentExpression" && retStmtCount !== 1) {
946
+ else if ((context.type === "AssignmentExpression" ||
947
+ context.type === "VariableDeclarator") &&
948
+ retStmtCount !== 1) {
639
949
  inlineDiagnostic(state, func, call, "Function did not have a return statement");
640
950
  return null;
641
951
  }
@@ -643,7 +953,9 @@ function inlineWithArgs(state, func, call, context) {
643
953
  const last = func.node.body.body.slice(-1)[0];
644
954
  if (!last ||
645
955
  last.type !== "ReturnStatement" ||
646
- (context.type === "AssignmentExpression" && !last.argument)) {
956
+ ((context.type === "AssignmentExpression" ||
957
+ context.type === "VariableDeclarator") &&
958
+ !last.argument)) {
647
959
  inlineDiagnostic(state, func, call, "There was a return statement, but not at the end of the function");
648
960
  return null;
649
961
  }
@@ -667,139 +979,1495 @@ function inlineWithArgs(state, func, call, context) {
667
979
  if (last.type != "ReturnStatement") {
668
980
  throw new Error("ReturnStatement got lost!");
669
981
  }
670
- if (context.type === "AssignmentExpression") {
671
- context.right = last.argument;
672
- body.body[body.body.length - 1] = {
673
- type: "ExpressionStatement",
674
- expression: context,
982
+ if (last.argument) {
983
+ if (context.type === "AssignmentExpression") {
984
+ context.right = last.argument;
985
+ body.body[body.body.length - 1] = {
986
+ type: "ExpressionStatement",
987
+ expression: context,
988
+ };
989
+ }
990
+ else if (context.type === "VariableDeclarator") {
991
+ const { id, init: _init, kind: _kind, ...rest } = context;
992
+ body.body[body.body.length - 1] = {
993
+ ...rest,
994
+ type: "ExpressionStatement",
995
+ expression: {
996
+ ...rest,
997
+ type: "AssignmentExpression",
998
+ operator: "=",
999
+ left: id.type === "Identifier" ? id : id.left,
1000
+ right: last.argument,
1001
+ },
1002
+ };
1003
+ }
1004
+ else {
1005
+ const side_exprs = inliner_unused(last.argument);
1006
+ body.body.splice(body.body.length - 1, 1, ...side_exprs);
1007
+ }
1008
+ }
1009
+ else {
1010
+ --body.body.length;
1011
+ }
1012
+ }
1013
+ return body;
1014
+ }
1015
+ function inliner_inlineFunction(state, func, call, context) {
1016
+ if (context) {
1017
+ return inlineWithArgs(state, func, call, context);
1018
+ }
1019
+ const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
1020
+ const params = Object.fromEntries(func.node.params.map((param, i) => [variableDeclarationName(param), i]));
1021
+ const map = fixupLocalsMap(state);
1022
+ const ret = processInlineBody(state, func, call, retArg, params);
1023
+ state.localsStack[state.localsStack.length - 1].map = map;
1024
+ return ret;
1025
+ }
1026
+ function applyTypeIfNeeded(node) {
1027
+ if ("enumType" in node && node.enumType) {
1028
+ node = {
1029
+ type: "BinaryExpression",
1030
+ operator: "as",
1031
+ left: node,
1032
+ right: { type: "TypeSpecList", ts: [node.enumType] },
1033
+ };
1034
+ }
1035
+ return node;
1036
+ }
1037
+ function fixNodeScope(state, lookupNode, nodeStack) {
1038
+ if (lookupNode.type === "Identifier") {
1039
+ const locals = state.localsStack[state.localsStack.length - 1];
1040
+ const { map } = locals;
1041
+ if (!map)
1042
+ throw new Error("No local variable map!");
1043
+ if (hasProperty(map, lookupNode.name) && map[lookupNode.name] !== false) {
1044
+ // map[name] !== false means its an entry that was created during inlining
1045
+ // so its definitely one of our locals.
1046
+ return lookupNode;
1047
+ }
1048
+ }
1049
+ const [, original] = state.lookup(lookupNode, null, nodeStack);
1050
+ if (!original) {
1051
+ return null;
1052
+ }
1053
+ const [, current] = state.lookup(lookupNode);
1054
+ // For now, leave it alone if it already maps to the same thing.
1055
+ // With a bit more work, we could find the guaranteed shortest
1056
+ // reference, and then use this to optimize *all* symbols, not
1057
+ // just fix inlined ones.
1058
+ if (current && sameLookupResult(original, current)) {
1059
+ return lookupNode;
1060
+ }
1061
+ const node = lookupNode.type === "Identifier"
1062
+ ? lookupNode
1063
+ : lookupNode.property;
1064
+ if (original.length === 1 &&
1065
+ original[0].results.length === 1 &&
1066
+ original[0].results[0].type === "EnumStringMember") {
1067
+ return applyTypeIfNeeded(original[0].results[0].init);
1068
+ }
1069
+ const prefixes = original
1070
+ .map((lookupDef) => lookupDef.results.map((sn) => {
1071
+ if (isStateNode(sn) && sn.fullName) {
1072
+ return sn.fullName;
1073
+ }
1074
+ return "";
1075
+ }))
1076
+ .flat();
1077
+ const member = (object, property) => ({
1078
+ type: "MemberExpression",
1079
+ object,
1080
+ property,
1081
+ computed: false,
1082
+ start: node.start,
1083
+ end: node.end,
1084
+ loc: node.loc,
1085
+ });
1086
+ if (prefixes.length &&
1087
+ prefixes[0].startsWith("$.") &&
1088
+ prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
1089
+ const prefix = prefixes[0].split(".").slice(0, -1).reverse();
1090
+ let found = false;
1091
+ return prefix.reduce((current, name) => {
1092
+ if (found)
1093
+ return current;
1094
+ const [, results] = state.lookup(current);
1095
+ if (results && sameLookupResult(original, results)) {
1096
+ found = true;
1097
+ return current;
1098
+ }
1099
+ const object = {
1100
+ type: "Identifier",
1101
+ name,
1102
+ start: node.start,
1103
+ end: node.end,
1104
+ loc: node.loc,
1105
+ };
1106
+ let root = null;
1107
+ let property = current;
1108
+ do {
1109
+ root = property;
1110
+ property = property.object;
1111
+ } while (property.type === "MemberExpression");
1112
+ if (property.type === "ThisExpression") {
1113
+ root.object = object;
1114
+ return root;
1115
+ }
1116
+ root.object = member(object, property);
1117
+ return current;
1118
+ }, member({
1119
+ type: "ThisExpression",
1120
+ text: "self",
1121
+ start: node.start,
1122
+ end: node.end,
1123
+ loc: node.loc,
1124
+ }, node));
1125
+ }
1126
+ return null;
1127
+ }
1128
+
1129
+ ;// CONCATENATED MODULE: external "./util.cjs"
1130
+ const external_util_cjs_namespaceObject = require("./util.cjs");
1131
+ ;// CONCATENATED MODULE: ./src/control-flow.ts
1132
+
1133
+
1134
+ const Terminals = {
1135
+ BreakStatement: "break",
1136
+ ContinueStatement: "continue",
1137
+ ReturnStatement: null,
1138
+ ThrowStatement: "throw",
1139
+ };
1140
+ class LocalState {
1141
+ constructor(func) {
1142
+ this.stack = [];
1143
+ this.info = new Map();
1144
+ this.curBlock = {};
1145
+ this.unreachable = false;
1146
+ this.push(func);
1147
+ }
1148
+ push(node) {
1149
+ const top = { node };
1150
+ this.stack.push(top);
1151
+ return top;
1152
+ }
1153
+ pop() {
1154
+ return this.stack.pop();
1155
+ }
1156
+ top(depth) {
1157
+ return this.stack[this.stack.length - (depth || 1)];
1158
+ }
1159
+ addEdge(from, to) {
1160
+ if (!from.succs) {
1161
+ from.succs = [to];
1162
+ }
1163
+ else {
1164
+ pushUnique(from.succs, to);
1165
+ }
1166
+ if (!to.preds) {
1167
+ to.preds = [from];
1168
+ }
1169
+ else {
1170
+ pushUnique(to.preds, from);
1171
+ }
1172
+ }
1173
+ newBlock(block) {
1174
+ if (!block)
1175
+ block = {};
1176
+ if (!this.unreachable) {
1177
+ this.addEdge(this.curBlock, block);
1178
+ }
1179
+ this.unreachable = false;
1180
+ for (let i = this.stack.length; i--;) {
1181
+ const si = this.stack[i];
1182
+ if (si.throw) {
1183
+ block.exsucc = si.throw;
1184
+ if (!si.throw.expreds) {
1185
+ si.throw.expreds = [block];
1186
+ }
1187
+ else {
1188
+ si.throw.expreds.push(block);
1189
+ }
1190
+ break;
1191
+ }
1192
+ }
1193
+ return (this.curBlock = block);
1194
+ }
1195
+ terminal(type) {
1196
+ const re = Terminals[type];
1197
+ if (re) {
1198
+ for (let i = this.stack.length; i--;) {
1199
+ const target = this.stack[i][re];
1200
+ if (target) {
1201
+ this.addEdge(this.curBlock, target);
1202
+ break;
1203
+ }
1204
+ }
1205
+ }
1206
+ this.unreachable = true;
1207
+ }
1208
+ }
1209
+ function control_flow_buildReducedGraph(state, func, notice) {
1210
+ const { stack, pre, post } = state;
1211
+ try {
1212
+ const localState = new LocalState(func.node);
1213
+ const ret = localState.curBlock;
1214
+ state.stack = func.stack;
1215
+ const stmtStack = [func.node];
1216
+ let tryActive = 0;
1217
+ state.pre = (node) => {
1218
+ if (state.inType || localState.unreachable) {
1219
+ return [];
1220
+ }
1221
+ if (!localState.curBlock.node &&
1222
+ (isStatement(node) || isExpression(node))) {
1223
+ localState.curBlock.node = node;
1224
+ }
1225
+ if (isStatement(node)) {
1226
+ stmtStack.push(node);
1227
+ }
1228
+ switch (node.type) {
1229
+ case "AttributeList":
1230
+ return [];
1231
+ case "SwitchStatement": {
1232
+ const top = localState.push(node);
1233
+ top.break = {};
1234
+ state.traverse(node.discriminant);
1235
+ const testBlocks = [];
1236
+ let defaultSeen = false;
1237
+ node.cases.forEach((sc, i) => {
1238
+ if (sc.test) {
1239
+ state.traverse(sc.test);
1240
+ testBlocks[i] = localState.curBlock;
1241
+ localState.newBlock();
1242
+ }
1243
+ else {
1244
+ defaultSeen = true;
1245
+ }
1246
+ });
1247
+ const endOfTests = localState.curBlock;
1248
+ if (!defaultSeen) {
1249
+ localState.addEdge(endOfTests, top.break);
1250
+ }
1251
+ localState.unreachable = true;
1252
+ node.cases.forEach((sc, i) => {
1253
+ localState.newBlock();
1254
+ localState.addEdge(testBlocks[i] || endOfTests, localState.curBlock);
1255
+ sc.consequent.every((s) => {
1256
+ state.traverse(s);
1257
+ return !localState.unreachable;
1258
+ });
1259
+ });
1260
+ localState.newBlock(top.break);
1261
+ localState.unreachable = !top.break.preds;
1262
+ return [];
1263
+ }
1264
+ case "DoWhileStatement":
1265
+ case "WhileStatement": {
1266
+ localState.push(node);
1267
+ const top = localState.top();
1268
+ top.break = {};
1269
+ top.continue = {};
1270
+ let head;
1271
+ if (node.type === "WhileStatement") {
1272
+ head = localState.newBlock(top.continue);
1273
+ state.traverse(node.test);
1274
+ localState.addEdge(localState.newBlock(), top.break);
1275
+ }
1276
+ else {
1277
+ head = localState.newBlock();
1278
+ }
1279
+ state.traverse(node.body);
1280
+ if (node.type === "DoWhileStatement") {
1281
+ localState.newBlock(top.continue);
1282
+ state.traverse(node.test);
1283
+ localState.addEdge(localState.curBlock, top.break);
1284
+ }
1285
+ localState.addEdge(localState.curBlock, head);
1286
+ localState.curBlock = top.break;
1287
+ return [];
1288
+ }
1289
+ case "TryStatement": {
1290
+ const top = localState.push(node);
1291
+ const catches = (top.throw = {});
1292
+ // This edge shouldn't exist, but we can trigger
1293
+ // (incorrect) "variable may not be initialized" errors
1294
+ // in the monkey c compiler without it.
1295
+ // https://forums.garmin.com/developer/connect-iq/i/bug-reports/incorrect-maybe-uninitialized-error
1296
+ localState.addEdge(localState.curBlock, top.throw);
1297
+ localState.newBlock();
1298
+ tryActive++;
1299
+ state.traverse(node.block);
1300
+ tryActive--;
1301
+ delete top.throw;
1302
+ top.posttry = {};
1303
+ const tryFallsThrough = !localState.unreachable;
1304
+ if (node.finalizer) {
1305
+ tryActive++;
1306
+ top.throw = top.finally = {};
1307
+ // curBlock branches to finally, no matter how it exits.
1308
+ localState.addEdge(localState.curBlock, top.finally);
1309
+ }
1310
+ else {
1311
+ if (!localState.unreachable) {
1312
+ localState.addEdge(localState.curBlock, top.posttry);
1313
+ }
1314
+ }
1315
+ localState.unreachable = true;
1316
+ localState.newBlock(catches);
1317
+ if (node.handler) {
1318
+ state.traverse(node.handler);
1319
+ if (top.throw) {
1320
+ tryActive--;
1321
+ delete top.throw;
1322
+ }
1323
+ // Each "catch (ex instanceof Foo)" chains to the next,
1324
+ // but "catch (ex)" terminates the list. If the end
1325
+ // of the chain has a predecessor, its possible that
1326
+ // none of the conditions matched, so the exception
1327
+ // will propagate from there.
1328
+ if (localState.curBlock.preds) {
1329
+ localState.terminal("ThrowStatement");
1330
+ }
1331
+ }
1332
+ if (top.throw) {
1333
+ tryActive--;
1334
+ delete top.throw;
1335
+ }
1336
+ if (node.finalizer) {
1337
+ localState.unreachable = true;
1338
+ localState.newBlock(top.finally);
1339
+ delete top.finally;
1340
+ state.traverse(node.finalizer);
1341
+ if (tryFallsThrough && !localState.unreachable) {
1342
+ localState.addEdge(localState.curBlock, top.posttry);
1343
+ }
1344
+ localState.terminal("ThrowStatement");
1345
+ }
1346
+ localState.unreachable = true;
1347
+ localState.newBlock(top.posttry);
1348
+ return [];
1349
+ }
1350
+ case "CatchClause": {
1351
+ const top = localState.top();
1352
+ if (!localState.curBlock.preds && !localState.curBlock.expreds) {
1353
+ return [];
1354
+ }
1355
+ const next = {};
1356
+ if (node.param && node.param.type === "BinaryExpression") {
1357
+ state.traverse(node.param);
1358
+ localState.addEdge(localState.curBlock, next);
1359
+ localState.newBlock();
1360
+ }
1361
+ state.traverse(node.body);
1362
+ if (top.finally) {
1363
+ // this edge exists even if this point is unreachable
1364
+ localState.addEdge(localState.curBlock, top.finally);
1365
+ }
1366
+ if (!localState.unreachable) {
1367
+ if (!top.posttry)
1368
+ top.posttry = {};
1369
+ localState.addEdge(localState.curBlock, top.posttry);
1370
+ }
1371
+ localState.unreachable = true;
1372
+ localState.newBlock(next);
1373
+ return [];
1374
+ }
1375
+ case "ForStatement": {
1376
+ const top = localState.push(node);
1377
+ if (node.init)
1378
+ state.traverse(node.init);
1379
+ const head = localState.newBlock();
1380
+ top.break = {};
1381
+ top.continue = {};
1382
+ if (node.test) {
1383
+ state.traverse(node.test);
1384
+ localState.addEdge(localState.curBlock, top.break);
1385
+ localState.newBlock();
1386
+ }
1387
+ state.traverse(node.body);
1388
+ localState.newBlock(top.continue);
1389
+ if (node.update) {
1390
+ state.traverse(node.update);
1391
+ }
1392
+ if (!localState.unreachable) {
1393
+ localState.addEdge(localState.curBlock, head);
1394
+ }
1395
+ // there is no fall through from the end of the loop
1396
+ // to the next block. The only way there is via break
1397
+ // or the test failing.
1398
+ localState.unreachable = true;
1399
+ localState.newBlock(top.break);
1400
+ if (!top.break.preds) {
1401
+ localState.unreachable = true;
1402
+ }
1403
+ return [];
1404
+ }
1405
+ case "IfStatement":
1406
+ case "ConditionalExpression": {
1407
+ state.traverse(node.test);
1408
+ const alternate = {};
1409
+ localState.addEdge(localState.curBlock, alternate);
1410
+ localState.newBlock();
1411
+ state.traverse(node.consequent);
1412
+ const consequent = localState.unreachable
1413
+ ? null
1414
+ : localState.curBlock;
1415
+ localState.unreachable = true;
1416
+ localState.newBlock(alternate);
1417
+ if (node.alternate) {
1418
+ state.traverse(node.alternate);
1419
+ if (!localState.unreachable) {
1420
+ localState.newBlock();
1421
+ }
1422
+ }
1423
+ if (consequent) {
1424
+ if (localState.unreachable) {
1425
+ localState.newBlock();
1426
+ }
1427
+ localState.addEdge(consequent, localState.curBlock);
1428
+ }
1429
+ return [];
1430
+ }
1431
+ case "LogicalExpression": {
1432
+ state.traverse(node.left);
1433
+ if (localState.unreachable)
1434
+ break;
1435
+ const mid = localState.curBlock;
1436
+ localState.newBlock();
1437
+ state.traverse(node.right);
1438
+ localState.newBlock();
1439
+ localState.addEdge(mid, localState.curBlock);
1440
+ return [];
1441
+ }
1442
+ case "VariableDeclarator":
1443
+ return ["init"];
1444
+ case "MemberExpression":
1445
+ if (!node.computed) {
1446
+ return ["object"];
1447
+ }
1448
+ break;
1449
+ case "UnaryExpression":
1450
+ if (node.operator === ":") {
1451
+ return [];
1452
+ }
1453
+ break;
1454
+ case "UpdateExpression":
1455
+ // We don't want to traverse the argument, since then it would
1456
+ // look like a ref, rather than a def. But if its a
1457
+ // MemberExpression, we *do* want to traverse the subexpressions
1458
+ // as potential refs.
1459
+ if (node.argument.type === "MemberExpression") {
1460
+ state.traverse(node.argument.object);
1461
+ if (node.argument.computed) {
1462
+ state.traverse(node.argument.property);
1463
+ }
1464
+ }
1465
+ return [];
1466
+ case "AssignmentExpression":
1467
+ if (node.left.type === "MemberExpression") {
1468
+ state.traverse(node.left.object);
1469
+ if (node.left.computed) {
1470
+ state.traverse(node.left.property);
1471
+ }
1472
+ }
1473
+ return ["right"];
1474
+ case "ThrowStatement":
1475
+ case "ReturnStatement":
1476
+ if (node.argument) {
1477
+ state.traverse(node.argument);
1478
+ }
1479
+ // fall through
1480
+ case "BreakStatement":
1481
+ case "ContinueStatement":
1482
+ localState.terminal(node.type);
1483
+ return [];
1484
+ }
1485
+ return null;
1486
+ };
1487
+ const addEvent = (block, event) => {
1488
+ if (!block.events) {
1489
+ block.events = [event];
1490
+ }
1491
+ else {
1492
+ block.events.push(event);
1493
+ }
1494
+ };
1495
+ state.post = (node) => {
1496
+ const curStmt = stmtStack[stmtStack.length - 1];
1497
+ if (!state.inType) {
1498
+ const throws = tryActive > 0 && mayThrow(node);
1499
+ const event = notice(node, curStmt, throws);
1500
+ if (throws) {
1501
+ if (!event) {
1502
+ throw new Error("mayThrow expression in try/catch must generate an event");
1503
+ }
1504
+ }
1505
+ else if (event) {
1506
+ event.mayThrow = false;
1507
+ }
1508
+ if (event) {
1509
+ if (event.mayThrow) {
1510
+ for (let i = localState.stack.length; i--;) {
1511
+ const target = localState.stack[i].throw;
1512
+ if (target) {
1513
+ if (localState.curBlock.exsucc) {
1514
+ if (localState.curBlock.exsucc !== target) {
1515
+ throw new Error(`Block has multiple throw targets`);
1516
+ }
1517
+ }
1518
+ else {
1519
+ localState.curBlock.exsucc = target;
1520
+ if (!target.expreds) {
1521
+ target.expreds = [localState.curBlock];
1522
+ }
1523
+ else {
1524
+ target.expreds.push(localState.curBlock);
1525
+ }
1526
+ }
1527
+ break;
1528
+ }
1529
+ }
1530
+ }
1531
+ addEvent(localState.curBlock, event);
1532
+ }
1533
+ }
1534
+ if (curStmt === node) {
1535
+ stmtStack.pop();
1536
+ }
1537
+ if (localState.top().node === node) {
1538
+ localState.pop();
1539
+ }
1540
+ return null;
1541
+ };
1542
+ state.traverse(func.node);
1543
+ return cleanCfg(ret);
1544
+ }
1545
+ finally {
1546
+ state.pre = pre;
1547
+ state.post = post;
1548
+ state.stack = stack;
1549
+ }
1550
+ }
1551
+ function cleanCfg(head) {
1552
+ preOrderTraverse(head, (cur) => {
1553
+ if (cur.succs && cur.succs.length === 1) {
1554
+ const succ = cur.succs[0];
1555
+ if (succ !== head &&
1556
+ succ.preds.length === 1 &&
1557
+ (!cur.exsucc || cur.exsucc === succ.exsucc) &&
1558
+ (!succ.succs ||
1559
+ succ.succs.length === 1 ||
1560
+ (cur.preds && cur.preds.length === 1))) {
1561
+ if (cur.events) {
1562
+ if (succ.events) {
1563
+ cur.events.push(...succ.events);
1564
+ }
1565
+ }
1566
+ else if (succ.events) {
1567
+ cur.events = succ.events;
1568
+ }
1569
+ if (succ.exsucc) {
1570
+ const preds = succ.exsucc.expreds;
1571
+ for (let i = preds.length; i--;) {
1572
+ if (preds[i] === succ) {
1573
+ // If cur has an exsucc, we already
1574
+ // checked that its the same as succ's,
1575
+ // so we can just delete the edge.
1576
+ // Otherwise, we need to point it at cur.
1577
+ if (cur.exsucc) {
1578
+ preds.splice(i, 1);
1579
+ }
1580
+ else {
1581
+ preds[i] = cur;
1582
+ }
1583
+ }
1584
+ }
1585
+ }
1586
+ cur.exsucc = succ.exsucc;
1587
+ cur.succs = succ.succs;
1588
+ if (cur.succs) {
1589
+ cur.succs.forEach((s) => s.preds.forEach((p, i, arr) => {
1590
+ if (p === succ) {
1591
+ arr[i] = cur;
1592
+ }
1593
+ }));
1594
+ }
1595
+ }
1596
+ }
1597
+ });
1598
+ return head;
1599
+ }
1600
+ function postOrderTraverse(head, visitor) {
1601
+ const visited = new Set();
1602
+ const helper = (cur) => {
1603
+ if (visited.has(cur))
1604
+ return;
1605
+ visited.add(cur);
1606
+ if (cur.succs) {
1607
+ cur.succs.forEach((block) => helper(block));
1608
+ }
1609
+ if (cur.exsucc)
1610
+ helper(cur.exsucc);
1611
+ visitor(cur);
1612
+ };
1613
+ helper(head);
1614
+ }
1615
+ function preOrderTraverse(head, visitor) {
1616
+ const visited = new Set();
1617
+ const helper = (cur) => {
1618
+ if (visited.has(cur))
1619
+ return;
1620
+ visited.add(cur);
1621
+ visitor(cur);
1622
+ if (cur.succs) {
1623
+ cur.succs.forEach((block) => helper(block));
1624
+ }
1625
+ if (cur.exsucc)
1626
+ helper(cur.exsucc);
1627
+ };
1628
+ helper(head);
1629
+ }
1630
+ function control_flow_getPostOrder(head) {
1631
+ const blocks = [];
1632
+ postOrderTraverse(head, (block) => blocks.push(block));
1633
+ return blocks;
1634
+ }
1635
+ function getPreOrder(head) {
1636
+ const blocks = [];
1637
+ postOrderTraverse(head, (block) => blocks.push(block));
1638
+ return blocks;
1639
+ }
1640
+
1641
+ // EXTERNAL MODULE: ./node_modules/priorityqueuejs/index.js
1642
+ var priorityqueuejs = __webpack_require__(2789);
1643
+ ;// CONCATENATED MODULE: ./src/pre.ts
1644
+
1645
+
1646
+
1647
+
1648
+ /**
1649
+ * This implements a pseudo Partial Redundancy Elimination
1650
+ * pass. It isn't quite like traditional PRE because we're
1651
+ * aiming to minimize size, not dynamic instructions. So
1652
+ * for us, its worthwhile to take something like:
1653
+ *
1654
+ * switch (x) {
1655
+ * case 1: foo(A.B); break;
1656
+ * case 2: foo(C); break;
1657
+ * case 3: bar(A.B); break;
1658
+ * }
1659
+ *
1660
+ * and rewrite it as
1661
+ *
1662
+ * var tmp = A.B;
1663
+ * switch (x) {
1664
+ * case 1: foo(tmp); break;
1665
+ * case 2: foo(C); break;
1666
+ * case 3: bar(tmp); break;
1667
+ * }
1668
+ *
1669
+ * because even though A.B wasn't used on all paths where we
1670
+ * inserted the temporary, we still reduced the code size.
1671
+ */
1672
+ const logging = false;
1673
+ function declFullName(decl) {
1674
+ switch (decl.type) {
1675
+ case "Literal":
1676
+ return decl.raw || decl.value?.toString() || "null";
1677
+ case "VariableDeclarator":
1678
+ return decl.fullName;
1679
+ default:
1680
+ throw new Error(`Unexpected EventDecl type: ${decl.type}`);
1681
+ }
1682
+ }
1683
+ function declName(decl) {
1684
+ switch (decl.type) {
1685
+ case "Literal":
1686
+ return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
1687
+ case "VariableDeclarator":
1688
+ return decl.name;
1689
+ default:
1690
+ throw new Error(`Unexpected EventDecl type: ${decl.type}`);
1691
+ }
1692
+ }
1693
+ function pre_sizeBasedPRE(state, func) {
1694
+ if (!func.node.body)
1695
+ return;
1696
+ if (!state.config ||
1697
+ !state.config.sizeBasedPRE ||
1698
+ (typeof state.config.sizeBasedPRE === "string" &&
1699
+ state.config.sizeBasedPRE !== func.fullName)) {
1700
+ return;
1701
+ }
1702
+ const { graph: head, identifiers } = buildPREGraph(state, func);
1703
+ const candidates = computeAttributes(head);
1704
+ if (candidates) {
1705
+ if (logging) {
1706
+ console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
1707
+ candidates.forEach((s, decl) => {
1708
+ const defs = Array.from(s.ant).reduce((defs, event) => {
1709
+ if (event.type === "def")
1710
+ defs++;
1711
+ return defs;
1712
+ }, 0);
1713
+ console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live`);
1714
+ });
1715
+ }
1716
+ const nodeMap = new Map();
1717
+ const declMap = new Map();
1718
+ const variableDecl = withLoc({
1719
+ type: "VariableDeclaration",
1720
+ declarations: [],
1721
+ kind: "var",
1722
+ }, func.node.body);
1723
+ variableDecl.end = variableDecl.start;
1724
+ variableDecl.loc.end = variableDecl.loc.start;
1725
+ candidates.forEach((s, decl) => {
1726
+ let name;
1727
+ let i = 0;
1728
+ do {
1729
+ name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
1730
+ if (!identifiers.has(name))
1731
+ break;
1732
+ i++;
1733
+ } while (true);
1734
+ declMap.set(decl, name);
1735
+ variableDecl.declarations.push(withLoc({
1736
+ type: "VariableDeclarator",
1737
+ id: withLoc({ type: "Identifier", name }, variableDecl),
1738
+ kind: "var",
1739
+ }, variableDecl));
1740
+ s.ant.forEach((event) => {
1741
+ const events = nodeMap.get(event.node);
1742
+ if (!events) {
1743
+ nodeMap.set(event.node, [event]);
1744
+ }
1745
+ else {
1746
+ events.push(event);
1747
+ }
1748
+ });
1749
+ });
1750
+ applyReplacements(func.node, nodeMap, declMap);
1751
+ func.node.body.body.unshift(variableDecl);
1752
+ }
1753
+ }
1754
+ function unhandledExpression(node) {
1755
+ throw new Error(`Unhandled expression type: ${node.type}`);
1756
+ }
1757
+ function buildPREGraph(state, func) {
1758
+ const findDecl = (node) => {
1759
+ if (node.type === "Identifier" ||
1760
+ (node.type === "MemberExpression" && !node.computed)) {
1761
+ const [, results] = state.lookup(node);
1762
+ if (results &&
1763
+ results.length === 1 &&
1764
+ results[0].parent?.type != "BlockStatement" &&
1765
+ results[0].results.length === 1 &&
1766
+ results[0].results[0].type === "VariableDeclarator") {
1767
+ return results[0].results[0];
1768
+ }
1769
+ }
1770
+ return null;
1771
+ };
1772
+ const literals = new Map();
1773
+ const identifiers = new Set();
1774
+ const liveDefs = new Map();
1775
+ const liveStmts = new Map();
1776
+ const liveDef = (def, stmt) => {
1777
+ let curNodes = liveDefs.get(def);
1778
+ if (!curNodes) {
1779
+ liveDefs.set(def, (curNodes = new Set()));
1780
+ }
1781
+ curNodes.add(stmt);
1782
+ let defs = liveStmts.get(stmt);
1783
+ if (!defs) {
1784
+ liveStmts.set(stmt, (defs = new Map()));
1785
+ }
1786
+ defs.set(def, (defs.get(def) || 0) + 1);
1787
+ };
1788
+ return {
1789
+ identifiers,
1790
+ graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
1791
+ const defs = liveStmts.get(node);
1792
+ if (defs) {
1793
+ liveStmts.delete(node);
1794
+ defs.forEach((count, def) => {
1795
+ if (count > 1) {
1796
+ defs.set(def, count--);
1797
+ return;
1798
+ }
1799
+ const v = liveDefs.get(def);
1800
+ if (!v || !v.has(node)) {
1801
+ throw new Error(`No stmt in liveDef for ${def ? declFullName(def) : "null"}`);
1802
+ }
1803
+ v.delete(node);
1804
+ if (!v.size) {
1805
+ liveDefs.delete(def);
1806
+ }
1807
+ });
1808
+ }
1809
+ switch (node.type) {
1810
+ case "BinaryExpression":
1811
+ case "UnaryExpression":
1812
+ case "SizedArrayExpression":
1813
+ case "ArrayExpression":
1814
+ case "ObjectExpression":
1815
+ case "ThisExpression":
1816
+ case "LogicalExpression":
1817
+ case "ConditionalExpression":
1818
+ case "SequenceExpression":
1819
+ case "ParenthesizedExpression":
1820
+ break;
1821
+ case "Literal":
1822
+ if (!node.value && refCost(node) > LocalRefCost) {
1823
+ let decl = literals.get(node.value);
1824
+ if (!decl) {
1825
+ decl = node;
1826
+ literals.set(node.value, decl);
1827
+ }
1828
+ return {
1829
+ type: "ref",
1830
+ node,
1831
+ decl: decl,
1832
+ mayThrow,
1833
+ };
1834
+ }
1835
+ break;
1836
+ case "Identifier":
1837
+ identifiers.add(node.name);
1838
+ // fall through
1839
+ case "MemberExpression":
1840
+ {
1841
+ const decl = findDecl(node);
1842
+ if (decl && decl.type === "VariableDeclarator") {
1843
+ const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
1844
+ liveDefs.get(decl);
1845
+ if (defStmts) {
1846
+ break;
1847
+ /*
1848
+ // hold off on this for now. we need to communicate
1849
+ // which defs need to be fixed, which involves yet-another
1850
+ // table.
1851
+
1852
+ if (defStmts.size !== 1) break;
1853
+ const fixable = isFixableStmt([...defStmts][0]);
1854
+ if (fixable === false) break;
1855
+ cost += fixable;
1856
+ */
1857
+ }
1858
+ return {
1859
+ type: "ref",
1860
+ node,
1861
+ decl,
1862
+ mayThrow,
1863
+ };
1864
+ }
1865
+ }
1866
+ break;
1867
+ case "VariableDeclarator": {
1868
+ const decl = findDecl(node.id.type === "BinaryExpression" ? node.id.left : node.id);
1869
+ if (decl) {
1870
+ liveDef(decl, stmt);
1871
+ return {
1872
+ type: "def",
1873
+ node,
1874
+ decl,
1875
+ mayThrow,
1876
+ };
1877
+ }
1878
+ break;
1879
+ }
1880
+ case "AssignmentExpression": {
1881
+ const decl = findDecl(node.left);
1882
+ if (decl) {
1883
+ liveDef(decl, stmt);
1884
+ return {
1885
+ type: "def",
1886
+ node,
1887
+ decl,
1888
+ mayThrow,
1889
+ };
1890
+ }
1891
+ break;
1892
+ }
1893
+ case "UpdateExpression": {
1894
+ const decl = findDecl(node.argument);
1895
+ if (decl) {
1896
+ liveDef(decl, stmt);
1897
+ return {
1898
+ type: "def",
1899
+ node,
1900
+ decl,
1901
+ mayThrow,
1902
+ };
1903
+ }
1904
+ break;
1905
+ }
1906
+ case "NewExpression":
1907
+ case "CallExpression":
1908
+ liveDef(null, stmt);
1909
+ return { type: "mod", node, mayThrow };
1910
+ default:
1911
+ if (!isExpression(node))
1912
+ break;
1913
+ unhandledExpression(node);
1914
+ }
1915
+ if (mayThrow) {
1916
+ return { type: "exn", node, mayThrow };
1917
+ }
1918
+ return null;
1919
+ }),
1920
+ };
1921
+ }
1922
+ function anticipatedDecls() {
1923
+ return new Map();
1924
+ }
1925
+ function cloneSet(ae) {
1926
+ return new Set(ae);
1927
+ }
1928
+ function mergeSet(a, b) {
1929
+ b.forEach((event) => a.add(event));
1930
+ }
1931
+ function equalSet(a, b) {
1932
+ if (a.size != b.size)
1933
+ return false;
1934
+ for (const item of a) {
1935
+ if (!b.has(item))
1936
+ return false;
1937
+ }
1938
+ return true;
1939
+ }
1940
+ function equalMap(a, b) {
1941
+ if (a.size != b.size)
1942
+ return false;
1943
+ for (const [item, value] of a) {
1944
+ if (b.get(item) !== value)
1945
+ return false;
1946
+ }
1947
+ return true;
1948
+ }
1949
+ function anticipatedState(node, events) {
1950
+ return { ant: events || new Set(), live: true, node, members: new Map() };
1951
+ }
1952
+ function cloneAnticipatedState(as) {
1953
+ return {
1954
+ ant: cloneSet(as.ant),
1955
+ live: as.live,
1956
+ node: as.node,
1957
+ members: new Map(as.members),
1958
+ };
1959
+ }
1960
+ function cloneAnticipatedDecls(ad) {
1961
+ const copy = anticipatedDecls();
1962
+ for (const [k, v] of ad) {
1963
+ copy.set(k, cloneAnticipatedState(v));
1964
+ }
1965
+ return copy;
1966
+ }
1967
+ function mergeAnticipatedDecls(a, b) {
1968
+ for (const [k, v] of b) {
1969
+ const ae = a.get(k);
1970
+ if (ae) {
1971
+ mergeSet(ae.ant, v.ant);
1972
+ v.members.forEach((live, block) => ae.members.set(block, live));
1973
+ if (v.live)
1974
+ ae.live = true;
1975
+ }
1976
+ else {
1977
+ a.set(k, cloneAnticipatedState(v));
1978
+ }
1979
+ }
1980
+ }
1981
+ function equalStates(a, b) {
1982
+ if (a.size !== b.size)
1983
+ return false;
1984
+ for (const [k, ae] of a) {
1985
+ const be = b.get(k);
1986
+ if (!be ||
1987
+ be.live != ae.live ||
1988
+ !equalSet(ae.ant, be.ant) ||
1989
+ !equalMap(ae.members, be.members)) {
1990
+ return false;
1991
+ }
1992
+ }
1993
+ return true;
1994
+ }
1995
+ const LocalRefCost = 2;
1996
+ function refCost(node) {
1997
+ if (node.type === "Literal") {
1998
+ switch (typeof node.value) {
1999
+ case "string":
2000
+ return 5;
2001
+ case "number":
2002
+ return 5;
2003
+ case "boolean":
2004
+ return 2;
2005
+ default:
2006
+ if (node.value === null) {
2007
+ return 2;
2008
+ }
2009
+ return 0;
2010
+ }
2011
+ }
2012
+ // A read from a non-local identifier takes 8 bytes
2013
+ let cost = 8;
2014
+ if (node.type === "Identifier")
2015
+ return cost;
2016
+ while (true) {
2017
+ const next = node.object;
2018
+ if (next.type != "MemberExpression") {
2019
+ if (next.type != "ThisExpression") {
2020
+ cost += next.type === "Identifier" && next.name === "$" ? 4 : 6;
2021
+ }
2022
+ return cost;
2023
+ }
2024
+ node = next;
2025
+ cost += 6;
2026
+ }
2027
+ }
2028
+ function defCost(node) {
2029
+ return refCost(node) + 2;
2030
+ }
2031
+ function candidateBoundary(candState) {
2032
+ const boundary = new Set();
2033
+ candState.members.forEach((live, block) => {
2034
+ if (live && block !== candState.head) {
2035
+ if (block.preds) {
2036
+ block.preds.forEach((pred) => candState.members.has(pred) || boundary.add(pred));
2037
+ }
2038
+ }
2039
+ });
2040
+ if (candState.live) {
2041
+ if (!candState.head) {
2042
+ throw new Error(`Missing head`);
2043
+ }
2044
+ boundary.add(candState.head);
2045
+ }
2046
+ return boundary;
2047
+ }
2048
+ function candidateCost(candState) {
2049
+ let cost = 0;
2050
+ candState.ant.forEach((event) => {
2051
+ if (event.type === "ref") {
2052
+ cost -= refCost(candState.node) - LocalRefCost;
2053
+ }
2054
+ else {
2055
+ cost += defCost(candState.node);
2056
+ }
2057
+ });
2058
+ cost += defCost(candState.node) * candidateBoundary(candState).size;
2059
+ return cost;
2060
+ }
2061
+ function computeAttributes(head) {
2062
+ const order = getPostOrder(head);
2063
+ order.forEach((block, i) => {
2064
+ block.order = i;
2065
+ });
2066
+ if (logging) {
2067
+ order.forEach((block) => {
2068
+ console.log(block.order, `(${block.node ? block.node.loc?.start.line : "??"})`, `Preds: ${(block.preds || [])
2069
+ .map((block) => block.order)
2070
+ .join(", ")}`);
2071
+ if (block.events) {
2072
+ block.events.forEach((event) => event.type !== "exn" &&
2073
+ console.log(` ${event.type}: ${event.decl ? declFullName(event.decl) : "??"}`));
2074
+ }
2075
+ console.log(`Succs: ${(block.succs || [])
2076
+ .map((block) => block.order)
2077
+ .join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
2078
+ });
2079
+ }
2080
+ const enqueued = new Set();
2081
+ const queue = new PriorityQueue((b, a) => (a.order || 0) - (b.order || 0));
2082
+ const enqueue = (block) => {
2083
+ if (!enqueued.has(block)) {
2084
+ enqueued.add(block);
2085
+ queue.enq(block);
2086
+ }
2087
+ };
2088
+ const dequeue = () => {
2089
+ const block = queue.deq();
2090
+ enqueued.delete(block);
2091
+ return block;
2092
+ };
2093
+ const blockStates = [];
2094
+ /*
2095
+ Algorithm
2096
+ =========
2097
+
2098
+ Process blocks in post-order, and the events in reverse
2099
+ order to collect the AnticipatedState at the start of each
2100
+ Block.
2101
+
2102
+ Then for each EventDecl find the best starting block.
2103
+ */
2104
+ const modMap = new Map();
2105
+ const getMod = (event, decl, id) => {
2106
+ if (id.type !== "Identifier" && id.type !== "MemberExpression") {
2107
+ throw new Error("Trying to modify a non-variable");
2108
+ }
2109
+ let eventMap = modMap.get(event);
2110
+ if (!eventMap) {
2111
+ modMap.set(event, (eventMap = new Map()));
2112
+ }
2113
+ let result = eventMap.get(decl);
2114
+ if (!result) {
2115
+ result = {
2116
+ type: "mod",
2117
+ node: event.node,
2118
+ decl,
2119
+ id,
2120
+ mayThrow: event.mayThrow,
675
2121
  };
2122
+ eventMap.set(decl, result);
676
2123
  }
677
- else if (last.argument) {
678
- const side_exprs = inliner_unused(last.argument);
679
- body.body.splice(body.body.length - 1, 1, ...side_exprs);
2124
+ return result;
2125
+ };
2126
+ order.forEach((block) => enqueue(block));
2127
+ while (queue.size()) {
2128
+ const top = dequeue();
2129
+ if (top.order === undefined) {
2130
+ throw new Error(`Unreachable block was visited!`);
680
2131
  }
681
- else {
682
- --body.body.length;
2132
+ const curState = (top.succs &&
2133
+ top.succs.reduce((blockState, succ) => {
2134
+ const succState = blockStates[succ.order];
2135
+ if (succState) {
2136
+ if (!blockState) {
2137
+ blockState = cloneAnticipatedDecls(succState);
2138
+ }
2139
+ else {
2140
+ mergeAnticipatedDecls(blockState, succState);
2141
+ }
2142
+ }
2143
+ return blockState;
2144
+ }, null)) ||
2145
+ anticipatedDecls();
2146
+ if (top.events) {
2147
+ for (let i = top.events.length; i--;) {
2148
+ const event = top.events[i];
2149
+ if (event.mayThrow && top.exsucc) {
2150
+ const succState = blockStates[top.exsucc.order];
2151
+ if (succState) {
2152
+ mergeAnticipatedDecls(curState, succState);
2153
+ }
2154
+ }
2155
+ switch (event.type) {
2156
+ case "ref": {
2157
+ let candidates = curState.get(event.decl);
2158
+ if (!candidates) {
2159
+ candidates = anticipatedState(event.node);
2160
+ curState.set(event.decl, candidates);
2161
+ }
2162
+ candidates.ant.add(event);
2163
+ candidates.live = true;
2164
+ break;
2165
+ }
2166
+ case "mod": {
2167
+ curState.forEach((candidates, decl) => {
2168
+ if (decl.type === "VariableDeclarator" &&
2169
+ decl.node.kind === "var" &&
2170
+ candidates.live) {
2171
+ candidates.ant.add(getMod(event, decl, candidates.node));
2172
+ candidates.live = false;
2173
+ }
2174
+ });
2175
+ break;
2176
+ }
2177
+ case "def": {
2178
+ let candidates = curState.get(event.decl);
2179
+ const isUpdate = event.node.type === "UpdateExpression" ||
2180
+ (event.node.type === "AssignmentExpression" &&
2181
+ event.node.operator !== "=");
2182
+ if (!candidates) {
2183
+ const target = event.node.type === "AssignmentExpression"
2184
+ ? event.node.left
2185
+ : event.node.type === "UpdateExpression"
2186
+ ? event.node.argument
2187
+ : event.node.id.type === "BinaryExpression"
2188
+ ? event.node.id.left
2189
+ : event.node.id;
2190
+ candidates = anticipatedState(target);
2191
+ curState.set(event.decl, candidates);
2192
+ }
2193
+ if (isUpdate || candidates.live) {
2194
+ candidates.ant.add(event);
2195
+ }
2196
+ if (!isUpdate) {
2197
+ candidates.live = false;
2198
+ }
2199
+ break;
2200
+ }
2201
+ }
2202
+ }
2203
+ }
2204
+ curState.forEach((antState) => {
2205
+ antState.head = top;
2206
+ antState.members.set(top, antState.live);
2207
+ });
2208
+ const oldState = blockStates[top.order];
2209
+ if (oldState && equalStates(oldState, curState)) {
2210
+ continue;
2211
+ }
2212
+ blockStates[top.order] = curState;
2213
+ if (top.preds) {
2214
+ top.preds.forEach((pred) => enqueue(pred));
683
2215
  }
684
2216
  }
685
- return body;
686
- }
687
- function inliner_inlineFunction(state, func, call, context) {
688
- if (context) {
689
- return inlineWithArgs(state, func, call, context);
2217
+ const candidateDecls = anticipatedDecls();
2218
+ blockStates.forEach((blockState, i) => {
2219
+ blockState &&
2220
+ blockState.forEach((events, decl) => {
2221
+ const cost = candidateCost(events);
2222
+ if (cost >= 0)
2223
+ return;
2224
+ const existing = candidateDecls.get(decl);
2225
+ if (!existing || candidateCost(existing) > cost) {
2226
+ const boundary = candidateBoundary(events);
2227
+ if (!Array.from(boundary).every((block) => {
2228
+ if (block !== events.head && block.events) {
2229
+ if (events.node.type === "Literal") {
2230
+ return false;
2231
+ }
2232
+ let i = block.events.length;
2233
+ while (i--) {
2234
+ const event = block.events[i];
2235
+ if (event.type === "def" || event.type === "mod") {
2236
+ events.ant.add({
2237
+ type: "mod",
2238
+ node: event.node,
2239
+ decl,
2240
+ id: events.node,
2241
+ mayThrow: false,
2242
+ });
2243
+ events.members.set(block, false);
2244
+ return true;
2245
+ }
2246
+ }
2247
+ }
2248
+ const node = block.node;
2249
+ if (!node)
2250
+ return false;
2251
+ events.ant.add({
2252
+ type: "mod",
2253
+ node: node.type === "FunctionDeclaration" ? node.body : node,
2254
+ before: true,
2255
+ decl,
2256
+ id: events.node,
2257
+ mayThrow: false,
2258
+ });
2259
+ events.members.set(block, false);
2260
+ return true;
2261
+ })) {
2262
+ return;
2263
+ }
2264
+ events.live = false;
2265
+ if (candidateCost(events) != cost) {
2266
+ throw new Error(`cost of block ${i} changed`);
2267
+ }
2268
+ candidateDecls.set(decl, events);
2269
+ }
2270
+ });
2271
+ });
2272
+ if (candidateDecls.size) {
2273
+ return candidateDecls;
690
2274
  }
691
- const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
692
- const params = Object.fromEntries(func.node.params.map((param, i) => [variableDeclarationName(param), i]));
693
- const map = fixupLocalsMap(state);
694
- const ret = processInlineBody(state, func, call, retArg, params);
695
- state.localsStack[state.localsStack.length - 1].map = map;
696
- return ret;
2275
+ return null;
697
2276
  }
698
- function applyTypeIfNeeded(node) {
699
- if ("enumType" in node && node.enumType) {
700
- node = {
701
- type: "BinaryExpression",
702
- operator: "as",
703
- left: node,
704
- right: { type: "TypeSpecList", ts: [node.enumType] },
705
- };
2277
+ /*
2278
+ * Determine the cost of fixing a def under a statement.
2279
+ *
2280
+ * eg:
2281
+ *
2282
+ * if (foo()) {
2283
+ * bar(X.y);
2284
+ * } else {
2285
+ * baz(X.y);
2286
+ * }
2287
+ *
2288
+ * Here, we could pull out X.y as a local, but if foo might modify
2289
+ * X.y, we have nowhere to insert the temporary. But we can rewrite
2290
+ * it as:
2291
+ *
2292
+ * var tmp = foo();
2293
+ * if (tmp) {
2294
+ * bar(X.y);
2295
+ * } else {
2296
+ * baz(X.y);
2297
+ * }
2298
+ *
2299
+ * and now we can insert a temporary before the if, but it costs
2300
+ * 4 bytes to do so.
2301
+ *
2302
+ * We can do the same for switch statements unless (ugh!)
2303
+ * the cases might modify the decl too.
2304
+ *
2305
+ * eg
2306
+ *
2307
+ * switch (foo()) {
2308
+ * case bar(): ...
2309
+ * }
2310
+ *
2311
+ */
2312
+ function _isFixableStmt(node) {
2313
+ switch (node.type) {
2314
+ case "IfStatement":
2315
+ return 4;
2316
+ case "SwitchStatement":
2317
+ if (node.cases.every((c) => !c.test ||
2318
+ c.test.type === "Literal" ||
2319
+ c.test.type === "Identifier" ||
2320
+ c.test.type === "InstanceOfCase" ||
2321
+ (c.test.type === "UnaryExpression" && c.test.operator === ":"))) {
2322
+ return 4;
2323
+ }
2324
+ break;
706
2325
  }
707
- return node;
2326
+ return false;
708
2327
  }
709
- function fixNodeScope(state, lookupNode, nodeStack) {
710
- if (lookupNode.type === "Identifier") {
711
- const locals = state.localsStack[state.localsStack.length - 1];
712
- const { map } = locals;
713
- if (!map)
714
- throw new Error("No local variable map!");
715
- if (hasProperty(map, lookupNode.name) && map[lookupNode.name] !== false) {
716
- // map[name] !== false means its an entry that was created during inlining
717
- // so its definitely one of our locals.
718
- return lookupNode;
2328
+ function applyReplacements(func, nodeMap, declMap) {
2329
+ const ident = (name, node) => {
2330
+ return withLoc({ type: "Identifier", name }, node);
2331
+ };
2332
+ const pendingMap = new Map();
2333
+ const stmtStack = [func];
2334
+ traverseAst(func, (node) => {
2335
+ if (isStatement(node)) {
2336
+ stmtStack.push(node);
719
2337
  }
720
- }
721
- const [, original] = state.lookup(lookupNode, null, nodeStack);
722
- if (!original) {
723
- return null;
724
- }
725
- const [, current] = state.lookup(lookupNode);
726
- // For now, leave it alone if it already maps to the same thing.
727
- // With a bit more work, we could find the guaranteed shortest
728
- // reference, and then use this to optimize *all* symbols, not
729
- // just fix inlined ones.
730
- if (current && sameLookupResult(original, current)) {
731
- return lookupNode;
732
- }
733
- const node = lookupNode.type === "Identifier"
734
- ? lookupNode
735
- : lookupNode.property;
736
- if (original.length === 1 &&
737
- original[0].results.length === 1 &&
738
- original[0].results[0].type === "EnumStringMember") {
739
- return applyTypeIfNeeded(original[0].results[0].init);
740
- }
741
- const prefixes = original
742
- .map((lookupDef) => lookupDef.results.map((sn) => {
743
- if (isStateNode(sn) && sn.fullName) {
744
- return sn.fullName;
2338
+ }, (node) => {
2339
+ const stmt = stmtStack[stmtStack.length - 1];
2340
+ if (stmt === node)
2341
+ stmtStack.pop();
2342
+ const events = nodeMap.get(node);
2343
+ if (events) {
2344
+ if (events.length === 1) {
2345
+ if (events[0].type === "ref") {
2346
+ if (node.type !== "Identifier" &&
2347
+ node.type !== "MemberExpression" &&
2348
+ node.type !== "Literal") {
2349
+ throw new Error(`Ref found, but wrong type of node: ${node.type}`);
2350
+ }
2351
+ const name = declMap.get(events[0].decl);
2352
+ if (!name) {
2353
+ throw new Error(`No replacement found for "${formatAst(node)}"`);
2354
+ }
2355
+ return ident(name, node);
2356
+ }
2357
+ else if (events[0].type === "def") {
2358
+ if (node.type !== "AssignmentExpression" &&
2359
+ node.type !== "UpdateExpression") {
2360
+ throw new Error(`Def found, but wrong type of node: ${node.type}`);
2361
+ }
2362
+ const target = node.type === "AssignmentExpression"
2363
+ ? node.left
2364
+ : node.argument;
2365
+ const name = declMap.get(events[0].decl);
2366
+ if (!name) {
2367
+ throw new Error(`No replacement found for "${formatAst(target)}"`);
2368
+ }
2369
+ const id = ident(name, target);
2370
+ const assign = withLoc({
2371
+ type: "AssignmentExpression",
2372
+ left: target,
2373
+ right: { ...id },
2374
+ operator: "=",
2375
+ }, node);
2376
+ if (node.type === "AssignmentExpression") {
2377
+ node.left = id;
2378
+ }
2379
+ else {
2380
+ node.argument = id;
2381
+ }
2382
+ return withLoc({ type: "SequenceExpression", expressions: [node, assign] }, node);
2383
+ }
2384
+ }
2385
+ events.forEach((event) => {
2386
+ if (event.type !== "mod") {
2387
+ throw new Error(`Unexpected ${event.type} found amongst multiple events`);
2388
+ }
2389
+ if (!event.decl) {
2390
+ throw new Error(`Unexpected null decl on mod event`);
2391
+ }
2392
+ let pending = pendingMap.get(stmt);
2393
+ if (!pending) {
2394
+ pendingMap.set(stmt, (pending = new Set()));
2395
+ }
2396
+ pending.add(event);
2397
+ });
745
2398
  }
746
- return "";
747
- }))
748
- .flat();
749
- const member = (object, property) => ({
750
- type: "MemberExpression",
751
- object,
752
- property,
753
- computed: false,
754
- start: node.start,
755
- end: node.end,
756
- loc: node.loc,
757
- });
758
- if (prefixes.length &&
759
- prefixes[0].startsWith("$.") &&
760
- prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
761
- const prefix = prefixes[0].split(".").slice(0, -1).reverse();
762
- let found = false;
763
- return prefix.reduce((current, name) => {
764
- if (found)
765
- return current;
766
- const [, results] = state.lookup(current);
767
- if (results && sameLookupResult(original, results)) {
768
- found = true;
769
- return current;
2399
+ const pending = pendingMap.get(node);
2400
+ if (node.type === "SequenceExpression") {
2401
+ if (pending) {
2402
+ throw new Error(`Unexpected pending list at SequenceExpression`);
770
2403
  }
771
- const object = {
772
- type: "Identifier",
773
- name,
774
- start: node.start,
775
- end: node.end,
776
- loc: node.loc,
777
- };
778
- let root = null;
779
- let property = current;
780
- do {
781
- root = property;
782
- property = property.object;
783
- } while (property.type === "MemberExpression");
784
- if (property.type === "ThisExpression") {
785
- root.object = object;
786
- return root;
2404
+ for (let i = node.expressions.length; i--;) {
2405
+ const ni = node.expressions[i];
2406
+ if (ni.type === "SequenceExpression") {
2407
+ node.expressions.splice(i, 1, ...ni.expressions);
2408
+ }
787
2409
  }
788
- root.object = member(object, property);
789
- return current;
790
- }, member({
791
- type: "ThisExpression",
792
- text: "self",
793
- start: node.start,
794
- end: node.end,
795
- loc: node.loc,
796
- }, node));
797
- }
798
- return null;
2410
+ }
2411
+ const applyPending = (results, locNode) => {
2412
+ const target = results.length === 1 && results[0].type === "BlockStatement"
2413
+ ? results[0]
2414
+ : null;
2415
+ pendingMap.delete(node);
2416
+ pending.forEach((event) => {
2417
+ const decl = event.decl;
2418
+ const name = declMap.get(decl);
2419
+ if (!name) {
2420
+ throw new Error(`No replacement found for "${declFullName(decl)}"`);
2421
+ }
2422
+ if (!event.id) {
2423
+ throw new Error(`Missing id for mod event for "${declFullName(decl)}"`);
2424
+ }
2425
+ const rhs = withLocDeep(event.id, locNode, locNode);
2426
+ rhs.end = rhs.start;
2427
+ if (rhs.loc) {
2428
+ rhs.loc.end = rhs.loc.start;
2429
+ }
2430
+ const insertion = withLoc({
2431
+ type: "ExpressionStatement",
2432
+ expression: withLoc({
2433
+ type: "AssignmentExpression",
2434
+ left: ident(name, rhs),
2435
+ right: rhs,
2436
+ operator: "=",
2437
+ }, rhs),
2438
+ }, rhs);
2439
+ if (event.type === "mod" && event.before) {
2440
+ if (target) {
2441
+ target.body.unshift(insertion);
2442
+ }
2443
+ else {
2444
+ results.unshift(insertion);
2445
+ }
2446
+ }
2447
+ else {
2448
+ results.push(insertion);
2449
+ }
2450
+ });
2451
+ return results.length === 1 ? null : results;
2452
+ };
2453
+ if (node.type === "ExpressionStatement" &&
2454
+ node.expression.type === "SequenceExpression") {
2455
+ const results = [];
2456
+ node.expression.expressions.forEach((expression) => {
2457
+ results.push({ ...node, expression });
2458
+ });
2459
+ if (!pending) {
2460
+ return results;
2461
+ }
2462
+ return applyPending(results, node);
2463
+ }
2464
+ if (pending) {
2465
+ return applyPending([node], node);
2466
+ }
2467
+ return null;
2468
+ });
799
2469
  }
800
2470
 
801
- ;// CONCATENATED MODULE: external "./util.cjs"
802
- const external_util_cjs_namespaceObject = require("./util.cjs");
803
2471
  ;// CONCATENATED MODULE: ./src/visitor.ts
804
2472
 
805
2473
  function visitor_visitReferences(state, ast, name, defn, callback) {
@@ -902,6 +2570,7 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
902
2570
 
903
2571
 
904
2572
 
2573
+
905
2574
  function collectClassInfo(state) {
906
2575
  const toybox = state.stack[0].decls["Toybox"][0];
907
2576
  const lang = toybox.decls["Lang"][0];
@@ -1203,7 +2872,50 @@ function getNodeValue(node) {
1203
2872
  }
1204
2873
  return [node, type];
1205
2874
  }
1206
- function optimizeNode(node) {
2875
+ function fullTypeName(state, tsp) {
2876
+ if (typeof tsp.name === "string") {
2877
+ return tsp.name;
2878
+ }
2879
+ const [, results] = state.lookupType(tsp.name);
2880
+ if (results && results.length === 1 && results[0].results.length === 1) {
2881
+ const result = results[0].results[0];
2882
+ if (isStateNode(result)) {
2883
+ return result.fullName;
2884
+ }
2885
+ }
2886
+ return null;
2887
+ }
2888
+ function isBooleanExpression(state, node) {
2889
+ switch (node.type) {
2890
+ case "Literal":
2891
+ return typeof node.value === "boolean";
2892
+ case "BinaryExpression":
2893
+ switch (node.operator) {
2894
+ case "==":
2895
+ case "!=":
2896
+ case "<=":
2897
+ case ">=":
2898
+ case "<":
2899
+ case ">":
2900
+ return true;
2901
+ case "as":
2902
+ return node.right.ts.length === 1 &&
2903
+ node.right.ts[0].type === "TypeSpecPart" &&
2904
+ node.right.ts[0].name &&
2905
+ fullTypeName(state, node.right.ts[0]) === "$.Toybox.Lang.Boolean"
2906
+ ? true
2907
+ : false;
2908
+ }
2909
+ return false;
2910
+ case "LogicalExpression":
2911
+ return (isBooleanExpression(state, node.left) &&
2912
+ isBooleanExpression(state, node.right));
2913
+ case "UnaryExpression":
2914
+ return node.operator === "!" && isBooleanExpression(state, node.argument);
2915
+ }
2916
+ return false;
2917
+ }
2918
+ function optimizeNode(state, node) {
1207
2919
  switch (node.type) {
1208
2920
  case "UnaryExpression": {
1209
2921
  const [arg, type] = getNodeValue(node.argument);
@@ -1255,8 +2967,18 @@ function optimizeNode(node) {
1255
2967
  "%": (left, right) => left % right,
1256
2968
  "&": (left, right, type) => type === "Number" ? left & right : null,
1257
2969
  "|": (left, right, type) => type === "Number" ? left | right : null,
2970
+ "^": (left, right, type) => type === "Number" ? left ^ right : null,
1258
2971
  "<<": (left, right, type) => type === "Number" ? left << right : null,
1259
2972
  ">>": (left, right, type) => type === "Number" ? left >> right : null,
2973
+ "==": (left, right) => left == right,
2974
+ "!=": (left, right) => left != right,
2975
+ "<=": (left, right) => left <= right,
2976
+ ">=": (left, right) => left >= right,
2977
+ "<": (left, right) => left < right,
2978
+ ">": (left, right) => left > right,
2979
+ as: null,
2980
+ instanceof: null,
2981
+ has: null,
1260
2982
  };
1261
2983
  const op = operators[node.operator];
1262
2984
  if (op) {
@@ -1264,11 +2986,17 @@ function optimizeNode(node) {
1264
2986
  const [right, right_type] = getNodeValue(node.right);
1265
2987
  if (!left || !right)
1266
2988
  break;
2989
+ let value = null;
1267
2990
  if (left_type != right_type ||
1268
2991
  (left_type != "Number" && left_type != "Long")) {
1269
- break;
2992
+ if (node.operator !== "==" && node.operator !== "!=") {
2993
+ break;
2994
+ }
2995
+ value = operators[node.operator](left.value, right.value);
2996
+ }
2997
+ else {
2998
+ value = op(left.value, right.value, left_type);
1270
2999
  }
1271
- const value = op(left.value, right.value, left_type);
1272
3000
  if (value === null)
1273
3001
  break;
1274
3002
  return {
@@ -1279,15 +3007,47 @@ function optimizeNode(node) {
1279
3007
  }
1280
3008
  break;
1281
3009
  }
3010
+ case "LogicalExpression": {
3011
+ const [left, left_type] = getNodeValue(node.left);
3012
+ if (!left)
3013
+ break;
3014
+ const falsy = left.value === false ||
3015
+ left.value === null ||
3016
+ (left.value === 0 && (left_type === "Number" || left_type === "Long"));
3017
+ if (falsy === (node.operator === "&&")) {
3018
+ return left;
3019
+ }
3020
+ if (left_type !== "Boolean" &&
3021
+ left_type !== "Number" &&
3022
+ left_type !== "Long") {
3023
+ break;
3024
+ }
3025
+ const [right, right_type] = getNodeValue(node.right);
3026
+ if (right && right_type === left_type) {
3027
+ if (left_type === "Boolean" || node.operator === "||") {
3028
+ return right;
3029
+ }
3030
+ if (node.operator !== "&&") {
3031
+ throw new Error(`Unexpected operator "${node.operator}"`);
3032
+ }
3033
+ return { ...node, type: "BinaryExpression", operator: "&" };
3034
+ }
3035
+ if (left_type === "Boolean") {
3036
+ if (isBooleanExpression(state, node.right)) {
3037
+ return node.right;
3038
+ }
3039
+ }
3040
+ break;
3041
+ }
1282
3042
  case "FunctionDeclaration":
1283
- if (node.body && evaluateFunction(node, null) !== false) {
3043
+ if (node.body && evaluateFunction(state, node, null) !== false) {
1284
3044
  node.optimizable = true;
1285
3045
  }
1286
3046
  break;
1287
3047
  }
1288
3048
  return null;
1289
3049
  }
1290
- function evaluateFunction(func, args) {
3050
+ function evaluateFunction(state, func, args) {
1291
3051
  if (!func.body || (args && args.length != func.params.length)) {
1292
3052
  return false;
1293
3053
  }
@@ -1326,7 +3086,7 @@ function evaluateFunction(func, args) {
1326
3086
  }
1327
3087
  // fall through;
1328
3088
  default: {
1329
- const repl = optimizeNode(node);
3089
+ const repl = optimizeNode(state, node);
1330
3090
  if (repl && repl.type === "Literal")
1331
3091
  return repl;
1332
3092
  throw new Error("Didn't optimize");
@@ -1386,10 +3146,19 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
1386
3146
  if (!objects) {
1387
3147
  return false;
1388
3148
  }
1389
- const obj = getLiteralFromDecls(objects);
3149
+ let obj = getLiteralFromDecls(objects);
1390
3150
  if (!obj) {
1391
3151
  return false;
1392
3152
  }
3153
+ while (obj.type === "BinaryExpression") {
3154
+ if (obj.left.type === "BinaryExpression" && obj.left.operator === "as") {
3155
+ obj = { ...obj, left: obj.left.left };
3156
+ }
3157
+ else {
3158
+ obj = { ...obj, left: { ...obj.left } };
3159
+ break;
3160
+ }
3161
+ }
1393
3162
  inPlaceReplacement(node, obj);
1394
3163
  return true;
1395
3164
  };
@@ -1607,14 +3376,20 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
1607
3376
  return null;
1608
3377
  };
1609
3378
  state.post = (node) => {
1610
- if (topLocals().node === node) {
3379
+ const locals = topLocals();
3380
+ if (locals.node === node) {
1611
3381
  state.localsStack.pop();
1612
3382
  }
1613
- const opt = optimizeNode(node);
3383
+ const opt = optimizeNode(state, node);
1614
3384
  if (opt) {
1615
3385
  return replace(opt, node);
1616
3386
  }
1617
3387
  switch (node.type) {
3388
+ case "BlockStatement":
3389
+ if (node.body.length === 1 && node.body[0].type === "BlockStatement") {
3390
+ node.body.splice(0, 1, ...node.body[0].body);
3391
+ }
3392
+ break;
1618
3393
  case "ConditionalExpression":
1619
3394
  case "IfStatement":
1620
3395
  if (node.test.type === "Literal" &&
@@ -1624,6 +3399,12 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
1624
3399
  return false;
1625
3400
  return replace(rep, rep);
1626
3401
  }
3402
+ else if (node.type === "IfStatement" &&
3403
+ node.alternate &&
3404
+ node.alternate.type === "BlockStatement" &&
3405
+ !node.alternate.body.length) {
3406
+ delete node.alternate;
3407
+ }
1627
3408
  break;
1628
3409
  case "WhileStatement":
1629
3410
  if (node.test.type === "Literal" && node.test.value === false) {
@@ -1651,6 +3432,48 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
1651
3432
  return { type: "Literal", value: null, raw: "null" };
1652
3433
  }
1653
3434
  break;
3435
+ case "VariableDeclaration": {
3436
+ const locals = topLocals();
3437
+ if (locals.map &&
3438
+ locals.node &&
3439
+ locals.node.type === "BlockStatement") {
3440
+ let results;
3441
+ const declarations = node.declarations;
3442
+ let i = 0;
3443
+ let j = 0;
3444
+ while (i < node.declarations.length) {
3445
+ const decl = declarations[i++];
3446
+ if (decl.init && decl.init.type === "CallExpression") {
3447
+ const inlined = optimizeCall(state, decl.init, decl);
3448
+ if (!inlined)
3449
+ continue;
3450
+ if (inlined.type != "BlockStatement") {
3451
+ throw new Error("Unexpected inlined result");
3452
+ }
3453
+ if (!results) {
3454
+ results = [];
3455
+ }
3456
+ delete decl.init;
3457
+ results.push(withLoc({
3458
+ ...node,
3459
+ declarations: declarations.slice(j, i),
3460
+ }, j ? declarations[j] : null, decl.id));
3461
+ results.push(inlined);
3462
+ j = i;
3463
+ }
3464
+ }
3465
+ if (results) {
3466
+ if (j < i) {
3467
+ results.push({
3468
+ ...node,
3469
+ declarations: declarations.slice(j, i),
3470
+ });
3471
+ }
3472
+ return results;
3473
+ }
3474
+ }
3475
+ break;
3476
+ }
1654
3477
  case "ExpressionStatement":
1655
3478
  if (node.expression.type === "CallExpression") {
1656
3479
  return replace(optimizeCall(state, node.expression, node), node.expression);
@@ -1695,6 +3518,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
1695
3518
  });
1696
3519
  delete state.pre;
1697
3520
  delete state.post;
3521
+ state.allFunctions.forEach((fn) => sizeBasedPRE(state, fn));
1698
3522
  const cleanup = (node) => {
1699
3523
  switch (node.type) {
1700
3524
  case "ThisExpression":
@@ -1820,7 +3644,7 @@ function optimizeCall(state, node, context) {
1820
3644
  callee.optimizable &&
1821
3645
  !callee.hasOverride &&
1822
3646
  node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
1823
- const ret = evaluateFunction(callee, node.arguments);
3647
+ const ret = evaluateFunction(state, callee, node.arguments);
1824
3648
  if (ret) {
1825
3649
  return ret;
1826
3650
  }
@@ -1980,11 +3804,8 @@ async function api_getApiMapping(state, barrelList) {
1980
3804
  return null;
1981
3805
  }
1982
3806
  }
1983
- function api_hasProperty(obj, prop) {
1984
- return obj ? Object.prototype.hasOwnProperty.call(obj, prop) : false;
1985
- }
1986
3807
  function api_isStateNode(node) {
1987
- return api_hasProperty(node, "node");
3808
+ return ast_hasProperty(node, "node");
1988
3809
  }
1989
3810
  function api_variableDeclarationName(node) {
1990
3811
  return ("left" in node ? node.left : node).name;
@@ -2004,7 +3825,7 @@ function checkOne(state, ns, decls, node, isStatic) {
2004
3825
  }
2005
3826
  return cls.superClass.reduce((result, sup) => {
2006
3827
  const sdecls = sup[decls];
2007
- const next = api_hasProperty(sdecls, node.name)
3828
+ const next = ast_hasProperty(sdecls, node.name)
2008
3829
  ? sdecls[node.name]
2009
3830
  : superChain(sup);
2010
3831
  return next ? (result ? result.concat(next) : next) : result;
@@ -2029,7 +3850,7 @@ function checkOne(state, ns, decls, node, isStatic) {
2029
3850
  };
2030
3851
  if (api_isStateNode(ns)) {
2031
3852
  const ndecls = ns[decls];
2032
- if (api_hasProperty(ndecls, node.name)) {
3853
+ if (ast_hasProperty(ndecls, node.name)) {
2033
3854
  return ndecls[node.name];
2034
3855
  }
2035
3856
  switch (ns.type) {
@@ -2309,7 +4130,7 @@ function api_collectNamespaces(ast, stateIn) {
2309
4130
  if (name) {
2310
4131
  if (!parent.decls)
2311
4132
  parent.decls = {};
2312
- if (api_hasProperty(parent.decls, name)) {
4133
+ if (ast_hasProperty(parent.decls, name)) {
2313
4134
  const what = node.type == "ModuleDeclaration" ? "type" : "node";
2314
4135
  const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
2315
4136
  if (e != null) {
@@ -2335,7 +4156,7 @@ function api_collectNamespaces(ast, stateIn) {
2335
4156
  elm.decls = { [name]: [elm] };
2336
4157
  if (!parent.type_decls)
2337
4158
  parent.type_decls = {};
2338
- if (!api_hasProperty(parent.type_decls, name)) {
4159
+ if (!ast_hasProperty(parent.type_decls, name)) {
2339
4160
  parent.type_decls[name] = [];
2340
4161
  }
2341
4162
  parent.type_decls[name].push(elm);
@@ -2359,7 +4180,7 @@ function api_collectNamespaces(ast, stateIn) {
2359
4180
  const [parent] = state.stack.slice(-1);
2360
4181
  if (!parent.type_decls)
2361
4182
  parent.type_decls = {};
2362
- if (!api_hasProperty(parent.type_decls, name)) {
4183
+ if (!ast_hasProperty(parent.type_decls, name)) {
2363
4184
  parent.type_decls[name] = [];
2364
4185
  }
2365
4186
  else if (parent.type_decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == node)) {
@@ -2383,7 +4204,7 @@ function api_collectNamespaces(ast, stateIn) {
2383
4204
  const stack = state.stackClone();
2384
4205
  node.declarations.forEach((decl) => {
2385
4206
  const name = api_variableDeclarationName(decl.id);
2386
- if (!api_hasProperty(decls, name)) {
4207
+ if (!ast_hasProperty(decls, name)) {
2387
4208
  decls[name] = [];
2388
4209
  }
2389
4210
  else if (decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == decl)) {
@@ -2398,7 +4219,7 @@ function api_collectNamespaces(ast, stateIn) {
2398
4219
  stack,
2399
4220
  });
2400
4221
  if (node.kind == "const") {
2401
- if (!api_hasProperty(state.index, name)) {
4222
+ if (!ast_hasProperty(state.index, name)) {
2402
4223
  state.index[name] = [];
2403
4224
  }
2404
4225
  (0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
@@ -2444,11 +4265,11 @@ function api_collectNamespaces(ast, stateIn) {
2444
4265
  prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
2445
4266
  prev = init.value;
2446
4267
  }
2447
- if (!api_hasProperty(values, name)) {
4268
+ if (!ast_hasProperty(values, name)) {
2448
4269
  values[name] = [];
2449
4270
  }
2450
4271
  (0,external_util_cjs_namespaceObject.pushUnique)(values[name], m);
2451
- if (!api_hasProperty(state.index, name)) {
4272
+ if (!ast_hasProperty(state.index, name)) {
2452
4273
  state.index[name] = [];
2453
4274
  }
2454
4275
  (0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
@@ -2499,7 +4320,7 @@ function api_collectNamespaces(ast, stateIn) {
2499
4320
  }
2500
4321
  }
2501
4322
  }
2502
- if (ret === false) {
4323
+ if (ret != null) {
2503
4324
  state.removeNodeComments(node, ast);
2504
4325
  }
2505
4326
  return ret;
@@ -2588,7 +4409,7 @@ function findUsing(state, stack, using) {
2588
4409
  find(node.object);
2589
4410
  name = node.property.name;
2590
4411
  }
2591
- if (api_hasProperty(module.decls, name)) {
4412
+ if (ast_hasProperty(module.decls, name)) {
2592
4413
  const decls = module.decls[name];
2593
4414
  if (decls &&
2594
4415
  decls.length === 1 &&
@@ -2611,7 +4432,7 @@ function findUsing(state, stack, using) {
2611
4432
  function findUsingForNode(state, stack, i, node, isType) {
2612
4433
  while (i >= 0) {
2613
4434
  const si = stack[i--];
2614
- if (api_hasProperty(si.usings, node.name)) {
4435
+ if (ast_hasProperty(si.usings, node.name)) {
2615
4436
  const using = si.usings[node.name];
2616
4437
  const module = findUsing(state, stack, using);
2617
4438
  return module && [module];
@@ -2621,7 +4442,7 @@ function findUsingForNode(state, stack, i, node, isType) {
2621
4442
  const using = si.imports[j];
2622
4443
  const module = findUsing(state, stack, using);
2623
4444
  if (module) {
2624
- if (api_hasProperty(module.type_decls, node.name)) {
4445
+ if (ast_hasProperty(module.type_decls, node.name)) {
2625
4446
  return module.type_decls[node.name];
2626
4447
  }
2627
4448
  }
@@ -2631,6 +4452,8 @@ function findUsingForNode(state, stack, i, node, isType) {
2631
4452
  return null;
2632
4453
  }
2633
4454
 
4455
+ })();
4456
+
2634
4457
  var __webpack_export_target__ = exports;
2635
4458
  for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i];
2636
4459
  if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });