@markw65/monkeyc-optimizer 1.0.21 → 1.0.22

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.
@@ -10890,11 +10890,13 @@ function getArgSafety(state, func, args, requireAll) {
10890
10890
  case "Identifier":
10891
10891
  case "MemberExpression": {
10892
10892
  const [, results] = state.lookup(arg);
10893
- if (!results || results.length !== 1) {
10893
+ if (!results ||
10894
+ results.length !== 1 ||
10895
+ results[0].results.length !== 1) {
10894
10896
  safeArgs.push(null);
10895
10897
  return !requireAll;
10896
10898
  }
10897
- const safety = getSafety(results[0]);
10899
+ const safety = getSafety(results[0].results[0]);
10898
10900
  safeArgs.push(safety);
10899
10901
  if (!safety) {
10900
10902
  allSafe = false;
@@ -10986,12 +10988,6 @@ function inliningLooksUseful(func, node) {
10986
10988
  }
10987
10989
  return false;
10988
10990
  }
10989
- var InlineStatus;
10990
- (function (InlineStatus) {
10991
- InlineStatus[InlineStatus["Never"] = 0] = "Never";
10992
- InlineStatus[InlineStatus["AsExpression"] = 1] = "AsExpression";
10993
- InlineStatus[InlineStatus["AsStatement"] = 2] = "AsStatement";
10994
- })(InlineStatus || (InlineStatus = {}));
10995
10991
  function inlineRequested(state, func) {
10996
10992
  const excludeAnnotations = (func.node.loc?.source &&
10997
10993
  state.fnMap[func.node.loc?.source]?.excludeAnnotations) ||
@@ -11001,7 +10997,7 @@ function inlineRequested(state, func) {
11001
10997
  func.node.attrs.attributes.elements.some((attr) => attr.type === "UnaryExpression" &&
11002
10998
  (attr.argument.name === "inline" ||
11003
10999
  (attr.argument.name.startsWith("inline_") &&
11004
- (0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
11000
+ !(0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
11005
11001
  return true;
11006
11002
  }
11007
11003
  return false;
@@ -11171,7 +11167,7 @@ function unused(expression, top) {
11171
11167
  },
11172
11168
  ];
11173
11169
  }
11174
- function diagnostic(state, loc, message) {
11170
+ function diagnostic(state, loc, message, type = "INFO") {
11175
11171
  if (!loc || !loc.source)
11176
11172
  return;
11177
11173
  const source = loc.source;
@@ -11187,7 +11183,7 @@ function diagnostic(state, loc, message) {
11187
11183
  if (message) {
11188
11184
  if (index < 0)
11189
11185
  index = diags.length;
11190
- diags[index] = { type: "INFO", loc, message };
11186
+ diags[index] = { type, loc, message };
11191
11187
  }
11192
11188
  else if (index >= 0) {
11193
11189
  diags.splice(index, 1);
@@ -11306,23 +11302,25 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11306
11302
  // With a bit more work, we could find the guaranteed shortest
11307
11303
  // reference, and then use this to optimize *all* symbols, not
11308
11304
  // just fix inlined ones.
11309
- if (current &&
11310
- current.length === original.length &&
11311
- current.every((item, index) => item == original[index])) {
11305
+ if (current && (0,external_api_cjs_namespaceObject.sameLookupResult)(original, current)) {
11312
11306
  return lookupNode;
11313
11307
  }
11314
11308
  const node = lookupNode.type === "Identifier"
11315
11309
  ? lookupNode
11316
11310
  : lookupNode.property;
11317
- if (original.length === 1 && original[0].type === "EnumStringMember") {
11318
- return applyTypeIfNeeded(original[0].init);
11311
+ if (original.length === 1 &&
11312
+ original[0].results.length === 1 &&
11313
+ original[0].results[0].type === "EnumStringMember") {
11314
+ return applyTypeIfNeeded(original[0].results[0].init);
11319
11315
  }
11320
- const prefixes = original.map((sn) => {
11316
+ const prefixes = original
11317
+ .map((lookupDef) => lookupDef.results.map((sn) => {
11321
11318
  if ((0,external_api_cjs_namespaceObject.isStateNode)(sn) && sn.fullName) {
11322
11319
  return sn.fullName;
11323
11320
  }
11324
11321
  return "";
11325
- });
11322
+ }))
11323
+ .flat();
11326
11324
  if (prefixes.length &&
11327
11325
  prefixes[0].startsWith("$.") &&
11328
11326
  prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
@@ -11332,9 +11330,7 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11332
11330
  if (found)
11333
11331
  return current;
11334
11332
  const [, results] = state.lookup(current);
11335
- if (results &&
11336
- results.length === original.length &&
11337
- results.every((result, i) => result === original[i])) {
11333
+ if (results && (0,external_api_cjs_namespaceObject.sameLookupResult)(original, results)) {
11338
11334
  found = true;
11339
11335
  return current;
11340
11336
  }
@@ -11374,6 +11370,85 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11374
11370
  return null;
11375
11371
  }
11376
11372
 
11373
+ ;// CONCATENATED MODULE: ./src/visitor.ts
11374
+
11375
+ function visitReferences(state, ast, name, defn, callback) {
11376
+ const checkResults = ([name, results], node) => {
11377
+ if (name && results) {
11378
+ if (!defn || (0,external_api_cjs_namespaceObject.sameLookupResult)(results, defn)) {
11379
+ if (callback(node, results, false) === false) {
11380
+ return [];
11381
+ }
11382
+ }
11383
+ }
11384
+ else if (defn === false) {
11385
+ if (callback(node, [], results === null) === false) {
11386
+ return [];
11387
+ }
11388
+ }
11389
+ return null;
11390
+ };
11391
+ state.pre = (node) => {
11392
+ switch (node.type) {
11393
+ case "AttributeList":
11394
+ return [];
11395
+ case "UnaryExpression":
11396
+ // a bare symbol isn't a reference
11397
+ if (node.operator === ":")
11398
+ return [];
11399
+ break;
11400
+ case "BinaryExpression":
11401
+ /*
11402
+ * `expr has :symbol` can be treated as a reference
11403
+ * to expr.symbol.
11404
+ */
11405
+ if (node.operator === "has") {
11406
+ if (node.right.type === "UnaryExpression" &&
11407
+ node.right.operator === ":") {
11408
+ if (!name || node.right.argument.name === name) {
11409
+ return checkResults(state.lookup({
11410
+ type: "MemberExpression",
11411
+ object: node.left,
11412
+ property: node.right.argument,
11413
+ computed: false,
11414
+ }), node.right.argument);
11415
+ }
11416
+ }
11417
+ }
11418
+ break;
11419
+ case "CallExpression":
11420
+ // A call expression whose callee is an identifier is looked
11421
+ // up as a non-local. ie even if there's a same named local,
11422
+ // it will be ignored, and the lookup will start as if the
11423
+ // call had been written self.foo() rather than foo().
11424
+ if (node.callee.type === "Identifier") {
11425
+ if (!name || node.callee.name === name) {
11426
+ /* ignore return value */
11427
+ checkResults(state.lookupNonlocal(node.callee), node.callee);
11428
+ }
11429
+ return ["arguments"];
11430
+ }
11431
+ break;
11432
+ case "Identifier":
11433
+ if (!name || node.name === name) {
11434
+ return checkResults(state.lookup(node), node);
11435
+ }
11436
+ break;
11437
+ case "MemberExpression":
11438
+ if (!node.computed && node.property.type === "Identifier") {
11439
+ if (!name || node.property.name === name) {
11440
+ return checkResults(state.lookup(node), node) || ["object"];
11441
+ }
11442
+ return ["object"];
11443
+ }
11444
+ break;
11445
+ }
11446
+ return null;
11447
+ };
11448
+ (0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
11449
+ delete state.pre;
11450
+ }
11451
+
11377
11452
  ;// CONCATENATED MODULE: ./src/mc-rewrite.ts
11378
11453
 
11379
11454
 
@@ -11381,43 +11456,24 @@ function fixNodeScope(state, lookupNode, nodeStack) {
11381
11456
 
11382
11457
 
11383
11458
 
11384
- function processImports(allImports, lookup) {
11385
- allImports.forEach(({ node, stack }) => {
11386
- const [name, module] = lookup(node.id, ("as" in node && node.as && node.as.name) || null, stack);
11387
- if (name && module) {
11388
- const [parent] = stack.slice(-1);
11389
- if (!parent.decls)
11390
- parent.decls = {};
11391
- const decls = parent.decls;
11392
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(decls, name))
11393
- decls[name] = [];
11394
- module.forEach((m) => {
11395
- if ((0,external_api_cjs_namespaceObject.isStateNode)(m) && m.type == "ModuleDeclaration") {
11396
- (0,external_util_cjs_namespaceObject.pushUnique)(decls[name], m);
11397
- if (!parent.type_decls)
11398
- parent.type_decls = {};
11399
- const tdecls = parent.type_decls;
11400
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
11401
- tdecls[name] = [];
11402
- (0,external_util_cjs_namespaceObject.pushUnique)(tdecls[name], m);
11403
- if (node.type == "ImportModule" && m.type_decls) {
11404
- Object.entries(m.type_decls).forEach(([name, decls]) => {
11405
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
11406
- tdecls[name] = [];
11407
- decls.forEach((decl) => (0,external_util_cjs_namespaceObject.pushUnique)(tdecls[name], decl));
11408
- });
11409
- }
11410
- }
11411
- });
11412
- }
11413
- });
11414
- }
11459
+
11415
11460
  function collectClassInfo(state) {
11461
+ const toybox = state.stack[0].decls["Toybox"][0];
11462
+ const lang = toybox.decls["Lang"][0];
11463
+ const object = lang.decls["Object"];
11416
11464
  state.allClasses.forEach((elm) => {
11465
+ if (elm.stack[elm.stack.length - 1].type === "ClassDeclaration") {
11466
+ // nested classes don't get access to their contained
11467
+ // context. Put them in the global scope instead.
11468
+ elm.stack = elm.stack.slice(0, 1);
11469
+ }
11417
11470
  if (elm.node.superClass) {
11418
- const [name, classes] = state.lookup(elm.node.superClass, null, elm.stack);
11419
- const superClass = classes &&
11420
- classes.filter((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && c.type === "ClassDeclaration");
11471
+ const [name, lookupDefns] = state.lookup(elm.node.superClass, null, elm.stack);
11472
+ const superClass = lookupDefns &&
11473
+ lookupDefns
11474
+ .map((lookupDefn) => lookupDefn.results)
11475
+ .flat()
11476
+ .filter((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && c.type === "ClassDeclaration");
11421
11477
  // set it "true" if there is a superClass, but we can't find it.
11422
11478
  elm.superClass = superClass && superClass.length ? superClass : true;
11423
11479
  if (name && elm.superClass !== true) {
@@ -11449,6 +11505,9 @@ function collectClassInfo(state) {
11449
11505
  elm.decls[name] = elm.superClass;
11450
11506
  }
11451
11507
  }
11508
+ else if (elm !== object[0]) {
11509
+ elm.superClass = object;
11510
+ }
11452
11511
  });
11453
11512
  const markOverrides = (cls, scls) => {
11454
11513
  if (scls === true)
@@ -11501,11 +11560,12 @@ function getFileASTs(fnMap) {
11501
11560
  return ok;
11502
11561
  }, true));
11503
11562
  }
11504
- async function analyze(fnMap) {
11563
+ async function analyze(fnMap, barrelList, config) {
11505
11564
  let hasTests = false;
11506
- const allImports = [];
11565
+ let markApi = true;
11507
11566
  const preState = {
11508
11567
  fnMap,
11568
+ config,
11509
11569
  allFunctions: [],
11510
11570
  allClasses: [],
11511
11571
  shouldExclude(node) {
@@ -11533,45 +11593,37 @@ async function analyze(fnMap) {
11533
11593
  }
11534
11594
  return false;
11535
11595
  },
11536
- post(node, state) {
11596
+ pre(node, state) {
11537
11597
  switch (node.type) {
11538
11598
  case "FunctionDeclaration":
11599
+ if (markApi) {
11600
+ node.body = null;
11601
+ break;
11602
+ }
11603
+ case "ModuleDeclaration":
11539
11604
  case "ClassDeclaration": {
11540
11605
  const [scope] = state.stack.slice(-1);
11541
- const stack = state.stack.slice(0, -1);
11542
- scope.stack = stack;
11606
+ scope.stack = state.stackClone().slice(0, -1);
11543
11607
  if (scope.type == "FunctionDeclaration") {
11608
+ scope.isStatic =
11609
+ scope.stack.slice(-1)[0].type !== "ClassDeclaration" ||
11610
+ (scope.node.attrs &&
11611
+ scope.node.attrs.access &&
11612
+ scope.node.attrs.access.includes("static"));
11544
11613
  state.allFunctions.push(scope);
11545
11614
  }
11546
- else {
11615
+ else if (scope.type === "ClassDeclaration") {
11547
11616
  state.allClasses.push(scope);
11548
11617
  }
11549
- return null;
11618
+ break;
11550
11619
  }
11551
- case "Using":
11552
- case "ImportModule":
11553
- allImports.push({ node, stack: state.stack.slice() });
11554
- return null;
11555
- default:
11556
- return null;
11557
11620
  }
11621
+ return null;
11558
11622
  },
11559
11623
  };
11560
- await (0,external_api_cjs_namespaceObject.getApiMapping)(preState);
11624
+ await (0,external_api_cjs_namespaceObject.getApiMapping)(preState, barrelList);
11625
+ markApi = false;
11561
11626
  const state = preState;
11562
- // Mark all functions from api.mir as "special" by
11563
- // setting their bodies to null. In api.mir, they're
11564
- // all empty, which makes it look like they're
11565
- // do-nothing functions.
11566
- const markApi = (node) => {
11567
- if (node.type == "FunctionDeclaration") {
11568
- node.node.body = null;
11569
- }
11570
- if ((0,external_api_cjs_namespaceObject.isStateNode)(node) && node.decls) {
11571
- Object.values(node.decls).forEach((v) => v.forEach(markApi));
11572
- }
11573
- };
11574
- markApi(state.stack[0]);
11575
11627
  await getFileASTs(fnMap);
11576
11628
  Object.entries(fnMap).forEach(([name, value]) => {
11577
11629
  const { ast, parserError } = value;
@@ -11584,8 +11636,28 @@ async function analyze(fnMap) {
11584
11636
  });
11585
11637
  delete state.shouldExclude;
11586
11638
  delete state.post;
11587
- processImports(allImports, state.lookup);
11588
11639
  collectClassInfo(state);
11640
+ const diagnosticType = config?.checkInvalidSymbols !== "OFF"
11641
+ ? config?.checkInvalidSymbols || "WARNING"
11642
+ : null;
11643
+ if (diagnosticType &&
11644
+ !config?.compilerOptions?.includes("--Eno-invalid-symbol")) {
11645
+ const checkTypes = config?.typeCheckLevel && config.typeCheckLevel !== "Off";
11646
+ Object.entries(fnMap).forEach(([k, v]) => {
11647
+ visitReferences(state, v.ast, null, false, (node, results, error) => {
11648
+ if (!error)
11649
+ return undefined;
11650
+ const nodeStr = (0,external_api_cjs_namespaceObject.formatAst)(node);
11651
+ if (state.inType) {
11652
+ if (!checkTypes || nodeStr.match(/^Void|Null$/)) {
11653
+ return undefined;
11654
+ }
11655
+ }
11656
+ diagnostic(state, node.loc, `Undefined symbol ${nodeStr}`, diagnosticType);
11657
+ return false;
11658
+ });
11659
+ });
11660
+ }
11589
11661
  return state;
11590
11662
  }
11591
11663
  function compareLiteralLike(a, b) {
@@ -11595,11 +11667,11 @@ function compareLiteralLike(a, b) {
11595
11667
  b = b.left;
11596
11668
  return a.type === "Literal" && b.type === "Literal" && a.value === b.value;
11597
11669
  }
11598
- function getLiteralFromDecls(decls) {
11599
- if (!decls.length)
11670
+ function getLiteralFromDecls(lookupDefns) {
11671
+ if (!lookupDefns.length)
11600
11672
  return null;
11601
11673
  let result = null;
11602
- if (decls.every((d) => {
11674
+ if (lookupDefns.every((lookupDefn) => lookupDefn.results.every((d) => {
11603
11675
  if (d.type === "EnumStringMember" ||
11604
11676
  (d.type === "VariableDeclarator" && d.node.kind === "const")) {
11605
11677
  const init = getLiteralNode(d.type === "EnumStringMember" ? d.init : d.node.init);
@@ -11614,7 +11686,7 @@ function getLiteralFromDecls(decls) {
11614
11686
  }
11615
11687
  }
11616
11688
  return false;
11617
- })) {
11689
+ }))) {
11618
11690
  return result;
11619
11691
  }
11620
11692
  return null;
@@ -11825,20 +11897,23 @@ function markFunctionCalled(state, func) {
11825
11897
  }
11826
11898
  (0,external_util_cjs_namespaceObject.pushUnique)(state.calledFunctions[func.id.name], func);
11827
11899
  }
11828
- async function optimizeMonkeyC(fnMap) {
11900
+ async function optimizeMonkeyC(fnMap, barrelList, config) {
11829
11901
  const state = {
11830
- ...(await analyze(fnMap)),
11902
+ ...(await analyze(fnMap, barrelList, config)),
11831
11903
  localsStack: [{}],
11832
11904
  exposed: {},
11833
11905
  calledFunctions: {},
11834
11906
  };
11835
- const replace = (node) => {
11907
+ const replace = (node, old) => {
11836
11908
  if (node === false || node === null)
11837
11909
  return node;
11838
11910
  const rep = state.traverse(node);
11839
- return rep === false || rep ? rep : node;
11911
+ if (rep === false || Array.isArray(rep))
11912
+ return rep;
11913
+ return { ...(rep || node), loc: old.loc, start: old.start, end: old.end };
11840
11914
  };
11841
11915
  const inPlaceReplacement = (node, obj) => {
11916
+ const { start, end, loc } = node;
11842
11917
  for (const k of Object.keys(node)) {
11843
11918
  delete node[k];
11844
11919
  }
@@ -11846,13 +11921,16 @@ async function optimizeMonkeyC(fnMap) {
11846
11921
  obj = {
11847
11922
  type: "BinaryExpression",
11848
11923
  operator: "as",
11849
- left: obj,
11924
+ left: { ...obj, start, end, loc },
11850
11925
  right: { type: "TypeSpecList", ts: [obj.enumType] },
11851
11926
  };
11852
11927
  }
11853
11928
  for (const [k, v] of Object.entries(obj)) {
11854
11929
  node[k] = v;
11855
11930
  }
11931
+ node.loc = loc;
11932
+ node.start = start;
11933
+ node.end = end;
11856
11934
  };
11857
11935
  const lookupAndReplace = (node) => {
11858
11936
  const [, objects] = state.lookup(node);
@@ -11971,6 +12049,37 @@ async function optimizeMonkeyC(fnMap) {
11971
12049
  }
11972
12050
  return ["init"];
11973
12051
  }
12052
+ case "CatchClause":
12053
+ if (node.param) {
12054
+ state.localsStack.push({ node, map: { ...(topLocals().map || {}) } });
12055
+ const locals = topLocals();
12056
+ const map = locals.map;
12057
+ const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.param);
12058
+ const name = renameVariable(state, locals, declName);
12059
+ if (name) {
12060
+ if (node.param.type === "Identifier") {
12061
+ node.param.name = name;
12062
+ }
12063
+ else {
12064
+ node.param.left.name = name;
12065
+ }
12066
+ }
12067
+ else {
12068
+ map[declName] = true;
12069
+ }
12070
+ return ["body"];
12071
+ }
12072
+ break;
12073
+ case "BinaryExpression":
12074
+ if (node.operator === "has") {
12075
+ if (node.right.type === "UnaryExpression" &&
12076
+ node.right.operator === ":") {
12077
+ // Using `expr has :symbol` doesn't "expose"
12078
+ // symbol. So skip the right operand.
12079
+ return ["left"];
12080
+ }
12081
+ }
12082
+ break;
11974
12083
  case "UnaryExpression":
11975
12084
  if (node.operator == ":") {
11976
12085
  // If we produce a Symbol, for a given name,
@@ -12053,7 +12162,7 @@ async function optimizeMonkeyC(fnMap) {
12053
12162
  }
12054
12163
  const opt = optimizeNode(node);
12055
12164
  if (opt) {
12056
- return replace(opt);
12165
+ return replace(opt, node);
12057
12166
  }
12058
12167
  switch (node.type) {
12059
12168
  case "ConditionalExpression":
@@ -12063,7 +12172,7 @@ async function optimizeMonkeyC(fnMap) {
12063
12172
  const rep = node.test.value ? node.consequent : node.alternate;
12064
12173
  if (!rep)
12065
12174
  return false;
12066
- return replace(rep);
12175
+ return replace(rep, rep);
12067
12176
  }
12068
12177
  break;
12069
12178
  case "WhileStatement":
@@ -12078,11 +12187,11 @@ async function optimizeMonkeyC(fnMap) {
12078
12187
  break;
12079
12188
  case "ReturnStatement":
12080
12189
  if (node.argument && node.argument.type === "CallExpression") {
12081
- return replace(optimizeCall(state, node.argument, node));
12190
+ return replace(optimizeCall(state, node.argument, node), node.argument);
12082
12191
  }
12083
12192
  break;
12084
12193
  case "CallExpression": {
12085
- return replace(optimizeCall(state, node, null));
12194
+ return replace(optimizeCall(state, node, null), node);
12086
12195
  }
12087
12196
  case "AssignmentExpression":
12088
12197
  if (node.operator === "=" &&
@@ -12094,7 +12203,7 @@ async function optimizeMonkeyC(fnMap) {
12094
12203
  break;
12095
12204
  case "ExpressionStatement":
12096
12205
  if (node.expression.type === "CallExpression") {
12097
- return replace(optimizeCall(state, node.expression, node));
12206
+ return replace(optimizeCall(state, node.expression, node), node.expression);
12098
12207
  }
12099
12208
  else if (node.expression.type === "AssignmentExpression") {
12100
12209
  if (node.expression.right.type === "CallExpression") {
@@ -12106,10 +12215,10 @@ async function optimizeMonkeyC(fnMap) {
12106
12215
  }
12107
12216
  if (!ok && node.expression.operator == "=") {
12108
12217
  const [, result] = state.lookup(node.expression.left);
12109
- ok = result != null;
12218
+ ok = !!result;
12110
12219
  }
12111
12220
  if (ok) {
12112
- return replace(optimizeCall(state, node.expression.right, node.expression));
12221
+ return replace(optimizeCall(state, node.expression.right, node.expression), node.expression.right);
12113
12222
  }
12114
12223
  }
12115
12224
  }
@@ -12117,7 +12226,7 @@ async function optimizeMonkeyC(fnMap) {
12117
12226
  const ret = unused(node.expression, true);
12118
12227
  if (ret) {
12119
12228
  return ret
12120
- .map(replace)
12229
+ .map((r) => replace(r, r))
12121
12230
  .flat(1)
12122
12231
  .filter((s) => !!s);
12123
12232
  }
@@ -12138,6 +12247,9 @@ async function optimizeMonkeyC(fnMap) {
12138
12247
  delete state.post;
12139
12248
  const cleanup = (node) => {
12140
12249
  switch (node.type) {
12250
+ case "ThisExpression":
12251
+ node.text = "self";
12252
+ break;
12141
12253
  case "EnumStringBody":
12142
12254
  if (node.members.every((m) => {
12143
12255
  const name = "name" in m ? m.name : m.id.name;
@@ -12202,6 +12314,19 @@ async function optimizeMonkeyC(fnMap) {
12202
12314
  return false;
12203
12315
  }
12204
12316
  break;
12317
+ case "ClassDeclaration":
12318
+ case "ModuleDeclaration":
12319
+ // none of the attributes means anything on classes and
12320
+ // modules, and the new compiler complains about some
12321
+ // of them. Just drop them all.
12322
+ if (node.attrs && node.attrs.access) {
12323
+ if (node.attrs.attributes) {
12324
+ delete node.attrs.access;
12325
+ }
12326
+ else {
12327
+ delete node.attrs;
12328
+ }
12329
+ }
12205
12330
  }
12206
12331
  return null;
12207
12332
  };
@@ -12217,9 +12342,12 @@ async function optimizeMonkeyC(fnMap) {
12217
12342
  return state.diagnostics;
12218
12343
  }
12219
12344
  function optimizeCall(state, node, context) {
12220
- const [name, results] = state.lookup(node.callee);
12345
+ const [name, results] = state.lookupNonlocal(node.callee);
12221
12346
  const callees = results &&
12222
- results.filter((c) => c.type === "FunctionDeclaration");
12347
+ results
12348
+ .map((r) => r.results)
12349
+ .flat()
12350
+ .filter((c) => c.type === "FunctionDeclaration");
12223
12351
  if (!callees || !callees.length) {
12224
12352
  const n = name ||
12225
12353
  ("name" in node.callee && node.callee.name) ||
@@ -12260,23 +12388,28 @@ function optimizeCall(state, node, context) {
12260
12388
 
12261
12389
  ;// CONCATENATED MODULE: ./src/pragma-checker.ts
12262
12390
 
12263
- function pragmaChecker(ast) {
12391
+ function pragmaChecker(ast, diagnostics) {
12264
12392
  const comments = ast.comments;
12265
12393
  if (!comments)
12266
12394
  return;
12395
+ diagnostics = diagnostics
12396
+ ?.slice()
12397
+ .sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
12398
+ let diagIndex = 0;
12267
12399
  let index = -1;
12268
12400
  let comment;
12269
12401
  let matchers;
12270
12402
  const next = () => {
12271
12403
  while (++index < comments.length) {
12272
12404
  comment = comments[index];
12273
- let match = comment.value.match(/^\s*@match\s+(.+)/);
12405
+ let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
12274
12406
  if (!match)
12275
12407
  continue;
12276
- let str = match[1];
12408
+ const kind = match[1];
12409
+ let str = match[2];
12277
12410
  matchers = [];
12278
12411
  while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
12279
- matchers.push({ quote: match[1], needle: match[2] });
12412
+ matchers.push({ kind, quote: match[1], needle: match[2] });
12280
12413
  str = str.substring(match[0].length);
12281
12414
  if (!str.length)
12282
12415
  break;
@@ -12286,35 +12419,79 @@ function pragmaChecker(ast) {
12286
12419
  if (!matchers.length) {
12287
12420
  match = str.match(/^(\S+)\s+$/);
12288
12421
  if (match) {
12289
- matchers.push({ quote: '"', needle: match[1] });
12422
+ matchers.push({ kind, quote: '"', needle: match[1] });
12290
12423
  break;
12291
12424
  }
12292
12425
  }
12293
12426
  throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
12294
12427
  }
12295
12428
  };
12429
+ const matcher = (quote, needle, haystack) => {
12430
+ if (quote == '"') {
12431
+ return haystack.includes(needle);
12432
+ }
12433
+ const re = new RegExp(needle);
12434
+ return re.test(haystack);
12435
+ };
12296
12436
  next();
12297
12437
  (0,external_api_cjs_namespaceObject.traverseAst)(ast, (node) => {
12298
12438
  if (index >= comments.length)
12299
12439
  return false;
12300
12440
  if (node.start && node.start >= (comment.end || Infinity)) {
12301
- const { quote, needle } = matchers.shift();
12302
- const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/[\r\n]/g, " ");
12303
- let found = false;
12304
- if (quote == '"') {
12305
- found = haystack.includes(needle);
12306
- }
12307
- else {
12308
- const re = new RegExp(needle);
12309
- found = re.test(haystack);
12441
+ const { kind, quote, needle } = matchers.shift();
12442
+ if (kind === "match") {
12443
+ if (!matcher(quote, needle, (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " "))) {
12444
+ throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
12445
+ }
12310
12446
  }
12311
- if (!found) {
12312
- throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
12447
+ else if (kind === "expect") {
12448
+ const locCmp = (a, b) => {
12449
+ if (!b)
12450
+ return -1;
12451
+ if (a.start.line < b.start.line)
12452
+ return -1;
12453
+ if (a.start.line === b.start.line &&
12454
+ a.start.column < b.start.column) {
12455
+ return -1;
12456
+ }
12457
+ if (a.end.line > b.end.line)
12458
+ return 1;
12459
+ if (a.end.line === b.end.line && a.end.column >= b.end.column) {
12460
+ return 1;
12461
+ }
12462
+ return 0;
12463
+ };
12464
+ let found = false;
12465
+ if (diagnostics) {
12466
+ while (true) {
12467
+ if (diagIndex >= diagnostics.length) {
12468
+ diagnostics = null;
12469
+ break;
12470
+ }
12471
+ const diag = diagnostics[diagIndex];
12472
+ const cmp = locCmp(diag.loc, node.loc);
12473
+ if (cmp > 0) {
12474
+ break;
12475
+ }
12476
+ diagIndex++;
12477
+ if (cmp < 0)
12478
+ continue;
12479
+ if (matcher(quote, needle, diag.message)) {
12480
+ found = true;
12481
+ diag.type = "INFO";
12482
+ }
12483
+ }
12484
+ }
12485
+ if (!found) {
12486
+ throw new Error(`Missing error message '${needle} at ${comment.loc.source}:${comment.loc.start.line}`);
12487
+ }
12313
12488
  }
12314
- if (!matchers.length) {
12315
- next();
12489
+ if (matchers.length) {
12490
+ // if we're checking a series of nodes, we need
12491
+ // to skip over this one.
12492
+ return false;
12316
12493
  }
12317
- return false;
12494
+ next();
12318
12495
  }
12319
12496
  return null;
12320
12497
  });
@@ -12702,6 +12879,7 @@ const configOptionsToCheck = [
12702
12879
  "ignoredExcludeAnnotations",
12703
12880
  "ignoredAnnotations",
12704
12881
  "ignoredSourcePaths",
12882
+ "checkInvalidSymbols",
12705
12883
  ];
12706
12884
  /**
12707
12885
  * @param {BuildConfig} config
@@ -12753,21 +12931,21 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
12753
12931
  // the oldest optimized file, we don't need to regenerate
12754
12932
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
12755
12933
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
12756
- if (source_time < opt_time && 1654811717108 < opt_time) {
12934
+ if (source_time < opt_time && 1655479110007 < opt_time) {
12757
12935
  return { hasTests, diagnostics: prevDiagnostics };
12758
12936
  }
12759
12937
  }
12760
12938
  await promises_namespaceObject.rm(output, { recursive: true, force: true });
12761
12939
  await promises_namespaceObject.mkdir(output, { recursive: true });
12762
- const diagnostics = await optimizeMonkeyC(fnMap);
12763
- return Promise.all(Object.values(fnMap).map(async (info) => {
12940
+ const diagnostics = await optimizeMonkeyC(fnMap, Object.keys(buildConfig.barrelMap || {}), config);
12941
+ return Promise.all(Object.entries(fnMap).map(async ([inFile, info]) => {
12764
12942
  const name = info.output;
12765
12943
  const dir = external_path_.dirname(name);
12766
12944
  await promises_namespaceObject.mkdir(dir, { recursive: true });
12767
12945
  const opt_source = (0,external_api_cjs_namespaceObject.formatAst)(info.ast, info.monkeyCSource);
12768
12946
  await promises_namespaceObject.writeFile(name, opt_source);
12769
12947
  if (config.checkBuildPragmas) {
12770
- pragmaChecker(info.ast);
12948
+ pragmaChecker(info.ast, diagnostics?.[inFile]);
12771
12949
  }
12772
12950
  return info.hasTests;
12773
12951
  })).then((results) => {
@@ -12802,7 +12980,13 @@ async function getProjectAnalysis(targets, analysis, options) {
12802
12980
  if (!(await getFileASTs(fnMap))) {
12803
12981
  return { fnMap, paths };
12804
12982
  }
12805
- const state = await analyze(fnMap);
12983
+ const barrelObj = {};
12984
+ targets.forEach((target) => {
12985
+ if (target.qualifier.barrelMap) {
12986
+ Object.keys(target.qualifier.barrelMap).forEach((key) => (barrelObj[key] = true));
12987
+ }
12988
+ });
12989
+ const state = await analyze(fnMap, Object.keys(barrelObj), options);
12806
12990
  return { fnMap: fnMap, paths, state };
12807
12991
  }
12808
12992
  /**