@markw65/monkeyc-optimizer 1.0.15 → 1.0.18

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.
@@ -1,4 +1,4 @@
1
- 0 && (module.exports = {copyRecursiveAsNeeded,get_jungle,launchSimulator,manifestProducts,mctree,simulateProgram,defaultConfig,isErrorWithLocation,buildOptimizedProject,generateOptimizedProject,getProjectAnalysis,generateApiMirTests});
1
+ 0 && (module.exports = {buildOptimizedProject,copyRecursiveAsNeeded,defaultConfig,generateApiMirTests,generateOptimizedProject,getProjectAnalysis,get_jungle,isErrorWithLocation,launchSimulator,manifestProducts,mctree,simulateProgram});
2
2
  /******/ (() => { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -10791,11 +10791,485 @@ function simulateProgram(prg, device, test) {
10791
10791
  return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, (line) => console.log(line)).then(() => { }));
10792
10792
  }
10793
10793
 
10794
+ ;// CONCATENATED MODULE: ./src/variable-renamer.ts
10795
+
10796
+ function renameVariable(state, locals, declName) {
10797
+ const map = locals.map;
10798
+ if (!(0,external_api_cjs_namespaceObject.hasProperty)(map, declName))
10799
+ return null;
10800
+ let suffix = 0;
10801
+ let node_name = declName;
10802
+ const match = node_name.match(/^pmcr_(.*)_(\d+)$/);
10803
+ if (match) {
10804
+ node_name = match[1];
10805
+ suffix = parseInt(match[2], 10) + 1;
10806
+ }
10807
+ if (!locals.inners) {
10808
+ // find all the names declared in this scope, to avoid
10809
+ // more conflicts
10810
+ locals.inners = {};
10811
+ const inners = locals.inners;
10812
+ (0,external_api_cjs_namespaceObject.traverseAst)(locals.node, (node) => {
10813
+ if (node.type === "VariableDeclarator") {
10814
+ inners[(0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id)] = true;
10815
+ }
10816
+ });
10817
+ }
10818
+ let name;
10819
+ while (true) {
10820
+ name = `pmcr_${node_name}_${suffix}`;
10821
+ if (!(0,external_api_cjs_namespaceObject.hasProperty)(map, name) && !(0,external_api_cjs_namespaceObject.hasProperty)(locals.inners, name)) {
10822
+ // we also need to ensure that we don't hide the name of
10823
+ // an outer module, class, function, enum or variable,
10824
+ // since someone might want to access it from this scope.
10825
+ let ok = false;
10826
+ let i;
10827
+ for (i = state.stack.length; i--;) {
10828
+ const elm = state.stack[i];
10829
+ if (ok) {
10830
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(elm.decls, name)) {
10831
+ break;
10832
+ }
10833
+ }
10834
+ else if (elm.node && elm.node.type === "FunctionDeclaration") {
10835
+ ok = true;
10836
+ }
10837
+ }
10838
+ if (i < 0) {
10839
+ break;
10840
+ }
10841
+ }
10842
+ suffix++;
10843
+ }
10844
+ map[declName] = name;
10845
+ map[name] = true;
10846
+ return name;
10847
+ }
10848
+
10849
+ ;// CONCATENATED MODULE: ./src/inliner.ts
10850
+
10851
+
10852
+ function getArgSafety(state, func, args, requireAll) {
10853
+ // determine whether decl might be changed by a function call
10854
+ // or assignment during the evaluation of FunctionStateNode.
10855
+ const getSafety = (decl) => {
10856
+ // enums are constant, they cant change
10857
+ if (decl.type === "EnumStringMember")
10858
+ return true;
10859
+ if (decl.type === "VariableDeclarator") {
10860
+ // constants also can't change
10861
+ if (decl.node.kind === "const")
10862
+ return true;
10863
+ // if decl is a local, it also can't be changed
10864
+ // by a call to another function.
10865
+ for (let i = 0;; i++) {
10866
+ if (!state.stack[i] || decl.stack[i] !== state.stack[i])
10867
+ return false;
10868
+ if (state.stack[i].type === "FunctionDeclaration")
10869
+ return true;
10870
+ }
10871
+ }
10872
+ return null;
10873
+ };
10874
+ const safeArgs = [];
10875
+ let allSafe = true;
10876
+ if (!args.every((arg) => {
10877
+ switch (arg.type) {
10878
+ case "Literal":
10879
+ safeArgs.push(true);
10880
+ return true;
10881
+ case "Identifier":
10882
+ case "MemberExpression": {
10883
+ const [, results] = state.lookup(arg);
10884
+ if (!results || results.length !== 1) {
10885
+ safeArgs.push(null);
10886
+ return !requireAll;
10887
+ }
10888
+ const safety = getSafety(results[0]);
10889
+ safeArgs.push(safety);
10890
+ if (!safety) {
10891
+ allSafe = false;
10892
+ if (safety === null) {
10893
+ return !requireAll;
10894
+ }
10895
+ }
10896
+ return true;
10897
+ }
10898
+ }
10899
+ allSafe = false;
10900
+ safeArgs.push(null);
10901
+ return !requireAll;
10902
+ })) {
10903
+ return false;
10904
+ }
10905
+ if (allSafe && requireAll)
10906
+ return true;
10907
+ let callSeen = false;
10908
+ let ok = true;
10909
+ const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
10910
+ const getLoc = (node) => (Array.isArray(node) ? node[0].start : node.start) || 0;
10911
+ // look for uses of "unsafe" args that occur after a call.
10912
+ // use post to do the checking, because arguments are evaluated
10913
+ // prior to the call, so eg "return f(x.y);" is fine, but
10914
+ // "return f()+x.y" is not.
10915
+ //
10916
+ // We also have to use a "pre" to ensure that child nodes are
10917
+ // visited in source order (otherwise we could visit x.y before f()
10918
+ // in the above example)
10919
+ (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
10920
+ return Object.entries(node)
10921
+ .filter((kv) => Array.isArray(kv[1])
10922
+ ? kv[1].length !== 0 && (0,external_api_cjs_namespaceObject.hasProperty)(kv[1][0], "type")
10923
+ : (0,external_api_cjs_namespaceObject.hasProperty)(kv[1], "type"))
10924
+ .sort(([, a], [, b]) => getLoc(a) - getLoc(b))
10925
+ .map(([key]) => key);
10926
+ }, (node) => {
10927
+ switch (node.type) {
10928
+ case "AssignmentExpression":
10929
+ case "UpdateExpression": {
10930
+ const v = node.type == "UpdateExpression" ? node.argument : node.left;
10931
+ if (v.type === "Identifier" && (0,external_api_cjs_namespaceObject.hasProperty)(params, v.name)) {
10932
+ safeArgs[params[v.name]] = null;
10933
+ }
10934
+ }
10935
+ // fall through
10936
+ case "CallExpression":
10937
+ case "NewExpression":
10938
+ callSeen = true;
10939
+ break;
10940
+ case "Identifier":
10941
+ if (callSeen &&
10942
+ (0,external_api_cjs_namespaceObject.hasProperty)(params, node.name) &&
10943
+ !safeArgs[params[node.name]]) {
10944
+ safeArgs[params[node.name]] = null;
10945
+ }
10946
+ }
10947
+ });
10948
+ return safeArgs;
10949
+ }
10950
+ function canInline(state, func, args) {
10951
+ const safeArgs = getArgSafety(state, func, args, true);
10952
+ if (safeArgs === true || safeArgs === false) {
10953
+ return safeArgs;
10954
+ }
10955
+ return safeArgs.every((arg) => arg !== null);
10956
+ }
10957
+ function inliningLooksUseful(func, node) {
10958
+ while (true) {
10959
+ if (node.type === "BinaryExpression" && node.operator === "as") {
10960
+ node = node.left;
10961
+ }
10962
+ else if (node.type === "UnaryExpression" && node.operator === " as") {
10963
+ node = node.argument;
10964
+ }
10965
+ else {
10966
+ break;
10967
+ }
10968
+ }
10969
+ if (node.type === "Literal")
10970
+ return true;
10971
+ if (node.type === "Identifier") {
10972
+ if (func.params.length === 1 &&
10973
+ (0,external_api_cjs_namespaceObject.variableDeclarationName)(func.params[0]) === node.name) {
10974
+ return 1;
10975
+ }
10976
+ return true;
10977
+ }
10978
+ return false;
10979
+ }
10980
+ var InlineStatus;
10981
+ (function (InlineStatus) {
10982
+ InlineStatus[InlineStatus["Never"] = 0] = "Never";
10983
+ InlineStatus[InlineStatus["AsExpression"] = 1] = "AsExpression";
10984
+ InlineStatus[InlineStatus["AsStatement"] = 2] = "AsStatement";
10985
+ })(InlineStatus || (InlineStatus = {}));
10986
+ function shouldInline(state, func, args) {
10987
+ let autoInline = false;
10988
+ let inlineAsExpression = false;
10989
+ if (func.node.body &&
10990
+ func.node.body.body.length === 1 &&
10991
+ func.node.body.body[0].type === "ReturnStatement" &&
10992
+ func.node.body.body[0].argument &&
10993
+ func.node.params.length === args.length) {
10994
+ inlineAsExpression = true;
10995
+ autoInline = inliningLooksUseful(func.node, func.node.body.body[0].argument);
10996
+ }
10997
+ if (autoInline === 1) {
10998
+ return InlineStatus.AsExpression;
10999
+ }
11000
+ const excludeAnnotations = (func.node.loc?.source &&
11001
+ state.fnMap[func.node.loc?.source]?.excludeAnnotations) ||
11002
+ {};
11003
+ const inlineRequested = func.node.attrs &&
11004
+ func.node.attrs.attrs &&
11005
+ func.node.attrs.attrs.some((attr) => attr.type === "UnaryExpression" &&
11006
+ (attr.argument.name === "inline" ||
11007
+ (attr.argument.name.startsWith("inline_") &&
11008
+ (0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name.substring(7)))));
11009
+ if (autoInline || inlineRequested) {
11010
+ return inlineAsExpression && canInline(state, func, args)
11011
+ ? InlineStatus.AsExpression
11012
+ : InlineStatus.AsStatement;
11013
+ }
11014
+ return InlineStatus.Never;
11015
+ }
11016
+ function processInlineBody(state, func, call, root, insertedVariableDecls, params) {
11017
+ if (!params) {
11018
+ const safeArgs = getArgSafety(state, func, call.arguments, false);
11019
+ params = Object.fromEntries(func.node.params.map((param, i) => {
11020
+ const argnum = safeArgs === true || (safeArgs !== false && safeArgs[i] !== null)
11021
+ ? i
11022
+ : -1;
11023
+ const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
11024
+ return [name, argnum];
11025
+ }));
11026
+ }
11027
+ const pre = state.pre;
11028
+ const post = state.post;
11029
+ try {
11030
+ state.pre = (node) => {
11031
+ node.start = call.start;
11032
+ node.end = call.end;
11033
+ node.loc = call.loc;
11034
+ if (node === insertedVariableDecls)
11035
+ return false;
11036
+ const result = pre(node, state);
11037
+ if (!insertedVariableDecls && node.type === "BlockStatement") {
11038
+ const locals = state.localsStack[state.localsStack.length - 1];
11039
+ const { map } = locals;
11040
+ if (!map)
11041
+ throw new Error("No local variable map!");
11042
+ const declarations = func.node.params
11043
+ .map((param, i) => {
11044
+ const paramName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
11045
+ if (params[paramName] >= 0)
11046
+ return null;
11047
+ const name = renameVariable(state, locals, paramName) || paramName;
11048
+ return {
11049
+ type: "VariableDeclarator",
11050
+ id: { type: "Identifier", name },
11051
+ kind: "var",
11052
+ init: call.arguments[i],
11053
+ };
11054
+ })
11055
+ .filter((n) => n != null);
11056
+ insertedVariableDecls = {
11057
+ type: "VariableDeclaration",
11058
+ declarations,
11059
+ kind: "var",
11060
+ };
11061
+ node.body.unshift(insertedVariableDecls);
11062
+ }
11063
+ return result;
11064
+ };
11065
+ state.post = (node) => {
11066
+ let replacement = null;
11067
+ switch (node.type) {
11068
+ case "Identifier": {
11069
+ if (state.inType)
11070
+ break;
11071
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(params, node.name)) {
11072
+ const ix = params[node.name];
11073
+ if (ix >= 0) {
11074
+ replacement = call.arguments[ix];
11075
+ }
11076
+ break;
11077
+ }
11078
+ replacement = fixNodeScope(state, node, func.stack);
11079
+ if (!replacement) {
11080
+ throw new Error(`Inliner: Couldn't fix the scope of '${node.name}`);
11081
+ }
11082
+ break;
11083
+ }
11084
+ }
11085
+ return post(replacement || node, state) || replacement;
11086
+ };
11087
+ return state.traverse(root) || null;
11088
+ }
11089
+ catch (ex) {
11090
+ if (ex instanceof Error) {
11091
+ if (ex.message.startsWith("Inliner: ")) {
11092
+ return null;
11093
+ }
11094
+ }
11095
+ throw ex;
11096
+ }
11097
+ finally {
11098
+ state.pre = pre;
11099
+ state.post = post;
11100
+ }
11101
+ }
11102
+ function unused(expression, top) {
11103
+ switch (expression.type) {
11104
+ case "Literal":
11105
+ return [];
11106
+ case "Identifier":
11107
+ return [];
11108
+ case "BinaryExpression":
11109
+ if (expression.operator === "as") {
11110
+ return unused(expression.left);
11111
+ }
11112
+ // fall through
11113
+ case "LogicalExpression":
11114
+ return unused(expression.left).concat(unused(expression.right));
11115
+ case "UnaryExpression":
11116
+ return unused(expression.argument);
11117
+ case "MemberExpression":
11118
+ return unused(expression.object).concat(unused(expression.property));
11119
+ }
11120
+ return top
11121
+ ? null
11122
+ : [
11123
+ {
11124
+ type: "ExpressionStatement",
11125
+ expression,
11126
+ },
11127
+ ];
11128
+ }
11129
+ function inlineWithArgs(state, func, call) {
11130
+ if (!func.node || !func.node.body) {
11131
+ return null;
11132
+ }
11133
+ let retStmtCount = 0;
11134
+ (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
11135
+ node.type === "ReturnStatement" && retStmtCount++;
11136
+ });
11137
+ if (retStmtCount > 1 ||
11138
+ (retStmtCount === 1 &&
11139
+ func.node.body.body.slice(-1)[0].type !== "ReturnStatement")) {
11140
+ return null;
11141
+ }
11142
+ const body = JSON.parse(JSON.stringify(func.node.body));
11143
+ processInlineBody(state, func, call, body, func.node.params.length ? false : true);
11144
+ if (retStmtCount) {
11145
+ const last = body.body[body.body.length - 1];
11146
+ if (last.type != "ReturnStatement") {
11147
+ throw new Error("ReturnStatement got lost!");
11148
+ }
11149
+ if (last.argument) {
11150
+ const side_exprs = unused(last.argument);
11151
+ body.body.splice(body.body.length - 1, 1, ...side_exprs);
11152
+ }
11153
+ else {
11154
+ --body.body.length;
11155
+ }
11156
+ }
11157
+ return body;
11158
+ }
11159
+ function inlineFunction(state, func, call, inlineStatus) {
11160
+ if (inlineStatus == InlineStatus.AsStatement) {
11161
+ return inlineWithArgs(state, func, call);
11162
+ }
11163
+ const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
11164
+ const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
11165
+ return processInlineBody(state, func, call, retArg, true, params) || retArg;
11166
+ }
11167
+ function applyTypeIfNeeded(node) {
11168
+ if ("enumType" in node && node.enumType) {
11169
+ node = {
11170
+ type: "BinaryExpression",
11171
+ operator: "as",
11172
+ left: node,
11173
+ right: { type: "TypeSpecList", ts: [node.enumType] },
11174
+ };
11175
+ }
11176
+ return node;
11177
+ }
11178
+ function fixNodeScope(state, lookupNode, nodeStack) {
11179
+ if (lookupNode.type === "Identifier") {
11180
+ for (let i = state.stack.length; --i > nodeStack.length;) {
11181
+ const si = state.stack[i];
11182
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(si.decls, lookupNode.name)) {
11183
+ // its a local from the inlined function.
11184
+ // Nothing to do.
11185
+ return lookupNode;
11186
+ }
11187
+ }
11188
+ }
11189
+ const [, original] = state.lookup(lookupNode, null, nodeStack);
11190
+ if (!original) {
11191
+ return null;
11192
+ }
11193
+ const [, current] = state.lookup(lookupNode);
11194
+ // For now, leave it alone if it already maps to the same thing.
11195
+ // With a bit more work, we could find the guaranteed shortest
11196
+ // reference, and then use this to optimize *all* symbols, not
11197
+ // just fix inlined ones.
11198
+ if (current &&
11199
+ current.length === original.length &&
11200
+ current.every((item, index) => item == original[index])) {
11201
+ return lookupNode;
11202
+ }
11203
+ const node = lookupNode.type === "Identifier"
11204
+ ? lookupNode
11205
+ : lookupNode.property;
11206
+ if (original.length === 1 && original[0].type === "EnumStringMember") {
11207
+ return applyTypeIfNeeded(original[0].init);
11208
+ }
11209
+ const prefixes = original.map((sn) => {
11210
+ if ((0,external_api_cjs_namespaceObject.isStateNode)(sn) && sn.fullName) {
11211
+ return sn.fullName;
11212
+ }
11213
+ return "";
11214
+ });
11215
+ if (prefixes.length &&
11216
+ prefixes[0].startsWith("$.") &&
11217
+ prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
11218
+ const prefix = prefixes[0].split(".").slice(0, -1).reverse();
11219
+ let found = false;
11220
+ return prefix.reduce((current, name) => {
11221
+ if (found)
11222
+ return current;
11223
+ const [, results] = state.lookup(current);
11224
+ if (results &&
11225
+ results.length === original.length &&
11226
+ results.every((result, i) => result === original[i])) {
11227
+ found = true;
11228
+ return current;
11229
+ }
11230
+ const object = typeof name === "string"
11231
+ ? {
11232
+ type: "Identifier",
11233
+ name,
11234
+ start: node.start,
11235
+ end: node.end,
11236
+ loc: node.loc,
11237
+ }
11238
+ : name;
11239
+ let root = null;
11240
+ let property = current;
11241
+ while (property.type !== "Identifier") {
11242
+ root = property;
11243
+ property = property.object;
11244
+ }
11245
+ const mb = {
11246
+ type: "MemberExpression",
11247
+ object,
11248
+ property,
11249
+ computed: false,
11250
+ start: node.start,
11251
+ end: node.end,
11252
+ loc: node.loc,
11253
+ };
11254
+ if (root) {
11255
+ root.object = mb;
11256
+ }
11257
+ else {
11258
+ current = mb;
11259
+ }
11260
+ return current;
11261
+ }, node);
11262
+ }
11263
+ return null;
11264
+ }
11265
+
10794
11266
  ;// CONCATENATED MODULE: ./src/mc-rewrite.ts
10795
11267
 
10796
11268
 
10797
11269
 
10798
11270
 
11271
+
11272
+
10799
11273
  function processImports(allImports, lookup) {
10800
11274
  allImports.forEach(({ node, stack }) => {
10801
11275
  const [name, module] = lookup(node.id, ("as" in node && node.as && node.as.name) || null, stack);
@@ -10809,10 +11283,13 @@ function processImports(allImports, lookup) {
10809
11283
  module.forEach((m) => {
10810
11284
  if ((0,external_api_cjs_namespaceObject.isStateNode)(m) && m.type == "ModuleDeclaration") {
10811
11285
  (0,external_util_cjs_namespaceObject.pushUnique)(decls[name], m);
11286
+ if (!parent.type_decls)
11287
+ parent.type_decls = {};
11288
+ const tdecls = parent.type_decls;
11289
+ if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
11290
+ tdecls[name] = [];
11291
+ (0,external_util_cjs_namespaceObject.pushUnique)(tdecls[name], m);
10812
11292
  if (node.type == "ImportModule" && m.type_decls) {
10813
- if (!parent.type_decls)
10814
- parent.type_decls = {};
10815
- const tdecls = parent.type_decls;
10816
11293
  Object.entries(m.type_decls).forEach(([name, decls]) => {
10817
11294
  if (!(0,external_api_cjs_namespaceObject.hasProperty)(tdecls, name))
10818
11295
  tdecls[name] = [];
@@ -10914,30 +11391,34 @@ function getFileASTs(fnMap) {
10914
11391
  }, true));
10915
11392
  }
10916
11393
  async function analyze(fnMap) {
10917
- let excludeAnnotations;
10918
11394
  let hasTests = false;
10919
11395
  const allImports = [];
10920
11396
  const preState = {
11397
+ fnMap,
10921
11398
  allFunctions: [],
10922
11399
  allClasses: [],
10923
11400
  shouldExclude(node) {
10924
11401
  if ("attrs" in node &&
10925
11402
  node.attrs &&
10926
11403
  "attrs" in node.attrs &&
10927
- node.attrs.attrs) {
10928
- return node.attrs.attrs.reduce((drop, attr) => {
10929
- if (attr.type != "UnaryExpression")
10930
- return drop;
10931
- if (attr.argument.type != "Identifier")
11404
+ node.attrs.attrs &&
11405
+ node.loc?.source) {
11406
+ const excludeAnnotations = fnMap[node.loc.source].excludeAnnotations;
11407
+ if (excludeAnnotations) {
11408
+ return node.attrs.attrs.reduce((drop, attr) => {
11409
+ if (attr.type != "UnaryExpression")
11410
+ return drop;
11411
+ if (attr.argument.type != "Identifier")
11412
+ return drop;
11413
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name)) {
11414
+ return true;
11415
+ }
11416
+ if (attr.argument.name == "test") {
11417
+ hasTests = true;
11418
+ }
10932
11419
  return drop;
10933
- if ((0,external_api_cjs_namespaceObject.hasProperty)(excludeAnnotations, attr.argument.name)) {
10934
- return true;
10935
- }
10936
- if (attr.argument.name == "test") {
10937
- hasTests = true;
10938
- }
10939
- return drop;
10940
- }, false);
11420
+ }, false);
11421
+ }
10941
11422
  }
10942
11423
  return false;
10943
11424
  },
@@ -10986,7 +11467,6 @@ async function analyze(fnMap) {
10986
11467
  if (!ast) {
10987
11468
  throw parserError || new Error(`Failed to parse ${name}`);
10988
11469
  }
10989
- excludeAnnotations = value.excludeAnnotations;
10990
11470
  hasTests = false;
10991
11471
  (0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
10992
11472
  value.hasTests = hasTests;
@@ -11010,8 +11490,8 @@ function getLiteralFromDecls(decls) {
11010
11490
  let result = null;
11011
11491
  if (decls.every((d) => {
11012
11492
  if (d.type === "EnumStringMember" ||
11013
- (d.type === "VariableDeclarator" && d.kind === "const")) {
11014
- const init = getLiteralNode(d.init);
11493
+ (d.type === "VariableDeclarator" && d.node.kind === "const")) {
11494
+ const init = getLiteralNode(d.type === "EnumStringMember" ? d.init : d.node.init);
11015
11495
  if (!init)
11016
11496
  return false;
11017
11497
  if (!result) {
@@ -11350,57 +11830,8 @@ async function optimizeMonkeyC(fnMap) {
11350
11830
  const { map } = locals;
11351
11831
  if (map) {
11352
11832
  const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id);
11353
- if ((0,external_api_cjs_namespaceObject.hasProperty)(map, declName)) {
11354
- // We already have a variable with this name in scope
11355
- // Recent monkeyc compilers complain, so rename it
11356
- let suffix = 0;
11357
- let node_name = declName;
11358
- const match = node_name.match(/^pmcr_(.*)_(\d+)$/);
11359
- if (match) {
11360
- node_name = match[1];
11361
- suffix = parseInt(match[2], 10) + 1;
11362
- }
11363
- if (!locals.inners) {
11364
- // find all the names declared in this scope, to avoid
11365
- // more conflicts
11366
- locals.inners = {};
11367
- const inners = locals.inners;
11368
- (0,external_api_cjs_namespaceObject.traverseAst)(locals.node, (node) => {
11369
- if (node.type === "VariableDeclarator") {
11370
- inners[(0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id)] = true;
11371
- }
11372
- });
11373
- }
11374
- let name;
11375
- while (true) {
11376
- name = `pmcr_${node_name}_${suffix}`;
11377
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(map, name) &&
11378
- !(0,external_api_cjs_namespaceObject.hasProperty)(locals.inners, name)) {
11379
- // we also need to ensure that we don't hide the name of
11380
- // an outer module, class, function, enum or variable,
11381
- // since someone might want to access it from this scope.
11382
- let ok = false;
11383
- let i;
11384
- for (i = state.stack.length; i--;) {
11385
- const elm = state.stack[i];
11386
- if (ok) {
11387
- if ((0,external_api_cjs_namespaceObject.hasProperty)(elm.decls, name)) {
11388
- break;
11389
- }
11390
- }
11391
- else if (elm.node &&
11392
- elm.node.type === "FunctionDeclaration") {
11393
- ok = true;
11394
- }
11395
- }
11396
- if (i < 0) {
11397
- break;
11398
- }
11399
- }
11400
- suffix++;
11401
- }
11402
- map[declName] = name;
11403
- map[name] = true;
11833
+ const name = renameVariable(state, locals, declName);
11834
+ if (name) {
11404
11835
  if (node.id.type === "Identifier") {
11405
11836
  node.id.name = name;
11406
11837
  }
@@ -11424,7 +11855,7 @@ async function optimizeMonkeyC(fnMap) {
11424
11855
  state.exposed[node.argument.name] = true;
11425
11856
  // In any case, we can't replace *this* use of the
11426
11857
  // symbol with its value...
11427
- return false;
11858
+ return [];
11428
11859
  }
11429
11860
  break;
11430
11861
  case "Identifier": {
@@ -11442,7 +11873,7 @@ async function optimizeMonkeyC(fnMap) {
11442
11873
  state.exposed[node.name] = true;
11443
11874
  }
11444
11875
  }
11445
- return false;
11876
+ return [];
11446
11877
  }
11447
11878
  case "MemberExpression":
11448
11879
  if (node.property.type === "Identifier" && !node.computed) {
@@ -11524,49 +11955,37 @@ async function optimizeMonkeyC(fnMap) {
11524
11955
  }
11525
11956
  break;
11526
11957
  case "CallExpression": {
11527
- const [name, callees] = state.lookup(node.callee);
11528
- if (!callees || !callees.length) {
11529
- const n = name ||
11530
- ("name" in node.callee && node.callee.name) ||
11531
- ("property" in node.callee &&
11532
- node.callee.property &&
11533
- "name" in node.callee.property &&
11534
- node.callee.property.name);
11535
- if (n) {
11536
- state.exposed[n] = true;
11537
- }
11538
- else {
11539
- // There are unnamed CallExpressions, such as new [size]
11540
- // So there's nothing to do here.
11541
- }
11542
- return null;
11958
+ const ret = optimizeCall(state, node, false);
11959
+ if (ret) {
11960
+ replace(node, ret);
11543
11961
  }
11544
- if (callees.length == 1) {
11545
- const callee = (0,external_api_cjs_namespaceObject.isStateNode)(callees[0]) && callees[0].node;
11546
- if (callee &&
11547
- callee.type == "FunctionDeclaration" &&
11548
- callee.optimizable &&
11549
- !callee.hasOverride &&
11550
- node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
11551
- const ret = evaluateFunction(callee, node.arguments);
11552
- if (ret) {
11553
- replace(node, ret);
11554
- return null;
11962
+ break;
11963
+ }
11964
+ case "ExpressionStatement":
11965
+ if (node.expression.type === "CallExpression") {
11966
+ const ret = optimizeCall(state, node.expression, true);
11967
+ if (ret) {
11968
+ if (ret.type === "BlockStatement") {
11969
+ return ret;
11555
11970
  }
11971
+ node.expression = ret;
11556
11972
  }
11557
11973
  }
11558
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(state.calledFunctions, name)) {
11559
- state.calledFunctions[name] = [];
11974
+ else {
11975
+ const ret = unused(node.expression, true);
11976
+ if (ret) {
11977
+ return ret;
11978
+ }
11560
11979
  }
11561
- callees.forEach((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && state.calledFunctions[name].push(c.node));
11562
11980
  break;
11563
- }
11564
11981
  }
11565
11982
  return null;
11566
11983
  };
11567
11984
  Object.values(fnMap).forEach((f) => {
11568
11985
  (0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
11569
11986
  });
11987
+ delete state.pre;
11988
+ delete state.post;
11570
11989
  const cleanup = (node) => {
11571
11990
  switch (node.type) {
11572
11991
  case "EnumStringBody":
@@ -11641,6 +12060,98 @@ async function optimizeMonkeyC(fnMap) {
11641
12060
  });
11642
12061
  });
11643
12062
  }
12063
+ function optimizeCall(state, node, asStatement) {
12064
+ const [name, callees] = state.lookup(node.callee);
12065
+ if (!callees || !callees.length) {
12066
+ const n = name ||
12067
+ ("name" in node.callee && node.callee.name) ||
12068
+ ("property" in node.callee &&
12069
+ node.callee.property &&
12070
+ "name" in node.callee.property &&
12071
+ node.callee.property.name);
12072
+ if (n) {
12073
+ state.exposed[n] = true;
12074
+ }
12075
+ else {
12076
+ // There are unnamed CallExpressions, such as new [size]
12077
+ // So there's nothing to do here.
12078
+ }
12079
+ return null;
12080
+ }
12081
+ if (callees.length == 1 && callees[0].type === "FunctionDeclaration") {
12082
+ const callee = callees[0].node;
12083
+ if (callee.optimizable &&
12084
+ !callee.hasOverride &&
12085
+ node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
12086
+ const ret = evaluateFunction(callee, node.arguments);
12087
+ if (ret) {
12088
+ return ret;
12089
+ }
12090
+ }
12091
+ const inlineStatus = shouldInline(state, callees[0], node.arguments);
12092
+ if (inlineStatus === InlineStatus.AsExpression ||
12093
+ (asStatement && inlineStatus === InlineStatus.AsStatement)) {
12094
+ const ret = inlineFunction(state, callees[0], node, inlineStatus);
12095
+ if (ret) {
12096
+ return ret;
12097
+ }
12098
+ }
12099
+ }
12100
+ if (!(0,external_api_cjs_namespaceObject.hasProperty)(state.calledFunctions, name)) {
12101
+ state.calledFunctions[name] = [];
12102
+ }
12103
+ callees.forEach((c) => (0,external_api_cjs_namespaceObject.isStateNode)(c) && state.calledFunctions[name].push(c.node));
12104
+ return null;
12105
+ }
12106
+
12107
+ ;// CONCATENATED MODULE: ./src/pragma-checker.ts
12108
+
12109
+ function pragmaChecker(ast) {
12110
+ const comments = ast.comments;
12111
+ if (!comments)
12112
+ return;
12113
+ let index = -1;
12114
+ let comment;
12115
+ const next = () => {
12116
+ while (++index < comments.length) {
12117
+ comment = comments[index];
12118
+ if (comment.value.match(/^\s*@match\s+/)) {
12119
+ break;
12120
+ }
12121
+ }
12122
+ };
12123
+ next();
12124
+ (0,external_api_cjs_namespaceObject.traverseAst)(ast, (node) => {
12125
+ if (index >= comments.length)
12126
+ return false;
12127
+ if (node.start && node.start >= (comment.end || Infinity)) {
12128
+ let match = comment.value.match(/^\s*@match\s+([/%&#@"])(.+(?<!\\)(?:\\{2})*)\1\s+$/) || comment.value.match(/^\s*@match\s+(\S+)\s+$/);
12129
+ if (!match) {
12130
+ throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
12131
+ }
12132
+ const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/[\r\n]/g, " ");
12133
+ let found = false;
12134
+ let needle = match[1];
12135
+ if (match.length == 2) {
12136
+ found = haystack.includes(needle);
12137
+ }
12138
+ else {
12139
+ if (needle == '"') {
12140
+ found = haystack.includes((needle = match[2]));
12141
+ }
12142
+ else {
12143
+ const re = new RegExp((needle = match[2]));
12144
+ found = re.test(haystack);
12145
+ }
12146
+ }
12147
+ if (!found) {
12148
+ throw new Error(`Didn't find '${needle}' in ${comment.loc.source}:${comment.loc.start.line}`);
12149
+ }
12150
+ next();
12151
+ }
12152
+ return null;
12153
+ });
12154
+ }
11644
12155
 
11645
12156
  ;// CONCATENATED MODULE: ./src/optimizer.ts
11646
12157
 
@@ -11656,6 +12167,7 @@ async function optimizeMonkeyC(fnMap) {
11656
12167
 
11657
12168
 
11658
12169
 
12170
+
11659
12171
  function relative_path_no_dotdot(relative) {
11660
12172
  return relative.replace(/^(\.\.[\\\/])+/, (str) => `__${"dot".repeat(str.length / 3)}__${str.slice(-1)}`);
11661
12173
  }
@@ -12054,6 +12566,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
12054
12566
  // might have altered it), and that the options we care about haven't
12055
12567
  // changed
12056
12568
  if (hasTests != null &&
12569
+ !config.checkBuildPragmas &&
12057
12570
  configOptionsToCheck.every((option) => prevOptions[option] === config[option]) &&
12058
12571
  actualOptimizedFiles.length == Object.values(fnMap).length &&
12059
12572
  Object.values(fnMap)
@@ -12064,7 +12577,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
12064
12577
  // the oldest optimized file, we don't need to regenerate
12065
12578
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
12066
12579
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
12067
- if (source_time < opt_time && 1653954367574 < opt_time) {
12580
+ if (source_time < opt_time && 1654389404778 < opt_time) {
12068
12581
  return hasTests;
12069
12582
  }
12070
12583
  }
@@ -12077,6 +12590,9 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
12077
12590
  await promises_namespaceObject.mkdir(dir, { recursive: true });
12078
12591
  const opt_source = (0,external_api_cjs_namespaceObject.formatAst)(info.ast, info.monkeyCSource);
12079
12592
  await promises_namespaceObject.writeFile(name, opt_source);
12593
+ if (config.checkBuildPragmas) {
12594
+ pragmaChecker(info.ast);
12595
+ }
12080
12596
  return info.hasTests;
12081
12597
  })).then((results) => {
12082
12598
  const hasTests = results.some((v) => v);
@@ -12133,11 +12649,12 @@ async function generateApiMirTests(options) {
12133
12649
  return;
12134
12650
  const d = decl[0];
12135
12651
  if (d.type === "EnumStringMember" ||
12136
- (d.type === "VariableDeclarator" && d.kind === "const")) {
12137
- if (!d.init) {
12652
+ (d.type === "VariableDeclarator" && d.node.kind === "const")) {
12653
+ const init = (0,external_api_cjs_namespaceObject.isStateNode)(d) ? d.node.init : d.init;
12654
+ if (!init) {
12138
12655
  throw new Error(`Missing init for ${node.fullName}.${key}`);
12139
12656
  }
12140
- tests.push([`${node.fullName}.${key}`, (0,external_api_cjs_namespaceObject.formatAst)(d.init)]);
12657
+ tests.push([`${node.fullName}.${key}`, (0,external_api_cjs_namespaceObject.formatAst)(init)]);
12141
12658
  }
12142
12659
  else if ((0,external_api_cjs_namespaceObject.isStateNode)(d)) {
12143
12660
  findConstants(d);