@markw65/monkeyc-optimizer 1.0.39 → 1.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/api.cjs CHANGED
@@ -1,4 +1,4 @@
1
- 0 && (module.exports = {collectNamespaces,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,hasProperty,isLookupCandidate,isStateNode,markInvokeClassMethod,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visitorNode});
1
+ 0 && (module.exports = {checkCompilerVersion,collectNamespaces,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,hasProperty,isLookupCandidate,isStateNode,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visitorNode});
2
2
  /******/ (() => { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -258,6 +258,7 @@ __webpack_require__.r(__webpack_exports__);
258
258
 
259
259
  // EXPORTS
260
260
  __webpack_require__.d(__webpack_exports__, {
261
+ "checkCompilerVersion": () => (/* binding */ api_checkCompilerVersion),
261
262
  "collectNamespaces": () => (/* binding */ api_collectNamespaces),
262
263
  "findUsingForNode": () => (/* binding */ findUsingForNode),
263
264
  "formatAst": () => (/* binding */ api_formatAst),
@@ -267,6 +268,7 @@ __webpack_require__.d(__webpack_exports__, {
267
268
  "isLookupCandidate": () => (/* binding */ api_isLookupCandidate),
268
269
  "isStateNode": () => (/* binding */ api_isStateNode),
269
270
  "markInvokeClassMethod": () => (/* binding */ api_markInvokeClassMethod),
271
+ "parseSdkVersion": () => (/* binding */ parseSdkVersion),
270
272
  "sameLookupResult": () => (/* binding */ api_sameLookupResult),
271
273
  "traverseAst": () => (/* reexport */ ast_traverseAst),
272
274
  "variableDeclarationName": () => (/* binding */ api_variableDeclarationName),
@@ -651,6 +653,15 @@ function function_info_findCalleesForNew(lookupDefs) {
651
653
  .filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
652
654
  }
653
655
 
656
+ ;// CONCATENATED MODULE: ./src/optimizer-types.ts
657
+ var optimizer_types_StateNodeAttributes;
658
+ (function (StateNodeAttributes) {
659
+ StateNodeAttributes[StateNodeAttributes["PUBLIC"] = 1] = "PUBLIC";
660
+ StateNodeAttributes[StateNodeAttributes["PROTECTED"] = 2] = "PROTECTED";
661
+ StateNodeAttributes[StateNodeAttributes["PRIVATE"] = 4] = "PRIVATE";
662
+ StateNodeAttributes[StateNodeAttributes["STATIC"] = 8] = "STATIC";
663
+ })(optimizer_types_StateNodeAttributes || (optimizer_types_StateNodeAttributes = {}));
664
+
654
665
  ;// CONCATENATED MODULE: ./src/variable-renamer.ts
655
666
 
656
667
 
@@ -717,6 +728,7 @@ function variable_renamer_renameVariable(state, locals, declName) {
717
728
 
718
729
 
719
730
 
731
+
720
732
  // Note: Keep in sync with replaceInlinedSubExpression below
721
733
  function inliner_inlinableSubExpression(expr) {
722
734
  while (true) {
@@ -1036,6 +1048,12 @@ function processInlineBody(state, func, call, root, params) {
1036
1048
  state.inlining = true;
1037
1049
  let insertedVariableDecls = null;
1038
1050
  const replacements = new Set();
1051
+ // lookup determines static-ness of the lookup context based on seeing
1052
+ // a static FunctionDeclaration, but the FunctionDeclaration's stack
1053
+ // doesn't include the FunctionDeclaration itself.
1054
+ const stack = func.attributes & StateNodeAttributes.STATIC
1055
+ ? func.stack.concat(func)
1056
+ : func.stack;
1039
1057
  try {
1040
1058
  state.pre = (node) => {
1041
1059
  if (failed)
@@ -1085,7 +1103,7 @@ function processInlineBody(state, func, call, root, params) {
1085
1103
  }
1086
1104
  return null;
1087
1105
  }
1088
- const replacement = fixNodeScope(state, node, func.stack);
1106
+ const replacement = fixNodeScope(state, node, stack);
1089
1107
  if (!replacement) {
1090
1108
  failed = true;
1091
1109
  inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
@@ -1140,7 +1158,7 @@ function processInlineBody(state, func, call, root, params) {
1140
1158
  delete state.inlining;
1141
1159
  }
1142
1160
  }
1143
- function inliner_unused(expression, top) {
1161
+ function inliner_unused(state, expression, top) {
1144
1162
  const estmt = (expression) => withLoc({
1145
1163
  type: "ExpressionStatement",
1146
1164
  expression,
@@ -1154,19 +1172,19 @@ function inliner_unused(expression, top) {
1154
1172
  return [];
1155
1173
  case "BinaryExpression":
1156
1174
  if (expression.operator === "as") {
1157
- return inliner_unused(expression.left);
1175
+ return inliner_unused(state, expression.left);
1158
1176
  }
1159
- return inliner_unused(expression.left).concat(inliner_unused(expression.right));
1177
+ return inliner_unused(state, expression.left).concat(inliner_unused(state, expression.right));
1160
1178
  case "LogicalExpression": {
1161
- const right = inliner_unused(expression.right);
1179
+ const right = inliner_unused(state, expression.right);
1162
1180
  if (!right.length)
1163
- return inliner_unused(expression.left);
1181
+ return inliner_unused(state, expression.left);
1164
1182
  const consequent = withLoc({
1165
1183
  type: "BlockStatement",
1166
1184
  body: [estmt(expression.right)],
1167
1185
  }, expression.right);
1168
1186
  let alternate;
1169
- if (expression.operator == "||") {
1187
+ if (expression.operator == "||" || expression.operator == "or") {
1170
1188
  alternate = { ...consequent };
1171
1189
  consequent.body = [];
1172
1190
  }
@@ -1180,10 +1198,10 @@ function inliner_unused(expression, top) {
1180
1198
  ];
1181
1199
  }
1182
1200
  case "ConditionalExpression": {
1183
- const consequentExprs = inliner_unused(expression.consequent);
1184
- const alternateExprs = inliner_unused(expression.alternate);
1201
+ const consequentExprs = inliner_unused(state, expression.consequent);
1202
+ const alternateExprs = inliner_unused(state, expression.alternate);
1185
1203
  if (!consequentExprs.length && !alternateExprs.length) {
1186
- return inliner_unused(expression.test);
1204
+ return inliner_unused(state, expression.test);
1187
1205
  }
1188
1206
  return [
1189
1207
  withLoc({
@@ -1201,20 +1219,24 @@ function inliner_unused(expression, top) {
1201
1219
  ];
1202
1220
  }
1203
1221
  case "UnaryExpression":
1204
- return inliner_unused(expression.argument);
1222
+ return inliner_unused(state, expression.argument);
1205
1223
  case "MemberExpression":
1206
1224
  if (expression.computed) {
1207
- return inliner_unused(expression.object).concat(inliner_unused(expression.property));
1225
+ return inliner_unused(state, expression.object).concat(inliner_unused(state, expression.property));
1208
1226
  }
1209
- if (expression.object.type === "NewExpression") {
1227
+ if ((state.sdkVersion || 0) < 4001007 &&
1228
+ expression.object.type === "NewExpression") {
1229
+ // prior to 4.1.7 top level new expressions were discarded,
1230
+ // but (new X()).a was not. After 4.1.7, top level new is
1231
+ // executed, but top level (new X()).a is an error.
1210
1232
  break;
1211
1233
  }
1212
- return inliner_unused(expression.object);
1234
+ return inliner_unused(state, expression.object);
1213
1235
  case "ArrayExpression":
1214
- return expression.elements.map((e) => inliner_unused(e)).flat(1);
1236
+ return expression.elements.map((e) => inliner_unused(state, e)).flat(1);
1215
1237
  case "ObjectExpression":
1216
1238
  return expression.properties
1217
- .map((p) => inliner_unused(p.key).concat(inliner_unused(p.value)))
1239
+ .map((p) => inliner_unused(state, p.key).concat(inliner_unused(state, p.value)))
1218
1240
  .flat(1);
1219
1241
  }
1220
1242
  return top ? null : [estmt(expression)];
@@ -1374,7 +1396,7 @@ function inlineWithArgs(state, func, call, context) {
1374
1396
  ];
1375
1397
  }
1376
1398
  else {
1377
- const side_exprs = inliner_unused(last.argument);
1399
+ const side_exprs = inliner_unused(state, last.argument);
1378
1400
  block.body.splice(block.body.length - 1, 1, ...side_exprs);
1379
1401
  }
1380
1402
  }
@@ -1509,7 +1531,7 @@ function pragma_checker_pragmaChecker(state, ast, diagnostics) {
1509
1531
  return;
1510
1532
  diagnostics = diagnostics
1511
1533
  ?.slice()
1512
- .sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
1534
+ .sort((d1, d2) => d1.loc.start.offset - d2.loc.start.offset);
1513
1535
  let diagIndex = 0;
1514
1536
  let index = -1;
1515
1537
  let comment;
@@ -1522,6 +1544,12 @@ function pragma_checker_pragmaChecker(state, ast, diagnostics) {
1522
1544
  continue;
1523
1545
  const kind = match[1];
1524
1546
  let str = match[2];
1547
+ const verCheck = checkCompilerVersion(str.replace(/\s.*/, ""), state.sdkVersion || 0);
1548
+ if (verCheck === false)
1549
+ continue;
1550
+ if (verCheck === true) {
1551
+ str = str.replace(/^\S+\s+/, "");
1552
+ }
1525
1553
  matchers = [];
1526
1554
  while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
1527
1555
  matchers.push({ kind, quote: match[1], needle: match[2] });
@@ -3076,7 +3104,7 @@ function unused_exprs_cleanupUnusedVars(state, node) {
3076
3104
  if (node.expression.type === "AssignmentExpression") {
3077
3105
  if (node.expression.left.type === "Identifier" &&
3078
3106
  hasProperty(toRemove, node.expression.left.name)) {
3079
- return unused(node.expression.right);
3107
+ return unused(state, node.expression.right);
3080
3108
  }
3081
3109
  }
3082
3110
  else if (node.expression.type === "UpdateExpression" &&
@@ -3091,7 +3119,7 @@ function unused_exprs_cleanupUnusedVars(state, node) {
3091
3119
  if (expr.type === "AssignmentExpression") {
3092
3120
  if (expr.left.type === "Identifier" &&
3093
3121
  hasProperty(toRemove, expr.left.name)) {
3094
- const rep = unused(expr.right);
3122
+ const rep = unused(state, expr.right);
3095
3123
  if (!rep.length) {
3096
3124
  node.expressions.splice(i, 1);
3097
3125
  }
@@ -3121,13 +3149,16 @@ function unused_exprs_cleanupUnusedVars(state, node) {
3121
3149
  const vdecl = decl.declarations[i];
3122
3150
  const name = variableDeclarationName(vdecl.id);
3123
3151
  if (hasProperty(toRemove, name)) {
3124
- const rep = vdecl.init ? unused(vdecl.init) : [];
3152
+ const rep = vdecl.init ? unused(state, vdecl.init) : [];
3125
3153
  if (rep.length) {
3126
- if (rep.find((s) => s.type === "ExpressionStatement" &&
3127
- (s.expression.type === "NewExpression" ||
3128
- (s.expression.type === "MemberExpression" &&
3129
- !s.expression.computed &&
3130
- s.expression.object.type === "NewExpression")))) {
3154
+ if ((state.sdkVersion || 0) < 4001007 &&
3155
+ rep.find((s) => s.type === "ExpressionStatement" &&
3156
+ (s.expression.type === "NewExpression" ||
3157
+ (s.expression.type === "MemberExpression" &&
3158
+ !s.expression.computed &&
3159
+ s.expression.object.type === "NewExpression")))) {
3160
+ // prior to 4.1.7 vanilla new expressions were discarded,
3161
+ // so don't create top level new expressions.
3131
3162
  continue;
3132
3163
  }
3133
3164
  if (parent.node.type === "ForStatement") {
@@ -3191,6 +3222,7 @@ function unused_exprs_cleanupUnusedVars(state, node) {
3191
3222
 
3192
3223
 
3193
3224
 
3225
+
3194
3226
  function collectClassInfo(state) {
3195
3227
  const toybox = state.stack[0].decls["Toybox"][0];
3196
3228
  const lang = toybox.decls["Lang"][0];
@@ -3266,7 +3298,8 @@ function collectClassInfo(state) {
3266
3298
  if (elm.hasInvoke && elm.decls) {
3267
3299
  Object.values(elm.decls).forEach((funcs) => {
3268
3300
  funcs.forEach((f) => {
3269
- if (f.type === "FunctionDeclaration" && !f.isStatic) {
3301
+ if (f.type === "FunctionDeclaration" &&
3302
+ !(f.attributes & StateNodeAttributes.STATIC)) {
3270
3303
  markInvokeClassMethod(f);
3271
3304
  }
3272
3305
  });
@@ -3346,11 +3379,6 @@ async function analyze(fnMap, resourcesMap, config) {
3346
3379
  const [scope] = state.stack.slice(-1);
3347
3380
  scope.stack = state.stackClone().slice(0, -1);
3348
3381
  if (scope.type == "FunctionDeclaration") {
3349
- scope.isStatic =
3350
- scope.stack.slice(-1)[0].type !== "ClassDeclaration" ||
3351
- (scope.node.attrs &&
3352
- scope.node.attrs.access &&
3353
- scope.node.attrs.access.includes("static"));
3354
3382
  if (markApi) {
3355
3383
  node.body = null;
3356
3384
  scope.info = getApiFunctionInfo(scope);
@@ -3397,18 +3425,45 @@ function reportMissingSymbols(state, config) {
3397
3425
  const diagnosticType = config?.checkInvalidSymbols !== "OFF"
3398
3426
  ? config?.checkInvalidSymbols || "WARNING"
3399
3427
  : null;
3428
+ const compiler2DiagnosticType = config?.checkCompilerLookupRules !== "OFF"
3429
+ ? config?.checkCompilerLookupRules || "WARNING"
3430
+ : null;
3400
3431
  if (diagnosticType &&
3401
3432
  !config?.compilerOptions?.includes("--Eno-invalid-symbol")) {
3402
3433
  const checkTypes = config?.typeCheckLevel && config.typeCheckLevel !== "Off";
3403
3434
  Object.entries(state.fnMap).forEach(([, v]) => {
3404
3435
  visitReferences(state, v.ast, null, false, (node, results, error) => {
3405
- if (!error)
3406
- return undefined;
3407
3436
  if (node.type === "BinaryExpression" && node.operator === "has") {
3408
3437
  // Its not an error to check whether a property exists...
3409
3438
  return undefined;
3410
3439
  }
3411
3440
  const nodeStr = formatAst(node);
3441
+ if (!error) {
3442
+ if (state.sdkVersion === 4001006 &&
3443
+ compiler2DiagnosticType &&
3444
+ node.type === "MemberExpression" &&
3445
+ (node.object.type === "Identifier" ||
3446
+ node.object.type === "MemberExpression") &&
3447
+ results.some((result) => {
3448
+ const parent = result.parent;
3449
+ if (!parent || parent.type !== "ClassDeclaration") {
3450
+ return false;
3451
+ }
3452
+ return result.results.some((sn) => {
3453
+ switch (sn.type) {
3454
+ case "VariableDeclarator":
3455
+ case "FunctionDeclaration":
3456
+ return (sn.attributes &
3457
+ (StateNodeAttributes.PRIVATE |
3458
+ StateNodeAttributes.PROTECTED));
3459
+ }
3460
+ return false;
3461
+ });
3462
+ })) {
3463
+ diagnostic(state, node.loc, `The expression ${nodeStr} will fail at runtime using sdk-4.1.6`, compiler2DiagnosticType);
3464
+ }
3465
+ return undefined;
3466
+ }
3412
3467
  if (state.inType) {
3413
3468
  if (!checkTypes || nodeStr.match(/^Void|Null$/)) {
3414
3469
  return undefined;
@@ -3622,7 +3677,7 @@ function optimizeNode(state, node) {
3622
3677
  left.value === null ||
3623
3678
  ((left_type === "Number" || left_type === "Long") &&
3624
3679
  (left.value === 0 || left.value === 0n));
3625
- if (falsy === (node.operator === "&&")) {
3680
+ if (falsy === (node.operator === "&&" || node.operator === "and")) {
3626
3681
  return left;
3627
3682
  }
3628
3683
  if (left_type !== "Boolean" &&
@@ -3632,10 +3687,12 @@ function optimizeNode(state, node) {
3632
3687
  }
3633
3688
  const [right, right_type] = getNodeValue(node.right);
3634
3689
  if (right && right_type === left_type) {
3635
- if (left_type === "Boolean" || node.operator === "||") {
3690
+ if (left_type === "Boolean" ||
3691
+ node.operator === "||" ||
3692
+ node.operator === "or") {
3636
3693
  return right;
3637
3694
  }
3638
- if (node.operator !== "&&") {
3695
+ if (node.operator !== "&&" && node.operator !== "and") {
3639
3696
  throw new Error(`Unexpected operator "${node.operator}"`);
3640
3697
  }
3641
3698
  return { ...node, type: "BinaryExpression", operator: "&" };
@@ -4125,7 +4182,6 @@ async function optimizeMonkeyC(fnMap, resourcesMap, config) {
4125
4182
  if ((obj.type === "ModuleDeclaration" ||
4126
4183
  obj.type === "Program" ||
4127
4184
  obj.type === "ClassDeclaration") &&
4128
- obj.decls &&
4129
4185
  obj.stack) {
4130
4186
  const exists = hasProperty(obj.decls, node.right.argument.name) ||
4131
4187
  // This is overkill, since we've already looked up
@@ -4226,7 +4282,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, config) {
4226
4282
  }
4227
4283
  }
4228
4284
  else {
4229
- const ret = unused(node.expression, true);
4285
+ const ret = unused(state, node.expression, true);
4230
4286
  if (ret) {
4231
4287
  return ret
4232
4288
  .map((r) => replace(r, r))
@@ -4715,7 +4771,7 @@ function visitorNode(node) {
4715
4771
  }
4716
4772
  return node;
4717
4773
  }
4718
- function visitor_visitReferences(state, ast, name, defn, callback) {
4774
+ function visitor_visitReferences(state, ast, name, defn, callback, includeDefs = false) {
4719
4775
  const checkResults = ([name, results], node) => {
4720
4776
  if (name && results) {
4721
4777
  if (!defn || (0,external_api_cjs_namespaceObject.sameLookupResult)(results, defn)) {
@@ -4800,6 +4856,37 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
4800
4856
  }
4801
4857
  return ["returnType"];
4802
4858
  }
4859
+ case "ModuleDeclaration":
4860
+ if (includeDefs)
4861
+ break;
4862
+ return ["body"];
4863
+ case "ClassDeclaration":
4864
+ if (includeDefs)
4865
+ break;
4866
+ return ["body", "superClass"];
4867
+ case "FunctionDeclaration":
4868
+ if (includeDefs)
4869
+ break;
4870
+ return ["params", "returnType", "body"];
4871
+ case "TypedefDeclaration":
4872
+ if (includeDefs)
4873
+ break;
4874
+ return ["ts"];
4875
+ case "VariableDeclarator":
4876
+ if (includeDefs)
4877
+ break;
4878
+ return ["init"];
4879
+ case "EnumDeclaration":
4880
+ if (includeDefs)
4881
+ break;
4882
+ return [];
4883
+ case "CatchClause":
4884
+ if (includeDefs)
4885
+ break;
4886
+ if (node.param && node.param.type !== "Identifier") {
4887
+ state.traverse(node.param.right);
4888
+ }
4889
+ return ["body"];
4803
4890
  }
4804
4891
  return null;
4805
4892
  };
@@ -4820,6 +4907,7 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
4820
4907
 
4821
4908
 
4822
4909
 
4910
+
4823
4911
  /*
4824
4912
  * This is an unfortunate hack. I want to be able to extract things
4825
4913
  * like the types of all of a Class's variables (in particular the type
@@ -4829,11 +4917,48 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
4829
4917
  * undocumented. The same could be said of compiler.json and simulator.json,
4830
4918
  * but those are at least in a standard format.
4831
4919
  */
4920
+ function parseSdkVersion(version) {
4921
+ if (!version)
4922
+ return 0;
4923
+ const match = version.match(/^(\d+)[._](\d+)[._](\d+)$/);
4924
+ if (!match)
4925
+ return 0;
4926
+ return (parseInt(match[1], 10) * 1000000 +
4927
+ parseInt(match[2], 10) * 1000 +
4928
+ parseInt(match[3], 10));
4929
+ }
4930
+ function api_checkCompilerVersion(version, sdkVer) {
4931
+ const match = version.match(/^(\d+[._]\d+[._]\d+)?([-_])?(\d+[._]\d+[._]\d+)?$/);
4932
+ if (!match ||
4933
+ (match[1] && match[3] && !match[2]) ||
4934
+ (!match[1] && !match[3])) {
4935
+ return undefined;
4936
+ }
4937
+ const v1 = parseSdkVersion(match[1]);
4938
+ const v2 = parseSdkVersion(match[3]);
4939
+ if (v1) {
4940
+ if (v2) {
4941
+ return v1 <= sdkVer && sdkVer <= v2;
4942
+ }
4943
+ if (match[2]) {
4944
+ return v1 <= sdkVer;
4945
+ }
4946
+ return v1 === sdkVer;
4947
+ }
4948
+ return sdkVer <= v2;
4949
+ }
4832
4950
  // Extract all enum values from api.mir
4833
4951
  async function api_getApiMapping(state, resourcesMap) {
4834
4952
  // get the path to the currently active sdk
4835
4953
  const parser = (prettier_plugin_monkeyc_default()).parsers.monkeyc;
4836
4954
  const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
4955
+ if (state) {
4956
+ state.sdk = sdk;
4957
+ const match = state.sdk?.match(/-(\d+\.\d+\.\d+)/);
4958
+ if (match) {
4959
+ state.sdkVersion = parseSdkVersion(match[1]);
4960
+ }
4961
+ }
4837
4962
  const api = (await promises_namespaceObject.readFile(`${sdk}bin/api.mir`))
4838
4963
  .toString()
4839
4964
  .replace(/\r\n/g, "\n")
@@ -4890,6 +5015,26 @@ function api_isStateNode(node) {
4890
5015
  function api_variableDeclarationName(node) {
4891
5016
  return ("left" in node ? node.left : node).name;
4892
5017
  }
5018
+ function stateNodeAttrs(attrs) {
5019
+ return attrs && attrs.access
5020
+ ? attrs.access.reduce((cur, attr) => {
5021
+ switch (attr) {
5022
+ case "static":
5023
+ return cur | optimizer_types_StateNodeAttributes.STATIC;
5024
+ case "public":
5025
+ return cur | optimizer_types_StateNodeAttributes.PUBLIC;
5026
+ case "protected":
5027
+ return cur | optimizer_types_StateNodeAttributes.PROTECTED;
5028
+ case "hidden":
5029
+ return cur | optimizer_types_StateNodeAttributes.PROTECTED;
5030
+ case "private":
5031
+ return cur | optimizer_types_StateNodeAttributes.PRIVATE;
5032
+ default:
5033
+ return cur;
5034
+ }
5035
+ }, 0)
5036
+ : 0;
5037
+ }
4893
5038
  function lookupToStateNodeDecls(results) {
4894
5039
  return results.reduce((result, current) => current.results.length
4895
5040
  ? result
@@ -4897,7 +5042,7 @@ function lookupToStateNodeDecls(results) {
4897
5042
  : current.results
4898
5043
  : result, null);
4899
5044
  }
4900
- function checkOne(state, ns, decls, node, isStatic) {
5045
+ function checkOne(state, ns, decls, node) {
4901
5046
  // follow the superchain, looking up node in each class
4902
5047
  const superChain = (cls) => {
4903
5048
  if (!cls.superClass || cls.superClass === true) {
@@ -4912,7 +5057,7 @@ function checkOne(state, ns, decls, node, isStatic) {
4912
5057
  }, null);
4913
5058
  };
4914
5059
  const lookupInContext = (ns) => {
4915
- const [, lkup] = lookup(state, decls, node, null, ns.stack);
5060
+ const [, lkup] = lookup(state, decls, node, null, ns.stack, false, true);
4916
5061
  return lkup && lookupToStateNodeDecls(lkup);
4917
5062
  };
4918
5063
  // follow the superchain, looking up node in each class's scope
@@ -4934,10 +5079,7 @@ function checkOne(state, ns, decls, node, isStatic) {
4934
5079
  }
4935
5080
  switch (ns.type) {
4936
5081
  case "ClassDeclaration":
4937
- if (!isStatic) {
4938
- return superChain(ns) || superChainScopes(ns) || false;
4939
- }
4940
- // fall through
5082
+ return superChain(ns) || superChainScopes(ns) || false;
4941
5083
  case "ModuleDeclaration":
4942
5084
  return lookupInContext(ns) || false;
4943
5085
  }
@@ -4985,7 +5127,7 @@ function api_isLookupCandidate(node) {
4985
5127
  * - [false, false] - if the lookup fails, but its not an error because its not the kind of expression we can lookup
4986
5128
  * - [null, null] - if the lookup fails unexpectedly.
4987
5129
  */
4988
- function lookup(state, decls, node, name, maybeStack, nonlocal) {
5130
+ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
4989
5131
  const stack = maybeStack || state.stack;
4990
5132
  switch (node.type) {
4991
5133
  case "MemberExpression": {
@@ -4994,7 +5136,7 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
4994
5136
  break;
4995
5137
  let result;
4996
5138
  if (node.object.type === "ThisExpression") {
4997
- [, result] = lookup(state, decls, node.property, name, stack, true);
5139
+ [, result] = lookup(state, decls, node.property, name, stack, true, true);
4998
5140
  }
4999
5141
  else {
5000
5142
  const [, results] = lookup(state, decls, node.object, name, stack, false);
@@ -5008,7 +5150,7 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
5008
5150
  if (!api_isStateNode(module)) {
5009
5151
  return null;
5010
5152
  }
5011
- const res = checkOne(state, module, decls, property, false);
5153
+ const res = checkOne(state, module, decls, property);
5012
5154
  return res ? { parent: module, results: res } : null;
5013
5155
  })
5014
5156
  .filter((r) => r != null);
@@ -5051,30 +5193,66 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
5051
5193
  return [name || node.name, [{ parent: null, results: [stack[0]] }]];
5052
5194
  }
5053
5195
  let inStatic = false;
5054
- let checkedImports = false;
5196
+ let checkedImports = ignoreImports;
5197
+ let imports = null;
5055
5198
  for (let i = stack.length; i--;) {
5056
5199
  const si = stack[i];
5057
5200
  switch (si.type) {
5058
5201
  case "ClassDeclaration":
5202
+ if (inStatic && state.config?.enforceStatic != "NO") {
5203
+ inStatic = false;
5204
+ if (ast_hasProperty(si.decls, node.name)) {
5205
+ const r = si.decls[node.name].filter((s) => {
5206
+ switch (s.type) {
5207
+ case "FunctionDeclaration":
5208
+ case "VariableDeclarator":
5209
+ case "ClassDeclaration":
5210
+ // In theory we should include EnumStringMember here too, but
5211
+ // without adding an attributes field to EnumStringMember,
5212
+ // or turning it into a StateNodeDecl, we don't know whether
5213
+ // its static or not. But thats ok, because the optimizer
5214
+ // will replace its use with its value, so the optimized
5215
+ // code *will* work anyway.
5216
+ return s.attributes & optimizer_types_StateNodeAttributes.STATIC;
5217
+ default:
5218
+ return true;
5219
+ }
5220
+ });
5221
+ if (r.length) {
5222
+ return [name || node.name, [{ parent: si, results: r }]];
5223
+ }
5224
+ }
5225
+ continue;
5226
+ }
5227
+ // fall through
5059
5228
  case "ModuleDeclaration":
5060
5229
  case "Program":
5061
5230
  if (!checkedImports) {
5062
5231
  checkedImports = true;
5063
- const results = findUsingForNode(state, stack, i, node, decls === "type_decls");
5232
+ const results = findUsingForNode(state, stack, i, node);
5064
5233
  if (results) {
5065
- return [name || node.name, [{ parent: si, results }]];
5234
+ if (Array.isArray(results)) {
5235
+ if (!imports)
5236
+ imports = results;
5237
+ }
5238
+ else {
5239
+ return [
5240
+ name || node.name,
5241
+ [{ parent: si, results: [results] }],
5242
+ ];
5243
+ }
5066
5244
  }
5067
5245
  }
5068
5246
  break;
5069
5247
  case "FunctionDeclaration":
5070
- inStatic = si.isStatic === true;
5248
+ inStatic = !!(si.attributes & optimizer_types_StateNodeAttributes.STATIC);
5071
5249
  // fall through
5072
5250
  default:
5073
5251
  if (nonlocal)
5074
5252
  continue;
5075
5253
  break;
5076
5254
  }
5077
- const results = checkOne(state, si, decls, node, inStatic);
5255
+ const results = checkOne(state, si, decls, node);
5078
5256
  if (results) {
5079
5257
  return [name || node.name, [{ parent: si, results }]];
5080
5258
  }
@@ -5082,6 +5260,31 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
5082
5260
  break;
5083
5261
  }
5084
5262
  }
5263
+ if (imports) {
5264
+ if (imports.length > 1) {
5265
+ if (state.config?.checkInvalidSymbols !== "OFF") {
5266
+ inliner_diagnostic(state, node.loc, `${api_formatAst(node)} is ambiguous and exists in multiple imported modules [${imports
5267
+ .map(({ name }) => name)
5268
+ .join(", ")}]`, state.config?.checkInvalidSymbols || "WARNING");
5269
+ }
5270
+ else if (decls !== "type_decls" &&
5271
+ state.lookupRules === "COMPILER1") {
5272
+ return [null, null];
5273
+ }
5274
+ return [name || node.name, imports.map((d) => d.decls)];
5275
+ }
5276
+ if (imports.length == 1) {
5277
+ if (decls !== "type_decls") {
5278
+ if (state.config?.checkCompilerLookupRules !== "OFF") {
5279
+ inliner_diagnostic(state, node.loc, `${api_formatAst(node)} will only be found when compiled with compiler2 at -O1 or above`, state.config?.checkCompilerLookupRules || "WARNING");
5280
+ }
5281
+ else if (state.lookupRules === "COMPILER1") {
5282
+ return [null, null];
5283
+ }
5284
+ }
5285
+ return [name || node.name, [imports[0].decls]];
5286
+ }
5287
+ }
5085
5288
  return [null, null];
5086
5289
  }
5087
5290
  }
@@ -5095,9 +5298,27 @@ function api_collectNamespaces(ast, stateIn) {
5095
5298
  state.index = {};
5096
5299
  if (!state.stack) {
5097
5300
  state.stack = [
5098
- { type: "Program", name: "$", fullName: "$", node: undefined },
5301
+ {
5302
+ type: "Program",
5303
+ name: "$",
5304
+ fullName: "$",
5305
+ node: undefined,
5306
+ attributes: 0,
5307
+ },
5099
5308
  ];
5100
5309
  }
5310
+ if (!state.lookupRules) {
5311
+ const rules = state?.config?.compilerLookupRules || "DEFAULT";
5312
+ if (rules !== "COMPILER1" && rules !== "COMPILER2") {
5313
+ const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
5314
+ if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
5315
+ state.lookupRules = "COMPILER2";
5316
+ }
5317
+ else {
5318
+ state.lookupRules = "COMPILER1";
5319
+ }
5320
+ }
5321
+ }
5101
5322
  state.removeNodeComments = (node, ast) => {
5102
5323
  if (node.start && node.end && ast.comments && ast.comments.length) {
5103
5324
  let low = 0, high = ast.comments.length;
@@ -5192,6 +5413,7 @@ function api_collectNamespaces(ast, stateIn) {
5192
5413
  name: undefined,
5193
5414
  node: node.body,
5194
5415
  decls: { [id.name]: [id] },
5416
+ attributes: 0,
5195
5417
  });
5196
5418
  }
5197
5419
  break;
@@ -5202,6 +5424,7 @@ function api_collectNamespaces(ast, stateIn) {
5202
5424
  fullName: undefined,
5203
5425
  name: undefined,
5204
5426
  node: node,
5427
+ attributes: 0,
5205
5428
  });
5206
5429
  }
5207
5430
  break;
@@ -5229,6 +5452,9 @@ function api_collectNamespaces(ast, stateIn) {
5229
5452
  name,
5230
5453
  fullName,
5231
5454
  node,
5455
+ attributes: node.type === "BlockStatement"
5456
+ ? 0
5457
+ : stateNodeAttrs(node.attrs),
5232
5458
  };
5233
5459
  state.stack.push(elm);
5234
5460
  if (name) {
@@ -5255,9 +5481,6 @@ function api_collectNamespaces(ast, stateIn) {
5255
5481
  parent.decls[name].push(elm);
5256
5482
  if (node.type == "ModuleDeclaration" ||
5257
5483
  node.type == "ClassDeclaration") {
5258
- // Inject the class/module name into itself,
5259
- // so you can say Graphics.Graphics.Graphics.COLOR_RED
5260
- elm.decls = { [name]: [elm] };
5261
5484
  if (!parent.type_decls)
5262
5485
  parent.type_decls = {};
5263
5486
  if (!ast_hasProperty(parent.type_decls, name)) {
@@ -5299,6 +5522,7 @@ function api_collectNamespaces(ast, stateIn) {
5299
5522
  node,
5300
5523
  name,
5301
5524
  fullName: parent.fullName + "." + name,
5525
+ attributes: stateNodeAttrs(node.attrs),
5302
5526
  });
5303
5527
  break;
5304
5528
  }
@@ -5317,12 +5541,13 @@ function api_collectNamespaces(ast, stateIn) {
5317
5541
  return;
5318
5542
  }
5319
5543
  decl.kind = node.kind;
5320
- (0,external_util_cjs_namespaceObject.pushUnique)(decls[name], {
5544
+ decls[name].push({
5321
5545
  type: "VariableDeclarator",
5322
5546
  node: decl,
5323
5547
  name,
5324
5548
  fullName: parent.fullName + "." + name,
5325
5549
  stack,
5550
+ attributes: stateNodeAttrs(node.attrs),
5326
5551
  });
5327
5552
  if (node.kind == "const") {
5328
5553
  if (!ast_hasProperty(state.index, name)) {
@@ -5547,27 +5772,32 @@ function findUsing(state, stack, using) {
5547
5772
  }
5548
5773
  return null;
5549
5774
  }
5550
- function findUsingForNode(state, stack, i, node, isType) {
5775
+ function findUsingForNode(state, stack, i, node) {
5776
+ let imports = null;
5551
5777
  while (i >= 0) {
5552
5778
  const si = stack[i--];
5553
5779
  if (ast_hasProperty(si.usings, node.name)) {
5554
5780
  const using = si.usings[node.name];
5555
- const module = findUsing(state, stack, using);
5556
- return module && [module];
5781
+ return findUsing(state, stack, using);
5557
5782
  }
5558
- if (si.imports && isType) {
5783
+ if (si.imports) {
5559
5784
  for (let j = si.imports.length; j--;) {
5560
5785
  const using = si.imports[j];
5561
5786
  const module = findUsing(state, stack, using);
5562
5787
  if (module) {
5563
5788
  if (ast_hasProperty(module.type_decls, node.name)) {
5564
- return module.type_decls[node.name];
5789
+ if (!imports)
5790
+ imports = [];
5791
+ imports.push({
5792
+ name: `${module.fullName}.${node.name}`,
5793
+ decls: { parent: si, results: module.type_decls[node.name] },
5794
+ });
5565
5795
  }
5566
5796
  }
5567
5797
  }
5568
5798
  }
5569
5799
  }
5570
- return null;
5800
+ return imports;
5571
5801
  }
5572
5802
  const invokeInfo = {};
5573
5803
  const toyboxFnInfo = {};