@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/README.md +28 -0
- package/build/api.cjs +296 -66
- package/build/optimizer.cjs +118 -54
- package/build/sdk-util.cjs +3 -2
- package/build/src/api.d.ts +10 -2
- package/build/src/inliner.d.ts +2 -2
- package/build/src/jungles.d.ts +1 -1
- package/build/src/launch.d.ts +1 -1
- package/build/src/optimizer-types.d.ts +16 -2
- package/build/src/projects.d.ts +2 -0
- package/build/src/visitor.d.ts +1 -1
- package/build/src/xml-util.d.ts +2 -1
- package/package.json +3 -2
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,
|
|
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 (
|
|
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
|
|
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 (
|
|
3127
|
-
(s.
|
|
3128
|
-
(s.expression.type === "
|
|
3129
|
-
|
|
3130
|
-
|
|
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" &&
|
|
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" ||
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
5232
|
+
const results = findUsingForNode(state, stack, i, node);
|
|
5064
5233
|
if (results) {
|
|
5065
|
-
|
|
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.
|
|
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
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
5556
|
-
return module && [module];
|
|
5781
|
+
return findUsing(state, stack, using);
|
|
5557
5782
|
}
|
|
5558
|
-
if (si.imports
|
|
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
|
-
|
|
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
|
|
5800
|
+
return imports;
|
|
5571
5801
|
}
|
|
5572
5802
|
const invokeInfo = {};
|
|
5573
5803
|
const toyboxFnInfo = {};
|