@markw65/monkeyc-optimizer 1.0.21 → 1.0.24
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 +36 -0
- package/build/api.cjs +717 -237
- package/build/optimizer.cjs +499 -161
- package/build/src/api.d.ts +7 -3
- package/build/src/ast.d.ts +2 -0
- package/build/src/inliner.d.ts +1 -5
- package/build/src/mc-rewrite.d.ts +4 -4
- package/build/src/optimizer.d.ts +28 -11
- package/build/src/pragma-checker.d.ts +1 -1
- package/build/src/util.d.ts +1 -0
- package/build/src/visitor.d.ts +2 -0
- package/build/util.cjs +10 -4
- package/package.json +9 -4
package/build/optimizer.cjs
CHANGED
|
@@ -9858,7 +9858,7 @@ const external_util_cjs_namespaceObject = require("./util.cjs");
|
|
|
9858
9858
|
async function build_project(product, options, lineCallback) {
|
|
9859
9859
|
const { workspace, program, jungleFiles, developerKeyPath, simulatorBuild, releaseBuild, testBuild, compilerOptions, compilerWarnings, typeCheckLevel, returnCommand, } = options;
|
|
9860
9860
|
const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
|
|
9861
|
-
|
|
9861
|
+
const extraArgs = [];
|
|
9862
9862
|
if (compilerOptions) {
|
|
9863
9863
|
extraArgs.push(...compilerOptions.split(/\s+/));
|
|
9864
9864
|
}
|
|
@@ -9894,6 +9894,9 @@ async function build_project(product, options, lineCallback) {
|
|
|
9894
9894
|
else if (testBuild) {
|
|
9895
9895
|
throw new Error("Building for tests requires a device to build for!");
|
|
9896
9896
|
}
|
|
9897
|
+
if (!program || !jungleFiles || !developerKeyPath || !workspace) {
|
|
9898
|
+
throw new Error("Required arguments were missing!");
|
|
9899
|
+
}
|
|
9897
9900
|
const exe = external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "monkeyc.bat" : "monkeyc");
|
|
9898
9901
|
const args = [
|
|
9899
9902
|
["-o", program],
|
|
@@ -9928,9 +9931,8 @@ async function readManifest(manifest) {
|
|
|
9928
9931
|
return (0,xml2js.parseStringPromise)(data.toString(), { trim: true });
|
|
9929
9932
|
}
|
|
9930
9933
|
async function writeManifest(filename, xml) {
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
return promises_namespaceObject.writeFile(filename, text);
|
|
9934
|
+
const builder = new xml2js.Builder();
|
|
9935
|
+
return promises_namespaceObject.writeFile(filename, builder.buildObject(xml));
|
|
9934
9936
|
}
|
|
9935
9937
|
function manifestProducts(manifest) {
|
|
9936
9938
|
const app = manifest["iq:manifest"]["iq:application"] ||
|
|
@@ -10228,7 +10230,7 @@ function resolve_node_by_path(state, path) {
|
|
|
10228
10230
|
}
|
|
10229
10231
|
if (!s[n] && s["."]) {
|
|
10230
10232
|
const sdot = s["."];
|
|
10231
|
-
|
|
10233
|
+
const resolved = resolve_node_list(state, sdot);
|
|
10232
10234
|
if (!resolved.length)
|
|
10233
10235
|
return undefined;
|
|
10234
10236
|
const r = resolved[0][n];
|
|
@@ -10317,11 +10319,11 @@ async function resolve_literals(qualifier, default_source, deviceInfo) {
|
|
|
10317
10319
|
return resolve_file_list(v.values);
|
|
10318
10320
|
}
|
|
10319
10321
|
let resolved = resolve_filename(v, default_source);
|
|
10320
|
-
if (/[
|
|
10322
|
+
if (/[*?[\]{}]/.test(resolved)) {
|
|
10321
10323
|
// Jungle files can contain "./**.mc" which is supposed to match
|
|
10322
10324
|
// any mc file under "./". The standard way to express that
|
|
10323
10325
|
// is "./**/*.mc", which is what glob expects, so translate.
|
|
10324
|
-
resolved = resolved.replace(/[
|
|
10326
|
+
resolved = resolved.replace(/[\\/]\*\*([^\\/])/g, "/**/*$1");
|
|
10325
10327
|
const match = await (0,external_util_cjs_namespaceObject.globa)(resolved);
|
|
10326
10328
|
return match.length ? resolved : null;
|
|
10327
10329
|
}
|
|
@@ -10595,7 +10597,7 @@ function resolve_barrel(barrel, barrelDir, products, options) {
|
|
|
10595
10597
|
const sha1 = external_crypto_namespaceObject.createHash("sha1")
|
|
10596
10598
|
.update(barrel, "binary")
|
|
10597
10599
|
.digest("base64")
|
|
10598
|
-
.replace(/[
|
|
10600
|
+
.replace(/[/=+]/g, "");
|
|
10599
10601
|
const localPath = external_path_.resolve(barrelDir, `${external_path_.basename(barrel, ".barrel")}-${sha1}`);
|
|
10600
10602
|
rawBarrel = external_path_.resolve(localPath, "barrel.jungle");
|
|
10601
10603
|
promise = promise.then(() => promises_namespaceObject.stat(localPath)
|
|
@@ -10745,7 +10747,9 @@ async function get_jungle_and_barrels(jungleFiles, defaultProducts, options) {
|
|
|
10745
10747
|
targets.push({ product, qualifier, shape });
|
|
10746
10748
|
return resolve_barrels(product, qualifier, barrels, products, options);
|
|
10747
10749
|
})
|
|
10748
|
-
.then(() => {
|
|
10750
|
+
.then(() => {
|
|
10751
|
+
return;
|
|
10752
|
+
});
|
|
10749
10753
|
};
|
|
10750
10754
|
products.forEach((product) => {
|
|
10751
10755
|
if ((0,external_api_cjs_namespaceObject.hasProperty)(state, product)) {
|
|
@@ -10788,11 +10792,151 @@ function simulateProgram(prg, device, test = false, logger) {
|
|
|
10788
10792
|
const args = [prg, device];
|
|
10789
10793
|
if (test)
|
|
10790
10794
|
args.push("-t");
|
|
10791
|
-
return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, logger || ((line) => console.log(line))).then(() => {
|
|
10795
|
+
return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, logger || ((line) => console.log(line))).then(() => {
|
|
10796
|
+
return;
|
|
10797
|
+
}));
|
|
10798
|
+
}
|
|
10799
|
+
|
|
10800
|
+
;// CONCATENATED MODULE: ./src/ast.ts
|
|
10801
|
+
/*
|
|
10802
|
+
* This ensures that mctreeTypeInfo has every key of MCTreeTypeInfo,
|
|
10803
|
+
* and that the corresponding arrays contain every element of the
|
|
10804
|
+
* corresponding type.
|
|
10805
|
+
*
|
|
10806
|
+
* ie, any time mctree.Node changes, we'll get errors here if
|
|
10807
|
+
* mctreeTypeInfo needs updating.
|
|
10808
|
+
*
|
|
10809
|
+
*/
|
|
10810
|
+
function _check(x) {
|
|
10811
|
+
const y = x;
|
|
10812
|
+
x = y;
|
|
10813
|
+
}
|
|
10814
|
+
const mctreeTypeInfo = {
|
|
10815
|
+
ArrayExpression: ["elements"],
|
|
10816
|
+
AssignmentExpression: ["left", "right"],
|
|
10817
|
+
AttributeList: ["attributes"],
|
|
10818
|
+
Attributes: ["elements"],
|
|
10819
|
+
BinaryExpression: ["left", "right"],
|
|
10820
|
+
Block: [],
|
|
10821
|
+
BlockStatement: ["body", "innerComments"],
|
|
10822
|
+
BreakStatement: [],
|
|
10823
|
+
CallExpression: ["callee", "arguments"],
|
|
10824
|
+
CatchClause: ["param", "body"],
|
|
10825
|
+
CatchClauses: ["catches"],
|
|
10826
|
+
ClassBody: ["body"],
|
|
10827
|
+
ClassDeclaration: ["attrs", "id", "superClass", "body"],
|
|
10828
|
+
ClassElement: ["item"],
|
|
10829
|
+
ConditionalExpression: ["test", "consequent", "alternate"],
|
|
10830
|
+
ContinueStatement: [],
|
|
10831
|
+
DoWhileStatement: ["body", "test"],
|
|
10832
|
+
EnumDeclaration: ["attrs", "id", "body"],
|
|
10833
|
+
EnumStringBody: ["members"],
|
|
10834
|
+
EnumStringMember: ["id", "init"],
|
|
10835
|
+
ExpressionStatement: ["expression"],
|
|
10836
|
+
ForStatement: ["init", "test", "body", "update"],
|
|
10837
|
+
FunctionDeclaration: ["attrs", "id", "params", "body"],
|
|
10838
|
+
Identifier: [],
|
|
10839
|
+
IfStatement: ["test", "consequent", "alternate"],
|
|
10840
|
+
ImportModule: ["id"],
|
|
10841
|
+
InstanceOfCase: ["id"],
|
|
10842
|
+
Line: [],
|
|
10843
|
+
Literal: [],
|
|
10844
|
+
LogicalExpression: ["left", "right"],
|
|
10845
|
+
MemberExpression: ["object", "property"],
|
|
10846
|
+
MethodDefinition: ["params", "returnType"],
|
|
10847
|
+
ModuleDeclaration: ["attrs", "id", "body"],
|
|
10848
|
+
MultiLine: [],
|
|
10849
|
+
NewExpression: ["callee", "arguments"],
|
|
10850
|
+
ObjectExpression: ["properties"],
|
|
10851
|
+
ParenthesizedExpression: ["expression"],
|
|
10852
|
+
Program: ["body", "comments"],
|
|
10853
|
+
Property: ["key", "value"],
|
|
10854
|
+
ReturnStatement: ["argument"],
|
|
10855
|
+
SequenceExpression: ["expressions"],
|
|
10856
|
+
SizedArrayExpression: ["size", "ts"],
|
|
10857
|
+
SwitchCase: ["test", "consequent"],
|
|
10858
|
+
SwitchStatement: ["discriminant", "cases"],
|
|
10859
|
+
ThisExpression: [],
|
|
10860
|
+
ThrowStatement: ["argument"],
|
|
10861
|
+
TryStatement: ["block", "handler", "finalizer"],
|
|
10862
|
+
TypedefDeclaration: ["attrs", "id", "ts"],
|
|
10863
|
+
TypeSpecList: ["ts"],
|
|
10864
|
+
TypeSpecPart: ["name", "body", "callspec", "generics"],
|
|
10865
|
+
UnaryExpression: ["argument"],
|
|
10866
|
+
UpdateExpression: ["argument"],
|
|
10867
|
+
Using: ["id", "as"],
|
|
10868
|
+
VariableDeclaration: ["attrs", "declarations"],
|
|
10869
|
+
VariableDeclarator: ["id", "init"],
|
|
10870
|
+
WhileStatement: ["test", "body"],
|
|
10871
|
+
};
|
|
10872
|
+
function isMCTreeNode(node) {
|
|
10873
|
+
return node ? typeof node === "object" && "type" in node : false;
|
|
10874
|
+
}
|
|
10875
|
+
/*
|
|
10876
|
+
* Traverse the ast rooted at node, calling pre before
|
|
10877
|
+
* visiting each node, and post after.
|
|
10878
|
+
*
|
|
10879
|
+
* - if pre returns false, the node is not traversed, and
|
|
10880
|
+
* post is not called;
|
|
10881
|
+
* - if pre returns a list of child nodes, only those will
|
|
10882
|
+
* be traversed
|
|
10883
|
+
* - otherwise all child nodes are traversed
|
|
10884
|
+
*
|
|
10885
|
+
* - if post returns false, the node it was called on is
|
|
10886
|
+
* removed.
|
|
10887
|
+
*/
|
|
10888
|
+
function traverseAst(node, pre, post) {
|
|
10889
|
+
const nodes = pre && pre(node);
|
|
10890
|
+
if (nodes === false)
|
|
10891
|
+
return;
|
|
10892
|
+
if (!mctreeTypeInfo[node.type]) {
|
|
10893
|
+
throw new Error("what?");
|
|
10894
|
+
}
|
|
10895
|
+
for (const key of nodes || mctreeTypeInfo[node.type]) {
|
|
10896
|
+
const value = node[key];
|
|
10897
|
+
if (!value)
|
|
10898
|
+
continue;
|
|
10899
|
+
if (Array.isArray(value)) {
|
|
10900
|
+
const values = value;
|
|
10901
|
+
const deletions = values.reduce((state, obj, i) => {
|
|
10902
|
+
if (isMCTreeNode(obj)) {
|
|
10903
|
+
const repl = traverseAst(obj, pre, post);
|
|
10904
|
+
if (repl === false) {
|
|
10905
|
+
if (!state)
|
|
10906
|
+
state = {};
|
|
10907
|
+
state[i] = true;
|
|
10908
|
+
}
|
|
10909
|
+
else if (repl != null) {
|
|
10910
|
+
if (!state)
|
|
10911
|
+
state = {};
|
|
10912
|
+
values[i] = repl;
|
|
10913
|
+
}
|
|
10914
|
+
}
|
|
10915
|
+
return state;
|
|
10916
|
+
}, null);
|
|
10917
|
+
if (deletions) {
|
|
10918
|
+
values.splice(0, values.length, ...values.filter((obj, i) => deletions[i] !== true).flat(1));
|
|
10919
|
+
}
|
|
10920
|
+
}
|
|
10921
|
+
else if (isMCTreeNode(value)) {
|
|
10922
|
+
const repl = traverseAst(value, pre, post);
|
|
10923
|
+
if (repl === false) {
|
|
10924
|
+
delete node[key];
|
|
10925
|
+
}
|
|
10926
|
+
else if (repl != null) {
|
|
10927
|
+
if (Array.isArray(repl)) {
|
|
10928
|
+
throw new Error("Array returned by traverseAst in Node context");
|
|
10929
|
+
}
|
|
10930
|
+
node[key] = repl;
|
|
10931
|
+
}
|
|
10932
|
+
}
|
|
10933
|
+
}
|
|
10934
|
+
return post && post(node);
|
|
10792
10935
|
}
|
|
10793
10936
|
|
|
10794
10937
|
;// CONCATENATED MODULE: ./src/variable-renamer.ts
|
|
10795
10938
|
|
|
10939
|
+
|
|
10796
10940
|
function renameVariable(state, locals, declName) {
|
|
10797
10941
|
const map = locals.map;
|
|
10798
10942
|
if (!(0,external_api_cjs_namespaceObject.hasProperty)(map, declName))
|
|
@@ -10809,7 +10953,7 @@ function renameVariable(state, locals, declName) {
|
|
|
10809
10953
|
// more conflicts
|
|
10810
10954
|
locals.inners = {};
|
|
10811
10955
|
const inners = locals.inners;
|
|
10812
|
-
|
|
10956
|
+
traverseAst(locals.node, (node) => {
|
|
10813
10957
|
if (node.type === "VariableDeclarator") {
|
|
10814
10958
|
inners[(0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id)] = true;
|
|
10815
10959
|
}
|
|
@@ -10849,6 +10993,7 @@ function renameVariable(state, locals, declName) {
|
|
|
10849
10993
|
;// CONCATENATED MODULE: ./src/inliner.ts
|
|
10850
10994
|
|
|
10851
10995
|
|
|
10996
|
+
|
|
10852
10997
|
function getArgSafety(state, func, args, requireAll) {
|
|
10853
10998
|
// determine whether decl might be changed by a function call
|
|
10854
10999
|
// or assignment during the evaluation of FunctionStateNode.
|
|
@@ -10890,11 +11035,13 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
10890
11035
|
case "Identifier":
|
|
10891
11036
|
case "MemberExpression": {
|
|
10892
11037
|
const [, results] = state.lookup(arg);
|
|
10893
|
-
if (!results ||
|
|
11038
|
+
if (!results ||
|
|
11039
|
+
results.length !== 1 ||
|
|
11040
|
+
results[0].results.length !== 1) {
|
|
10894
11041
|
safeArgs.push(null);
|
|
10895
11042
|
return !requireAll;
|
|
10896
11043
|
}
|
|
10897
|
-
const safety = getSafety(results[0]);
|
|
11044
|
+
const safety = getSafety(results[0].results[0]);
|
|
10898
11045
|
safeArgs.push(safety);
|
|
10899
11046
|
if (!safety) {
|
|
10900
11047
|
allSafe = false;
|
|
@@ -10914,25 +11061,12 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
10914
11061
|
if (allSafe && requireAll)
|
|
10915
11062
|
return true;
|
|
10916
11063
|
let callSeen = false;
|
|
10917
|
-
let ok = true;
|
|
10918
11064
|
const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
|
|
10919
|
-
const getLoc = (node) => (Array.isArray(node) ? node[0].start : node.start) || 0;
|
|
10920
11065
|
// look for uses of "unsafe" args that occur after a call.
|
|
10921
11066
|
// use post to do the checking, because arguments are evaluated
|
|
10922
11067
|
// prior to the call, so eg "return f(x.y);" is fine, but
|
|
10923
11068
|
// "return f()+x.y" is not.
|
|
10924
|
-
|
|
10925
|
-
// We also have to use a "pre" to ensure that child nodes are
|
|
10926
|
-
// visited in source order (otherwise we could visit x.y before f()
|
|
10927
|
-
// in the above example)
|
|
10928
|
-
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
|
|
10929
|
-
return Object.entries(node)
|
|
10930
|
-
.filter((kv) => Array.isArray(kv[1])
|
|
10931
|
-
? kv[1].length !== 0 && (0,external_api_cjs_namespaceObject.hasProperty)(kv[1][0], "type")
|
|
10932
|
-
: (0,external_api_cjs_namespaceObject.hasProperty)(kv[1], "type"))
|
|
10933
|
-
.sort(([, a], [, b]) => getLoc(a) - getLoc(b))
|
|
10934
|
-
.map(([key]) => key);
|
|
10935
|
-
}, (node) => {
|
|
11069
|
+
traverseAst(func.node.body, null, (node) => {
|
|
10936
11070
|
switch (node.type) {
|
|
10937
11071
|
case "AssignmentExpression":
|
|
10938
11072
|
case "UpdateExpression": {
|
|
@@ -10986,12 +11120,6 @@ function inliningLooksUseful(func, node) {
|
|
|
10986
11120
|
}
|
|
10987
11121
|
return false;
|
|
10988
11122
|
}
|
|
10989
|
-
var InlineStatus;
|
|
10990
|
-
(function (InlineStatus) {
|
|
10991
|
-
InlineStatus[InlineStatus["Never"] = 0] = "Never";
|
|
10992
|
-
InlineStatus[InlineStatus["AsExpression"] = 1] = "AsExpression";
|
|
10993
|
-
InlineStatus[InlineStatus["AsStatement"] = 2] = "AsStatement";
|
|
10994
|
-
})(InlineStatus || (InlineStatus = {}));
|
|
10995
11123
|
function inlineRequested(state, func) {
|
|
10996
11124
|
const excludeAnnotations = (func.node.loc?.source &&
|
|
10997
11125
|
state.fnMap[func.node.loc?.source]?.excludeAnnotations) ||
|
|
@@ -11001,7 +11129,7 @@ function inlineRequested(state, func) {
|
|
|
11001
11129
|
func.node.attrs.attributes.elements.some((attr) => attr.type === "UnaryExpression" &&
|
|
11002
11130
|
(attr.argument.name === "inline" ||
|
|
11003
11131
|
(attr.argument.name.startsWith("inline_") &&
|
|
11004
|
-
(0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
|
|
11132
|
+
!(0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))))) {
|
|
11005
11133
|
return true;
|
|
11006
11134
|
}
|
|
11007
11135
|
return false;
|
|
@@ -11171,7 +11299,7 @@ function unused(expression, top) {
|
|
|
11171
11299
|
},
|
|
11172
11300
|
];
|
|
11173
11301
|
}
|
|
11174
|
-
function diagnostic(state, loc, message) {
|
|
11302
|
+
function diagnostic(state, loc, message, type = "INFO") {
|
|
11175
11303
|
if (!loc || !loc.source)
|
|
11176
11304
|
return;
|
|
11177
11305
|
const source = loc.source;
|
|
@@ -11187,7 +11315,7 @@ function diagnostic(state, loc, message) {
|
|
|
11187
11315
|
if (message) {
|
|
11188
11316
|
if (index < 0)
|
|
11189
11317
|
index = diags.length;
|
|
11190
|
-
diags[index] = { type
|
|
11318
|
+
diags[index] = { type, loc, message };
|
|
11191
11319
|
}
|
|
11192
11320
|
else if (index >= 0) {
|
|
11193
11321
|
diags.splice(index, 1);
|
|
@@ -11211,7 +11339,7 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11211
11339
|
}
|
|
11212
11340
|
}
|
|
11213
11341
|
else {
|
|
11214
|
-
|
|
11342
|
+
traverseAst(func.node.body, (node) => {
|
|
11215
11343
|
node.type === "ReturnStatement" && retStmtCount++;
|
|
11216
11344
|
});
|
|
11217
11345
|
if (retStmtCount > 1) {
|
|
@@ -11306,23 +11434,25 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
11306
11434
|
// With a bit more work, we could find the guaranteed shortest
|
|
11307
11435
|
// reference, and then use this to optimize *all* symbols, not
|
|
11308
11436
|
// just fix inlined ones.
|
|
11309
|
-
if (current &&
|
|
11310
|
-
current.length === original.length &&
|
|
11311
|
-
current.every((item, index) => item == original[index])) {
|
|
11437
|
+
if (current && (0,external_api_cjs_namespaceObject.sameLookupResult)(original, current)) {
|
|
11312
11438
|
return lookupNode;
|
|
11313
11439
|
}
|
|
11314
11440
|
const node = lookupNode.type === "Identifier"
|
|
11315
11441
|
? lookupNode
|
|
11316
11442
|
: lookupNode.property;
|
|
11317
|
-
if (original.length === 1 &&
|
|
11318
|
-
|
|
11443
|
+
if (original.length === 1 &&
|
|
11444
|
+
original[0].results.length === 1 &&
|
|
11445
|
+
original[0].results[0].type === "EnumStringMember") {
|
|
11446
|
+
return applyTypeIfNeeded(original[0].results[0].init);
|
|
11319
11447
|
}
|
|
11320
|
-
const prefixes = original
|
|
11448
|
+
const prefixes = original
|
|
11449
|
+
.map((lookupDef) => lookupDef.results.map((sn) => {
|
|
11321
11450
|
if ((0,external_api_cjs_namespaceObject.isStateNode)(sn) && sn.fullName) {
|
|
11322
11451
|
return sn.fullName;
|
|
11323
11452
|
}
|
|
11324
11453
|
return "";
|
|
11325
|
-
})
|
|
11454
|
+
}))
|
|
11455
|
+
.flat();
|
|
11326
11456
|
if (prefixes.length &&
|
|
11327
11457
|
prefixes[0].startsWith("$.") &&
|
|
11328
11458
|
prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
|
|
@@ -11332,9 +11462,7 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
11332
11462
|
if (found)
|
|
11333
11463
|
return current;
|
|
11334
11464
|
const [, results] = state.lookup(current);
|
|
11335
|
-
if (results &&
|
|
11336
|
-
results.length === original.length &&
|
|
11337
|
-
results.every((result, i) => result === original[i])) {
|
|
11465
|
+
if (results && (0,external_api_cjs_namespaceObject.sameLookupResult)(original, results)) {
|
|
11338
11466
|
found = true;
|
|
11339
11467
|
return current;
|
|
11340
11468
|
}
|
|
@@ -11374,6 +11502,99 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
11374
11502
|
return null;
|
|
11375
11503
|
}
|
|
11376
11504
|
|
|
11505
|
+
;// CONCATENATED MODULE: ./src/visitor.ts
|
|
11506
|
+
|
|
11507
|
+
function visitReferences(state, ast, name, defn, callback) {
|
|
11508
|
+
const checkResults = ([name, results], node) => {
|
|
11509
|
+
if (name && results) {
|
|
11510
|
+
if (!defn || (0,external_api_cjs_namespaceObject.sameLookupResult)(results, defn)) {
|
|
11511
|
+
if (callback(node, results, false) === false) {
|
|
11512
|
+
return [];
|
|
11513
|
+
}
|
|
11514
|
+
}
|
|
11515
|
+
}
|
|
11516
|
+
else if (defn === false) {
|
|
11517
|
+
if (callback(node, [], results === null) === false) {
|
|
11518
|
+
return [];
|
|
11519
|
+
}
|
|
11520
|
+
}
|
|
11521
|
+
return null;
|
|
11522
|
+
};
|
|
11523
|
+
state.pre = (node) => {
|
|
11524
|
+
switch (node.type) {
|
|
11525
|
+
case "AttributeList":
|
|
11526
|
+
return [];
|
|
11527
|
+
case "UnaryExpression":
|
|
11528
|
+
// a bare symbol isn't a reference
|
|
11529
|
+
if (node.operator === ":")
|
|
11530
|
+
return [];
|
|
11531
|
+
break;
|
|
11532
|
+
case "BinaryExpression":
|
|
11533
|
+
/*
|
|
11534
|
+
* `expr has :symbol` can be treated as a reference
|
|
11535
|
+
* to expr.symbol.
|
|
11536
|
+
*/
|
|
11537
|
+
if (node.operator === "has") {
|
|
11538
|
+
if (node.right.type === "UnaryExpression" &&
|
|
11539
|
+
node.right.operator === ":") {
|
|
11540
|
+
if (!name || node.right.argument.name === name) {
|
|
11541
|
+
return checkResults(state.lookup({
|
|
11542
|
+
type: "MemberExpression",
|
|
11543
|
+
object: node.left,
|
|
11544
|
+
property: node.right.argument,
|
|
11545
|
+
computed: false,
|
|
11546
|
+
}), node.right.argument);
|
|
11547
|
+
}
|
|
11548
|
+
}
|
|
11549
|
+
}
|
|
11550
|
+
break;
|
|
11551
|
+
case "CallExpression":
|
|
11552
|
+
// A call expression whose callee is an identifier is looked
|
|
11553
|
+
// up as a non-local. ie even if there's a same named local,
|
|
11554
|
+
// it will be ignored, and the lookup will start as if the
|
|
11555
|
+
// call had been written self.foo() rather than foo().
|
|
11556
|
+
if (node.callee.type === "Identifier") {
|
|
11557
|
+
if (!name || node.callee.name === name) {
|
|
11558
|
+
/* ignore return value */
|
|
11559
|
+
checkResults(state.lookupNonlocal(node.callee), node.callee);
|
|
11560
|
+
}
|
|
11561
|
+
return ["arguments"];
|
|
11562
|
+
}
|
|
11563
|
+
break;
|
|
11564
|
+
case "Identifier":
|
|
11565
|
+
if (!name || node.name === name) {
|
|
11566
|
+
return checkResults(state.lookup(node), node);
|
|
11567
|
+
}
|
|
11568
|
+
break;
|
|
11569
|
+
case "MemberExpression":
|
|
11570
|
+
if (!node.computed && node.property.type === "Identifier") {
|
|
11571
|
+
if (!name || node.property.name === name) {
|
|
11572
|
+
return checkResults(state.lookup(node), node) || ["object"];
|
|
11573
|
+
}
|
|
11574
|
+
return ["object"];
|
|
11575
|
+
}
|
|
11576
|
+
break;
|
|
11577
|
+
case "MethodDefinition": {
|
|
11578
|
+
if (!state.inType) {
|
|
11579
|
+
throw new Error("Method definition outside of type!");
|
|
11580
|
+
}
|
|
11581
|
+
if (node.params) {
|
|
11582
|
+
node.params.forEach((param) => {
|
|
11583
|
+
if (param.type == "BinaryExpression") {
|
|
11584
|
+
state.traverse(param.right);
|
|
11585
|
+
state.inType = true;
|
|
11586
|
+
}
|
|
11587
|
+
});
|
|
11588
|
+
}
|
|
11589
|
+
return ["returnType"];
|
|
11590
|
+
}
|
|
11591
|
+
}
|
|
11592
|
+
return null;
|
|
11593
|
+
};
|
|
11594
|
+
(0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
|
|
11595
|
+
delete state.pre;
|
|
11596
|
+
}
|
|
11597
|
+
|
|
11377
11598
|
;// CONCATENATED MODULE: ./src/mc-rewrite.ts
|
|
11378
11599
|
|
|
11379
11600
|
|
|
@@ -11381,43 +11602,25 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
11381
11602
|
|
|
11382
11603
|
|
|
11383
11604
|
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
const [name, module] = lookup(node.id, ("as" in node && node.as && node.as.name) || null, stack);
|
|
11387
|
-
if (name && module) {
|
|
11388
|
-
const [parent] = stack.slice(-1);
|
|
11389
|
-
if (!parent.decls)
|
|
11390
|
-
parent.decls = {};
|
|
11391
|
-
const decls = parent.decls;
|
|
11392
|
-
if (!(0,external_api_cjs_namespaceObject.hasProperty)(decls, name))
|
|
11393
|
-
decls[name] = [];
|
|
11394
|
-
module.forEach((m) => {
|
|
11395
|
-
if ((0,external_api_cjs_namespaceObject.isStateNode)(m) && m.type == "ModuleDeclaration") {
|
|
11396
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(decls[name], m);
|
|
11397
|
-
if (!parent.type_decls)
|
|
11398
|
-
parent.type_decls = {};
|
|
11399
|
-
const tdecls = parent.type_decls;
|
|
11400
|
-
if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
|
|
11401
|
-
tdecls[name] = [];
|
|
11402
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(tdecls[name], m);
|
|
11403
|
-
if (node.type == "ImportModule" && m.type_decls) {
|
|
11404
|
-
Object.entries(m.type_decls).forEach(([name, decls]) => {
|
|
11405
|
-
if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
|
|
11406
|
-
tdecls[name] = [];
|
|
11407
|
-
decls.forEach((decl) => (0,external_util_cjs_namespaceObject.pushUnique)(tdecls[name], decl));
|
|
11408
|
-
});
|
|
11409
|
-
}
|
|
11410
|
-
}
|
|
11411
|
-
});
|
|
11412
|
-
}
|
|
11413
|
-
});
|
|
11414
|
-
}
|
|
11605
|
+
|
|
11606
|
+
|
|
11415
11607
|
function collectClassInfo(state) {
|
|
11608
|
+
const toybox = state.stack[0].decls["Toybox"][0];
|
|
11609
|
+
const lang = toybox.decls["Lang"][0];
|
|
11610
|
+
const object = lang.decls["Object"];
|
|
11416
11611
|
state.allClasses.forEach((elm) => {
|
|
11612
|
+
if (elm.stack[elm.stack.length - 1].type === "ClassDeclaration") {
|
|
11613
|
+
// nested classes don't get access to their contained
|
|
11614
|
+
// context. Put them in the global scope instead.
|
|
11615
|
+
elm.stack = elm.stack.slice(0, 1);
|
|
11616
|
+
}
|
|
11417
11617
|
if (elm.node.superClass) {
|
|
11418
|
-
const [name,
|
|
11419
|
-
const superClass =
|
|
11420
|
-
|
|
11618
|
+
const [name, lookupDefns] = state.lookup(elm.node.superClass, null, elm.stack);
|
|
11619
|
+
const superClass = lookupDefns &&
|
|
11620
|
+
lookupDefns
|
|
11621
|
+
.map((lookupDefn) => lookupDefn.results)
|
|
11622
|
+
.flat()
|
|
11623
|
+
.filter((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && c.type === "ClassDeclaration");
|
|
11421
11624
|
// set it "true" if there is a superClass, but we can't find it.
|
|
11422
11625
|
elm.superClass = superClass && superClass.length ? superClass : true;
|
|
11423
11626
|
if (name && elm.superClass !== true) {
|
|
@@ -11449,6 +11652,9 @@ function collectClassInfo(state) {
|
|
|
11449
11652
|
elm.decls[name] = elm.superClass;
|
|
11450
11653
|
}
|
|
11451
11654
|
}
|
|
11655
|
+
else if (elm !== object[0]) {
|
|
11656
|
+
elm.superClass = object;
|
|
11657
|
+
}
|
|
11452
11658
|
});
|
|
11453
11659
|
const markOverrides = (cls, scls) => {
|
|
11454
11660
|
if (scls === true)
|
|
@@ -11478,7 +11684,9 @@ function getFileSources(fnMap) {
|
|
|
11478
11684
|
return (value.monkeyCSource ||
|
|
11479
11685
|
promises_namespaceObject.readFile(name)
|
|
11480
11686
|
.then((data) => (value.monkeyCSource = data.toString().replace(/\r\n/g, "\n"))));
|
|
11481
|
-
})).then(() => {
|
|
11687
|
+
})).then(() => {
|
|
11688
|
+
return;
|
|
11689
|
+
});
|
|
11482
11690
|
}
|
|
11483
11691
|
function getFileASTs(fnMap) {
|
|
11484
11692
|
return getFileSources(fnMap).then(() => Object.entries(fnMap).reduce((ok, [name, value]) => {
|
|
@@ -11501,11 +11709,12 @@ function getFileASTs(fnMap) {
|
|
|
11501
11709
|
return ok;
|
|
11502
11710
|
}, true));
|
|
11503
11711
|
}
|
|
11504
|
-
async function analyze(fnMap) {
|
|
11712
|
+
async function analyze(fnMap, barrelList, config) {
|
|
11505
11713
|
let hasTests = false;
|
|
11506
|
-
|
|
11714
|
+
let markApi = true;
|
|
11507
11715
|
const preState = {
|
|
11508
11716
|
fnMap,
|
|
11717
|
+
config,
|
|
11509
11718
|
allFunctions: [],
|
|
11510
11719
|
allClasses: [],
|
|
11511
11720
|
shouldExclude(node) {
|
|
@@ -11533,45 +11742,38 @@ async function analyze(fnMap) {
|
|
|
11533
11742
|
}
|
|
11534
11743
|
return false;
|
|
11535
11744
|
},
|
|
11536
|
-
|
|
11745
|
+
pre(node, state) {
|
|
11537
11746
|
switch (node.type) {
|
|
11538
11747
|
case "FunctionDeclaration":
|
|
11748
|
+
if (markApi) {
|
|
11749
|
+
node.body = null;
|
|
11750
|
+
break;
|
|
11751
|
+
}
|
|
11752
|
+
// falls through
|
|
11753
|
+
case "ModuleDeclaration":
|
|
11539
11754
|
case "ClassDeclaration": {
|
|
11540
11755
|
const [scope] = state.stack.slice(-1);
|
|
11541
|
-
|
|
11542
|
-
scope.stack = stack;
|
|
11756
|
+
scope.stack = state.stackClone().slice(0, -1);
|
|
11543
11757
|
if (scope.type == "FunctionDeclaration") {
|
|
11758
|
+
scope.isStatic =
|
|
11759
|
+
scope.stack.slice(-1)[0].type !== "ClassDeclaration" ||
|
|
11760
|
+
(scope.node.attrs &&
|
|
11761
|
+
scope.node.attrs.access &&
|
|
11762
|
+
scope.node.attrs.access.includes("static"));
|
|
11544
11763
|
state.allFunctions.push(scope);
|
|
11545
11764
|
}
|
|
11546
|
-
else {
|
|
11765
|
+
else if (scope.type === "ClassDeclaration") {
|
|
11547
11766
|
state.allClasses.push(scope);
|
|
11548
11767
|
}
|
|
11549
|
-
|
|
11768
|
+
break;
|
|
11550
11769
|
}
|
|
11551
|
-
case "Using":
|
|
11552
|
-
case "ImportModule":
|
|
11553
|
-
allImports.push({ node, stack: state.stack.slice() });
|
|
11554
|
-
return null;
|
|
11555
|
-
default:
|
|
11556
|
-
return null;
|
|
11557
11770
|
}
|
|
11771
|
+
return null;
|
|
11558
11772
|
},
|
|
11559
11773
|
};
|
|
11560
|
-
await (0,external_api_cjs_namespaceObject.getApiMapping)(preState);
|
|
11774
|
+
await (0,external_api_cjs_namespaceObject.getApiMapping)(preState, barrelList);
|
|
11775
|
+
markApi = false;
|
|
11561
11776
|
const state = preState;
|
|
11562
|
-
// Mark all functions from api.mir as "special" by
|
|
11563
|
-
// setting their bodies to null. In api.mir, they're
|
|
11564
|
-
// all empty, which makes it look like they're
|
|
11565
|
-
// do-nothing functions.
|
|
11566
|
-
const markApi = (node) => {
|
|
11567
|
-
if (node.type == "FunctionDeclaration") {
|
|
11568
|
-
node.node.body = null;
|
|
11569
|
-
}
|
|
11570
|
-
if ((0,external_api_cjs_namespaceObject.isStateNode)(node) && node.decls) {
|
|
11571
|
-
Object.values(node.decls).forEach((v) => v.forEach(markApi));
|
|
11572
|
-
}
|
|
11573
|
-
};
|
|
11574
|
-
markApi(state.stack[0]);
|
|
11575
11777
|
await getFileASTs(fnMap);
|
|
11576
11778
|
Object.entries(fnMap).forEach(([name, value]) => {
|
|
11577
11779
|
const { ast, parserError } = value;
|
|
@@ -11584,8 +11786,28 @@ async function analyze(fnMap) {
|
|
|
11584
11786
|
});
|
|
11585
11787
|
delete state.shouldExclude;
|
|
11586
11788
|
delete state.post;
|
|
11587
|
-
processImports(allImports, state.lookup);
|
|
11588
11789
|
collectClassInfo(state);
|
|
11790
|
+
const diagnosticType = config?.checkInvalidSymbols !== "OFF"
|
|
11791
|
+
? config?.checkInvalidSymbols || "WARNING"
|
|
11792
|
+
: null;
|
|
11793
|
+
if (diagnosticType &&
|
|
11794
|
+
!config?.compilerOptions?.includes("--Eno-invalid-symbol")) {
|
|
11795
|
+
const checkTypes = config?.typeCheckLevel && config.typeCheckLevel !== "Off";
|
|
11796
|
+
Object.entries(fnMap).forEach(([, v]) => {
|
|
11797
|
+
visitReferences(state, v.ast, null, false, (node, results, error) => {
|
|
11798
|
+
if (!error)
|
|
11799
|
+
return undefined;
|
|
11800
|
+
const nodeStr = (0,external_api_cjs_namespaceObject.formatAst)(node);
|
|
11801
|
+
if (state.inType) {
|
|
11802
|
+
if (!checkTypes || nodeStr.match(/^Void|Null$/)) {
|
|
11803
|
+
return undefined;
|
|
11804
|
+
}
|
|
11805
|
+
}
|
|
11806
|
+
diagnostic(state, node.loc, `Undefined symbol ${nodeStr}`, diagnosticType);
|
|
11807
|
+
return false;
|
|
11808
|
+
});
|
|
11809
|
+
});
|
|
11810
|
+
}
|
|
11589
11811
|
return state;
|
|
11590
11812
|
}
|
|
11591
11813
|
function compareLiteralLike(a, b) {
|
|
@@ -11595,11 +11817,11 @@ function compareLiteralLike(a, b) {
|
|
|
11595
11817
|
b = b.left;
|
|
11596
11818
|
return a.type === "Literal" && b.type === "Literal" && a.value === b.value;
|
|
11597
11819
|
}
|
|
11598
|
-
function getLiteralFromDecls(
|
|
11599
|
-
if (!
|
|
11820
|
+
function getLiteralFromDecls(lookupDefns) {
|
|
11821
|
+
if (!lookupDefns.length)
|
|
11600
11822
|
return null;
|
|
11601
11823
|
let result = null;
|
|
11602
|
-
if (
|
|
11824
|
+
if (lookupDefns.every((lookupDefn) => lookupDefn.results.every((d) => {
|
|
11603
11825
|
if (d.type === "EnumStringMember" ||
|
|
11604
11826
|
(d.type === "VariableDeclarator" && d.node.kind === "const")) {
|
|
11605
11827
|
const init = getLiteralNode(d.type === "EnumStringMember" ? d.init : d.node.init);
|
|
@@ -11614,7 +11836,7 @@ function getLiteralFromDecls(decls) {
|
|
|
11614
11836
|
}
|
|
11615
11837
|
}
|
|
11616
11838
|
return false;
|
|
11617
|
-
})) {
|
|
11839
|
+
}))) {
|
|
11618
11840
|
return result;
|
|
11619
11841
|
}
|
|
11620
11842
|
return null;
|
|
@@ -11777,7 +11999,7 @@ function evaluateFunction(func, args) {
|
|
|
11777
11999
|
? JSON.parse(JSON.stringify(func.body))
|
|
11778
12000
|
: func.body;
|
|
11779
12001
|
try {
|
|
11780
|
-
|
|
12002
|
+
traverseAst(body, (node) => {
|
|
11781
12003
|
switch (node.type) {
|
|
11782
12004
|
case "BlockStatement":
|
|
11783
12005
|
case "ReturnStatement":
|
|
@@ -11825,20 +12047,23 @@ function markFunctionCalled(state, func) {
|
|
|
11825
12047
|
}
|
|
11826
12048
|
(0,external_util_cjs_namespaceObject.pushUnique)(state.calledFunctions[func.id.name], func);
|
|
11827
12049
|
}
|
|
11828
|
-
async function optimizeMonkeyC(fnMap) {
|
|
12050
|
+
async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
11829
12051
|
const state = {
|
|
11830
|
-
...(await analyze(fnMap)),
|
|
12052
|
+
...(await analyze(fnMap, barrelList, config)),
|
|
11831
12053
|
localsStack: [{}],
|
|
11832
12054
|
exposed: {},
|
|
11833
12055
|
calledFunctions: {},
|
|
11834
12056
|
};
|
|
11835
|
-
const replace = (node) => {
|
|
12057
|
+
const replace = (node, old) => {
|
|
11836
12058
|
if (node === false || node === null)
|
|
11837
12059
|
return node;
|
|
11838
12060
|
const rep = state.traverse(node);
|
|
11839
|
-
|
|
12061
|
+
if (rep === false || Array.isArray(rep))
|
|
12062
|
+
return rep;
|
|
12063
|
+
return { ...(rep || node), loc: old.loc, start: old.start, end: old.end };
|
|
11840
12064
|
};
|
|
11841
12065
|
const inPlaceReplacement = (node, obj) => {
|
|
12066
|
+
const { start, end, loc } = node;
|
|
11842
12067
|
for (const k of Object.keys(node)) {
|
|
11843
12068
|
delete node[k];
|
|
11844
12069
|
}
|
|
@@ -11846,13 +12071,16 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11846
12071
|
obj = {
|
|
11847
12072
|
type: "BinaryExpression",
|
|
11848
12073
|
operator: "as",
|
|
11849
|
-
left: obj,
|
|
12074
|
+
left: { ...obj, start, end, loc },
|
|
11850
12075
|
right: { type: "TypeSpecList", ts: [obj.enumType] },
|
|
11851
12076
|
};
|
|
11852
12077
|
}
|
|
11853
12078
|
for (const [k, v] of Object.entries(obj)) {
|
|
11854
12079
|
node[k] = v;
|
|
11855
12080
|
}
|
|
12081
|
+
node.loc = loc;
|
|
12082
|
+
node.start = start;
|
|
12083
|
+
node.end = end;
|
|
11856
12084
|
};
|
|
11857
12085
|
const lookupAndReplace = (node) => {
|
|
11858
12086
|
const [, objects] = state.lookup(node);
|
|
@@ -11910,7 +12138,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11910
12138
|
case "ConditionalExpression":
|
|
11911
12139
|
case "IfStatement":
|
|
11912
12140
|
case "DoWhileStatement":
|
|
11913
|
-
case "WhileStatement":
|
|
12141
|
+
case "WhileStatement": {
|
|
11914
12142
|
const test = (state.traverse(node.test) ||
|
|
11915
12143
|
node.test);
|
|
11916
12144
|
const [value, type] = getNodeValue(test);
|
|
@@ -11942,6 +12170,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11942
12170
|
}
|
|
11943
12171
|
}
|
|
11944
12172
|
return null;
|
|
12173
|
+
}
|
|
11945
12174
|
case "EnumDeclaration":
|
|
11946
12175
|
return false;
|
|
11947
12176
|
case "ForStatement": {
|
|
@@ -11971,6 +12200,37 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
11971
12200
|
}
|
|
11972
12201
|
return ["init"];
|
|
11973
12202
|
}
|
|
12203
|
+
case "CatchClause":
|
|
12204
|
+
if (node.param) {
|
|
12205
|
+
state.localsStack.push({ node, map: { ...(topLocals().map || {}) } });
|
|
12206
|
+
const locals = topLocals();
|
|
12207
|
+
const map = locals.map;
|
|
12208
|
+
const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.param);
|
|
12209
|
+
const name = renameVariable(state, locals, declName);
|
|
12210
|
+
if (name) {
|
|
12211
|
+
if (node.param.type === "Identifier") {
|
|
12212
|
+
node.param.name = name;
|
|
12213
|
+
}
|
|
12214
|
+
else {
|
|
12215
|
+
node.param.left.name = name;
|
|
12216
|
+
}
|
|
12217
|
+
}
|
|
12218
|
+
else {
|
|
12219
|
+
map[declName] = true;
|
|
12220
|
+
}
|
|
12221
|
+
return ["body"];
|
|
12222
|
+
}
|
|
12223
|
+
break;
|
|
12224
|
+
case "BinaryExpression":
|
|
12225
|
+
if (node.operator === "has") {
|
|
12226
|
+
if (node.right.type === "UnaryExpression" &&
|
|
12227
|
+
node.right.operator === ":") {
|
|
12228
|
+
// Using `expr has :symbol` doesn't "expose"
|
|
12229
|
+
// symbol. So skip the right operand.
|
|
12230
|
+
return ["left"];
|
|
12231
|
+
}
|
|
12232
|
+
}
|
|
12233
|
+
break;
|
|
11974
12234
|
case "UnaryExpression":
|
|
11975
12235
|
if (node.operator == ":") {
|
|
11976
12236
|
// If we produce a Symbol, for a given name,
|
|
@@ -12053,7 +12313,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12053
12313
|
}
|
|
12054
12314
|
const opt = optimizeNode(node);
|
|
12055
12315
|
if (opt) {
|
|
12056
|
-
return replace(opt);
|
|
12316
|
+
return replace(opt, node);
|
|
12057
12317
|
}
|
|
12058
12318
|
switch (node.type) {
|
|
12059
12319
|
case "ConditionalExpression":
|
|
@@ -12063,7 +12323,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12063
12323
|
const rep = node.test.value ? node.consequent : node.alternate;
|
|
12064
12324
|
if (!rep)
|
|
12065
12325
|
return false;
|
|
12066
|
-
return replace(rep);
|
|
12326
|
+
return replace(rep, rep);
|
|
12067
12327
|
}
|
|
12068
12328
|
break;
|
|
12069
12329
|
case "WhileStatement":
|
|
@@ -12078,11 +12338,11 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12078
12338
|
break;
|
|
12079
12339
|
case "ReturnStatement":
|
|
12080
12340
|
if (node.argument && node.argument.type === "CallExpression") {
|
|
12081
|
-
return replace(optimizeCall(state, node.argument, node));
|
|
12341
|
+
return replace(optimizeCall(state, node.argument, node), node.argument);
|
|
12082
12342
|
}
|
|
12083
12343
|
break;
|
|
12084
12344
|
case "CallExpression": {
|
|
12085
|
-
return replace(optimizeCall(state, node, null));
|
|
12345
|
+
return replace(optimizeCall(state, node, null), node);
|
|
12086
12346
|
}
|
|
12087
12347
|
case "AssignmentExpression":
|
|
12088
12348
|
if (node.operator === "=" &&
|
|
@@ -12094,7 +12354,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12094
12354
|
break;
|
|
12095
12355
|
case "ExpressionStatement":
|
|
12096
12356
|
if (node.expression.type === "CallExpression") {
|
|
12097
|
-
return replace(optimizeCall(state, node.expression, node));
|
|
12357
|
+
return replace(optimizeCall(state, node.expression, node), node.expression);
|
|
12098
12358
|
}
|
|
12099
12359
|
else if (node.expression.type === "AssignmentExpression") {
|
|
12100
12360
|
if (node.expression.right.type === "CallExpression") {
|
|
@@ -12106,10 +12366,10 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12106
12366
|
}
|
|
12107
12367
|
if (!ok && node.expression.operator == "=") {
|
|
12108
12368
|
const [, result] = state.lookup(node.expression.left);
|
|
12109
|
-
ok = result
|
|
12369
|
+
ok = !!result;
|
|
12110
12370
|
}
|
|
12111
12371
|
if (ok) {
|
|
12112
|
-
return replace(optimizeCall(state, node.expression.right, node.expression));
|
|
12372
|
+
return replace(optimizeCall(state, node.expression.right, node.expression), node.expression.right);
|
|
12113
12373
|
}
|
|
12114
12374
|
}
|
|
12115
12375
|
}
|
|
@@ -12117,7 +12377,7 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12117
12377
|
const ret = unused(node.expression, true);
|
|
12118
12378
|
if (ret) {
|
|
12119
12379
|
return ret
|
|
12120
|
-
.map(replace)
|
|
12380
|
+
.map((r) => replace(r, r))
|
|
12121
12381
|
.flat(1)
|
|
12122
12382
|
.filter((s) => !!s);
|
|
12123
12383
|
}
|
|
@@ -12138,6 +12398,9 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12138
12398
|
delete state.post;
|
|
12139
12399
|
const cleanup = (node) => {
|
|
12140
12400
|
switch (node.type) {
|
|
12401
|
+
case "ThisExpression":
|
|
12402
|
+
node.text = "self";
|
|
12403
|
+
break;
|
|
12141
12404
|
case "EnumStringBody":
|
|
12142
12405
|
if (node.members.every((m) => {
|
|
12143
12406
|
const name = "name" in m ? m.name : m.id.name;
|
|
@@ -12202,11 +12465,24 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12202
12465
|
return false;
|
|
12203
12466
|
}
|
|
12204
12467
|
break;
|
|
12468
|
+
case "ClassDeclaration":
|
|
12469
|
+
case "ModuleDeclaration":
|
|
12470
|
+
// none of the attributes means anything on classes and
|
|
12471
|
+
// modules, and the new compiler complains about some
|
|
12472
|
+
// of them. Just drop them all.
|
|
12473
|
+
if (node.attrs && node.attrs.access) {
|
|
12474
|
+
if (node.attrs.attributes) {
|
|
12475
|
+
delete node.attrs.access;
|
|
12476
|
+
}
|
|
12477
|
+
else {
|
|
12478
|
+
delete node.attrs;
|
|
12479
|
+
}
|
|
12480
|
+
}
|
|
12205
12481
|
}
|
|
12206
12482
|
return null;
|
|
12207
12483
|
};
|
|
12208
12484
|
Object.values(fnMap).forEach((f) => {
|
|
12209
|
-
|
|
12485
|
+
traverseAst(f.ast, undefined, (node) => {
|
|
12210
12486
|
const ret = cleanup(node);
|
|
12211
12487
|
if (ret === false) {
|
|
12212
12488
|
state.removeNodeComments(node, f.ast);
|
|
@@ -12217,9 +12493,12 @@ async function optimizeMonkeyC(fnMap) {
|
|
|
12217
12493
|
return state.diagnostics;
|
|
12218
12494
|
}
|
|
12219
12495
|
function optimizeCall(state, node, context) {
|
|
12220
|
-
const [name, results] = state.
|
|
12496
|
+
const [name, results] = state.lookupNonlocal(node.callee);
|
|
12221
12497
|
const callees = results &&
|
|
12222
|
-
results
|
|
12498
|
+
results
|
|
12499
|
+
.map((r) => r.results)
|
|
12500
|
+
.flat()
|
|
12501
|
+
.filter((c) => c.type === "FunctionDeclaration");
|
|
12223
12502
|
if (!callees || !callees.length) {
|
|
12224
12503
|
const n = name ||
|
|
12225
12504
|
("name" in node.callee && node.callee.name) ||
|
|
@@ -12260,23 +12539,29 @@ function optimizeCall(state, node, context) {
|
|
|
12260
12539
|
|
|
12261
12540
|
;// CONCATENATED MODULE: ./src/pragma-checker.ts
|
|
12262
12541
|
|
|
12263
|
-
|
|
12542
|
+
|
|
12543
|
+
function pragmaChecker(ast, diagnostics) {
|
|
12264
12544
|
const comments = ast.comments;
|
|
12265
12545
|
if (!comments)
|
|
12266
12546
|
return;
|
|
12547
|
+
diagnostics = diagnostics
|
|
12548
|
+
?.slice()
|
|
12549
|
+
.sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
|
|
12550
|
+
let diagIndex = 0;
|
|
12267
12551
|
let index = -1;
|
|
12268
12552
|
let comment;
|
|
12269
12553
|
let matchers;
|
|
12270
12554
|
const next = () => {
|
|
12271
12555
|
while (++index < comments.length) {
|
|
12272
12556
|
comment = comments[index];
|
|
12273
|
-
let match = comment.value.match(/^\s*@match\s+(.+)/);
|
|
12557
|
+
let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
|
|
12274
12558
|
if (!match)
|
|
12275
12559
|
continue;
|
|
12276
|
-
|
|
12560
|
+
const kind = match[1];
|
|
12561
|
+
let str = match[2];
|
|
12277
12562
|
matchers = [];
|
|
12278
12563
|
while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
|
|
12279
|
-
matchers.push({ quote: match[1], needle: match[2] });
|
|
12564
|
+
matchers.push({ kind, quote: match[1], needle: match[2] });
|
|
12280
12565
|
str = str.substring(match[0].length);
|
|
12281
12566
|
if (!str.length)
|
|
12282
12567
|
break;
|
|
@@ -12286,35 +12571,79 @@ function pragmaChecker(ast) {
|
|
|
12286
12571
|
if (!matchers.length) {
|
|
12287
12572
|
match = str.match(/^(\S+)\s+$/);
|
|
12288
12573
|
if (match) {
|
|
12289
|
-
matchers.push({ quote: '"', needle: match[1] });
|
|
12574
|
+
matchers.push({ kind, quote: '"', needle: match[1] });
|
|
12290
12575
|
break;
|
|
12291
12576
|
}
|
|
12292
12577
|
}
|
|
12293
12578
|
throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12294
12579
|
}
|
|
12295
12580
|
};
|
|
12581
|
+
const matcher = (quote, needle, haystack) => {
|
|
12582
|
+
if (quote == '"') {
|
|
12583
|
+
return haystack.includes(needle);
|
|
12584
|
+
}
|
|
12585
|
+
const re = new RegExp(needle);
|
|
12586
|
+
return re.test(haystack);
|
|
12587
|
+
};
|
|
12296
12588
|
next();
|
|
12297
|
-
|
|
12589
|
+
traverseAst(ast, (node) => {
|
|
12298
12590
|
if (index >= comments.length)
|
|
12299
12591
|
return false;
|
|
12300
12592
|
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
12301
|
-
const { quote, needle } = matchers.shift();
|
|
12302
|
-
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
|
|
12306
|
-
}
|
|
12307
|
-
else {
|
|
12308
|
-
const re = new RegExp(needle);
|
|
12309
|
-
found = re.test(haystack);
|
|
12593
|
+
const { kind, quote, needle } = matchers.shift();
|
|
12594
|
+
if (kind === "match") {
|
|
12595
|
+
if (!matcher(quote, needle, (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " "))) {
|
|
12596
|
+
throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12597
|
+
}
|
|
12310
12598
|
}
|
|
12311
|
-
if (
|
|
12312
|
-
|
|
12599
|
+
else if (kind === "expect") {
|
|
12600
|
+
const locCmp = (a, b) => {
|
|
12601
|
+
if (!b)
|
|
12602
|
+
return -1;
|
|
12603
|
+
if (a.start.line < b.start.line)
|
|
12604
|
+
return -1;
|
|
12605
|
+
if (a.start.line === b.start.line &&
|
|
12606
|
+
a.start.column < b.start.column) {
|
|
12607
|
+
return -1;
|
|
12608
|
+
}
|
|
12609
|
+
if (a.end.line > b.end.line)
|
|
12610
|
+
return 1;
|
|
12611
|
+
if (a.end.line === b.end.line && a.end.column >= b.end.column) {
|
|
12612
|
+
return 1;
|
|
12613
|
+
}
|
|
12614
|
+
return 0;
|
|
12615
|
+
};
|
|
12616
|
+
let found = false;
|
|
12617
|
+
if (diagnostics) {
|
|
12618
|
+
while (true) {
|
|
12619
|
+
if (diagIndex >= diagnostics.length) {
|
|
12620
|
+
diagnostics = null;
|
|
12621
|
+
break;
|
|
12622
|
+
}
|
|
12623
|
+
const diag = diagnostics[diagIndex];
|
|
12624
|
+
const cmp = locCmp(diag.loc, node.loc);
|
|
12625
|
+
if (cmp > 0) {
|
|
12626
|
+
break;
|
|
12627
|
+
}
|
|
12628
|
+
diagIndex++;
|
|
12629
|
+
if (cmp < 0)
|
|
12630
|
+
continue;
|
|
12631
|
+
if (matcher(quote, needle, diag.message)) {
|
|
12632
|
+
found = true;
|
|
12633
|
+
diag.type = "INFO";
|
|
12634
|
+
}
|
|
12635
|
+
}
|
|
12636
|
+
}
|
|
12637
|
+
if (!found) {
|
|
12638
|
+
throw new Error(`Missing error message '${needle} at ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12639
|
+
}
|
|
12313
12640
|
}
|
|
12314
|
-
if (
|
|
12315
|
-
|
|
12641
|
+
if (matchers.length) {
|
|
12642
|
+
// if we're checking a series of nodes, we need
|
|
12643
|
+
// to skip over this one.
|
|
12644
|
+
return false;
|
|
12316
12645
|
}
|
|
12317
|
-
|
|
12646
|
+
next();
|
|
12318
12647
|
}
|
|
12319
12648
|
return null;
|
|
12320
12649
|
});
|
|
@@ -12336,7 +12665,7 @@ function pragmaChecker(ast) {
|
|
|
12336
12665
|
|
|
12337
12666
|
|
|
12338
12667
|
function relative_path_no_dotdot(relative) {
|
|
12339
|
-
return relative.replace(/^(\.\.[
|
|
12668
|
+
return relative.replace(/^(\.\.[\\/])+/, (str) => `__${"dot".repeat(str.length / 3)}__${str.slice(-1)}`);
|
|
12340
12669
|
}
|
|
12341
12670
|
async function getVSCodeSettings(path) {
|
|
12342
12671
|
try {
|
|
@@ -12468,7 +12797,7 @@ async function createLocalBarrels(targets, options) {
|
|
|
12468
12797
|
const sha1 = external_crypto_namespaceObject.createHash("sha1")
|
|
12469
12798
|
.update(rawBarrelDir, "binary")
|
|
12470
12799
|
.digest("base64")
|
|
12471
|
-
.replace(/[
|
|
12800
|
+
.replace(/[/=+]/g, "");
|
|
12472
12801
|
const optBarrelDir = external_path_.resolve(barrelDir, `${barrel}-${sha1}`);
|
|
12473
12802
|
if (!(0,external_api_cjs_namespaceObject.hasProperty)(optBarrels, barrel)) {
|
|
12474
12803
|
optBarrels[barrel] = {
|
|
@@ -12516,7 +12845,9 @@ async function generateOptimizedProject(options) {
|
|
|
12516
12845
|
}
|
|
12517
12846
|
return {
|
|
12518
12847
|
jungleFiles: config.jungleFiles,
|
|
12848
|
+
xml,
|
|
12519
12849
|
program: external_path_.basename(external_path_.dirname(manifest)),
|
|
12850
|
+
hasTests: !!config.testBuild,
|
|
12520
12851
|
};
|
|
12521
12852
|
}
|
|
12522
12853
|
let dropBarrels = false;
|
|
@@ -12617,7 +12948,7 @@ async function generateOptimizedProject(options) {
|
|
|
12617
12948
|
}
|
|
12618
12949
|
const prefix = `${product}.`;
|
|
12619
12950
|
process_field(prefix, qualifier, "sourcePath", (s) => external_path_.join(group.dir, "source", relative_path_no_dotdot(external_path_.relative(workspace, s)))
|
|
12620
|
-
.replace(/([
|
|
12951
|
+
.replace(/([\\/]\*\*)[\\/]\*/g, "$1"));
|
|
12621
12952
|
if (group.optimizerConfig.optBarrels) {
|
|
12622
12953
|
parts.push(`${prefix}barrelPath = ${Object.values(group.optimizerConfig.optBarrels)
|
|
12623
12954
|
.map((value) => `[${value.jungleFiles
|
|
@@ -12631,7 +12962,7 @@ async function generateOptimizedProject(options) {
|
|
|
12631
12962
|
.map(([barrel, resolvedBarrel]) => {
|
|
12632
12963
|
const root = external_path_.dirname(resolvedBarrel.jungles[0]);
|
|
12633
12964
|
return (resolvedBarrel.qualifier.sourcePath || []).map((s) => external_path_.join(group.dir, "barrels", barrel, external_path_.relative(root, s))
|
|
12634
|
-
.replace(/([
|
|
12965
|
+
.replace(/([\\/]\*\*)[\\/]\*/g, "$1"));
|
|
12635
12966
|
})
|
|
12636
12967
|
.flat()
|
|
12637
12968
|
.sort()
|
|
@@ -12702,6 +13033,7 @@ const configOptionsToCheck = [
|
|
|
12702
13033
|
"ignoredExcludeAnnotations",
|
|
12703
13034
|
"ignoredAnnotations",
|
|
12704
13035
|
"ignoredSourcePaths",
|
|
13036
|
+
"checkInvalidSymbols",
|
|
12705
13037
|
];
|
|
12706
13038
|
/**
|
|
12707
13039
|
* @param {BuildConfig} config
|
|
@@ -12753,21 +13085,21 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12753
13085
|
// the oldest optimized file, we don't need to regenerate
|
|
12754
13086
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
12755
13087
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
12756
|
-
if (source_time < opt_time &&
|
|
13088
|
+
if (source_time < opt_time && 1655680070380 < opt_time) {
|
|
12757
13089
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
12758
13090
|
}
|
|
12759
13091
|
}
|
|
12760
13092
|
await promises_namespaceObject.rm(output, { recursive: true, force: true });
|
|
12761
13093
|
await promises_namespaceObject.mkdir(output, { recursive: true });
|
|
12762
|
-
const diagnostics = await optimizeMonkeyC(fnMap);
|
|
12763
|
-
return Promise.all(Object.
|
|
13094
|
+
const diagnostics = await optimizeMonkeyC(fnMap, Object.keys(buildConfig.barrelMap || {}), config);
|
|
13095
|
+
return Promise.all(Object.entries(fnMap).map(async ([inFile, info]) => {
|
|
12764
13096
|
const name = info.output;
|
|
12765
13097
|
const dir = external_path_.dirname(name);
|
|
12766
13098
|
await promises_namespaceObject.mkdir(dir, { recursive: true });
|
|
12767
13099
|
const opt_source = (0,external_api_cjs_namespaceObject.formatAst)(info.ast, info.monkeyCSource);
|
|
12768
13100
|
await promises_namespaceObject.writeFile(name, opt_source);
|
|
12769
13101
|
if (config.checkBuildPragmas) {
|
|
12770
|
-
pragmaChecker(info.ast);
|
|
13102
|
+
pragmaChecker(info.ast, diagnostics?.[inFile]);
|
|
12771
13103
|
}
|
|
12772
13104
|
return info.hasTests;
|
|
12773
13105
|
})).then((results) => {
|
|
@@ -12802,7 +13134,13 @@ async function getProjectAnalysis(targets, analysis, options) {
|
|
|
12802
13134
|
if (!(await getFileASTs(fnMap))) {
|
|
12803
13135
|
return { fnMap, paths };
|
|
12804
13136
|
}
|
|
12805
|
-
const
|
|
13137
|
+
const barrelObj = {};
|
|
13138
|
+
targets.forEach((target) => {
|
|
13139
|
+
if (target.qualifier.barrelMap) {
|
|
13140
|
+
Object.keys(target.qualifier.barrelMap).forEach((key) => (barrelObj[key] = true));
|
|
13141
|
+
}
|
|
13142
|
+
});
|
|
13143
|
+
const state = await analyze(fnMap, Object.keys(barrelObj), options);
|
|
12806
13144
|
return { fnMap: fnMap, paths, state };
|
|
12807
13145
|
}
|
|
12808
13146
|
/**
|