@markw65/monkeyc-optimizer 1.0.30 → 1.0.33

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.
@@ -10977,6 +10977,7 @@ function simulateProgram(prg, device, test = false, logger) {
10977
10977
  }
10978
10978
 
10979
10979
  ;// CONCATENATED MODULE: ./src/ast.ts
10980
+
10980
10981
  /*
10981
10982
  * This ensures that mctreeTypeInfo has every key of MCTreeTypeInfo,
10982
10983
  * and that the corresponding arrays contain every element of the
@@ -11163,18 +11164,185 @@ function withLoc(node, start, end) {
11163
11164
  }
11164
11165
  return node;
11165
11166
  }
11166
- function withLocDeep(node, start, end) {
11167
- node = withLoc({ ...node }, start, end);
11167
+ function withLocDeep(node, start, end, inplace) {
11168
+ node = withLoc(inplace ? node : { ...node }, start, end);
11168
11169
  for (const key of mctreeTypeInfo[node.type].keys) {
11169
11170
  const value = node[key];
11170
11171
  if (!value)
11171
11172
  continue;
11172
- const fix = (v) => isMCTreeNode(v) ? withLocDeep(v, start, end) : v;
11173
+ const fix = (v) => isMCTreeNode(v) ? withLocDeep(v, start, end, inplace) : v;
11173
11174
  const repl = Array.isArray(value) ? value.map(fix) : fix(value);
11174
- node[key] = repl;
11175
+ inplace || (node[key] = repl);
11175
11176
  }
11176
11177
  return node;
11177
11178
  }
11179
+ function cloneDeep(node) {
11180
+ return withLocDeep(node, null);
11181
+ }
11182
+ function getNodeValue(node) {
11183
+ if (node.type == "BinaryExpression" &&
11184
+ node.operator == "as" &&
11185
+ node.right.type == "TypeSpecList" &&
11186
+ node.right.ts.length == 1 &&
11187
+ typeof node.right.ts[0] == "string") {
11188
+ // this is a cast we inserted to retain the type of an enum
11189
+ // any arithmetic on it will revert to "Number", or "Long",
11190
+ // so just ignore it.
11191
+ return getNodeValue(node.left);
11192
+ }
11193
+ if (node.type != "Literal") {
11194
+ return [null, null];
11195
+ }
11196
+ if (node.value === null) {
11197
+ return [node, "Null"];
11198
+ }
11199
+ const type = typeof node.value;
11200
+ if (type === "number") {
11201
+ const match = prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.exec(node.raw);
11202
+ if (match) {
11203
+ return match[2] === "l" || match[2] === "L"
11204
+ ? [node, "Long"]
11205
+ : [node, "Number"];
11206
+ }
11207
+ return [node, node.raw.endsWith("d") ? "Double" : "Float"];
11208
+ }
11209
+ if (type === "bigint") {
11210
+ return [node, "Long"];
11211
+ }
11212
+ if (type === "string") {
11213
+ return [node, "String"];
11214
+ }
11215
+ if (type === "boolean") {
11216
+ return [node, "Boolean"];
11217
+ }
11218
+ throw new Error(`Literal has unknown type '${type}'`);
11219
+ }
11220
+
11221
+ ;// CONCATENATED MODULE: ./src/function-info.ts
11222
+
11223
+ function cloneSet(ae) {
11224
+ return new Set(ae);
11225
+ }
11226
+ function mergeSet(a, b) {
11227
+ b.forEach((event) => a.add(event));
11228
+ }
11229
+ function recordModifiedDecl(func, decl) {
11230
+ if (!func.next_info) {
11231
+ func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
11232
+ }
11233
+ func.next_info.modifiedDecls.add(decl);
11234
+ return null;
11235
+ }
11236
+ function recordModifiedDecls(func, lookupDefs) {
11237
+ lookupDefs.forEach((lookupDef) => lookupDef.results.forEach((result) => {
11238
+ if (result.type == "VariableDeclarator" && result.node.kind === "var") {
11239
+ recordModifiedDecl(func, result);
11240
+ }
11241
+ }));
11242
+ }
11243
+ function recordModifiedName(func, name) {
11244
+ if (!func.next_info) {
11245
+ func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
11246
+ }
11247
+ if (!func.next_info.modifiedNames) {
11248
+ func.next_info.modifiedNames = new Set();
11249
+ }
11250
+ func.next_info.modifiedNames.add(name);
11251
+ }
11252
+ function recordModifiedUnknown(func) {
11253
+ if (!func.next_info) {
11254
+ func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
11255
+ }
11256
+ func.next_info.modifiedUnknown = true;
11257
+ }
11258
+ function recordCalledFunc(func, callee) {
11259
+ if (!func.next_info) {
11260
+ func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
11261
+ }
11262
+ func.next_info.calledFuncs.add(callee);
11263
+ return null;
11264
+ }
11265
+ function recordCalledFuncs(func, callees) {
11266
+ callees.forEach((callee) => {
11267
+ recordCalledFunc(func, callee);
11268
+ });
11269
+ }
11270
+ function functionMayModify(state, func, decl) {
11271
+ const info = func.info;
11272
+ if (!info || info.modifiedUnknown)
11273
+ return true;
11274
+ if (info.resolvedDecls) {
11275
+ return info.resolvedDecls.has(decl);
11276
+ }
11277
+ if (info.modifiedNames?.has(decl.name))
11278
+ return true;
11279
+ if (info.modifiedDecls.has(decl))
11280
+ return true;
11281
+ const visited = new Set();
11282
+ const resolved = new Set();
11283
+ const resolveDecls = (f) => {
11284
+ if (visited.has(f))
11285
+ return true;
11286
+ if (!f.info)
11287
+ return false;
11288
+ if (f.info.modifiedUnknown) {
11289
+ info.modifiedUnknown = true;
11290
+ return false;
11291
+ }
11292
+ if (f.info.modifiedNames) {
11293
+ if (info.modifiedNames) {
11294
+ mergeSet(info.modifiedNames, f.info.modifiedNames);
11295
+ }
11296
+ else {
11297
+ info.modifiedNames = cloneSet(f.info.modifiedNames);
11298
+ }
11299
+ }
11300
+ mergeSet(resolved, f.info.modifiedDecls);
11301
+ visited.add(f);
11302
+ const q = true;
11303
+ if (q &&
11304
+ f.info.callsExposed &&
11305
+ state.exposed &&
11306
+ !Object.keys(state.exposed).every((key) => !state.allFunctions[key] ||
11307
+ state.allFunctions[key].every(resolveDecls))) {
11308
+ return false;
11309
+ }
11310
+ return Array.from(f.info.calledFuncs).every(resolveDecls);
11311
+ };
11312
+ if (resolveDecls(func)) {
11313
+ info.resolvedDecls = resolved;
11314
+ return resolved.has(decl);
11315
+ }
11316
+ return true;
11317
+ }
11318
+ function findCallees(lookupDefs) {
11319
+ const decls = lookupDefs.reduce((decls, r) => (decls ? decls.concat(r.results) : r.results), null);
11320
+ return (decls &&
11321
+ decls.filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
11322
+ }
11323
+ function findCalleesForNew(lookupDefs) {
11324
+ const initializer = (decl) => {
11325
+ if (hasProperty(decl.decls, "initialize")) {
11326
+ return decl.decls["initialize"];
11327
+ }
11328
+ if (decl.superClass && decl.superClass !== true) {
11329
+ return decl.superClass.reduce((cur, cls) => {
11330
+ const init = initializer(cls);
11331
+ if (init) {
11332
+ if (!cur)
11333
+ return init;
11334
+ return cur.concat(init);
11335
+ }
11336
+ return cur;
11337
+ }, null);
11338
+ }
11339
+ return null;
11340
+ };
11341
+ return lookupDefs.flatMap((r) => r.results
11342
+ .filter((decl) => decl.type === "ClassDeclaration")
11343
+ .flatMap(initializer)
11344
+ .filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
11345
+ }
11178
11346
 
11179
11347
  ;// CONCATENATED MODULE: ./src/variable-renamer.ts
11180
11348
 
@@ -11236,6 +11404,7 @@ function renameVariable(state, locals, declName) {
11236
11404
 
11237
11405
 
11238
11406
 
11407
+
11239
11408
  function getArgSafety(state, func, args, requireAll) {
11240
11409
  // determine whether decl might be changed by a function call
11241
11410
  // or assignment during the evaluation of FunctionStateNode.
@@ -11268,8 +11437,9 @@ function getArgSafety(state, func, args, requireAll) {
11268
11437
  }
11269
11438
  };
11270
11439
  const safeArgs = [];
11440
+ const argDecls = [];
11271
11441
  let allSafe = true;
11272
- if (!args.every((arg) => {
11442
+ if (!args.every((arg, i) => {
11273
11443
  switch (arg.type) {
11274
11444
  case "Literal":
11275
11445
  safeArgs.push(true);
@@ -11283,13 +11453,17 @@ function getArgSafety(state, func, args, requireAll) {
11283
11453
  safeArgs.push(null);
11284
11454
  return !requireAll;
11285
11455
  }
11286
- const safety = getSafety(results[0].results[0]);
11456
+ const decl = results[0].results[0];
11457
+ const safety = getSafety(decl);
11287
11458
  safeArgs.push(safety);
11288
11459
  if (!safety) {
11289
11460
  allSafe = false;
11290
11461
  if (safety === null) {
11291
11462
  return !requireAll;
11292
11463
  }
11464
+ else if (decl.type === "VariableDeclarator") {
11465
+ argDecls[i] = decl;
11466
+ }
11293
11467
  }
11294
11468
  return true;
11295
11469
  }
@@ -11302,34 +11476,91 @@ function getArgSafety(state, func, args, requireAll) {
11302
11476
  }
11303
11477
  if (allSafe && requireAll)
11304
11478
  return true;
11305
- let callSeen = false;
11479
+ const callsSeen = new Set();
11480
+ const modifiedDecls = new Set();
11481
+ let modifiedUnknown = false;
11306
11482
  const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
11307
11483
  // look for uses of "unsafe" args that occur after a call.
11308
11484
  // use post to do the checking, because arguments are evaluated
11309
11485
  // prior to the call, so eg "return f(x.y);" is fine, but
11310
11486
  // "return f()+x.y" is not.
11311
- traverseAst(func.node.body, null, (node) => {
11312
- switch (node.type) {
11313
- case "AssignmentExpression":
11314
- case "UpdateExpression": {
11315
- const v = node.type == "UpdateExpression" ? node.argument : node.left;
11316
- if (v.type === "Identifier" && (0,external_api_cjs_namespaceObject.hasProperty)(params, v.name)) {
11317
- safeArgs[params[v.name]] = null;
11487
+ const { pre, post, stack } = state;
11488
+ try {
11489
+ delete state.pre;
11490
+ state.post = (node) => {
11491
+ switch (node.type) {
11492
+ case "AssignmentExpression":
11493
+ case "UpdateExpression": {
11494
+ const v = node.type == "UpdateExpression" ? node.argument : node.left;
11495
+ if (v.type === "Identifier" && (0,external_api_cjs_namespaceObject.hasProperty)(params, v.name)) {
11496
+ // If a parameter is modified, we can't just substitute the
11497
+ // argument wherever the parameter is used.
11498
+ safeArgs[params[v.name]] = null;
11499
+ break;
11500
+ }
11501
+ if (modifiedUnknown)
11502
+ break;
11503
+ const [, results] = state.lookup(v);
11504
+ if (results) {
11505
+ results.forEach((r) => r.results.forEach((decl) => decl.type === "VariableDeclarator" && modifiedDecls.add(decl)));
11506
+ }
11507
+ else {
11508
+ modifiedUnknown = true;
11509
+ }
11510
+ break;
11318
11511
  }
11512
+ case "CallExpression":
11513
+ case "NewExpression":
11514
+ if (!modifiedUnknown) {
11515
+ const [, results] = state.lookup(node.callee, null,
11516
+ // calls are looked up as non-locals, but new is not
11517
+ node.type === "CallExpression" ? func.stack : state.stack);
11518
+ if (!results) {
11519
+ const callee_name = node.callee.type === "Identifier"
11520
+ ? node.callee
11521
+ : node.callee.type === "MemberExpression"
11522
+ ? (0,external_api_cjs_namespaceObject.isLookupCandidate)(node.callee)
11523
+ : null;
11524
+ if (callee_name) {
11525
+ const callees = state.allFunctions[callee_name.name];
11526
+ if (callees) {
11527
+ callees.forEach((callee) => callsSeen.add(callee));
11528
+ }
11529
+ }
11530
+ else {
11531
+ modifiedUnknown = true;
11532
+ }
11533
+ }
11534
+ else {
11535
+ const callees = node.type === "CallExpression"
11536
+ ? findCallees(results)
11537
+ : findCalleesForNew(results);
11538
+ if (callees) {
11539
+ callees.forEach((callee) => callsSeen.add(callee));
11540
+ }
11541
+ }
11542
+ }
11543
+ break;
11544
+ case "Identifier":
11545
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(params, node.name) &&
11546
+ !safeArgs[params[node.name]] &&
11547
+ (modifiedUnknown ||
11548
+ !argDecls[params[node.name]] ||
11549
+ modifiedDecls.has(argDecls[params[node.name]]) ||
11550
+ Array.from(callsSeen).some((callee) => functionMayModify(state, callee, argDecls[params[node.name]])))) {
11551
+ safeArgs[params[node.name]] = null;
11552
+ }
11319
11553
  }
11320
- // fall through
11321
- case "CallExpression":
11322
- case "NewExpression":
11323
- callSeen = true;
11324
- break;
11325
- case "Identifier":
11326
- if (callSeen &&
11327
- (0,external_api_cjs_namespaceObject.hasProperty)(params, node.name) &&
11328
- !safeArgs[params[node.name]]) {
11329
- safeArgs[params[node.name]] = null;
11330
- }
11331
- }
11332
- });
11554
+ return null;
11555
+ };
11556
+ state.stack = func.stack;
11557
+ state.traverse(func.node.body);
11558
+ }
11559
+ finally {
11560
+ state.pre = pre;
11561
+ state.post = post;
11562
+ state.stack = stack;
11563
+ }
11333
11564
  return safeArgs;
11334
11565
  }
11335
11566
  function canInline(state, func, args) {
@@ -11434,9 +11665,6 @@ function processInlineBody(state, func, call, root, params) {
11434
11665
  state.pre = (node) => {
11435
11666
  if (failed)
11436
11667
  return [];
11437
- node.start = call.start;
11438
- node.end = call.end;
11439
- node.loc = call.loc;
11440
11668
  if (replacements.has(node))
11441
11669
  return false;
11442
11670
  const result = pre(node, state);
@@ -11451,6 +11679,7 @@ function processInlineBody(state, func, call, root, params) {
11451
11679
  if (params[paramName] >= 0)
11452
11680
  return null;
11453
11681
  const name = renameVariable(state, locals, paramName) || paramName;
11682
+ locals.map[name] = true;
11454
11683
  return {
11455
11684
  type: "VariableDeclarator",
11456
11685
  id: { type: "Identifier", name },
@@ -11469,31 +11698,49 @@ function processInlineBody(state, func, call, root, params) {
11469
11698
  }
11470
11699
  return result;
11471
11700
  };
11701
+ const fixId = (node) => {
11702
+ if (state.inType)
11703
+ return null;
11704
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(params, node.name)) {
11705
+ const ix = params[node.name];
11706
+ if (ix >= 0) {
11707
+ const replacement = { ...call.arguments[ix] };
11708
+ replacements.add(replacement);
11709
+ return replacement;
11710
+ }
11711
+ return null;
11712
+ }
11713
+ const replacement = fixNodeScope(state, node, func.stack);
11714
+ if (!replacement) {
11715
+ failed = true;
11716
+ inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
11717
+ }
11718
+ return replacement;
11719
+ };
11472
11720
  state.post = (node) => {
11473
11721
  if (failed)
11474
11722
  return post(node, state);
11475
11723
  let replacement = null;
11476
11724
  switch (node.type) {
11477
- case "Identifier": {
11478
- if (state.inType)
11479
- break;
11480
- if ((0,external_api_cjs_namespaceObject.hasProperty)(params, node.name)) {
11481
- const ix = params[node.name];
11482
- if (ix >= 0) {
11483
- replacement = { ...call.arguments[ix] };
11484
- replacements.add(replacement);
11485
- return replacement;
11725
+ case "AssignmentExpression":
11726
+ if (node.left.type === "Identifier") {
11727
+ const rep = fixId(node.left);
11728
+ if (rep) {
11729
+ node.left = rep;
11486
11730
  }
11487
- break;
11488
11731
  }
11489
- replacement = fixNodeScope(state, node, func.stack);
11490
- if (!replacement) {
11491
- failed = true;
11492
- inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
11493
- return post(node, state);
11732
+ break;
11733
+ case "UpdateExpression":
11734
+ if (node.argument.type === "Identifier") {
11735
+ const rep = fixId(node.argument);
11736
+ if (rep) {
11737
+ node.argument = rep;
11738
+ }
11494
11739
  }
11495
11740
  break;
11496
- }
11741
+ case "Identifier":
11742
+ replacement = fixId(node);
11743
+ break;
11497
11744
  }
11498
11745
  const ret = post(replacement || node, state);
11499
11746
  return ret === false || ret ? ret : replacement;
@@ -11662,7 +11909,7 @@ function inlineWithArgs(state, func, call, context) {
11662
11909
  }
11663
11910
  }
11664
11911
  }
11665
- const body = JSON.parse(JSON.stringify(func.node.body));
11912
+ const body = cloneDeep(func.node.body);
11666
11913
  const safeArgs = getArgSafety(state, func, call.arguments, false);
11667
11914
  const params = Object.fromEntries(func.node.params.map((param, i) => {
11668
11915
  const argnum = safeArgs === true || (safeArgs !== false && safeArgs[i] !== null)
@@ -11711,18 +11958,19 @@ function inlineWithArgs(state, func, call, context) {
11711
11958
  --block.body.length;
11712
11959
  }
11713
11960
  }
11961
+ withLocDeep(body, context, context, true);
11714
11962
  return body;
11715
11963
  }
11716
11964
  function inlineFunction(state, func, call, context) {
11717
11965
  if (context) {
11718
11966
  return inlineWithArgs(state, func, call, context);
11719
11967
  }
11720
- const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
11968
+ const retArg = cloneDeep(func.node.body.body[0].argument);
11721
11969
  const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
11722
11970
  const map = fixupLocalsMap(state);
11723
11971
  const ret = processInlineBody(state, func, call, retArg, params);
11724
11972
  state.localsStack[state.localsStack.length - 1].map = map;
11725
- return ret;
11973
+ return ret && withLocDeep(ret, call, call, true);
11726
11974
  }
11727
11975
  function applyTypeIfNeeded(node) {
11728
11976
  if ("enumType" in node && node.enumType) {
@@ -11827,6 +12075,121 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11827
12075
  return null;
11828
12076
  }
11829
12077
 
12078
+ ;// CONCATENATED MODULE: ./src/pragma-checker.ts
12079
+
12080
+
12081
+
12082
+ function pragmaChecker(state, ast, diagnostics) {
12083
+ const comments = ast.comments;
12084
+ if (!comments)
12085
+ return;
12086
+ diagnostics = diagnostics
12087
+ ?.slice()
12088
+ .sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
12089
+ let diagIndex = 0;
12090
+ let index = -1;
12091
+ let comment;
12092
+ let matchers;
12093
+ const next = () => {
12094
+ while (++index < comments.length) {
12095
+ comment = comments[index];
12096
+ let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
12097
+ if (!match)
12098
+ continue;
12099
+ const kind = match[1];
12100
+ let str = match[2];
12101
+ matchers = [];
12102
+ while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
12103
+ matchers.push({ kind, quote: match[1], needle: match[2] });
12104
+ str = str.substring(match[0].length);
12105
+ if (!str.length)
12106
+ break;
12107
+ }
12108
+ if (!str.length)
12109
+ break;
12110
+ if (!matchers.length) {
12111
+ match = str.match(/^(\S+)\s+$/);
12112
+ if (match) {
12113
+ matchers.push({ kind, quote: '"', needle: match[1] });
12114
+ break;
12115
+ }
12116
+ }
12117
+ diagnostic(state, comment.loc, `Build pragma '${comment.value}' is invalid`, "ERROR");
12118
+ }
12119
+ };
12120
+ const matcher = (quote, needle, haystack) => {
12121
+ if (quote == '"') {
12122
+ return haystack.includes(needle);
12123
+ }
12124
+ const re = new RegExp(needle.replace(/@(\d+)/g, "(pre_)?$1(_\\d+)?"));
12125
+ return re.test(haystack);
12126
+ };
12127
+ next();
12128
+ traverseAst(ast, (node) => {
12129
+ if (index >= comments.length)
12130
+ return false;
12131
+ if (node.start && node.start >= (comment.end || Infinity)) {
12132
+ const { kind, quote, needle } = matchers.shift();
12133
+ if (kind === "match") {
12134
+ const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " ");
12135
+ if (!matcher(quote, needle, haystack)) {
12136
+ matcher(quote, needle, haystack);
12137
+ diagnostic(state, comment.loc, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
12138
+ }
12139
+ }
12140
+ else if (kind === "expect") {
12141
+ const locCmp = (a, b) => {
12142
+ if (!b)
12143
+ return -1;
12144
+ if (a.start.line < b.start.line)
12145
+ return -1;
12146
+ if (a.start.line === b.start.line &&
12147
+ a.start.column < b.start.column) {
12148
+ return -1;
12149
+ }
12150
+ if (a.end.line > b.end.line)
12151
+ return 1;
12152
+ if (a.end.line === b.end.line && a.end.column >= b.end.column) {
12153
+ return 1;
12154
+ }
12155
+ return 0;
12156
+ };
12157
+ let found = false;
12158
+ if (diagnostics) {
12159
+ while (true) {
12160
+ if (diagIndex >= diagnostics.length) {
12161
+ diagnostics = null;
12162
+ break;
12163
+ }
12164
+ const diag = diagnostics[diagIndex];
12165
+ const cmp = locCmp(diag.loc, node.loc);
12166
+ if (cmp > 0) {
12167
+ break;
12168
+ }
12169
+ diagIndex++;
12170
+ if (cmp < 0)
12171
+ continue;
12172
+ if (matcher(quote, needle, diag.message)) {
12173
+ found = true;
12174
+ diag.type = "INFO";
12175
+ }
12176
+ }
12177
+ }
12178
+ if (!found) {
12179
+ diagnostic(state, comment.loc, `Missing error message '${needle}`, "ERROR");
12180
+ }
12181
+ }
12182
+ if (matchers.length) {
12183
+ // if we're checking a series of nodes, we need
12184
+ // to skip over this one.
12185
+ return false;
12186
+ }
12187
+ next();
12188
+ }
12189
+ return null;
12190
+ });
12191
+ }
12192
+
11830
12193
  ;// CONCATENATED MODULE: ./src/control-flow.ts
11831
12194
 
11832
12195
 
@@ -12347,6 +12710,7 @@ var priorityqueuejs = __webpack_require__(2789);
12347
12710
 
12348
12711
 
12349
12712
 
12713
+
12350
12714
  /**
12351
12715
  * This implements a pseudo Partial Redundancy Elimination
12352
12716
  * pass. It isn't quite like traditional PRE because we're
@@ -12416,7 +12780,7 @@ function sizeBasedPRE(state, func) {
12416
12780
  return;
12417
12781
  }
12418
12782
  const { graph: head, identifiers } = buildPREGraph(state, func);
12419
- const candidates = computeAttributes(head);
12783
+ const candidates = computeAttributes(state, head);
12420
12784
  if (candidates) {
12421
12785
  if (logging) {
12422
12786
  console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
@@ -12436,8 +12800,10 @@ function sizeBasedPRE(state, func) {
12436
12800
  let i = 0;
12437
12801
  do {
12438
12802
  name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
12439
- if (!identifiers.has(name))
12803
+ if (!identifiers.has(name)) {
12804
+ identifiers.add(name);
12440
12805
  break;
12806
+ }
12441
12807
  i++;
12442
12808
  } while (true);
12443
12809
  declMap.set(decl, name);
@@ -12528,11 +12894,16 @@ function buildPREGraph(state, func) {
12528
12894
  case "ParenthesizedExpression":
12529
12895
  break;
12530
12896
  case "Literal":
12531
- if (!node.value && refCost(node) > LocalRefCost) {
12532
- let decl = literals.get(node.value);
12897
+ if (refCost(node) > LocalRefCost) {
12898
+ const result = getNodeValue(node);
12899
+ const key = result[1] +
12900
+ (result[0].value === null
12901
+ ? ""
12902
+ : "-" + result[0].value.toString());
12903
+ let decl = literals.get(key);
12533
12904
  if (!decl) {
12534
12905
  decl = node;
12535
- literals.set(node.value, decl);
12906
+ literals.set(key, decl);
12536
12907
  }
12537
12908
  return {
12538
12909
  type: "ref",
@@ -12612,10 +12983,18 @@ function buildPREGraph(state, func) {
12612
12983
  }
12613
12984
  break;
12614
12985
  }
12615
- case "NewExpression":
12616
- case "CallExpression":
12986
+ case "NewExpression": {
12987
+ const [, results] = state.lookup(node.callee);
12988
+ const callees = results ? findCalleesForNew(results) : null;
12989
+ liveDef(null, stmt);
12990
+ return { type: "mod", node, mayThrow, callees };
12991
+ }
12992
+ case "CallExpression": {
12617
12993
  liveDef(null, stmt);
12618
- return { type: "mod", node, mayThrow };
12994
+ const [, results] = state.lookup(node.callee);
12995
+ const callees = results ? findCallees(results) : null;
12996
+ return { type: "mod", node, mayThrow, callees };
12997
+ }
12619
12998
  default:
12620
12999
  if (!isExpression(node))
12621
13000
  break;
@@ -12631,12 +13010,6 @@ function buildPREGraph(state, func) {
12631
13010
  function anticipatedDecls() {
12632
13011
  return new Map();
12633
13012
  }
12634
- function cloneSet(ae) {
12635
- return new Set(ae);
12636
- }
12637
- function mergeSet(a, b) {
12638
- b.forEach((event) => a.add(event));
12639
- }
12640
13013
  function equalSet(a, b) {
12641
13014
  if (a.size != b.size)
12642
13015
  return false;
@@ -12715,6 +13088,7 @@ function refCost(node) {
12715
13088
  switch (typeof node.value) {
12716
13089
  case "string":
12717
13090
  return 5;
13091
+ case "bigint":
12718
13092
  case "number":
12719
13093
  return 5;
12720
13094
  case "boolean":
@@ -12776,7 +13150,7 @@ function candidateCost(candState) {
12776
13150
  cost += defCost(candState.node) * boundarySize;
12777
13151
  return cost;
12778
13152
  }
12779
- function computeAttributes(head) {
13153
+ function computeAttributes(state, head) {
12780
13154
  const order = getPostOrder(head);
12781
13155
  order.forEach((block, i) => {
12782
13156
  block.order = i;
@@ -12885,7 +13259,9 @@ function computeAttributes(head) {
12885
13259
  curState.forEach((candidates, decl) => {
12886
13260
  if (decl.type === "VariableDeclarator" &&
12887
13261
  decl.node.kind === "var" &&
12888
- candidates.live) {
13262
+ candidates.live &&
13263
+ (!event.callees ||
13264
+ event.callees.some((callee) => functionMayModify(state, callee, decl)))) {
12889
13265
  candidates.ant.add(getMod(event, decl, candidates.node));
12890
13266
  candidates.live = false;
12891
13267
  }
@@ -13074,20 +13450,26 @@ function applyReplacements(func, nodeMap, declMap) {
13074
13450
  stmtStack.pop();
13075
13451
  const events = nodeMap.get(node);
13076
13452
  if (events) {
13077
- if (events.length === 1) {
13078
- if (events[0].type === "ref") {
13453
+ const ret = events.reduce((ret, event) => {
13454
+ if (event.type === "ref") {
13455
+ if (ret) {
13456
+ throw new Error(`ref found when there was already a replacement for this node`);
13457
+ }
13079
13458
  if (node.type !== "Identifier" &&
13080
13459
  node.type !== "MemberExpression" &&
13081
13460
  node.type !== "Literal") {
13082
13461
  throw new Error(`Ref found, but wrong type of node: ${node.type}`);
13083
13462
  }
13084
- const name = declMap.get(events[0].decl);
13463
+ const name = declMap.get(event.decl);
13085
13464
  if (!name) {
13086
13465
  throw new Error(`No replacement found for "${(0,external_api_cjs_namespaceObject.formatAst)(node)}"`);
13087
13466
  }
13088
13467
  return ident(name, node);
13089
13468
  }
13090
- else if (events[0].type === "def") {
13469
+ if (event.type === "def") {
13470
+ if (ret) {
13471
+ throw new Error(`def found when there was already a replacement for this node`);
13472
+ }
13091
13473
  if (node.type !== "AssignmentExpression" &&
13092
13474
  node.type !== "UpdateExpression") {
13093
13475
  throw new Error(`Def found, but wrong type of node: ${node.type}`);
@@ -13095,7 +13477,7 @@ function applyReplacements(func, nodeMap, declMap) {
13095
13477
  const target = node.type === "AssignmentExpression"
13096
13478
  ? node.left
13097
13479
  : node.argument;
13098
- const name = declMap.get(events[0].decl);
13480
+ const name = declMap.get(event.decl);
13099
13481
  if (!name) {
13100
13482
  throw new Error(`No replacement found for "${(0,external_api_cjs_namespaceObject.formatAst)(target)}"`);
13101
13483
  }
@@ -13114,20 +13496,24 @@ function applyReplacements(func, nodeMap, declMap) {
13114
13496
  }
13115
13497
  return withLoc({ type: "SequenceExpression", expressions: [node, assign] }, node);
13116
13498
  }
13117
- }
13118
- events.forEach((event) => {
13119
- if (event.type !== "mod") {
13120
- throw new Error(`Unexpected ${event.type} found amongst multiple events`);
13121
- }
13122
- if (!event.decl) {
13123
- throw new Error(`Unexpected null decl on mod event`);
13499
+ if (event.type === "mod") {
13500
+ if (!event.decl) {
13501
+ throw new Error(`Unexpected null decl on mod event`);
13502
+ }
13503
+ let pending = pendingMap.get(stmt);
13504
+ if (!pending) {
13505
+ pendingMap.set(stmt, (pending = new Set()));
13506
+ }
13507
+ pending.add(event);
13124
13508
  }
13125
- let pending = pendingMap.get(stmt);
13126
- if (!pending) {
13127
- pendingMap.set(stmt, (pending = new Set()));
13509
+ else {
13510
+ throw new Error(`Unexpected ${event.type} found`);
13128
13511
  }
13129
- pending.add(event);
13130
- });
13512
+ return ret;
13513
+ }, null);
13514
+ if (ret) {
13515
+ return ret;
13516
+ }
13131
13517
  }
13132
13518
  const pending = pendingMap.get(node);
13133
13519
  if (node.type === "SequenceExpression") {
@@ -13201,6 +13587,148 @@ function applyReplacements(func, nodeMap, declMap) {
13201
13587
  });
13202
13588
  }
13203
13589
 
13590
+ ;// CONCATENATED MODULE: ./src/unused-exprs.ts
13591
+
13592
+
13593
+
13594
+ function cleanupUnusedVars(state, node) {
13595
+ const [parent] = state.stack.slice(-1);
13596
+ if (parent.node !== node) {
13597
+ return;
13598
+ }
13599
+ if (parent.type != "BlockStatement") {
13600
+ throw new Error(`Unexpected parent type '${parent.type}' for local declaration`);
13601
+ }
13602
+ if (parent.decls) {
13603
+ let toRemove = null;
13604
+ Object.values(parent.decls).forEach((decls) => {
13605
+ if (decls.length === 1 &&
13606
+ decls[0].type === "VariableDeclarator" &&
13607
+ !decls[0].used) {
13608
+ if (!toRemove)
13609
+ toRemove = {};
13610
+ toRemove[decls[0].name] = decls[0];
13611
+ }
13612
+ });
13613
+ if (toRemove) {
13614
+ const varDeclarations = new Map();
13615
+ traverseAst(node, null, (node) => {
13616
+ switch (node.type) {
13617
+ case "VariableDeclaration": {
13618
+ node.declarations.forEach((decl, i) => {
13619
+ const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id);
13620
+ if (hasProperty(toRemove, name)) {
13621
+ const indices = varDeclarations.get(node);
13622
+ if (indices) {
13623
+ indices.push(i);
13624
+ }
13625
+ else {
13626
+ varDeclarations.set(node, [i]);
13627
+ }
13628
+ }
13629
+ });
13630
+ break;
13631
+ }
13632
+ case "ExpressionStatement":
13633
+ if (node.expression.type === "AssignmentExpression") {
13634
+ if (node.expression.left.type === "Identifier" &&
13635
+ hasProperty(toRemove, node.expression.left.name)) {
13636
+ return unused(node.expression.right);
13637
+ }
13638
+ }
13639
+ else if (node.expression.type === "UpdateExpression" &&
13640
+ node.expression.argument.type === "Identifier" &&
13641
+ hasProperty(toRemove, node.expression.argument.name)) {
13642
+ return false;
13643
+ }
13644
+ break;
13645
+ case "SequenceExpression": {
13646
+ for (let i = node.expressions.length; i--;) {
13647
+ const expr = node.expressions[i];
13648
+ if (expr.type === "AssignmentExpression") {
13649
+ if (expr.left.type === "Identifier" &&
13650
+ hasProperty(toRemove, expr.left.name)) {
13651
+ const rep = unused(expr.right);
13652
+ if (!rep.length) {
13653
+ node.expressions.splice(i, 1);
13654
+ }
13655
+ else {
13656
+ // Sequence expressions can only be assignments
13657
+ // or update expressions. Even calls aren't allowed
13658
+ toRemove[expr.left.name] = null;
13659
+ expr.operator = "=";
13660
+ }
13661
+ }
13662
+ }
13663
+ else if (expr.type === "UpdateExpression" &&
13664
+ expr.argument.type === "Identifier" &&
13665
+ hasProperty(toRemove, expr.argument.name)) {
13666
+ node.expressions.splice(i, 1);
13667
+ }
13668
+ }
13669
+ break;
13670
+ }
13671
+ }
13672
+ return null;
13673
+ });
13674
+ varDeclarations.forEach((indices, decl) => {
13675
+ let index = -1;
13676
+ for (let ii = indices.length, j = decl.declarations.length; ii--;) {
13677
+ const i = indices[ii];
13678
+ const vdecl = decl.declarations[i];
13679
+ const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(vdecl.id);
13680
+ if (hasProperty(toRemove, name)) {
13681
+ const rep = vdecl.init ? unused(vdecl.init) : [];
13682
+ if (rep.length) {
13683
+ if (parent.node.type === "ForStatement") {
13684
+ // declarations whose inits have side effects
13685
+ // can't be deleted from for statements.
13686
+ continue;
13687
+ }
13688
+ if (index < 0) {
13689
+ index = parent.node.body.findIndex((s) => s === decl);
13690
+ if (index < 0) {
13691
+ throw new Error(`Failed to find variable declaration for ${(0,external_api_cjs_namespaceObject.variableDeclarationName)(vdecl.id)}`);
13692
+ }
13693
+ }
13694
+ if (j > i + 1) {
13695
+ const tail = {
13696
+ ...decl,
13697
+ declarations: decl.declarations.slice(i + 1, j),
13698
+ };
13699
+ if (decl.loc && vdecl.loc) {
13700
+ tail.loc = { ...decl.loc, start: vdecl.loc.end };
13701
+ tail.start = vdecl.end;
13702
+ }
13703
+ rep.push(tail);
13704
+ }
13705
+ if (decl.loc && vdecl.loc) {
13706
+ decl.loc = { ...decl.loc, end: vdecl.loc.start };
13707
+ decl.end = vdecl.start;
13708
+ }
13709
+ decl.declarations.splice(i);
13710
+ parent.node.body.splice(index + 1, 0, ...rep);
13711
+ j = i;
13712
+ continue;
13713
+ }
13714
+ if (toRemove[name]) {
13715
+ j--;
13716
+ decl.declarations.splice(i, 1);
13717
+ if (i === j && decl.loc && vdecl.loc) {
13718
+ decl.loc = { ...decl.loc, end: vdecl.loc.start };
13719
+ decl.end = vdecl.start;
13720
+ }
13721
+ }
13722
+ else {
13723
+ delete vdecl.init;
13724
+ }
13725
+ }
13726
+ }
13727
+ });
13728
+ }
13729
+ }
13730
+ }
13731
+
13204
13732
  ;// CONCATENATED MODULE: ./src/visitor.ts
13205
13733
 
13206
13734
  function visitReferences(state, ast, name, defn, callback) {
@@ -13265,14 +13793,16 @@ function visitReferences(state, ast, name, defn, callback) {
13265
13793
  return checkResults(state.lookup(node), node);
13266
13794
  }
13267
13795
  break;
13268
- case "MemberExpression":
13269
- if (!node.computed && node.property.type === "Identifier") {
13270
- if (!name || node.property.name === name) {
13796
+ case "MemberExpression": {
13797
+ const property = (0,external_api_cjs_namespaceObject.isLookupCandidate)(node);
13798
+ if (property) {
13799
+ if (!name || property.name === name) {
13271
13800
  return checkResults(state.lookup(node), node) || ["object"];
13272
13801
  }
13273
13802
  return ["object"];
13274
13803
  }
13275
13804
  break;
13805
+ }
13276
13806
  case "MethodDefinition": {
13277
13807
  if (!state.inType) {
13278
13808
  throw new Error("Method definition outside of type!");
@@ -13281,7 +13811,6 @@ function visitReferences(state, ast, name, defn, callback) {
13281
13811
  node.params.forEach((param) => {
13282
13812
  if (param.type == "BinaryExpression") {
13283
13813
  state.traverse(param.right);
13284
- state.inType = true;
13285
13814
  }
13286
13815
  });
13287
13816
  }
@@ -13304,6 +13833,9 @@ function visitReferences(state, ast, name, defn, callback) {
13304
13833
 
13305
13834
 
13306
13835
 
13836
+
13837
+
13838
+
13307
13839
  function collectClassInfo(state) {
13308
13840
  const toybox = state.stack[0].decls["Toybox"][0];
13309
13841
  const lang = toybox.decls["Lang"][0];
@@ -13363,8 +13895,7 @@ function collectClassInfo(state) {
13363
13895
  c.decls &&
13364
13896
  Object.values(c.decls).forEach((funcs) => {
13365
13897
  funcs.forEach((f) => {
13366
- if ((0,external_api_cjs_namespaceObject.isStateNode)(f) &&
13367
- f.type === "FunctionDeclaration" &&
13898
+ if (f.type === "FunctionDeclaration" &&
13368
13899
  (0,external_api_cjs_namespaceObject.hasProperty)(cls.decls, f.name)) {
13369
13900
  f.node.hasOverride = true;
13370
13901
  }
@@ -13377,6 +13908,15 @@ function collectClassInfo(state) {
13377
13908
  state.allClasses.forEach((elm) => {
13378
13909
  if (elm.superClass)
13379
13910
  markOverrides(elm, elm.superClass);
13911
+ if (elm.hasInvoke && elm.decls) {
13912
+ Object.values(elm.decls).forEach((funcs) => {
13913
+ funcs.forEach((f) => {
13914
+ if (f.type === "FunctionDeclaration" && !f.isStatic) {
13915
+ (0,external_api_cjs_namespaceObject.markInvokeClassMethod)(f);
13916
+ }
13917
+ });
13918
+ });
13919
+ }
13380
13920
  });
13381
13921
  }
13382
13922
  function getFileSources(fnMap) {
@@ -13415,7 +13955,7 @@ async function analyze(fnMap, barrelList, config) {
13415
13955
  const preState = {
13416
13956
  fnMap,
13417
13957
  config,
13418
- allFunctions: [],
13958
+ allFunctions: {},
13419
13959
  allClasses: [],
13420
13960
  shouldExclude(node) {
13421
13961
  if ("attrs" in node &&
@@ -13445,11 +13985,6 @@ async function analyze(fnMap, barrelList, config) {
13445
13985
  pre(node, state) {
13446
13986
  switch (node.type) {
13447
13987
  case "FunctionDeclaration":
13448
- if (markApi) {
13449
- node.body = null;
13450
- break;
13451
- }
13452
- // falls through
13453
13988
  case "ModuleDeclaration":
13454
13989
  case "ClassDeclaration": {
13455
13990
  const [scope] = state.stack.slice(-1);
@@ -13460,7 +13995,18 @@ async function analyze(fnMap, barrelList, config) {
13460
13995
  (scope.node.attrs &&
13461
13996
  scope.node.attrs.access &&
13462
13997
  scope.node.attrs.access.includes("static"));
13463
- state.allFunctions.push(scope);
13998
+ if (markApi) {
13999
+ node.body = null;
14000
+ scope.info = (0,external_api_cjs_namespaceObject.getApiFunctionInfo)(scope);
14001
+ delete scope.stack;
14002
+ }
14003
+ const allFuncs = state.allFunctions;
14004
+ if (!(0,external_api_cjs_namespaceObject.hasProperty)(allFuncs, scope.name)) {
14005
+ allFuncs[scope.name] = [scope];
14006
+ }
14007
+ else {
14008
+ allFuncs[scope.name].push(scope);
14009
+ }
13464
14010
  }
13465
14011
  else if (scope.type === "ClassDeclaration") {
13466
14012
  state.allClasses.push(scope);
@@ -13485,7 +14031,7 @@ async function analyze(fnMap, barrelList, config) {
13485
14031
  value.hasTests = hasTests;
13486
14032
  });
13487
14033
  delete state.shouldExclude;
13488
- delete state.post;
14034
+ delete state.pre;
13489
14035
  collectClassInfo(state);
13490
14036
  const diagnosticType = config?.checkInvalidSymbols !== "OFF"
13491
14037
  ? config?.checkInvalidSymbols || "WARNING"
@@ -13508,6 +14054,8 @@ async function analyze(fnMap, barrelList, config) {
13508
14054
  });
13509
14055
  });
13510
14056
  }
14057
+ state.exposed = state.nextExposed;
14058
+ state.nextExposed = {};
13511
14059
  return state;
13512
14060
  }
13513
14061
  function compareLiteralLike(a, b) {
@@ -13553,57 +14101,16 @@ function getLiteralNode(node) {
13553
14101
  if (node.argument.type != "Literal")
13554
14102
  return null;
13555
14103
  switch (node.operator) {
13556
- case "-":
13557
- if (typeof node.argument.value == "number") {
13558
- return {
13559
- ...node.argument,
13560
- value: -node.argument.value,
13561
- raw: "-" + node.argument.value,
13562
- enumType: node.enumType,
13563
- };
14104
+ case "-": {
14105
+ const [arg, type] = getNodeValue(node.argument);
14106
+ if (type === "Number" || type === "Long") {
14107
+ return replacementLiteral(arg, -arg.value, type);
13564
14108
  }
14109
+ }
13565
14110
  }
13566
14111
  }
13567
14112
  return null;
13568
14113
  }
13569
- function getNodeValue(node) {
13570
- if (node.type == "BinaryExpression" &&
13571
- node.operator == "as" &&
13572
- node.right.type == "TypeSpecList" &&
13573
- node.right.ts.length == 1 &&
13574
- typeof node.right.ts[0] == "string") {
13575
- // this is a cast we inserted to retain the type of an enum
13576
- // any arithmetic on it will revert to "Number", or "Long",
13577
- // so just ignore it.
13578
- return getNodeValue(node.left);
13579
- }
13580
- if (node.type != "Literal") {
13581
- return [null, null];
13582
- }
13583
- let type = node.value === null ? "Null" : typeof node.value;
13584
- if (type === "number") {
13585
- const match = node.raw && prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.exec(node.raw);
13586
- if (match) {
13587
- type = match[2] == "l" ? "Long" : "Number";
13588
- }
13589
- else if (node.raw && node.raw.endsWith("d")) {
13590
- type = "Double";
13591
- }
13592
- else {
13593
- type = "Float";
13594
- }
13595
- }
13596
- else if (type === "string") {
13597
- type = "String";
13598
- }
13599
- else if (type === "boolean") {
13600
- type = "Boolean";
13601
- }
13602
- else {
13603
- type = "Unknown";
13604
- }
13605
- return [node, type];
13606
- }
13607
14114
  function fullTypeName(state, tsp) {
13608
14115
  if (typeof tsp.name === "string") {
13609
14116
  return tsp.name;
@@ -13647,6 +14154,46 @@ function isBooleanExpression(state, node) {
13647
14154
  }
13648
14155
  return false;
13649
14156
  }
14157
+ function replacementLiteral(arg, value, type) {
14158
+ if (typeof value === "boolean") {
14159
+ type = "Boolean";
14160
+ }
14161
+ else if (type === "Number") {
14162
+ value = Number(BigInt.asIntN(32, BigInt(value)));
14163
+ }
14164
+ else if (type === "Long") {
14165
+ value = BigInt.asIntN(64, BigInt(value));
14166
+ }
14167
+ return {
14168
+ ...arg,
14169
+ value,
14170
+ raw: value.toString() + (type === "Long" ? "l" : ""),
14171
+ };
14172
+ }
14173
+ const operators = {
14174
+ "+": (left, right) => left + right,
14175
+ "-": (left, right) => left - right,
14176
+ "*": (left, right) => left * right,
14177
+ "/": (left, right) => left / right,
14178
+ "%": (left, right) => left % right,
14179
+ "&": (left, right) => left & right,
14180
+ "|": (left, right) => left | right,
14181
+ "^": (left, right) => left ^ right,
14182
+ "<<": (left, right) => left << (right & 127n),
14183
+ ">>": (left, right) => left >> (right & 127n),
14184
+ "==": (left, right) =>
14185
+ // two string literals will compare unequal, becuase string
14186
+ // equality is object equality.
14187
+ typeof left === "string" ? false : left === right,
14188
+ "!=": (left, right) => typeof left === "string" ? true : left !== right,
14189
+ "<=": (left, right) => left <= right,
14190
+ ">=": (left, right) => left >= right,
14191
+ "<": (left, right) => left < right,
14192
+ ">": (left, right) => left > right,
14193
+ as: null,
14194
+ instanceof: null,
14195
+ has: null,
14196
+ };
13650
14197
  function optimizeNode(state, node) {
13651
14198
  switch (node.type) {
13652
14199
  case "UnaryExpression": {
@@ -13661,29 +14208,17 @@ function optimizeNode(state, node) {
13661
14208
  break;
13662
14209
  case "-":
13663
14210
  if (type === "Number" || type === "Long") {
13664
- return {
13665
- ...arg,
13666
- value: -arg.value,
13667
- raw: (-arg.value).toString() + (type === "Long" ? "l" : ""),
13668
- };
14211
+ return replacementLiteral(arg, -arg.value, type);
13669
14212
  }
13670
14213
  break;
13671
14214
  case "!":
13672
14215
  case "~":
13673
14216
  {
13674
- let value;
13675
14217
  if (type === "Number" || type === "Long") {
13676
- value = -arg.value - 1;
14218
+ return replacementLiteral(arg, ~BigInt(arg.value), type);
13677
14219
  }
13678
- else if (type === "Boolean" && node.operator == "!") {
13679
- value = !arg.value;
13680
- }
13681
- if (value !== undefined) {
13682
- return {
13683
- ...arg,
13684
- value,
13685
- raw: value.toString() + (type === "Long" ? "l" : ""),
13686
- };
14220
+ if (type === "Boolean" && node.operator == "!") {
14221
+ return replacementLiteral(arg, !arg.value, type);
13687
14222
  }
13688
14223
  }
13689
14224
  break;
@@ -13691,27 +14226,6 @@ function optimizeNode(state, node) {
13691
14226
  break;
13692
14227
  }
13693
14228
  case "BinaryExpression": {
13694
- const operators = {
13695
- "+": (left, right) => left + right,
13696
- "-": (left, right) => left - right,
13697
- "*": (left, right) => left * right,
13698
- "/": (left, right) => Math.trunc(left / right),
13699
- "%": (left, right) => left % right,
13700
- "&": (left, right, type) => type === "Number" ? left & right : null,
13701
- "|": (left, right, type) => type === "Number" ? left | right : null,
13702
- "^": (left, right, type) => type === "Number" ? left ^ right : null,
13703
- "<<": (left, right, type) => type === "Number" ? left << right : null,
13704
- ">>": (left, right, type) => type === "Number" ? left >> right : null,
13705
- "==": (left, right) => left == right,
13706
- "!=": (left, right) => left != right,
13707
- "<=": (left, right) => left <= right,
13708
- ">=": (left, right) => left >= right,
13709
- "<": (left, right) => left < right,
13710
- ">": (left, right) => left > right,
13711
- as: null,
13712
- instanceof: null,
13713
- has: null,
13714
- };
13715
14229
  const op = operators[node.operator];
13716
14230
  if (op) {
13717
14231
  const [left, left_type] = getNodeValue(node.left);
@@ -13719,23 +14233,22 @@ function optimizeNode(state, node) {
13719
14233
  if (!left || !right)
13720
14234
  break;
13721
14235
  let value = null;
13722
- if (left_type != right_type ||
13723
- (left_type != "Number" && left_type != "Long")) {
14236
+ let type;
14237
+ if ((left_type != "Number" && left_type != "Long") ||
14238
+ left_type != right_type) {
13724
14239
  if (node.operator !== "==" && node.operator !== "!=") {
13725
14240
  break;
13726
14241
  }
13727
14242
  value = operators[node.operator](left.value, right.value);
14243
+ type = "Boolean";
13728
14244
  }
13729
14245
  else {
13730
- value = op(left.value, right.value, left_type);
14246
+ type = left_type;
14247
+ value = op(BigInt(left.value), BigInt(right.value));
13731
14248
  }
13732
14249
  if (value === null)
13733
14250
  break;
13734
- return {
13735
- ...left,
13736
- value,
13737
- raw: value.toString() + (left_type === "Long" ? "l" : ""),
13738
- };
14251
+ return replacementLiteral(left, value, type);
13739
14252
  }
13740
14253
  break;
13741
14254
  }
@@ -13745,7 +14258,8 @@ function optimizeNode(state, node) {
13745
14258
  break;
13746
14259
  const falsy = left.value === false ||
13747
14260
  left.value === null ||
13748
- (left.value === 0 && (left_type === "Number" || left_type === "Long"));
14261
+ ((left_type === "Number" || left_type === "Long") &&
14262
+ (left.value === 0 || left.value === 0n));
13749
14263
  if (falsy === (node.operator === "&&")) {
13750
14264
  return left;
13751
14265
  }
@@ -13786,9 +14300,7 @@ function evaluateFunction(state, func, args) {
13786
14300
  const paramValues = args &&
13787
14301
  Object.fromEntries(func.params.map((p, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(p), args[i]]));
13788
14302
  let ret = null;
13789
- const body = args
13790
- ? JSON.parse(JSON.stringify(func.body))
13791
- : func.body;
14303
+ const body = args ? cloneDeep(func.body) : func.body;
13792
14304
  try {
13793
14305
  traverseAst(body, (node) => {
13794
14306
  switch (node.type) {
@@ -13839,12 +14351,10 @@ function markFunctionCalled(state, func) {
13839
14351
  (0,external_util_cjs_namespaceObject.pushUnique)(state.calledFunctions[func.id.name], func);
13840
14352
  }
13841
14353
  async function optimizeMonkeyC(fnMap, barrelList, config) {
13842
- const state = {
13843
- ...(await analyze(fnMap, barrelList, config)),
13844
- localsStack: [{}],
13845
- exposed: {},
13846
- calledFunctions: {},
13847
- };
14354
+ const state = (await analyze(fnMap, barrelList, config));
14355
+ state.localsStack = [{}];
14356
+ state.calledFunctions = {};
14357
+ state.usedByName = {};
13848
14358
  const replace = (node, old) => {
13849
14359
  if (node === false || node === null)
13850
14360
  return node;
@@ -13933,6 +14443,58 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
13933
14443
  f.type == "FunctionDeclaration" &&
13934
14444
  maybeCalled(f.node))) ||
13935
14445
  (sc.superClass && checkInherited(sc, name))));
14446
+ const renamer = (idnode) => {
14447
+ const ident = idnode.type === "Identifier" ? idnode : idnode.left;
14448
+ const locals = topLocals();
14449
+ const { map } = locals;
14450
+ if (map) {
14451
+ const declName = ident.name;
14452
+ const name = renameVariable(state, locals, declName);
14453
+ if (name) {
14454
+ const [, results] = state.lookupValue(ident);
14455
+ if (!results) {
14456
+ throw new Error(`Didn't find local ${declName} which needed renaming`);
14457
+ }
14458
+ if (results.length !== 1) {
14459
+ throw new Error(`Lookup of local ${declName} found more than one result`);
14460
+ }
14461
+ const parent = results[0].parent;
14462
+ if (!parent) {
14463
+ throw new Error(`No parent in lookup of local ${declName}`);
14464
+ }
14465
+ const decls = parent.decls;
14466
+ if (!decls || !(0,external_api_cjs_namespaceObject.hasProperty)(decls, declName)) {
14467
+ throw new Error(`Missing decls in lookup of local ${declName}`);
14468
+ }
14469
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(decls, name)) {
14470
+ throw new Error(`While renaming ${declName} to ${name}, there was already a variable ${name}`);
14471
+ }
14472
+ if (decls[declName].length === 1) {
14473
+ decls[name] = decls[declName];
14474
+ delete decls[declName];
14475
+ }
14476
+ else {
14477
+ let i = decls[declName].length;
14478
+ while (i--) {
14479
+ const decl = decls[declName][i];
14480
+ if (decl === idnode ||
14481
+ (decl.type === "VariableDeclarator" && decl.node.id === idnode)) {
14482
+ decls[declName].splice(i, 1);
14483
+ decls[name] = [decl];
14484
+ break;
14485
+ }
14486
+ }
14487
+ if (i < 0) {
14488
+ throw new Error(`While renaming ${declName} to ${name}: Didn't find original declaration`);
14489
+ }
14490
+ }
14491
+ ident.name = name;
14492
+ }
14493
+ else {
14494
+ map[declName] = true;
14495
+ }
14496
+ }
14497
+ };
13936
14498
  state.pre = (node) => {
13937
14499
  switch (node.type) {
13938
14500
  case "ConditionalExpression":
@@ -13953,7 +14515,11 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
13953
14515
  result = !!value.value;
13954
14516
  }
13955
14517
  if (result !== null) {
13956
- node.test = { type: "Literal", value: result };
14518
+ node.test = {
14519
+ type: "Literal",
14520
+ value: result,
14521
+ raw: result.toString(),
14522
+ };
13957
14523
  if (node.type === "IfStatement" ||
13958
14524
  node.type === "ConditionalExpression") {
13959
14525
  return [result ? "consequent" : "alternate"];
@@ -13972,7 +14538,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
13972
14538
  return null;
13973
14539
  }
13974
14540
  case "EnumDeclaration":
13975
- return false;
14541
+ return [];
13976
14542
  case "ForStatement": {
13977
14543
  const map = topLocals().map;
13978
14544
  if (map) {
@@ -13981,43 +14547,13 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
13981
14547
  break;
13982
14548
  }
13983
14549
  case "VariableDeclarator": {
13984
- const locals = topLocals();
13985
- const { map } = locals;
13986
- if (map) {
13987
- const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id);
13988
- const name = renameVariable(state, locals, declName);
13989
- if (name) {
13990
- if (node.id.type === "Identifier") {
13991
- node.id.name = name;
13992
- }
13993
- else {
13994
- node.id.left.name = name;
13995
- }
13996
- }
13997
- else {
13998
- map[declName] = true;
13999
- }
14000
- }
14550
+ renamer(node.id);
14001
14551
  return ["init"];
14002
14552
  }
14003
14553
  case "CatchClause":
14004
14554
  if (node.param) {
14005
14555
  state.localsStack.push({ node, map: { ...(topLocals().map || {}) } });
14006
- const locals = topLocals();
14007
- const map = locals.map;
14008
- const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.param);
14009
- const name = renameVariable(state, locals, declName);
14010
- if (name) {
14011
- if (node.param.type === "Identifier") {
14012
- node.param.name = name;
14013
- }
14014
- else {
14015
- node.param.left.name = name;
14016
- }
14017
- }
14018
- else {
14019
- map[declName] = true;
14020
- }
14556
+ renamer(node.param);
14021
14557
  return ["body"];
14022
14558
  }
14023
14559
  break;
@@ -14033,14 +14569,8 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14033
14569
  break;
14034
14570
  case "UnaryExpression":
14035
14571
  if (node.operator == ":") {
14036
- // If we produce a Symbol, for a given name,
14037
- // its possible that someone uses that symbol
14038
- // indirectly, so we can't remove any enums or
14039
- // constants with that name (we can still replace
14040
- // uses of those constants though).
14041
- state.exposed[node.argument.name] = true;
14042
- // In any case, we can't replace *this* use of the
14043
- // symbol with its value...
14572
+ // node.argument is not a normal identifier.
14573
+ // don't visit it.
14044
14574
  return [];
14045
14575
  }
14046
14576
  break;
@@ -14052,29 +14582,73 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14052
14582
  if (typeof name === "string") {
14053
14583
  node.name = name;
14054
14584
  }
14585
+ const [, results] = state.lookupValue(node);
14586
+ if (results) {
14587
+ if (results.length !== 1 || results[0].results.length !== 1) {
14588
+ throw new Error(`Local ${node.name} had multiple lookup results`);
14589
+ }
14590
+ const parent = results[0].parent;
14591
+ if (!parent) {
14592
+ throw new Error(`Local ${node.name} had no parent`);
14593
+ }
14594
+ const decl = results[0].results[0];
14595
+ if (parent.type === "FunctionDeclaration" ||
14596
+ decl.type !== "VariableDeclarator") {
14597
+ // we can't optimize away function or catch parameters
14598
+ return [];
14599
+ }
14600
+ if (parent.type !== "BlockStatement") {
14601
+ throw new Error(`Local ${node.name} was not declared at block scope(??)`);
14602
+ }
14603
+ decl.used = true;
14604
+ }
14055
14605
  }
14056
14606
  }
14057
14607
  if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, node.name)) {
14058
14608
  if (!lookupAndReplace(node)) {
14059
- state.exposed[node.name] = true;
14609
+ state.usedByName[node.name] = true;
14060
14610
  }
14061
14611
  }
14062
14612
  return [];
14063
14613
  }
14064
- case "MemberExpression":
14065
- if (node.property.type === "Identifier" && !node.computed) {
14066
- if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, node.property.name)) {
14614
+ case "MemberExpression": {
14615
+ const property = (0,external_api_cjs_namespaceObject.isLookupCandidate)(node);
14616
+ if (property) {
14617
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, property.name)) {
14067
14618
  if (lookupAndReplace(node)) {
14068
14619
  return false;
14069
14620
  }
14070
14621
  else {
14071
- state.exposed[node.property.name] = true;
14622
+ state.usedByName[property.name] = true;
14072
14623
  }
14073
14624
  }
14074
14625
  // Don't optimize the property.
14075
14626
  return ["object"];
14076
14627
  }
14077
14628
  break;
14629
+ }
14630
+ case "AssignmentExpression":
14631
+ case "UpdateExpression": {
14632
+ const lhs = node.type === "AssignmentExpression" ? node.left : node.argument;
14633
+ if (lhs.type === "Identifier") {
14634
+ const map = topLocals().map;
14635
+ if (map) {
14636
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(map, lhs.name)) {
14637
+ const name = map[lhs.name];
14638
+ if (typeof name === "string") {
14639
+ lhs.name = name;
14640
+ }
14641
+ }
14642
+ }
14643
+ }
14644
+ else if (lhs.type === "MemberExpression") {
14645
+ state.traverse(lhs.object);
14646
+ if (lhs.computed) {
14647
+ state.traverse(lhs.property);
14648
+ }
14649
+ }
14650
+ return node.type === "AssignmentExpression" ? ["right"] : [];
14651
+ }
14078
14652
  case "BlockStatement": {
14079
14653
  const map = topLocals().map;
14080
14654
  if (map) {
@@ -14090,7 +14664,11 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14090
14664
  node.params &&
14091
14665
  node.params.forEach((p) => (map[(0,external_api_cjs_namespaceObject.variableDeclarationName)(p)] = true));
14092
14666
  state.localsStack.push({ node, map });
14093
- const [parent] = state.stack.slice(-2);
14667
+ const [parent, self] = state.stack.slice(-2);
14668
+ if (state.currentFunction) {
14669
+ throw new Error(`Nested functions: ${self.fullName} was activated during processing of ${state.currentFunction.fullName}`);
14670
+ }
14671
+ state.currentFunction = self;
14094
14672
  if (parent.type == "ClassDeclaration" && !maybeCalled(node)) {
14095
14673
  let used = false;
14096
14674
  if (node.id.name == "initialize") {
@@ -14117,10 +14695,23 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14117
14695
  return replace(opt, node);
14118
14696
  }
14119
14697
  switch (node.type) {
14698
+ case "FunctionDeclaration":
14699
+ if (!state.currentFunction) {
14700
+ throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
14701
+ }
14702
+ state.currentFunction.info = state.currentFunction.next_info;
14703
+ delete state.currentFunction.next_info;
14704
+ delete state.currentFunction;
14705
+ break;
14120
14706
  case "BlockStatement":
14121
14707
  if (node.body.length === 1 && node.body[0].type === "BlockStatement") {
14122
14708
  node.body.splice(0, 1, ...node.body[0].body);
14123
14709
  }
14710
+ // fall through
14711
+ case "ForStatement":
14712
+ if (locals.map) {
14713
+ cleanupUnusedVars(state, node);
14714
+ }
14124
14715
  break;
14125
14716
  case "ConditionalExpression":
14126
14717
  case "IfStatement":
@@ -14153,17 +14744,20 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14153
14744
  return replace(optimizeCall(state, node.argument, node), node.argument);
14154
14745
  }
14155
14746
  break;
14747
+ case "NewExpression":
14748
+ if (state.currentFunction) {
14749
+ const [, results] = state.lookup(node.callee);
14750
+ if (results) {
14751
+ recordCalledFuncs(state.currentFunction, findCalleesForNew(results));
14752
+ }
14753
+ else {
14754
+ recordModifiedUnknown(state.currentFunction);
14755
+ }
14756
+ }
14757
+ break;
14156
14758
  case "CallExpression": {
14157
14759
  return replace(optimizeCall(state, node, null), node);
14158
14760
  }
14159
- case "AssignmentExpression":
14160
- if (node.operator === "=" &&
14161
- node.left.type === "Identifier" &&
14162
- node.right.type === "Identifier" &&
14163
- node.left.name === node.right.name) {
14164
- return { type: "Literal", value: null, raw: "null" };
14165
- }
14166
- break;
14167
14761
  case "VariableDeclaration": {
14168
14762
  const locals = topLocals();
14169
14763
  if (locals.map &&
@@ -14237,6 +14831,32 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14237
14831
  }
14238
14832
  }
14239
14833
  break;
14834
+ case "AssignmentExpression":
14835
+ if (node.operator === "=" &&
14836
+ node.left.type === "Identifier" &&
14837
+ node.right.type === "Identifier" &&
14838
+ node.left.name === node.right.name) {
14839
+ return { type: "Literal", value: null, raw: "null" };
14840
+ }
14841
+ // fall through;
14842
+ case "UpdateExpression":
14843
+ if (state.currentFunction) {
14844
+ const lhs = node.type === "AssignmentExpression" ? node.left : node.argument;
14845
+ const [, results] = state.lookup(lhs);
14846
+ if (results) {
14847
+ recordModifiedDecls(state.currentFunction, results);
14848
+ }
14849
+ else {
14850
+ const id = lhs.type === "Identifier" ? lhs : (0,external_api_cjs_namespaceObject.isLookupCandidate)(lhs);
14851
+ if (id) {
14852
+ recordModifiedName(state.currentFunction, id.name);
14853
+ }
14854
+ else {
14855
+ recordModifiedUnknown(state.currentFunction);
14856
+ }
14857
+ }
14858
+ }
14859
+ break;
14240
14860
  }
14241
14861
  return null;
14242
14862
  };
@@ -14244,13 +14864,16 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14244
14864
  (0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
14245
14865
  });
14246
14866
  state.calledFunctions = {};
14247
- state.exposed = {};
14867
+ state.exposed = state.nextExposed;
14868
+ state.nextExposed = {};
14248
14869
  Object.values(fnMap).forEach((f) => {
14249
14870
  (0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
14250
14871
  });
14872
+ state.exposed = state.nextExposed;
14873
+ state.nextExposed = {};
14251
14874
  delete state.pre;
14252
14875
  delete state.post;
14253
- state.allFunctions.forEach((fn) => sizeBasedPRE(state, fn));
14876
+ Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
14254
14877
  const cleanup = (node) => {
14255
14878
  switch (node.type) {
14256
14879
  case "ThisExpression":
@@ -14260,7 +14883,8 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14260
14883
  if (node.members.every((m) => {
14261
14884
  const name = "name" in m ? m.name : m.id.name;
14262
14885
  return ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, name) &&
14263
- !(0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, name));
14886
+ !(0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, name) &&
14887
+ !(0,external_api_cjs_namespaceObject.hasProperty)(state.usedByName, name));
14264
14888
  })) {
14265
14889
  node.enumType = [
14266
14890
  ...new Set(node.members.map((m) => {
@@ -14303,7 +14927,9 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14303
14927
  case "VariableDeclaration": {
14304
14928
  node.declarations = node.declarations.filter((d) => {
14305
14929
  const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(d.id);
14306
- return (!(0,external_api_cjs_namespaceObject.hasProperty)(state.index, name) || (0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, name));
14930
+ return (!(0,external_api_cjs_namespaceObject.hasProperty)(state.index, name) ||
14931
+ (0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, name) ||
14932
+ (0,external_api_cjs_namespaceObject.hasProperty)(state.usedByName, name));
14307
14933
  });
14308
14934
  if (!node.declarations.length) {
14309
14935
  return false;
@@ -14317,6 +14943,11 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14317
14943
  break;
14318
14944
  case "FunctionDeclaration":
14319
14945
  if (!maybeCalled(node)) {
14946
+ if (node.attrs &&
14947
+ node.attrs.attributes &&
14948
+ node.attrs.attributes.elements.some((attr) => attr.type === "UnaryExpression" && attr.argument.name === "keep")) {
14949
+ break;
14950
+ }
14320
14951
  return false;
14321
14952
  }
14322
14953
  break;
@@ -14336,7 +14967,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14336
14967
  }
14337
14968
  return null;
14338
14969
  };
14339
- Object.values(fnMap).forEach((f) => {
14970
+ Object.entries(fnMap).forEach(([name, f]) => {
14340
14971
  traverseAst(f.ast, undefined, (node) => {
14341
14972
  const ret = cleanup(node);
14342
14973
  if (ret === false) {
@@ -14344,16 +14975,15 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
14344
14975
  }
14345
14976
  return ret;
14346
14977
  });
14978
+ if (state.config && state.config.checkBuildPragmas) {
14979
+ pragmaChecker(state, f.ast, state.diagnostics?.[name]);
14980
+ }
14347
14981
  });
14348
14982
  return state.diagnostics;
14349
14983
  }
14350
14984
  function optimizeCall(state, node, context) {
14351
14985
  const [name, results] = state.lookupNonlocal(node.callee);
14352
- const callees = results &&
14353
- results
14354
- .map((r) => r.results)
14355
- .flat()
14356
- .filter((c) => c.type === "FunctionDeclaration");
14986
+ const callees = results ? findCallees(results) : null;
14357
14987
  if (!callees || !callees.length) {
14358
14988
  const n = name ||
14359
14989
  ("name" in node.callee && node.callee.name) ||
@@ -14362,14 +14992,24 @@ function optimizeCall(state, node, context) {
14362
14992
  "name" in node.callee.property &&
14363
14993
  node.callee.property.name);
14364
14994
  if (n) {
14365
- state.exposed[n] = true;
14995
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(state.allFunctions, n)) {
14996
+ if (state.currentFunction) {
14997
+ recordCalledFuncs(state.currentFunction, state.allFunctions[n]);
14998
+ }
14999
+ state.allFunctions[n].forEach((fn) => markFunctionCalled(state, fn.node));
15000
+ }
14366
15001
  }
14367
- else {
14368
- // There are unnamed CallExpressions, such as new [size]
14369
- // So there's nothing to do here.
15002
+ else if (state.currentFunction) {
15003
+ // I don't think this can happen: foo[x](args)
15004
+ // doesn't parse, so you can't even do things like
15005
+ // $.Toybox.Lang[:format]("fmt", [])
15006
+ recordModifiedUnknown(state.currentFunction);
14370
15007
  }
14371
15008
  return null;
14372
15009
  }
15010
+ if (state.currentFunction) {
15011
+ recordCalledFuncs(state.currentFunction, callees);
15012
+ }
14373
15013
  if (callees.length == 1 && callees[0].type === "FunctionDeclaration") {
14374
15014
  const callee = callees[0].node;
14375
15015
  if (!context &&
@@ -14392,120 +15032,6 @@ function optimizeCall(state, node, context) {
14392
15032
  return null;
14393
15033
  }
14394
15034
 
14395
- ;// CONCATENATED MODULE: ./src/pragma-checker.ts
14396
-
14397
-
14398
- function pragmaChecker(ast, diagnostics) {
14399
- const comments = ast.comments;
14400
- if (!comments)
14401
- return;
14402
- diagnostics = diagnostics
14403
- ?.slice()
14404
- .sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
14405
- let diagIndex = 0;
14406
- let index = -1;
14407
- let comment;
14408
- let matchers;
14409
- const next = () => {
14410
- while (++index < comments.length) {
14411
- comment = comments[index];
14412
- let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
14413
- if (!match)
14414
- continue;
14415
- const kind = match[1];
14416
- let str = match[2];
14417
- matchers = [];
14418
- while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
14419
- matchers.push({ kind, quote: match[1], needle: match[2] });
14420
- str = str.substring(match[0].length);
14421
- if (!str.length)
14422
- break;
14423
- }
14424
- if (!str.length)
14425
- break;
14426
- if (!matchers.length) {
14427
- match = str.match(/^(\S+)\s+$/);
14428
- if (match) {
14429
- matchers.push({ kind, quote: '"', needle: match[1] });
14430
- break;
14431
- }
14432
- }
14433
- throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
14434
- }
14435
- };
14436
- const matcher = (quote, needle, haystack) => {
14437
- if (quote == '"') {
14438
- return haystack.includes(needle);
14439
- }
14440
- const re = new RegExp(needle.replace(/@(\d+)/g, "(pre_)?$1(_\\d+)?"));
14441
- return re.test(haystack);
14442
- };
14443
- next();
14444
- traverseAst(ast, (node) => {
14445
- if (index >= comments.length)
14446
- return false;
14447
- if (node.start && node.start >= (comment.end || Infinity)) {
14448
- const { kind, quote, needle } = matchers.shift();
14449
- if (kind === "match") {
14450
- const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " ");
14451
- if (!matcher(quote, needle, haystack)) {
14452
- matcher(quote, needle, haystack);
14453
- throw new Error(`Didn't find '${needle}' in '${haystack}' at ${comment.loc.source}:${comment.loc.start.line}`);
14454
- }
14455
- }
14456
- else if (kind === "expect") {
14457
- const locCmp = (a, b) => {
14458
- if (!b)
14459
- return -1;
14460
- if (a.start.line < b.start.line)
14461
- return -1;
14462
- if (a.start.line === b.start.line &&
14463
- a.start.column < b.start.column) {
14464
- return -1;
14465
- }
14466
- if (a.end.line > b.end.line)
14467
- return 1;
14468
- if (a.end.line === b.end.line && a.end.column >= b.end.column) {
14469
- return 1;
14470
- }
14471
- return 0;
14472
- };
14473
- let found = false;
14474
- if (diagnostics) {
14475
- while (true) {
14476
- if (diagIndex >= diagnostics.length) {
14477
- diagnostics = null;
14478
- break;
14479
- }
14480
- const diag = diagnostics[diagIndex];
14481
- const cmp = locCmp(diag.loc, node.loc);
14482
- if (cmp > 0) {
14483
- break;
14484
- }
14485
- diagIndex++;
14486
- if (cmp < 0)
14487
- continue;
14488
- if (matcher(quote, needle, diag.message)) {
14489
- found = true;
14490
- diag.type = "INFO";
14491
- }
14492
- }
14493
- }
14494
- if (!found) {
14495
- throw new Error(`Missing error message '${needle} at ${comment.loc.source}:${comment.loc.start.line}`);
14496
- }
14497
- }
14498
- if (matchers.length) {
14499
- // if we're checking a series of nodes, we need
14500
- // to skip over this one.
14501
- return false;
14502
- }
14503
- next();
14504
- }
14505
- return null;
14506
- });
14507
- }
14508
-
14509
15035
  ;// CONCATENATED MODULE: ./src/optimizer.ts
14510
15036
 
14511
15037
 
@@ -14943,22 +15469,19 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
14943
15469
  // the oldest optimized file, we don't need to regenerate
14944
15470
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
14945
15471
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
14946
- if (source_time < opt_time && 1656860602542 < opt_time) {
15472
+ if (source_time < opt_time && 1658088370253 < opt_time) {
14947
15473
  return { hasTests, diagnostics: prevDiagnostics };
14948
15474
  }
14949
15475
  }
14950
15476
  await promises_namespaceObject.rm(output, { recursive: true, force: true });
14951
15477
  await promises_namespaceObject.mkdir(output, { recursive: true });
14952
15478
  const diagnostics = await optimizeMonkeyC(fnMap, Object.keys(buildConfig.barrelMap || {}), config);
14953
- return Promise.all(Object.entries(fnMap).map(async ([inFile, info]) => {
15479
+ return Promise.all(Object.values(fnMap).map(async (info) => {
14954
15480
  const name = info.output;
14955
15481
  const dir = external_path_.dirname(name);
14956
15482
  await promises_namespaceObject.mkdir(dir, { recursive: true });
14957
15483
  const opt_source = (0,external_api_cjs_namespaceObject.formatAst)(info.ast, info.monkeyCSource);
14958
15484
  await promises_namespaceObject.writeFile(name, opt_source);
14959
- if (config.checkBuildPragmas) {
14960
- pragmaChecker(info.ast, diagnostics?.[inFile]);
14961
- }
14962
15485
  return info.hasTests;
14963
15486
  })).then((results) => {
14964
15487
  const hasTests = results.some((v) => v);