@markw65/monkeyc-optimizer 1.0.39 → 1.0.40
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 +23 -0
- package/build/api.cjs +270 -65
- 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/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))
|
|
@@ -4800,6 +4856,12 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
|
|
|
4800
4856
|
}
|
|
4801
4857
|
return ["returnType"];
|
|
4802
4858
|
}
|
|
4859
|
+
case "ModuleDeclaration":
|
|
4860
|
+
return ["body"];
|
|
4861
|
+
case "ClassDeclaration":
|
|
4862
|
+
return ["body", "superClass"];
|
|
4863
|
+
case "FunctionDeclaration":
|
|
4864
|
+
return ["params", "returnType", "body"];
|
|
4803
4865
|
}
|
|
4804
4866
|
return null;
|
|
4805
4867
|
};
|
|
@@ -4820,6 +4882,7 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
|
|
|
4820
4882
|
|
|
4821
4883
|
|
|
4822
4884
|
|
|
4885
|
+
|
|
4823
4886
|
/*
|
|
4824
4887
|
* This is an unfortunate hack. I want to be able to extract things
|
|
4825
4888
|
* like the types of all of a Class's variables (in particular the type
|
|
@@ -4829,11 +4892,48 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
|
|
|
4829
4892
|
* undocumented. The same could be said of compiler.json and simulator.json,
|
|
4830
4893
|
* but those are at least in a standard format.
|
|
4831
4894
|
*/
|
|
4895
|
+
function parseSdkVersion(version) {
|
|
4896
|
+
if (!version)
|
|
4897
|
+
return 0;
|
|
4898
|
+
const match = version.match(/^(\d+)[._](\d+)[._](\d+)$/);
|
|
4899
|
+
if (!match)
|
|
4900
|
+
return 0;
|
|
4901
|
+
return (parseInt(match[1], 10) * 1000000 +
|
|
4902
|
+
parseInt(match[2], 10) * 1000 +
|
|
4903
|
+
parseInt(match[3], 10));
|
|
4904
|
+
}
|
|
4905
|
+
function api_checkCompilerVersion(version, sdkVer) {
|
|
4906
|
+
const match = version.match(/^(\d+[._]\d+[._]\d+)?([-_])?(\d+[._]\d+[._]\d+)?$/);
|
|
4907
|
+
if (!match ||
|
|
4908
|
+
(match[1] && match[3] && !match[2]) ||
|
|
4909
|
+
(!match[1] && !match[3])) {
|
|
4910
|
+
return undefined;
|
|
4911
|
+
}
|
|
4912
|
+
const v1 = parseSdkVersion(match[1]);
|
|
4913
|
+
const v2 = parseSdkVersion(match[3]);
|
|
4914
|
+
if (v1) {
|
|
4915
|
+
if (v2) {
|
|
4916
|
+
return v1 <= sdkVer && sdkVer <= v2;
|
|
4917
|
+
}
|
|
4918
|
+
if (match[2]) {
|
|
4919
|
+
return v1 <= sdkVer;
|
|
4920
|
+
}
|
|
4921
|
+
return v1 === sdkVer;
|
|
4922
|
+
}
|
|
4923
|
+
return sdkVer <= v2;
|
|
4924
|
+
}
|
|
4832
4925
|
// Extract all enum values from api.mir
|
|
4833
4926
|
async function api_getApiMapping(state, resourcesMap) {
|
|
4834
4927
|
// get the path to the currently active sdk
|
|
4835
4928
|
const parser = (prettier_plugin_monkeyc_default()).parsers.monkeyc;
|
|
4836
4929
|
const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
|
|
4930
|
+
if (state) {
|
|
4931
|
+
state.sdk = sdk;
|
|
4932
|
+
const match = state.sdk?.match(/-(\d+\.\d+\.\d+)/);
|
|
4933
|
+
if (match) {
|
|
4934
|
+
state.sdkVersion = parseSdkVersion(match[1]);
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4837
4937
|
const api = (await promises_namespaceObject.readFile(`${sdk}bin/api.mir`))
|
|
4838
4938
|
.toString()
|
|
4839
4939
|
.replace(/\r\n/g, "\n")
|
|
@@ -4890,6 +4990,26 @@ function api_isStateNode(node) {
|
|
|
4890
4990
|
function api_variableDeclarationName(node) {
|
|
4891
4991
|
return ("left" in node ? node.left : node).name;
|
|
4892
4992
|
}
|
|
4993
|
+
function stateNodeAttrs(attrs) {
|
|
4994
|
+
return attrs && attrs.access
|
|
4995
|
+
? attrs.access.reduce((cur, attr) => {
|
|
4996
|
+
switch (attr) {
|
|
4997
|
+
case "static":
|
|
4998
|
+
return cur | optimizer_types_StateNodeAttributes.STATIC;
|
|
4999
|
+
case "public":
|
|
5000
|
+
return cur | optimizer_types_StateNodeAttributes.PUBLIC;
|
|
5001
|
+
case "protected":
|
|
5002
|
+
return cur | optimizer_types_StateNodeAttributes.PROTECTED;
|
|
5003
|
+
case "hidden":
|
|
5004
|
+
return cur | optimizer_types_StateNodeAttributes.PROTECTED;
|
|
5005
|
+
case "private":
|
|
5006
|
+
return cur | optimizer_types_StateNodeAttributes.PRIVATE;
|
|
5007
|
+
default:
|
|
5008
|
+
return cur;
|
|
5009
|
+
}
|
|
5010
|
+
}, 0)
|
|
5011
|
+
: 0;
|
|
5012
|
+
}
|
|
4893
5013
|
function lookupToStateNodeDecls(results) {
|
|
4894
5014
|
return results.reduce((result, current) => current.results.length
|
|
4895
5015
|
? result
|
|
@@ -4897,7 +5017,7 @@ function lookupToStateNodeDecls(results) {
|
|
|
4897
5017
|
: current.results
|
|
4898
5018
|
: result, null);
|
|
4899
5019
|
}
|
|
4900
|
-
function checkOne(state, ns, decls, node
|
|
5020
|
+
function checkOne(state, ns, decls, node) {
|
|
4901
5021
|
// follow the superchain, looking up node in each class
|
|
4902
5022
|
const superChain = (cls) => {
|
|
4903
5023
|
if (!cls.superClass || cls.superClass === true) {
|
|
@@ -4912,7 +5032,7 @@ function checkOne(state, ns, decls, node, isStatic) {
|
|
|
4912
5032
|
}, null);
|
|
4913
5033
|
};
|
|
4914
5034
|
const lookupInContext = (ns) => {
|
|
4915
|
-
const [, lkup] = lookup(state, decls, node, null, ns.stack);
|
|
5035
|
+
const [, lkup] = lookup(state, decls, node, null, ns.stack, false, true);
|
|
4916
5036
|
return lkup && lookupToStateNodeDecls(lkup);
|
|
4917
5037
|
};
|
|
4918
5038
|
// follow the superchain, looking up node in each class's scope
|
|
@@ -4934,10 +5054,7 @@ function checkOne(state, ns, decls, node, isStatic) {
|
|
|
4934
5054
|
}
|
|
4935
5055
|
switch (ns.type) {
|
|
4936
5056
|
case "ClassDeclaration":
|
|
4937
|
-
|
|
4938
|
-
return superChain(ns) || superChainScopes(ns) || false;
|
|
4939
|
-
}
|
|
4940
|
-
// fall through
|
|
5057
|
+
return superChain(ns) || superChainScopes(ns) || false;
|
|
4941
5058
|
case "ModuleDeclaration":
|
|
4942
5059
|
return lookupInContext(ns) || false;
|
|
4943
5060
|
}
|
|
@@ -4985,7 +5102,7 @@ function api_isLookupCandidate(node) {
|
|
|
4985
5102
|
* - [false, false] - if the lookup fails, but its not an error because its not the kind of expression we can lookup
|
|
4986
5103
|
* - [null, null] - if the lookup fails unexpectedly.
|
|
4987
5104
|
*/
|
|
4988
|
-
function lookup(state, decls, node, name, maybeStack, nonlocal) {
|
|
5105
|
+
function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
|
|
4989
5106
|
const stack = maybeStack || state.stack;
|
|
4990
5107
|
switch (node.type) {
|
|
4991
5108
|
case "MemberExpression": {
|
|
@@ -4994,7 +5111,7 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
|
|
|
4994
5111
|
break;
|
|
4995
5112
|
let result;
|
|
4996
5113
|
if (node.object.type === "ThisExpression") {
|
|
4997
|
-
[, result] = lookup(state, decls, node.property, name, stack, true);
|
|
5114
|
+
[, result] = lookup(state, decls, node.property, name, stack, true, true);
|
|
4998
5115
|
}
|
|
4999
5116
|
else {
|
|
5000
5117
|
const [, results] = lookup(state, decls, node.object, name, stack, false);
|
|
@@ -5008,7 +5125,7 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
|
|
|
5008
5125
|
if (!api_isStateNode(module)) {
|
|
5009
5126
|
return null;
|
|
5010
5127
|
}
|
|
5011
|
-
const res = checkOne(state, module, decls, property
|
|
5128
|
+
const res = checkOne(state, module, decls, property);
|
|
5012
5129
|
return res ? { parent: module, results: res } : null;
|
|
5013
5130
|
})
|
|
5014
5131
|
.filter((r) => r != null);
|
|
@@ -5051,30 +5168,66 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
|
|
|
5051
5168
|
return [name || node.name, [{ parent: null, results: [stack[0]] }]];
|
|
5052
5169
|
}
|
|
5053
5170
|
let inStatic = false;
|
|
5054
|
-
let checkedImports =
|
|
5171
|
+
let checkedImports = ignoreImports;
|
|
5172
|
+
let imports = null;
|
|
5055
5173
|
for (let i = stack.length; i--;) {
|
|
5056
5174
|
const si = stack[i];
|
|
5057
5175
|
switch (si.type) {
|
|
5058
5176
|
case "ClassDeclaration":
|
|
5177
|
+
if (inStatic && state.config?.enforceStatic != "NO") {
|
|
5178
|
+
inStatic = false;
|
|
5179
|
+
if (ast_hasProperty(si.decls, node.name)) {
|
|
5180
|
+
const r = si.decls[node.name].filter((s) => {
|
|
5181
|
+
switch (s.type) {
|
|
5182
|
+
case "FunctionDeclaration":
|
|
5183
|
+
case "VariableDeclarator":
|
|
5184
|
+
case "ClassDeclaration":
|
|
5185
|
+
// In theory we should include EnumStringMember here too, but
|
|
5186
|
+
// without adding an attributes field to EnumStringMember,
|
|
5187
|
+
// or turning it into a StateNodeDecl, we don't know whether
|
|
5188
|
+
// its static or not. But thats ok, because the optimizer
|
|
5189
|
+
// will replace its use with its value, so the optimized
|
|
5190
|
+
// code *will* work anyway.
|
|
5191
|
+
return s.attributes & optimizer_types_StateNodeAttributes.STATIC;
|
|
5192
|
+
default:
|
|
5193
|
+
return true;
|
|
5194
|
+
}
|
|
5195
|
+
});
|
|
5196
|
+
if (r.length) {
|
|
5197
|
+
return [name || node.name, [{ parent: si, results: r }]];
|
|
5198
|
+
}
|
|
5199
|
+
}
|
|
5200
|
+
continue;
|
|
5201
|
+
}
|
|
5202
|
+
// fall through
|
|
5059
5203
|
case "ModuleDeclaration":
|
|
5060
5204
|
case "Program":
|
|
5061
5205
|
if (!checkedImports) {
|
|
5062
5206
|
checkedImports = true;
|
|
5063
|
-
const results = findUsingForNode(state, stack, i, node
|
|
5207
|
+
const results = findUsingForNode(state, stack, i, node);
|
|
5064
5208
|
if (results) {
|
|
5065
|
-
|
|
5209
|
+
if (Array.isArray(results)) {
|
|
5210
|
+
if (!imports)
|
|
5211
|
+
imports = results;
|
|
5212
|
+
}
|
|
5213
|
+
else {
|
|
5214
|
+
return [
|
|
5215
|
+
name || node.name,
|
|
5216
|
+
[{ parent: si, results: [results] }],
|
|
5217
|
+
];
|
|
5218
|
+
}
|
|
5066
5219
|
}
|
|
5067
5220
|
}
|
|
5068
5221
|
break;
|
|
5069
5222
|
case "FunctionDeclaration":
|
|
5070
|
-
inStatic = si.
|
|
5223
|
+
inStatic = !!(si.attributes & optimizer_types_StateNodeAttributes.STATIC);
|
|
5071
5224
|
// fall through
|
|
5072
5225
|
default:
|
|
5073
5226
|
if (nonlocal)
|
|
5074
5227
|
continue;
|
|
5075
5228
|
break;
|
|
5076
5229
|
}
|
|
5077
|
-
const results = checkOne(state, si, decls, node
|
|
5230
|
+
const results = checkOne(state, si, decls, node);
|
|
5078
5231
|
if (results) {
|
|
5079
5232
|
return [name || node.name, [{ parent: si, results }]];
|
|
5080
5233
|
}
|
|
@@ -5082,6 +5235,31 @@ function lookup(state, decls, node, name, maybeStack, nonlocal) {
|
|
|
5082
5235
|
break;
|
|
5083
5236
|
}
|
|
5084
5237
|
}
|
|
5238
|
+
if (imports) {
|
|
5239
|
+
if (imports.length > 1) {
|
|
5240
|
+
if (state.config?.checkInvalidSymbols !== "OFF") {
|
|
5241
|
+
inliner_diagnostic(state, node.loc, `${api_formatAst(node)} is ambiguous and exists in multiple imported modules [${imports
|
|
5242
|
+
.map(({ name }) => name)
|
|
5243
|
+
.join(", ")}]`, state.config?.checkInvalidSymbols || "WARNING");
|
|
5244
|
+
}
|
|
5245
|
+
else if (decls !== "type_decls" &&
|
|
5246
|
+
state.lookupRules === "COMPILER1") {
|
|
5247
|
+
return [null, null];
|
|
5248
|
+
}
|
|
5249
|
+
return [name || node.name, imports.map((d) => d.decls)];
|
|
5250
|
+
}
|
|
5251
|
+
if (imports.length == 1) {
|
|
5252
|
+
if (decls !== "type_decls") {
|
|
5253
|
+
if (state.config?.checkCompilerLookupRules !== "OFF") {
|
|
5254
|
+
inliner_diagnostic(state, node.loc, `${api_formatAst(node)} will only be found when compiled with compiler2 at -O1 or above`, state.config?.checkCompilerLookupRules || "WARNING");
|
|
5255
|
+
}
|
|
5256
|
+
else if (state.lookupRules === "COMPILER1") {
|
|
5257
|
+
return [null, null];
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
5260
|
+
return [name || node.name, [imports[0].decls]];
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5085
5263
|
return [null, null];
|
|
5086
5264
|
}
|
|
5087
5265
|
}
|
|
@@ -5095,9 +5273,27 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
5095
5273
|
state.index = {};
|
|
5096
5274
|
if (!state.stack) {
|
|
5097
5275
|
state.stack = [
|
|
5098
|
-
{
|
|
5276
|
+
{
|
|
5277
|
+
type: "Program",
|
|
5278
|
+
name: "$",
|
|
5279
|
+
fullName: "$",
|
|
5280
|
+
node: undefined,
|
|
5281
|
+
attributes: 0,
|
|
5282
|
+
},
|
|
5099
5283
|
];
|
|
5100
5284
|
}
|
|
5285
|
+
if (!state.lookupRules) {
|
|
5286
|
+
const rules = state?.config?.compilerLookupRules || "DEFAULT";
|
|
5287
|
+
if (rules !== "COMPILER1" && rules !== "COMPILER2") {
|
|
5288
|
+
const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
|
|
5289
|
+
if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
|
|
5290
|
+
state.lookupRules = "COMPILER2";
|
|
5291
|
+
}
|
|
5292
|
+
else {
|
|
5293
|
+
state.lookupRules = "COMPILER1";
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
}
|
|
5101
5297
|
state.removeNodeComments = (node, ast) => {
|
|
5102
5298
|
if (node.start && node.end && ast.comments && ast.comments.length) {
|
|
5103
5299
|
let low = 0, high = ast.comments.length;
|
|
@@ -5192,6 +5388,7 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
5192
5388
|
name: undefined,
|
|
5193
5389
|
node: node.body,
|
|
5194
5390
|
decls: { [id.name]: [id] },
|
|
5391
|
+
attributes: 0,
|
|
5195
5392
|
});
|
|
5196
5393
|
}
|
|
5197
5394
|
break;
|
|
@@ -5202,6 +5399,7 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
5202
5399
|
fullName: undefined,
|
|
5203
5400
|
name: undefined,
|
|
5204
5401
|
node: node,
|
|
5402
|
+
attributes: 0,
|
|
5205
5403
|
});
|
|
5206
5404
|
}
|
|
5207
5405
|
break;
|
|
@@ -5229,6 +5427,9 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
5229
5427
|
name,
|
|
5230
5428
|
fullName,
|
|
5231
5429
|
node,
|
|
5430
|
+
attributes: node.type === "BlockStatement"
|
|
5431
|
+
? 0
|
|
5432
|
+
: stateNodeAttrs(node.attrs),
|
|
5232
5433
|
};
|
|
5233
5434
|
state.stack.push(elm);
|
|
5234
5435
|
if (name) {
|
|
@@ -5255,9 +5456,6 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
5255
5456
|
parent.decls[name].push(elm);
|
|
5256
5457
|
if (node.type == "ModuleDeclaration" ||
|
|
5257
5458
|
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
5459
|
if (!parent.type_decls)
|
|
5262
5460
|
parent.type_decls = {};
|
|
5263
5461
|
if (!ast_hasProperty(parent.type_decls, name)) {
|
|
@@ -5299,6 +5497,7 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
5299
5497
|
node,
|
|
5300
5498
|
name,
|
|
5301
5499
|
fullName: parent.fullName + "." + name,
|
|
5500
|
+
attributes: stateNodeAttrs(node.attrs),
|
|
5302
5501
|
});
|
|
5303
5502
|
break;
|
|
5304
5503
|
}
|
|
@@ -5317,12 +5516,13 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
5317
5516
|
return;
|
|
5318
5517
|
}
|
|
5319
5518
|
decl.kind = node.kind;
|
|
5320
|
-
|
|
5519
|
+
decls[name].push({
|
|
5321
5520
|
type: "VariableDeclarator",
|
|
5322
5521
|
node: decl,
|
|
5323
5522
|
name,
|
|
5324
5523
|
fullName: parent.fullName + "." + name,
|
|
5325
5524
|
stack,
|
|
5525
|
+
attributes: stateNodeAttrs(node.attrs),
|
|
5326
5526
|
});
|
|
5327
5527
|
if (node.kind == "const") {
|
|
5328
5528
|
if (!ast_hasProperty(state.index, name)) {
|
|
@@ -5547,27 +5747,32 @@ function findUsing(state, stack, using) {
|
|
|
5547
5747
|
}
|
|
5548
5748
|
return null;
|
|
5549
5749
|
}
|
|
5550
|
-
function findUsingForNode(state, stack, i, node
|
|
5750
|
+
function findUsingForNode(state, stack, i, node) {
|
|
5751
|
+
let imports = null;
|
|
5551
5752
|
while (i >= 0) {
|
|
5552
5753
|
const si = stack[i--];
|
|
5553
5754
|
if (ast_hasProperty(si.usings, node.name)) {
|
|
5554
5755
|
const using = si.usings[node.name];
|
|
5555
|
-
|
|
5556
|
-
return module && [module];
|
|
5756
|
+
return findUsing(state, stack, using);
|
|
5557
5757
|
}
|
|
5558
|
-
if (si.imports
|
|
5758
|
+
if (si.imports) {
|
|
5559
5759
|
for (let j = si.imports.length; j--;) {
|
|
5560
5760
|
const using = si.imports[j];
|
|
5561
5761
|
const module = findUsing(state, stack, using);
|
|
5562
5762
|
if (module) {
|
|
5563
5763
|
if (ast_hasProperty(module.type_decls, node.name)) {
|
|
5564
|
-
|
|
5764
|
+
if (!imports)
|
|
5765
|
+
imports = [];
|
|
5766
|
+
imports.push({
|
|
5767
|
+
name: `${module.fullName}.${node.name}`,
|
|
5768
|
+
decls: { parent: si, results: module.type_decls[node.name] },
|
|
5769
|
+
});
|
|
5565
5770
|
}
|
|
5566
5771
|
}
|
|
5567
5772
|
}
|
|
5568
5773
|
}
|
|
5569
5774
|
}
|
|
5570
|
-
return
|
|
5775
|
+
return imports;
|
|
5571
5776
|
}
|
|
5572
5777
|
const invokeInfo = {};
|
|
5573
5778
|
const toyboxFnInfo = {};
|