@markw65/monkeyc-optimizer 1.0.20 → 1.0.23

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.
@@ -9858,7 +9858,7 @@ const external_util_cjs_namespaceObject = require("./util.cjs");
9858
9858
  async function build_project(product, options, lineCallback) {
9859
9859
  const { workspace, program, jungleFiles, developerKeyPath, simulatorBuild, releaseBuild, testBuild, compilerOptions, compilerWarnings, typeCheckLevel, returnCommand, } = options;
9860
9860
  const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
9861
- let extraArgs = [];
9861
+ const extraArgs = [];
9862
9862
  if (compilerOptions) {
9863
9863
  extraArgs.push(...compilerOptions.split(/\s+/));
9864
9864
  }
@@ -9894,6 +9894,9 @@ async function build_project(product, options, lineCallback) {
9894
9894
  else if (testBuild) {
9895
9895
  throw new Error("Building for tests requires a device to build for!");
9896
9896
  }
9897
+ if (!program || !jungleFiles || !developerKeyPath || !workspace) {
9898
+ throw new Error("Required arguments were missing!");
9899
+ }
9897
9900
  const exe = external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "monkeyc.bat" : "monkeyc");
9898
9901
  const args = [
9899
9902
  ["-o", program],
@@ -9928,9 +9931,8 @@ async function readManifest(manifest) {
9928
9931
  return (0,xml2js.parseStringPromise)(data.toString(), { trim: true });
9929
9932
  }
9930
9933
  async function writeManifest(filename, xml) {
9931
- let builder = new xml2js.Builder();
9932
- let text = builder.buildObject(xml);
9933
- return promises_namespaceObject.writeFile(filename, text);
9934
+ const builder = new xml2js.Builder();
9935
+ return promises_namespaceObject.writeFile(filename, builder.buildObject(xml));
9934
9936
  }
9935
9937
  function manifestProducts(manifest) {
9936
9938
  const app = manifest["iq:manifest"]["iq:application"] ||
@@ -10228,7 +10230,7 @@ function resolve_node_by_path(state, path) {
10228
10230
  }
10229
10231
  if (!s[n] && s["."]) {
10230
10232
  const sdot = s["."];
10231
- let resolved = resolve_node_list(state, sdot);
10233
+ const resolved = resolve_node_list(state, sdot);
10232
10234
  if (!resolved.length)
10233
10235
  return undefined;
10234
10236
  const r = resolved[0][n];
@@ -10317,11 +10319,11 @@ async function resolve_literals(qualifier, default_source, deviceInfo) {
10317
10319
  return resolve_file_list(v.values);
10318
10320
  }
10319
10321
  let resolved = resolve_filename(v, default_source);
10320
- if (/[*?\[\]\{\}]/.test(resolved)) {
10322
+ if (/[*?[\]{}]/.test(resolved)) {
10321
10323
  // Jungle files can contain "./**.mc" which is supposed to match
10322
10324
  // any mc file under "./". The standard way to express that
10323
10325
  // is "./**/*.mc", which is what glob expects, so translate.
10324
- resolved = resolved.replace(/[\\\/]\*\*([^\\\/])/g, "/**/*$1");
10326
+ resolved = resolved.replace(/[\\/]\*\*([^\\/])/g, "/**/*$1");
10325
10327
  const match = await (0,external_util_cjs_namespaceObject.globa)(resolved);
10326
10328
  return match.length ? resolved : null;
10327
10329
  }
@@ -10595,7 +10597,7 @@ function resolve_barrel(barrel, barrelDir, products, options) {
10595
10597
  const sha1 = external_crypto_namespaceObject.createHash("sha1")
10596
10598
  .update(barrel, "binary")
10597
10599
  .digest("base64")
10598
- .replace(/[\/=+]/g, "");
10600
+ .replace(/[/=+]/g, "");
10599
10601
  const localPath = external_path_.resolve(barrelDir, `${external_path_.basename(barrel, ".barrel")}-${sha1}`);
10600
10602
  rawBarrel = external_path_.resolve(localPath, "barrel.jungle");
10601
10603
  promise = promise.then(() => promises_namespaceObject.stat(localPath)
@@ -10745,7 +10747,9 @@ async function get_jungle_and_barrels(jungleFiles, defaultProducts, options) {
10745
10747
  targets.push({ product, qualifier, shape });
10746
10748
  return resolve_barrels(product, qualifier, barrels, products, options);
10747
10749
  })
10748
- .then(() => { });
10750
+ .then(() => {
10751
+ return;
10752
+ });
10749
10753
  };
10750
10754
  products.forEach((product) => {
10751
10755
  if ((0,external_api_cjs_namespaceObject.hasProperty)(state, product)) {
@@ -10788,11 +10792,151 @@ function simulateProgram(prg, device, test = false, logger) {
10788
10792
  const args = [prg, device];
10789
10793
  if (test)
10790
10794
  args.push("-t");
10791
- return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, logger || ((line) => console.log(line))).then(() => { }));
10795
+ return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, logger || ((line) => console.log(line))).then(() => {
10796
+ return;
10797
+ }));
10798
+ }
10799
+
10800
+ ;// CONCATENATED MODULE: ./src/ast.ts
10801
+ /*
10802
+ * This ensures that mctreeTypeInfo has every key of MCTreeTypeInfo,
10803
+ * and that the corresponding arrays contain every element of the
10804
+ * corresponding type.
10805
+ *
10806
+ * ie, any time mctree.Node changes, we'll get errors here if
10807
+ * mctreeTypeInfo needs updating.
10808
+ *
10809
+ */
10810
+ function _check(x) {
10811
+ const y = x;
10812
+ x = y;
10813
+ }
10814
+ const mctreeTypeInfo = {
10815
+ ArrayExpression: ["elements"],
10816
+ AssignmentExpression: ["left", "right"],
10817
+ AttributeList: ["attributes"],
10818
+ Attributes: ["elements"],
10819
+ BinaryExpression: ["left", "right"],
10820
+ Block: [],
10821
+ BlockStatement: ["body", "innerComments"],
10822
+ BreakStatement: [],
10823
+ CallExpression: ["callee", "arguments"],
10824
+ CatchClause: ["param", "body"],
10825
+ CatchClauses: ["catches"],
10826
+ ClassBody: ["body"],
10827
+ ClassDeclaration: ["attrs", "id", "superClass", "body"],
10828
+ ClassElement: ["item"],
10829
+ ConditionalExpression: ["test", "consequent", "alternate"],
10830
+ ContinueStatement: [],
10831
+ DoWhileStatement: ["body", "test"],
10832
+ EnumDeclaration: ["attrs", "id", "body"],
10833
+ EnumStringBody: ["members"],
10834
+ EnumStringMember: ["id", "init"],
10835
+ ExpressionStatement: ["expression"],
10836
+ ForStatement: ["init", "test", "body", "update"],
10837
+ FunctionDeclaration: ["attrs", "id", "params", "body"],
10838
+ Identifier: [],
10839
+ IfStatement: ["test", "consequent", "alternate"],
10840
+ ImportModule: ["id"],
10841
+ InstanceOfCase: ["id"],
10842
+ Line: [],
10843
+ Literal: [],
10844
+ LogicalExpression: ["left", "right"],
10845
+ MemberExpression: ["object", "property"],
10846
+ MethodDefinition: ["params", "returnType"],
10847
+ ModuleDeclaration: ["attrs", "id", "body"],
10848
+ MultiLine: [],
10849
+ NewExpression: ["callee", "arguments"],
10850
+ ObjectExpression: ["properties"],
10851
+ ParenthesizedExpression: ["expression"],
10852
+ Program: ["body", "comments"],
10853
+ Property: ["key", "value"],
10854
+ ReturnStatement: ["argument"],
10855
+ SequenceExpression: ["expressions"],
10856
+ SizedArrayExpression: ["size", "ts"],
10857
+ SwitchCase: ["test", "consequent"],
10858
+ SwitchStatement: ["discriminant", "cases"],
10859
+ ThisExpression: [],
10860
+ ThrowStatement: ["argument"],
10861
+ TryStatement: ["block", "handler", "finalizer"],
10862
+ TypedefDeclaration: ["attrs", "id", "ts"],
10863
+ TypeSpecList: ["ts"],
10864
+ TypeSpecPart: ["body", "callspec", "generics"],
10865
+ UnaryExpression: ["argument"],
10866
+ UpdateExpression: ["argument"],
10867
+ Using: ["id", "as"],
10868
+ VariableDeclaration: ["attrs", "declarations"],
10869
+ VariableDeclarator: ["id", "init"],
10870
+ WhileStatement: ["test", "body"],
10871
+ };
10872
+ function isMCTreeNode(node) {
10873
+ return node ? typeof node === "object" && "type" in node : false;
10874
+ }
10875
+ /*
10876
+ * Traverse the ast rooted at node, calling pre before
10877
+ * visiting each node, and post after.
10878
+ *
10879
+ * - if pre returns false, the node is not traversed, and
10880
+ * post is not called;
10881
+ * - if pre returns a list of child nodes, only those will
10882
+ * be traversed
10883
+ * - otherwise all child nodes are traversed
10884
+ *
10885
+ * - if post returns false, the node it was called on is
10886
+ * removed.
10887
+ */
10888
+ function traverseAst(node, pre, post) {
10889
+ const nodes = pre && pre(node);
10890
+ if (nodes === false)
10891
+ return;
10892
+ if (!mctreeTypeInfo[node.type]) {
10893
+ throw new Error("what?");
10894
+ }
10895
+ for (const key of nodes || mctreeTypeInfo[node.type]) {
10896
+ const value = node[key];
10897
+ if (!value)
10898
+ continue;
10899
+ if (Array.isArray(value)) {
10900
+ const values = value;
10901
+ const deletions = values.reduce((state, obj, i) => {
10902
+ if (isMCTreeNode(obj)) {
10903
+ const repl = traverseAst(obj, pre, post);
10904
+ if (repl === false) {
10905
+ if (!state)
10906
+ state = {};
10907
+ state[i] = true;
10908
+ }
10909
+ else if (repl != null) {
10910
+ if (!state)
10911
+ state = {};
10912
+ values[i] = repl;
10913
+ }
10914
+ }
10915
+ return state;
10916
+ }, null);
10917
+ if (deletions) {
10918
+ values.splice(0, values.length, ...values.filter((obj, i) => deletions[i] !== true).flat(1));
10919
+ }
10920
+ }
10921
+ else if (isMCTreeNode(value)) {
10922
+ const repl = traverseAst(value, pre, post);
10923
+ if (repl === false) {
10924
+ delete node[key];
10925
+ }
10926
+ else if (repl != null) {
10927
+ if (Array.isArray(repl)) {
10928
+ throw new Error("Array returned by traverseAst in Node context");
10929
+ }
10930
+ node[key] = repl;
10931
+ }
10932
+ }
10933
+ }
10934
+ return post && post(node);
10792
10935
  }
10793
10936
 
10794
10937
  ;// CONCATENATED MODULE: ./src/variable-renamer.ts
10795
10938
 
10939
+
10796
10940
  function renameVariable(state, locals, declName) {
10797
10941
  const map = locals.map;
10798
10942
  if (!(0,external_api_cjs_namespaceObject.hasProperty)(map, declName))
@@ -10809,7 +10953,7 @@ function renameVariable(state, locals, declName) {
10809
10953
  // more conflicts
10810
10954
  locals.inners = {};
10811
10955
  const inners = locals.inners;
10812
- (0,external_api_cjs_namespaceObject.traverseAst)(locals.node, (node) => {
10956
+ traverseAst(locals.node, (node) => {
10813
10957
  if (node.type === "VariableDeclarator") {
10814
10958
  inners[(0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id)] = true;
10815
10959
  }
@@ -10849,27 +10993,37 @@ function renameVariable(state, locals, declName) {
10849
10993
  ;// CONCATENATED MODULE: ./src/inliner.ts
10850
10994
 
10851
10995
 
10996
+
10852
10997
  function getArgSafety(state, func, args, requireAll) {
10853
10998
  // determine whether decl might be changed by a function call
10854
10999
  // or assignment during the evaluation of FunctionStateNode.
10855
11000
  const getSafety = (decl) => {
10856
- // enums are constant, they cant change
10857
- if (decl.type === "EnumStringMember")
10858
- return true;
10859
- if (decl.type === "VariableDeclarator") {
10860
- // constants also can't change
10861
- if (decl.node.kind === "const")
11001
+ switch (decl.type) {
11002
+ // enums are constant, they cant change
11003
+ case "EnumStringMember":
10862
11004
  return true;
10863
- // if decl is a local, it also can't be changed
10864
- // by a call to another function.
10865
- for (let i = 0;; i++) {
10866
- if (!state.stack[i] || decl.stack[i] !== state.stack[i])
10867
- return false;
10868
- if (state.stack[i].type === "FunctionDeclaration")
11005
+ case "VariableDeclarator": {
11006
+ // constants also can't change
11007
+ if (decl.node.kind === "const")
10869
11008
  return true;
11009
+ // if decl is a local, it also can't be changed
11010
+ // by a call to another function.
11011
+ for (let i = 0;; i++) {
11012
+ if (!state.stack[i] || decl.stack[i] !== state.stack[i])
11013
+ return false;
11014
+ if (state.stack[i].type === "FunctionDeclaration")
11015
+ return true;
11016
+ }
10870
11017
  }
11018
+ case "Identifier":
11019
+ case "BinaryExpression":
11020
+ // This is a parameter of the calling function.
11021
+ // It also can't be changed during the execution
11022
+ // of the inlined function
11023
+ return true;
11024
+ default:
11025
+ return null;
10871
11026
  }
10872
- return null;
10873
11027
  };
10874
11028
  const safeArgs = [];
10875
11029
  let allSafe = true;
@@ -10881,11 +11035,13 @@ function getArgSafety(state, func, args, requireAll) {
10881
11035
  case "Identifier":
10882
11036
  case "MemberExpression": {
10883
11037
  const [, results] = state.lookup(arg);
10884
- if (!results || results.length !== 1) {
11038
+ if (!results ||
11039
+ results.length !== 1 ||
11040
+ results[0].results.length !== 1) {
10885
11041
  safeArgs.push(null);
10886
11042
  return !requireAll;
10887
11043
  }
10888
- const safety = getSafety(results[0]);
11044
+ const safety = getSafety(results[0].results[0]);
10889
11045
  safeArgs.push(safety);
10890
11046
  if (!safety) {
10891
11047
  allSafe = false;
@@ -10905,25 +11061,12 @@ function getArgSafety(state, func, args, requireAll) {
10905
11061
  if (allSafe && requireAll)
10906
11062
  return true;
10907
11063
  let callSeen = false;
10908
- let ok = true;
10909
11064
  const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
10910
- const getLoc = (node) => (Array.isArray(node) ? node[0].start : node.start) || 0;
10911
11065
  // look for uses of "unsafe" args that occur after a call.
10912
11066
  // use post to do the checking, because arguments are evaluated
10913
11067
  // prior to the call, so eg "return f(x.y);" is fine, but
10914
11068
  // "return f()+x.y" is not.
10915
- //
10916
- // We also have to use a "pre" to ensure that child nodes are
10917
- // visited in source order (otherwise we could visit x.y before f()
10918
- // in the above example)
10919
- (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
10920
- return Object.entries(node)
10921
- .filter((kv) => Array.isArray(kv[1])
10922
- ? kv[1].length !== 0 && (0,external_api_cjs_namespaceObject.hasProperty)(kv[1][0], "type")
10923
- : (0,external_api_cjs_namespaceObject.hasProperty)(kv[1], "type"))
10924
- .sort(([, a], [, b]) => getLoc(a) - getLoc(b))
10925
- .map(([key]) => key);
10926
- }, (node) => {
11069
+ traverseAst(func.node.body, null, (node) => {
10927
11070
  switch (node.type) {
10928
11071
  case "AssignmentExpression":
10929
11072
  case "UpdateExpression": {
@@ -10977,27 +11120,23 @@ function inliningLooksUseful(func, node) {
10977
11120
  }
10978
11121
  return false;
10979
11122
  }
10980
- var InlineStatus;
10981
- (function (InlineStatus) {
10982
- InlineStatus[InlineStatus["Never"] = 0] = "Never";
10983
- InlineStatus[InlineStatus["AsExpression"] = 1] = "AsExpression";
10984
- InlineStatus[InlineStatus["AsStatement"] = 2] = "AsStatement";
10985
- })(InlineStatus || (InlineStatus = {}));
10986
11123
  function inlineRequested(state, func) {
10987
11124
  const excludeAnnotations = (func.node.loc?.source &&
10988
11125
  state.fnMap[func.node.loc?.source]?.excludeAnnotations) ||
10989
11126
  {};
10990
11127
  if (func.node.attrs &&
10991
- func.node.attrs.attrs &&
10992
- func.node.attrs.attrs.some((attr) => attr.type === "UnaryExpression" &&
11128
+ func.node.attrs.attributes &&
11129
+ func.node.attrs.attributes.elements.some((attr) => attr.type === "UnaryExpression" &&
10993
11130
  (attr.argument.name === "inline" ||
10994
11131
  (attr.argument.name.startsWith("inline_") &&
10995
- (0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
11132
+ !(0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
10996
11133
  return true;
10997
11134
  }
10998
11135
  return false;
10999
11136
  }
11000
11137
  function shouldInline(state, func, call, context) {
11138
+ if (state.inlining)
11139
+ return false;
11001
11140
  let autoInline = false;
11002
11141
  let inlineAsExpression = false;
11003
11142
  const args = call.arguments;
@@ -11030,6 +11169,7 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
11030
11169
  let failed = false;
11031
11170
  const pre = state.pre;
11032
11171
  const post = state.post;
11172
+ state.inlining = true;
11033
11173
  try {
11034
11174
  state.pre = (node) => {
11035
11175
  if (failed)
@@ -11075,7 +11215,7 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
11075
11215
  };
11076
11216
  state.post = (node) => {
11077
11217
  if (failed)
11078
- return null;
11218
+ return post(node, state);
11079
11219
  let replacement = null;
11080
11220
  switch (node.type) {
11081
11221
  case "Identifier": {
@@ -11092,12 +11232,13 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
11092
11232
  if (!replacement) {
11093
11233
  failed = true;
11094
11234
  inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
11095
- return null;
11235
+ return post(node, state);
11096
11236
  }
11097
11237
  break;
11098
11238
  }
11099
11239
  }
11100
- return post(replacement || node, state) || replacement;
11240
+ const ret = post(replacement || node, state);
11241
+ return ret === false || ret ? ret : replacement;
11101
11242
  };
11102
11243
  let ret = state.traverse(root);
11103
11244
  if (failed) {
@@ -11116,6 +11257,7 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
11116
11257
  finally {
11117
11258
  state.pre = pre;
11118
11259
  state.post = post;
11260
+ delete state.inlining;
11119
11261
  }
11120
11262
  }
11121
11263
  function unused(expression, top) {
@@ -11157,7 +11299,7 @@ function unused(expression, top) {
11157
11299
  },
11158
11300
  ];
11159
11301
  }
11160
- function diagnostic(state, loc, message) {
11302
+ function diagnostic(state, loc, message, type = "INFO") {
11161
11303
  if (!loc || !loc.source)
11162
11304
  return;
11163
11305
  const source = loc.source;
@@ -11173,7 +11315,7 @@ function diagnostic(state, loc, message) {
11173
11315
  if (message) {
11174
11316
  if (index < 0)
11175
11317
  index = diags.length;
11176
- diags[index] = { type: "INFO", loc, message };
11318
+ diags[index] = { type, loc, message };
11177
11319
  }
11178
11320
  else if (index >= 0) {
11179
11321
  diags.splice(index, 1);
@@ -11197,7 +11339,7 @@ function inlineWithArgs(state, func, call, context) {
11197
11339
  }
11198
11340
  }
11199
11341
  else {
11200
- (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
11342
+ traverseAst(func.node.body, (node) => {
11201
11343
  node.type === "ReturnStatement" && retStmtCount++;
11202
11344
  });
11203
11345
  if (retStmtCount > 1) {
@@ -11292,23 +11434,25 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11292
11434
  // With a bit more work, we could find the guaranteed shortest
11293
11435
  // reference, and then use this to optimize *all* symbols, not
11294
11436
  // just fix inlined ones.
11295
- if (current &&
11296
- current.length === original.length &&
11297
- current.every((item, index) => item == original[index])) {
11437
+ if (current && (0,external_api_cjs_namespaceObject.sameLookupResult)(original, current)) {
11298
11438
  return lookupNode;
11299
11439
  }
11300
11440
  const node = lookupNode.type === "Identifier"
11301
11441
  ? lookupNode
11302
11442
  : lookupNode.property;
11303
- if (original.length === 1 && original[0].type === "EnumStringMember") {
11304
- return applyTypeIfNeeded(original[0].init);
11443
+ if (original.length === 1 &&
11444
+ original[0].results.length === 1 &&
11445
+ original[0].results[0].type === "EnumStringMember") {
11446
+ return applyTypeIfNeeded(original[0].results[0].init);
11305
11447
  }
11306
- const prefixes = original.map((sn) => {
11448
+ const prefixes = original
11449
+ .map((lookupDef) => lookupDef.results.map((sn) => {
11307
11450
  if ((0,external_api_cjs_namespaceObject.isStateNode)(sn) && sn.fullName) {
11308
11451
  return sn.fullName;
11309
11452
  }
11310
11453
  return "";
11311
- });
11454
+ }))
11455
+ .flat();
11312
11456
  if (prefixes.length &&
11313
11457
  prefixes[0].startsWith("$.") &&
11314
11458
  prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
@@ -11318,9 +11462,7 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11318
11462
  if (found)
11319
11463
  return current;
11320
11464
  const [, results] = state.lookup(current);
11321
- if (results &&
11322
- results.length === original.length &&
11323
- results.every((result, i) => result === original[i])) {
11465
+ if (results && (0,external_api_cjs_namespaceObject.sameLookupResult)(original, results)) {
11324
11466
  found = true;
11325
11467
  return current;
11326
11468
  }
@@ -11360,6 +11502,99 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11360
11502
  return null;
11361
11503
  }
11362
11504
 
11505
+ ;// CONCATENATED MODULE: ./src/visitor.ts
11506
+
11507
+ function visitReferences(state, ast, name, defn, callback) {
11508
+ const checkResults = ([name, results], node) => {
11509
+ if (name && results) {
11510
+ if (!defn || (0,external_api_cjs_namespaceObject.sameLookupResult)(results, defn)) {
11511
+ if (callback(node, results, false) === false) {
11512
+ return [];
11513
+ }
11514
+ }
11515
+ }
11516
+ else if (defn === false) {
11517
+ if (callback(node, [], results === null) === false) {
11518
+ return [];
11519
+ }
11520
+ }
11521
+ return null;
11522
+ };
11523
+ state.pre = (node) => {
11524
+ switch (node.type) {
11525
+ case "AttributeList":
11526
+ return [];
11527
+ case "UnaryExpression":
11528
+ // a bare symbol isn't a reference
11529
+ if (node.operator === ":")
11530
+ return [];
11531
+ break;
11532
+ case "BinaryExpression":
11533
+ /*
11534
+ * `expr has :symbol` can be treated as a reference
11535
+ * to expr.symbol.
11536
+ */
11537
+ if (node.operator === "has") {
11538
+ if (node.right.type === "UnaryExpression" &&
11539
+ node.right.operator === ":") {
11540
+ if (!name || node.right.argument.name === name) {
11541
+ return checkResults(state.lookup({
11542
+ type: "MemberExpression",
11543
+ object: node.left,
11544
+ property: node.right.argument,
11545
+ computed: false,
11546
+ }), node.right.argument);
11547
+ }
11548
+ }
11549
+ }
11550
+ break;
11551
+ case "CallExpression":
11552
+ // A call expression whose callee is an identifier is looked
11553
+ // up as a non-local. ie even if there's a same named local,
11554
+ // it will be ignored, and the lookup will start as if the
11555
+ // call had been written self.foo() rather than foo().
11556
+ if (node.callee.type === "Identifier") {
11557
+ if (!name || node.callee.name === name) {
11558
+ /* ignore return value */
11559
+ checkResults(state.lookupNonlocal(node.callee), node.callee);
11560
+ }
11561
+ return ["arguments"];
11562
+ }
11563
+ break;
11564
+ case "Identifier":
11565
+ if (!name || node.name === name) {
11566
+ return checkResults(state.lookup(node), node);
11567
+ }
11568
+ break;
11569
+ case "MemberExpression":
11570
+ if (!node.computed && node.property.type === "Identifier") {
11571
+ if (!name || node.property.name === name) {
11572
+ return checkResults(state.lookup(node), node) || ["object"];
11573
+ }
11574
+ return ["object"];
11575
+ }
11576
+ break;
11577
+ case "MethodDefinition": {
11578
+ if (!state.inType) {
11579
+ throw new Error("Method definition outside of type!");
11580
+ }
11581
+ if (node.params) {
11582
+ node.params.forEach((param) => {
11583
+ if (param.type == "BinaryExpression") {
11584
+ state.traverse(param.right);
11585
+ state.inType = true;
11586
+ }
11587
+ });
11588
+ }
11589
+ return ["returnType"];
11590
+ }
11591
+ }
11592
+ return null;
11593
+ };
11594
+ (0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
11595
+ delete state.pre;
11596
+ }
11597
+
11363
11598
  ;// CONCATENATED MODULE: ./src/mc-rewrite.ts
11364
11599
 
11365
11600
 
@@ -11367,43 +11602,25 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11367
11602
 
11368
11603
 
11369
11604
 
11370
- function processImports(allImports, lookup) {
11371
- allImports.forEach(({ node, stack }) => {
11372
- const [name, module] = lookup(node.id, ("as" in node && node.as && node.as.name) || null, stack);
11373
- if (name && module) {
11374
- const [parent] = stack.slice(-1);
11375
- if (!parent.decls)
11376
- parent.decls = {};
11377
- const decls = parent.decls;
11378
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(decls, name))
11379
- decls[name] = [];
11380
- module.forEach((m) => {
11381
- if ((0,external_api_cjs_namespaceObject.isStateNode)(m) && m.type == "ModuleDeclaration") {
11382
- (0,external_util_cjs_namespaceObject.pushUnique)(decls[name], m);
11383
- if (!parent.type_decls)
11384
- parent.type_decls = {};
11385
- const tdecls = parent.type_decls;
11386
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
11387
- tdecls[name] = [];
11388
- (0,external_util_cjs_namespaceObject.pushUnique)(tdecls[name], m);
11389
- if (node.type == "ImportModule" && m.type_decls) {
11390
- Object.entries(m.type_decls).forEach(([name, decls]) => {
11391
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
11392
- tdecls[name] = [];
11393
- decls.forEach((decl) => (0,external_util_cjs_namespaceObject.pushUnique)(tdecls[name], decl));
11394
- });
11395
- }
11396
- }
11397
- });
11398
- }
11399
- });
11400
- }
11605
+
11606
+
11401
11607
  function collectClassInfo(state) {
11608
+ const toybox = state.stack[0].decls["Toybox"][0];
11609
+ const lang = toybox.decls["Lang"][0];
11610
+ const object = lang.decls["Object"];
11402
11611
  state.allClasses.forEach((elm) => {
11612
+ if (elm.stack[elm.stack.length - 1].type === "ClassDeclaration") {
11613
+ // nested classes don't get access to their contained
11614
+ // context. Put them in the global scope instead.
11615
+ elm.stack = elm.stack.slice(0, 1);
11616
+ }
11403
11617
  if (elm.node.superClass) {
11404
- const [name, classes] = state.lookup(elm.node.superClass, null, elm.stack);
11405
- const superClass = classes &&
11406
- classes.filter((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && c.type === "ClassDeclaration");
11618
+ const [name, lookupDefns] = state.lookup(elm.node.superClass, null, elm.stack);
11619
+ const superClass = lookupDefns &&
11620
+ lookupDefns
11621
+ .map((lookupDefn) => lookupDefn.results)
11622
+ .flat()
11623
+ .filter((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && c.type === "ClassDeclaration");
11407
11624
  // set it "true" if there is a superClass, but we can't find it.
11408
11625
  elm.superClass = superClass && superClass.length ? superClass : true;
11409
11626
  if (name && elm.superClass !== true) {
@@ -11435,6 +11652,9 @@ function collectClassInfo(state) {
11435
11652
  elm.decls[name] = elm.superClass;
11436
11653
  }
11437
11654
  }
11655
+ else if (elm !== object[0]) {
11656
+ elm.superClass = object;
11657
+ }
11438
11658
  });
11439
11659
  const markOverrides = (cls, scls) => {
11440
11660
  if (scls === true)
@@ -11464,7 +11684,9 @@ function getFileSources(fnMap) {
11464
11684
  return (value.monkeyCSource ||
11465
11685
  promises_namespaceObject.readFile(name)
11466
11686
  .then((data) => (value.monkeyCSource = data.toString().replace(/\r\n/g, "\n"))));
11467
- })).then(() => { });
11687
+ })).then(() => {
11688
+ return;
11689
+ });
11468
11690
  }
11469
11691
  function getFileASTs(fnMap) {
11470
11692
  return getFileSources(fnMap).then(() => Object.entries(fnMap).reduce((ok, [name, value]) => {
@@ -11487,22 +11709,23 @@ function getFileASTs(fnMap) {
11487
11709
  return ok;
11488
11710
  }, true));
11489
11711
  }
11490
- async function analyze(fnMap) {
11712
+ async function analyze(fnMap, barrelList, config) {
11491
11713
  let hasTests = false;
11492
- const allImports = [];
11714
+ let markApi = true;
11493
11715
  const preState = {
11494
11716
  fnMap,
11717
+ config,
11495
11718
  allFunctions: [],
11496
11719
  allClasses: [],
11497
11720
  shouldExclude(node) {
11498
11721
  if ("attrs" in node &&
11499
11722
  node.attrs &&
11500
- "attrs" in node.attrs &&
11501
- node.attrs.attrs &&
11723
+ "attributes" in node.attrs &&
11724
+ node.attrs.attributes &&
11502
11725
  node.loc?.source) {
11503
11726
  const excludeAnnotations = fnMap[node.loc.source].excludeAnnotations;
11504
11727
  if (excludeAnnotations) {
11505
- return node.attrs.attrs.reduce((drop, attr) => {
11728
+ return node.attrs.attributes.elements.reduce((drop, attr) => {
11506
11729
  if (attr.type != "UnaryExpression")
11507
11730
  return drop;
11508
11731
  if (attr.argument.type != "Identifier")
@@ -11519,45 +11742,38 @@ async function analyze(fnMap) {
11519
11742
  }
11520
11743
  return false;
11521
11744
  },
11522
- post(node, state) {
11745
+ pre(node, state) {
11523
11746
  switch (node.type) {
11524
11747
  case "FunctionDeclaration":
11748
+ if (markApi) {
11749
+ node.body = null;
11750
+ break;
11751
+ }
11752
+ // falls through
11753
+ case "ModuleDeclaration":
11525
11754
  case "ClassDeclaration": {
11526
11755
  const [scope] = state.stack.slice(-1);
11527
- const stack = state.stack.slice(0, -1);
11528
- scope.stack = stack;
11756
+ scope.stack = state.stackClone().slice(0, -1);
11529
11757
  if (scope.type == "FunctionDeclaration") {
11758
+ scope.isStatic =
11759
+ scope.stack.slice(-1)[0].type !== "ClassDeclaration" ||
11760
+ (scope.node.attrs &&
11761
+ scope.node.attrs.access &&
11762
+ scope.node.attrs.access.includes("static"));
11530
11763
  state.allFunctions.push(scope);
11531
11764
  }
11532
- else {
11765
+ else if (scope.type === "ClassDeclaration") {
11533
11766
  state.allClasses.push(scope);
11534
11767
  }
11535
- return null;
11768
+ break;
11536
11769
  }
11537
- case "Using":
11538
- case "ImportModule":
11539
- allImports.push({ node, stack: state.stack.slice() });
11540
- return null;
11541
- default:
11542
- return null;
11543
11770
  }
11771
+ return null;
11544
11772
  },
11545
11773
  };
11546
- await (0,external_api_cjs_namespaceObject.getApiMapping)(preState);
11774
+ await (0,external_api_cjs_namespaceObject.getApiMapping)(preState, barrelList);
11775
+ markApi = false;
11547
11776
  const state = preState;
11548
- // Mark all functions from api.mir as "special" by
11549
- // setting their bodies to null. In api.mir, they're
11550
- // all empty, which makes it look like they're
11551
- // do-nothing functions.
11552
- const markApi = (node) => {
11553
- if (node.type == "FunctionDeclaration") {
11554
- node.node.body = null;
11555
- }
11556
- if ((0,external_api_cjs_namespaceObject.isStateNode)(node) && node.decls) {
11557
- Object.values(node.decls).forEach((v) => v.forEach(markApi));
11558
- }
11559
- };
11560
- markApi(state.stack[0]);
11561
11777
  await getFileASTs(fnMap);
11562
11778
  Object.entries(fnMap).forEach(([name, value]) => {
11563
11779
  const { ast, parserError } = value;
@@ -11570,8 +11786,28 @@ async function analyze(fnMap) {
11570
11786
  });
11571
11787
  delete state.shouldExclude;
11572
11788
  delete state.post;
11573
- processImports(allImports, state.lookup);
11574
11789
  collectClassInfo(state);
11790
+ const diagnosticType = config?.checkInvalidSymbols !== "OFF"
11791
+ ? config?.checkInvalidSymbols || "WARNING"
11792
+ : null;
11793
+ if (diagnosticType &&
11794
+ !config?.compilerOptions?.includes("--Eno-invalid-symbol")) {
11795
+ const checkTypes = config?.typeCheckLevel && config.typeCheckLevel !== "Off";
11796
+ Object.entries(fnMap).forEach(([, v]) => {
11797
+ visitReferences(state, v.ast, null, false, (node, results, error) => {
11798
+ if (!error)
11799
+ return undefined;
11800
+ const nodeStr = (0,external_api_cjs_namespaceObject.formatAst)(node);
11801
+ if (state.inType) {
11802
+ if (!checkTypes || nodeStr.match(/^Void|Null$/)) {
11803
+ return undefined;
11804
+ }
11805
+ }
11806
+ diagnostic(state, node.loc, `Undefined symbol ${nodeStr}`, diagnosticType);
11807
+ return false;
11808
+ });
11809
+ });
11810
+ }
11575
11811
  return state;
11576
11812
  }
11577
11813
  function compareLiteralLike(a, b) {
@@ -11581,11 +11817,11 @@ function compareLiteralLike(a, b) {
11581
11817
  b = b.left;
11582
11818
  return a.type === "Literal" && b.type === "Literal" && a.value === b.value;
11583
11819
  }
11584
- function getLiteralFromDecls(decls) {
11585
- if (!decls.length)
11820
+ function getLiteralFromDecls(lookupDefns) {
11821
+ if (!lookupDefns.length)
11586
11822
  return null;
11587
11823
  let result = null;
11588
- if (decls.every((d) => {
11824
+ if (lookupDefns.every((lookupDefn) => lookupDefn.results.every((d) => {
11589
11825
  if (d.type === "EnumStringMember" ||
11590
11826
  (d.type === "VariableDeclarator" && d.node.kind === "const")) {
11591
11827
  const init = getLiteralNode(d.type === "EnumStringMember" ? d.init : d.node.init);
@@ -11600,7 +11836,7 @@ function getLiteralFromDecls(decls) {
11600
11836
  }
11601
11837
  }
11602
11838
  return false;
11603
- })) {
11839
+ }))) {
11604
11840
  return result;
11605
11841
  }
11606
11842
  return null;
@@ -11763,7 +11999,7 @@ function evaluateFunction(func, args) {
11763
11999
  ? JSON.parse(JSON.stringify(func.body))
11764
12000
  : func.body;
11765
12001
  try {
11766
- (0,external_api_cjs_namespaceObject.traverseAst)(body, (node) => {
12002
+ traverseAst(body, (node) => {
11767
12003
  switch (node.type) {
11768
12004
  case "BlockStatement":
11769
12005
  case "ReturnStatement":
@@ -11811,14 +12047,23 @@ function markFunctionCalled(state, func) {
11811
12047
  }
11812
12048
  (0,external_util_cjs_namespaceObject.pushUnique)(state.calledFunctions[func.id.name], func);
11813
12049
  }
11814
- async function optimizeMonkeyC(fnMap) {
12050
+ async function optimizeMonkeyC(fnMap, barrelList, config) {
11815
12051
  const state = {
11816
- ...(await analyze(fnMap)),
12052
+ ...(await analyze(fnMap, barrelList, config)),
11817
12053
  localsStack: [{}],
11818
12054
  exposed: {},
11819
12055
  calledFunctions: {},
11820
12056
  };
11821
- const replace = (node, obj) => {
12057
+ const replace = (node, old) => {
12058
+ if (node === false || node === null)
12059
+ return node;
12060
+ const rep = state.traverse(node);
12061
+ if (rep === false || Array.isArray(rep))
12062
+ return rep;
12063
+ return { ...(rep || node), loc: old.loc, start: old.start, end: old.end };
12064
+ };
12065
+ const inPlaceReplacement = (node, obj) => {
12066
+ const { start, end, loc } = node;
11822
12067
  for (const k of Object.keys(node)) {
11823
12068
  delete node[k];
11824
12069
  }
@@ -11826,13 +12071,16 @@ async function optimizeMonkeyC(fnMap) {
11826
12071
  obj = {
11827
12072
  type: "BinaryExpression",
11828
12073
  operator: "as",
11829
- left: obj,
12074
+ left: { ...obj, start, end, loc },
11830
12075
  right: { type: "TypeSpecList", ts: [obj.enumType] },
11831
12076
  };
11832
12077
  }
11833
12078
  for (const [k, v] of Object.entries(obj)) {
11834
12079
  node[k] = v;
11835
12080
  }
12081
+ node.loc = loc;
12082
+ node.start = start;
12083
+ node.end = end;
11836
12084
  };
11837
12085
  const lookupAndReplace = (node) => {
11838
12086
  const [, objects] = state.lookup(node);
@@ -11843,7 +12091,7 @@ async function optimizeMonkeyC(fnMap) {
11843
12091
  if (!obj) {
11844
12092
  return false;
11845
12093
  }
11846
- replace(node, obj);
12094
+ inPlaceReplacement(node, obj);
11847
12095
  return true;
11848
12096
  };
11849
12097
  const topLocals = () => state.localsStack[state.localsStack.length - 1];
@@ -11859,8 +12107,8 @@ async function optimizeMonkeyC(fnMap) {
11859
12107
  if ((0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, func.id.name))
11860
12108
  return true;
11861
12109
  if (func.attrs &&
11862
- func.attrs.attrs &&
11863
- func.attrs.attrs.some((attr) => {
12110
+ func.attrs.attributes &&
12111
+ func.attrs.attributes.elements.some((attr) => {
11864
12112
  if (attr.type != "UnaryExpression")
11865
12113
  return false;
11866
12114
  if (attr.argument.type != "Identifier")
@@ -11890,7 +12138,7 @@ async function optimizeMonkeyC(fnMap) {
11890
12138
  case "ConditionalExpression":
11891
12139
  case "IfStatement":
11892
12140
  case "DoWhileStatement":
11893
- case "WhileStatement":
12141
+ case "WhileStatement": {
11894
12142
  const test = (state.traverse(node.test) ||
11895
12143
  node.test);
11896
12144
  const [value, type] = getNodeValue(test);
@@ -11922,6 +12170,7 @@ async function optimizeMonkeyC(fnMap) {
11922
12170
  }
11923
12171
  }
11924
12172
  return null;
12173
+ }
11925
12174
  case "EnumDeclaration":
11926
12175
  return false;
11927
12176
  case "ForStatement": {
@@ -11951,6 +12200,37 @@ async function optimizeMonkeyC(fnMap) {
11951
12200
  }
11952
12201
  return ["init"];
11953
12202
  }
12203
+ case "CatchClause":
12204
+ if (node.param) {
12205
+ state.localsStack.push({ node, map: { ...(topLocals().map || {}) } });
12206
+ const locals = topLocals();
12207
+ const map = locals.map;
12208
+ const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.param);
12209
+ const name = renameVariable(state, locals, declName);
12210
+ if (name) {
12211
+ if (node.param.type === "Identifier") {
12212
+ node.param.name = name;
12213
+ }
12214
+ else {
12215
+ node.param.left.name = name;
12216
+ }
12217
+ }
12218
+ else {
12219
+ map[declName] = true;
12220
+ }
12221
+ return ["body"];
12222
+ }
12223
+ break;
12224
+ case "BinaryExpression":
12225
+ if (node.operator === "has") {
12226
+ if (node.right.type === "UnaryExpression" &&
12227
+ node.right.operator === ":") {
12228
+ // Using `expr has :symbol` doesn't "expose"
12229
+ // symbol. So skip the right operand.
12230
+ return ["left"];
12231
+ }
12232
+ }
12233
+ break;
11954
12234
  case "UnaryExpression":
11955
12235
  if (node.operator == ":") {
11956
12236
  // If we produce a Symbol, for a given name,
@@ -12033,8 +12313,7 @@ async function optimizeMonkeyC(fnMap) {
12033
12313
  }
12034
12314
  const opt = optimizeNode(node);
12035
12315
  if (opt) {
12036
- replace(node, opt);
12037
- return null;
12316
+ return replace(opt, node);
12038
12317
  }
12039
12318
  switch (node.type) {
12040
12319
  case "ConditionalExpression":
@@ -12044,7 +12323,7 @@ async function optimizeMonkeyC(fnMap) {
12044
12323
  const rep = node.test.value ? node.consequent : node.alternate;
12045
12324
  if (!rep)
12046
12325
  return false;
12047
- replace(node, rep);
12326
+ return replace(rep, rep);
12048
12327
  }
12049
12328
  break;
12050
12329
  case "WhileStatement":
@@ -12059,15 +12338,11 @@ async function optimizeMonkeyC(fnMap) {
12059
12338
  break;
12060
12339
  case "ReturnStatement":
12061
12340
  if (node.argument && node.argument.type === "CallExpression") {
12062
- return optimizeCall(state, node.argument, node);
12341
+ return replace(optimizeCall(state, node.argument, node), node.argument);
12063
12342
  }
12064
12343
  break;
12065
12344
  case "CallExpression": {
12066
- const ret = optimizeCall(state, node, null);
12067
- if (ret) {
12068
- replace(node, ret);
12069
- }
12070
- break;
12345
+ return replace(optimizeCall(state, node, null), node);
12071
12346
  }
12072
12347
  case "AssignmentExpression":
12073
12348
  if (node.operator === "=" &&
@@ -12079,7 +12354,7 @@ async function optimizeMonkeyC(fnMap) {
12079
12354
  break;
12080
12355
  case "ExpressionStatement":
12081
12356
  if (node.expression.type === "CallExpression") {
12082
- return optimizeCall(state, node.expression, node);
12357
+ return replace(optimizeCall(state, node.expression, node), node.expression);
12083
12358
  }
12084
12359
  else if (node.expression.type === "AssignmentExpression") {
12085
12360
  if (node.expression.right.type === "CallExpression") {
@@ -12091,14 +12366,10 @@ async function optimizeMonkeyC(fnMap) {
12091
12366
  }
12092
12367
  if (!ok && node.expression.operator == "=") {
12093
12368
  const [, result] = state.lookup(node.expression.left);
12094
- ok = result != null;
12369
+ ok = !!result;
12095
12370
  }
12096
12371
  if (ok) {
12097
- const ret = optimizeCall(state, node.expression.right, node.expression);
12098
- if (ret && ret.type === "BlockStatement") {
12099
- const r2 = state.traverse(ret);
12100
- return r2 === false || r2 ? r2 : ret;
12101
- }
12372
+ return replace(optimizeCall(state, node.expression.right, node.expression), node.expression.right);
12102
12373
  }
12103
12374
  }
12104
12375
  }
@@ -12106,12 +12377,9 @@ async function optimizeMonkeyC(fnMap) {
12106
12377
  const ret = unused(node.expression, true);
12107
12378
  if (ret) {
12108
12379
  return ret
12109
- .map((s) => {
12110
- const r2 = state.traverse(s);
12111
- return r2 === false || r2 ? r2 : s;
12112
- })
12380
+ .map((r) => replace(r, r))
12113
12381
  .flat(1)
12114
- .filter((s) => s !== false);
12382
+ .filter((s) => !!s);
12115
12383
  }
12116
12384
  }
12117
12385
  break;
@@ -12130,6 +12398,9 @@ async function optimizeMonkeyC(fnMap) {
12130
12398
  delete state.post;
12131
12399
  const cleanup = (node) => {
12132
12400
  switch (node.type) {
12401
+ case "ThisExpression":
12402
+ node.text = "self";
12403
+ break;
12133
12404
  case "EnumStringBody":
12134
12405
  if (node.members.every((m) => {
12135
12406
  const name = "name" in m ? m.name : m.id.name;
@@ -12154,19 +12425,24 @@ async function optimizeMonkeyC(fnMap) {
12154
12425
  if (!node.body.members.length) {
12155
12426
  if (!node.id)
12156
12427
  return false;
12157
- if (!node.body["enumType"]) {
12428
+ if (!node.body.enumType) {
12158
12429
  throw new Error("Missing enumType on optimized enum");
12159
12430
  }
12160
- replace(node, {
12431
+ return {
12161
12432
  type: "TypedefDeclaration",
12162
12433
  id: node.id,
12163
12434
  ts: {
12164
12435
  type: "UnaryExpression",
12165
- argument: { type: "TypeSpecList", ts: [node.body.enumType] },
12436
+ argument: {
12437
+ type: "TypeSpecList",
12438
+ ts: [
12439
+ node.body.enumType,
12440
+ ],
12441
+ },
12166
12442
  prefix: true,
12167
12443
  operator: " as",
12168
12444
  },
12169
- });
12445
+ };
12170
12446
  }
12171
12447
  break;
12172
12448
  case "VariableDeclaration": {
@@ -12189,11 +12465,24 @@ async function optimizeMonkeyC(fnMap) {
12189
12465
  return false;
12190
12466
  }
12191
12467
  break;
12468
+ case "ClassDeclaration":
12469
+ case "ModuleDeclaration":
12470
+ // none of the attributes means anything on classes and
12471
+ // modules, and the new compiler complains about some
12472
+ // of them. Just drop them all.
12473
+ if (node.attrs && node.attrs.access) {
12474
+ if (node.attrs.attributes) {
12475
+ delete node.attrs.access;
12476
+ }
12477
+ else {
12478
+ delete node.attrs;
12479
+ }
12480
+ }
12192
12481
  }
12193
12482
  return null;
12194
12483
  };
12195
12484
  Object.values(fnMap).forEach((f) => {
12196
- (0,external_api_cjs_namespaceObject.traverseAst)(f.ast, undefined, (node) => {
12485
+ traverseAst(f.ast, undefined, (node) => {
12197
12486
  const ret = cleanup(node);
12198
12487
  if (ret === false) {
12199
12488
  state.removeNodeComments(node, f.ast);
@@ -12204,9 +12493,12 @@ async function optimizeMonkeyC(fnMap) {
12204
12493
  return state.diagnostics;
12205
12494
  }
12206
12495
  function optimizeCall(state, node, context) {
12207
- const [name, results] = state.lookup(node.callee);
12496
+ const [name, results] = state.lookupNonlocal(node.callee);
12208
12497
  const callees = results &&
12209
- results.filter((c) => c.type === "FunctionDeclaration");
12498
+ results
12499
+ .map((r) => r.results)
12500
+ .flat()
12501
+ .filter((c) => c.type === "FunctionDeclaration");
12210
12502
  if (!callees || !callees.length) {
12211
12503
  const n = name ||
12212
12504
  ("name" in node.callee && node.callee.name) ||
@@ -12247,23 +12539,29 @@ function optimizeCall(state, node, context) {
12247
12539
 
12248
12540
  ;// CONCATENATED MODULE: ./src/pragma-checker.ts
12249
12541
 
12250
- function pragmaChecker(ast) {
12542
+
12543
+ function pragmaChecker(ast, diagnostics) {
12251
12544
  const comments = ast.comments;
12252
12545
  if (!comments)
12253
12546
  return;
12547
+ diagnostics = diagnostics
12548
+ ?.slice()
12549
+ .sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
12550
+ let diagIndex = 0;
12254
12551
  let index = -1;
12255
12552
  let comment;
12256
12553
  let matchers;
12257
12554
  const next = () => {
12258
12555
  while (++index < comments.length) {
12259
12556
  comment = comments[index];
12260
- let match = comment.value.match(/^\s*@match\s+(.+)/);
12557
+ let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
12261
12558
  if (!match)
12262
12559
  continue;
12263
- let str = match[1];
12560
+ const kind = match[1];
12561
+ let str = match[2];
12264
12562
  matchers = [];
12265
12563
  while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
12266
- matchers.push({ quote: match[1], needle: match[2] });
12564
+ matchers.push({ kind, quote: match[1], needle: match[2] });
12267
12565
  str = str.substring(match[0].length);
12268
12566
  if (!str.length)
12269
12567
  break;
@@ -12273,35 +12571,79 @@ function pragmaChecker(ast) {
12273
12571
  if (!matchers.length) {
12274
12572
  match = str.match(/^(\S+)\s+$/);
12275
12573
  if (match) {
12276
- matchers.push({ quote: '"', needle: match[1] });
12574
+ matchers.push({ kind, quote: '"', needle: match[1] });
12277
12575
  break;
12278
12576
  }
12279
12577
  }
12280
12578
  throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
12281
12579
  }
12282
12580
  };
12581
+ const matcher = (quote, needle, haystack) => {
12582
+ if (quote == '"') {
12583
+ return haystack.includes(needle);
12584
+ }
12585
+ const re = new RegExp(needle);
12586
+ return re.test(haystack);
12587
+ };
12283
12588
  next();
12284
- (0,external_api_cjs_namespaceObject.traverseAst)(ast, (node) => {
12589
+ traverseAst(ast, (node) => {
12285
12590
  if (index >= comments.length)
12286
12591
  return false;
12287
12592
  if (node.start && node.start >= (comment.end || Infinity)) {
12288
- const { quote, needle } = matchers.shift();
12289
- const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/[\r\n]/g, " ");
12290
- let found = false;
12291
- if (quote == '"') {
12292
- found = haystack.includes(needle);
12293
- }
12294
- else {
12295
- const re = new RegExp(needle);
12296
- found = re.test(haystack);
12593
+ const { kind, quote, needle } = matchers.shift();
12594
+ if (kind === "match") {
12595
+ if (!matcher(quote, needle, (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " "))) {
12596
+ throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
12597
+ }
12297
12598
  }
12298
- if (!found) {
12299
- throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
12599
+ else if (kind === "expect") {
12600
+ const locCmp = (a, b) => {
12601
+ if (!b)
12602
+ return -1;
12603
+ if (a.start.line < b.start.line)
12604
+ return -1;
12605
+ if (a.start.line === b.start.line &&
12606
+ a.start.column < b.start.column) {
12607
+ return -1;
12608
+ }
12609
+ if (a.end.line > b.end.line)
12610
+ return 1;
12611
+ if (a.end.line === b.end.line && a.end.column >= b.end.column) {
12612
+ return 1;
12613
+ }
12614
+ return 0;
12615
+ };
12616
+ let found = false;
12617
+ if (diagnostics) {
12618
+ while (true) {
12619
+ if (diagIndex >= diagnostics.length) {
12620
+ diagnostics = null;
12621
+ break;
12622
+ }
12623
+ const diag = diagnostics[diagIndex];
12624
+ const cmp = locCmp(diag.loc, node.loc);
12625
+ if (cmp > 0) {
12626
+ break;
12627
+ }
12628
+ diagIndex++;
12629
+ if (cmp < 0)
12630
+ continue;
12631
+ if (matcher(quote, needle, diag.message)) {
12632
+ found = true;
12633
+ diag.type = "INFO";
12634
+ }
12635
+ }
12636
+ }
12637
+ if (!found) {
12638
+ throw new Error(`Missing error message '${needle} at ${comment.loc.source}:${comment.loc.start.line}`);
12639
+ }
12300
12640
  }
12301
- if (!matchers.length) {
12302
- next();
12641
+ if (matchers.length) {
12642
+ // if we're checking a series of nodes, we need
12643
+ // to skip over this one.
12644
+ return false;
12303
12645
  }
12304
- return false;
12646
+ next();
12305
12647
  }
12306
12648
  return null;
12307
12649
  });
@@ -12323,7 +12665,7 @@ function pragmaChecker(ast) {
12323
12665
 
12324
12666
 
12325
12667
  function relative_path_no_dotdot(relative) {
12326
- return relative.replace(/^(\.\.[\\\/])+/, (str) => `__${"dot".repeat(str.length / 3)}__${str.slice(-1)}`);
12668
+ return relative.replace(/^(\.\.[\\/])+/, (str) => `__${"dot".repeat(str.length / 3)}__${str.slice(-1)}`);
12327
12669
  }
12328
12670
  async function getVSCodeSettings(path) {
12329
12671
  try {
@@ -12455,7 +12797,7 @@ async function createLocalBarrels(targets, options) {
12455
12797
  const sha1 = external_crypto_namespaceObject.createHash("sha1")
12456
12798
  .update(rawBarrelDir, "binary")
12457
12799
  .digest("base64")
12458
- .replace(/[\/=+]/g, "");
12800
+ .replace(/[/=+]/g, "");
12459
12801
  const optBarrelDir = external_path_.resolve(barrelDir, `${barrel}-${sha1}`);
12460
12802
  if (!(0,external_api_cjs_namespaceObject.hasProperty)(optBarrels, barrel)) {
12461
12803
  optBarrels[barrel] = {
@@ -12503,7 +12845,9 @@ async function generateOptimizedProject(options) {
12503
12845
  }
12504
12846
  return {
12505
12847
  jungleFiles: config.jungleFiles,
12848
+ xml,
12506
12849
  program: external_path_.basename(external_path_.dirname(manifest)),
12850
+ hasTests: !!config.testBuild,
12507
12851
  };
12508
12852
  }
12509
12853
  let dropBarrels = false;
@@ -12604,7 +12948,7 @@ async function generateOptimizedProject(options) {
12604
12948
  }
12605
12949
  const prefix = `${product}.`;
12606
12950
  process_field(prefix, qualifier, "sourcePath", (s) => external_path_.join(group.dir, "source", relative_path_no_dotdot(external_path_.relative(workspace, s)))
12607
- .replace(/([\\\/]\*\*)[\\\/]\*/g, "$1"));
12951
+ .replace(/([\\/]\*\*)[\\/]\*/g, "$1"));
12608
12952
  if (group.optimizerConfig.optBarrels) {
12609
12953
  parts.push(`${prefix}barrelPath = ${Object.values(group.optimizerConfig.optBarrels)
12610
12954
  .map((value) => `[${value.jungleFiles
@@ -12618,7 +12962,7 @@ async function generateOptimizedProject(options) {
12618
12962
  .map(([barrel, resolvedBarrel]) => {
12619
12963
  const root = external_path_.dirname(resolvedBarrel.jungles[0]);
12620
12964
  return (resolvedBarrel.qualifier.sourcePath || []).map((s) => external_path_.join(group.dir, "barrels", barrel, external_path_.relative(root, s))
12621
- .replace(/([\\\/]\*\*)[\\\/]\*/g, "$1"));
12965
+ .replace(/([\\/]\*\*)[\\/]\*/g, "$1"));
12622
12966
  })
12623
12967
  .flat()
12624
12968
  .sort()
@@ -12689,6 +13033,7 @@ const configOptionsToCheck = [
12689
13033
  "ignoredExcludeAnnotations",
12690
13034
  "ignoredAnnotations",
12691
13035
  "ignoredSourcePaths",
13036
+ "checkInvalidSymbols",
12692
13037
  ];
12693
13038
  /**
12694
13039
  * @param {BuildConfig} config
@@ -12740,21 +13085,21 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
12740
13085
  // the oldest optimized file, we don't need to regenerate
12741
13086
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
12742
13087
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
12743
- if (source_time < opt_time && 1654708837029 < opt_time) {
13088
+ if (source_time < opt_time && 1655677006664 < opt_time) {
12744
13089
  return { hasTests, diagnostics: prevDiagnostics };
12745
13090
  }
12746
13091
  }
12747
13092
  await promises_namespaceObject.rm(output, { recursive: true, force: true });
12748
13093
  await promises_namespaceObject.mkdir(output, { recursive: true });
12749
- const diagnostics = await optimizeMonkeyC(fnMap);
12750
- return Promise.all(Object.values(fnMap).map(async (info) => {
13094
+ const diagnostics = await optimizeMonkeyC(fnMap, Object.keys(buildConfig.barrelMap || {}), config);
13095
+ return Promise.all(Object.entries(fnMap).map(async ([inFile, info]) => {
12751
13096
  const name = info.output;
12752
13097
  const dir = external_path_.dirname(name);
12753
13098
  await promises_namespaceObject.mkdir(dir, { recursive: true });
12754
13099
  const opt_source = (0,external_api_cjs_namespaceObject.formatAst)(info.ast, info.monkeyCSource);
12755
13100
  await promises_namespaceObject.writeFile(name, opt_source);
12756
13101
  if (config.checkBuildPragmas) {
12757
- pragmaChecker(info.ast);
13102
+ pragmaChecker(info.ast, diagnostics?.[inFile]);
12758
13103
  }
12759
13104
  return info.hasTests;
12760
13105
  })).then((results) => {
@@ -12789,7 +13134,13 @@ async function getProjectAnalysis(targets, analysis, options) {
12789
13134
  if (!(await getFileASTs(fnMap))) {
12790
13135
  return { fnMap, paths };
12791
13136
  }
12792
- const state = await analyze(fnMap);
13137
+ const barrelObj = {};
13138
+ targets.forEach((target) => {
13139
+ if (target.qualifier.barrelMap) {
13140
+ Object.keys(target.qualifier.barrelMap).forEach((key) => (barrelObj[key] = true));
13141
+ }
13142
+ });
13143
+ const state = await analyze(fnMap, Object.keys(barrelObj), options);
12793
13144
  return { fnMap: fnMap, paths, state };
12794
13145
  }
12795
13146
  /**