@markw65/monkeyc-optimizer 1.1.7 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/api.cjs CHANGED
@@ -1,4 +1,4 @@
1
- 0 && (module.exports = {checkCompilerVersion,collectNamespaces,diagnostic,diagnosticHelper,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,getSuperClasses,hasProperty,isLocal,isLookupCandidate,isStateNode,lookupNext,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
1
+ 0 && (module.exports = {checkCompilerVersion,collectNamespaces,createDocumentationMap,diagnostic,diagnosticHelper,findNamesInScope,findUsingForNode,formatAst,formatAstLongLines,getApiFunctionInfo,getApiMapping,getSuperClasses,hasProperty,isLocal,isLookupCandidate,isStateNode,lookupByFullName,lookupNext,lookupResultContains,lookupWithType,makeToyboxLink,mapVarDeclsByType,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
2
2
  /******/ (() => { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -1372,7 +1372,7 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
1372
1372
  });
1373
1373
  }
1374
1374
  if (wantsAllRefs) {
1375
- const scope = state.stack[state.stack.length - 1];
1375
+ const scope = state.top().sn;
1376
1376
  if (scope.node === node &&
1377
1377
  scope.type === "BlockStatement" &&
1378
1378
  scope.decls &&
@@ -1934,9 +1934,9 @@ function getArgSafety(state, func, args, requireAll) {
1934
1934
  // if decl is a local, it also can't be changed
1935
1935
  // by a call to another function.
1936
1936
  for (let i = 0;; i++) {
1937
- if (!state.stack[i] || decl.stack[i] !== state.stack[i])
1937
+ if (!state.stack[i] || decl.stack[i]?.sn !== state.stack[i].sn)
1938
1938
  return false;
1939
- if (state.stack[i].type === "FunctionDeclaration")
1939
+ if (state.stack[i].sn.type === "FunctionDeclaration")
1940
1940
  return true;
1941
1941
  }
1942
1942
  }
@@ -2073,7 +2073,7 @@ function getArgSafety(state, func, args, requireAll) {
2073
2073
  }
2074
2074
  return null;
2075
2075
  };
2076
- state.stack = func.stack.concat(func);
2076
+ state.stack = func.stack.concat({ sn: func });
2077
2077
  state.traverse(func.node.body);
2078
2078
  }
2079
2079
  finally {
@@ -2184,7 +2184,7 @@ function processInlineBody(state, func, call, root, params) {
2184
2184
  // lookup determines static-ness of the lookup context based on seeing
2185
2185
  // a static FunctionDeclaration, but the FunctionDeclaration's stack
2186
2186
  // doesn't include the FunctionDeclaration itself.
2187
- const lookupStack = func.stack.concat(func);
2187
+ const lookupStack = func.stack.concat({ sn: func });
2188
2188
  try {
2189
2189
  state.pre = (node) => {
2190
2190
  if (failed)
@@ -2574,10 +2574,11 @@ function inlineFunction(state, func, call, context) {
2574
2574
  if (!typecheckFalse) {
2575
2575
  return ret;
2576
2576
  }
2577
- const callerSn = state.stack.find((sn) => sn.type === "FunctionDeclaration");
2578
- if (!callerSn) {
2577
+ const callerElem = state.stack.find((elem) => elem.sn.type === "FunctionDeclaration");
2578
+ if (!callerElem) {
2579
2579
  return ret;
2580
2580
  }
2581
+ const callerSn = callerElem.sn;
2581
2582
  const caller = callerSn.node;
2582
2583
  if (!caller.attrs) {
2583
2584
  caller.attrs = withLoc({
@@ -2697,6 +2698,1122 @@ function fixNodeScope(state, lookupNode, nodeStack) {
2697
2698
  }
2698
2699
 
2699
2700
 
2701
+ /***/ }),
2702
+
2703
+ /***/ 5530:
2704
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2705
+
2706
+ "use strict";
2707
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2708
+ /* harmony export */ "BJ": () => (/* binding */ analyze)
2709
+ /* harmony export */ });
2710
+ /* unused harmony exports getFileSources, getFileASTs, reportMissingSymbols, getLiteralFromDecls, optimizeMonkeyC */
2711
+ /* harmony import */ var _markw65_prettier_plugin_monkeyc__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9642);
2712
+ /* harmony import */ var _markw65_prettier_plugin_monkeyc__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_markw65_prettier_plugin_monkeyc__WEBPACK_IMPORTED_MODULE_0__);
2713
+ /* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(560);
2714
+ /* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs_promises__WEBPACK_IMPORTED_MODULE_1__);
2715
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
2716
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
2717
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6652);
2718
+ /* harmony import */ var _function_info__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(819);
2719
+ /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(333);
2720
+ /* harmony import */ var _optimizer_types__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(9697);
2721
+ /* harmony import */ var _pragma_checker__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(1851);
2722
+ /* harmony import */ var _pre__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(9910);
2723
+ /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(4859);
2724
+ /* harmony import */ var _type_flow_could_be__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(4055);
2725
+ /* harmony import */ var _type_flow_interp__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(7161);
2726
+ /* harmony import */ var _type_flow_optimize__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(3687);
2727
+ /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(9234);
2728
+ /* harmony import */ var _unused_exprs__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(424);
2729
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(6906);
2730
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_15__);
2731
+ /* harmony import */ var _variable_renamer__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(4405);
2732
+
2733
+
2734
+
2735
+
2736
+
2737
+
2738
+
2739
+
2740
+
2741
+
2742
+
2743
+
2744
+
2745
+
2746
+
2747
+
2748
+
2749
+ /*
2750
+ * Map each name to the list of StateNodes that declare that
2751
+ * name (excluding Functions, which are already in allFunctions)
2752
+ */
2753
+ function collectDeclarationsByName(state) {
2754
+ state.allDeclarations = {};
2755
+ const allDecls = state.allDeclarations;
2756
+ const helper = (sn) => {
2757
+ if (sn.type === "ClassDeclaration" ||
2758
+ sn.type === "Program" ||
2759
+ sn.type === "ModuleDeclaration") {
2760
+ if (sn.decls) {
2761
+ Object.entries(sn.decls).forEach(([key, decls]) => {
2762
+ const keyed = [];
2763
+ decls.forEach((decl) => {
2764
+ switch (decl.type) {
2765
+ case "ClassDeclaration":
2766
+ case "ModuleDeclaration":
2767
+ helper(decl);
2768
+ // fall through;
2769
+ case "VariableDeclarator":
2770
+ case "EnumStringMember":
2771
+ case "FunctionDeclaration":
2772
+ keyed.push(sn);
2773
+ }
2774
+ });
2775
+ if (keyed.length) {
2776
+ if (!(0,_api__WEBPACK_IMPORTED_MODULE_2__.hasProperty)(allDecls, key)) {
2777
+ allDecls[key] = keyed;
2778
+ }
2779
+ else {
2780
+ allDecls[key].push(...keyed);
2781
+ }
2782
+ }
2783
+ });
2784
+ }
2785
+ }
2786
+ };
2787
+ helper(state.stack[0].sn);
2788
+ }
2789
+ function collectClassInfo(state) {
2790
+ const toybox = state.stack[0].sn.decls["Toybox"][0];
2791
+ const lang = toybox.decls["Lang"][0];
2792
+ const object = lang.decls["Object"];
2793
+ state.allClasses.forEach((elm) => {
2794
+ if (elm.stack[elm.stack.length - 1].sn.type === "ClassDeclaration") {
2795
+ // nested classes don't get access to their contained
2796
+ // context. Put them in the global scope instead.
2797
+ elm.stack = elm.stack.slice(0, 1);
2798
+ }
2799
+ if (elm.node.superClass) {
2800
+ const [name, lookupDefns] = state.lookup(elm.node.superClass, null, elm.stack);
2801
+ const superClass = lookupDefns &&
2802
+ lookupDefns
2803
+ .map((lookupDefn) => lookupDefn.results)
2804
+ .flat()
2805
+ .filter((c) => (0,_api__WEBPACK_IMPORTED_MODULE_2__.isStateNode)(c) && c.type === "ClassDeclaration");
2806
+ // set it "true" if there is a superClass, but we can't find it.
2807
+ elm.superClass = superClass && superClass.length ? superClass : true;
2808
+ if (name && elm.superClass !== true) {
2809
+ /*
2810
+ * The runtime behavior of monkeyc is strange. Lookups
2811
+ * of the name of the superclass, either bare, or via self.<name>
2812
+ * always find the superclass, even if there's a member variable
2813
+ * or method of the same name. So its ok to just overwrite
2814
+ * elm.decls[name] here.
2815
+ *
2816
+ * ie
2817
+ *
2818
+ * class A { function foo() as Number { return 1; } }
2819
+ * class B { function foo() as String { return "B"; } }
2820
+ * class C extends A {
2821
+ * var A as B = new B();
2822
+ * function initialize() {
2823
+ * A.initialize(); // class A's initialize
2824
+ * A.foo(); // returns 1
2825
+ * self.A.foo(); // still returns 1
2826
+ * }
2827
+ * }
2828
+ *
2829
+ * The typechecker seems to get confused in some circumstances
2830
+ * though (ie it doesn't always use the same rules)
2831
+ */
2832
+ if (!elm.decls)
2833
+ elm.decls = {};
2834
+ elm.decls[name] = elm.superClass;
2835
+ }
2836
+ }
2837
+ else if (elm !== object[0]) {
2838
+ elm.superClass = object;
2839
+ }
2840
+ });
2841
+ const markOverrides = (cls, scls) => {
2842
+ if (scls === true)
2843
+ return;
2844
+ scls.forEach((c) => {
2845
+ c.decls &&
2846
+ Object.values(c.decls).forEach((funcs) => {
2847
+ funcs.forEach((f) => {
2848
+ if (f.type === "FunctionDeclaration" &&
2849
+ (0,_api__WEBPACK_IMPORTED_MODULE_2__.hasProperty)(cls.decls, f.name)) {
2850
+ f.node.hasOverride = true;
2851
+ }
2852
+ });
2853
+ });
2854
+ if (c.superClass)
2855
+ markOverrides(cls, c.superClass);
2856
+ });
2857
+ };
2858
+ state.allClasses.forEach((elm) => {
2859
+ if (elm.superClass)
2860
+ markOverrides(elm, elm.superClass);
2861
+ if (elm.hasInvoke && elm.decls) {
2862
+ Object.values(elm.decls).forEach((funcs) => {
2863
+ funcs.forEach((f) => {
2864
+ if (f.type === "FunctionDeclaration" &&
2865
+ !(f.attributes & _optimizer_types__WEBPACK_IMPORTED_MODULE_6__/* .StateNodeAttributes.STATIC */ .m.STATIC)) {
2866
+ (0,_api__WEBPACK_IMPORTED_MODULE_2__.markInvokeClassMethod)(state, f);
2867
+ }
2868
+ });
2869
+ });
2870
+ }
2871
+ });
2872
+ }
2873
+ function getFileSources(fnMap) {
2874
+ return Promise.all(Object.entries(fnMap).map(([name, value]) => {
2875
+ return (value.monkeyCSource ||
2876
+ fs_promises__WEBPACK_IMPORTED_MODULE_1__.readFile(name)
2877
+ .then((data) => (value.monkeyCSource = data.toString().replace(/\r\n/g, "\n"))));
2878
+ })).then(() => {
2879
+ return;
2880
+ });
2881
+ }
2882
+ function getFileASTs(fnMap) {
2883
+ return getFileSources(fnMap).then(() => Object.entries(fnMap).reduce((ok, [name, value]) => {
2884
+ if (!value.ast) {
2885
+ try {
2886
+ value.ast = _markw65_prettier_plugin_monkeyc__WEBPACK_IMPORTED_MODULE_0___default().parsers.monkeyc.parse(value.monkeyCSource, null, {
2887
+ filepath: name,
2888
+ });
2889
+ }
2890
+ catch (e) {
2891
+ ok = false;
2892
+ if (e instanceof Error) {
2893
+ value.parserError = e;
2894
+ }
2895
+ else {
2896
+ value.parserError = new Error("An unknown parser error occurred");
2897
+ }
2898
+ }
2899
+ }
2900
+ return ok;
2901
+ }, true));
2902
+ }
2903
+ async function analyze(fnMap, resourcesMap, manifestXML, config) {
2904
+ let hasTests = false;
2905
+ let markApi = true;
2906
+ const preState = {
2907
+ fnMap,
2908
+ config,
2909
+ allFunctions: {},
2910
+ allClasses: [],
2911
+ shouldExclude(node) {
2912
+ if ("attrs" in node &&
2913
+ node.attrs &&
2914
+ "attributes" in node.attrs &&
2915
+ node.attrs.attributes &&
2916
+ node.loc?.source) {
2917
+ const excludeAnnotations = fnMap[node.loc.source].excludeAnnotations;
2918
+ if (excludeAnnotations) {
2919
+ return node.attrs.attributes.elements.reduce((drop, attr) => {
2920
+ if (attr.type !== "UnaryExpression")
2921
+ return drop;
2922
+ if (attr.argument.type !== "Identifier")
2923
+ return drop;
2924
+ if ((0,_api__WEBPACK_IMPORTED_MODULE_2__.hasProperty)(excludeAnnotations, attr.argument.name)) {
2925
+ return true;
2926
+ }
2927
+ if (attr.argument.name === "test") {
2928
+ hasTests = true;
2929
+ }
2930
+ return drop;
2931
+ }, false);
2932
+ }
2933
+ }
2934
+ return false;
2935
+ },
2936
+ pre(node, state) {
2937
+ switch (node.type) {
2938
+ case "FunctionDeclaration":
2939
+ case "ModuleDeclaration":
2940
+ case "ClassDeclaration": {
2941
+ const scope = state.top().sn;
2942
+ scope.stack = state.stackClone().slice(0, -1);
2943
+ if (scope.type === "FunctionDeclaration") {
2944
+ if (markApi) {
2945
+ node.body = null;
2946
+ scope.info = (0,_api__WEBPACK_IMPORTED_MODULE_2__.getApiFunctionInfo)(state, scope);
2947
+ }
2948
+ const allFuncs = state.allFunctions;
2949
+ if (!(0,_api__WEBPACK_IMPORTED_MODULE_2__.hasProperty)(allFuncs, scope.name)) {
2950
+ allFuncs[scope.name] = [scope];
2951
+ }
2952
+ else {
2953
+ allFuncs[scope.name].push(scope);
2954
+ }
2955
+ }
2956
+ else if (scope.type === "ClassDeclaration") {
2957
+ state.allClasses.push(scope);
2958
+ }
2959
+ break;
2960
+ }
2961
+ }
2962
+ return null;
2963
+ },
2964
+ };
2965
+ await (0,_api__WEBPACK_IMPORTED_MODULE_2__.getApiMapping)(preState, resourcesMap, manifestXML);
2966
+ markApi = false;
2967
+ const state = preState;
2968
+ await getFileASTs(fnMap);
2969
+ Object.entries(fnMap).forEach(([name, value]) => {
2970
+ const { ast, parserError } = value;
2971
+ if (!ast) {
2972
+ throw parserError || new Error(`Failed to parse ${name}`);
2973
+ }
2974
+ hasTests = false;
2975
+ (0,_api__WEBPACK_IMPORTED_MODULE_2__.collectNamespaces)(ast, state);
2976
+ value.hasTests = hasTests;
2977
+ });
2978
+ delete state.shouldExclude;
2979
+ delete state.pre;
2980
+ collectDeclarationsByName(state);
2981
+ collectClassInfo(state);
2982
+ state.exposed = state.nextExposed;
2983
+ state.nextExposed = {};
2984
+ return state;
2985
+ }
2986
+ function reportMissingSymbols(state, config) {
2987
+ const diagnosticType = config?.checkInvalidSymbols !== "OFF"
2988
+ ? config?.checkInvalidSymbols || "WARNING"
2989
+ : null;
2990
+ const compiler2DiagnosticType = config?.checkCompilerLookupRules !== "OFF"
2991
+ ? config?.checkCompilerLookupRules || "WARNING"
2992
+ : null;
2993
+ if (diagnosticType &&
2994
+ !config?.compilerOptions?.includes("--Eno-invalid-symbol")) {
2995
+ const checkTypes = config?.typeCheckLevel && config.typeCheckLevel !== "Off";
2996
+ const report = (ast) => {
2997
+ visitReferences(state, ast, null, false, (node, results, error) => {
2998
+ if (node.type === "BinaryExpression" && node.operator === "has") {
2999
+ // Its not an error to check whether a property exists...
3000
+ return undefined;
3001
+ }
3002
+ if (!error) {
3003
+ if (state.sdkVersion === 4001006 &&
3004
+ compiler2DiagnosticType &&
3005
+ node.type === "MemberExpression" &&
3006
+ (node.object.type === "Identifier" ||
3007
+ node.object.type === "MemberExpression") &&
3008
+ results.some((result) => {
3009
+ const parent = result.parent;
3010
+ if (!parent || parent.type !== "ClassDeclaration") {
3011
+ return false;
3012
+ }
3013
+ return result.results.some((sn) => {
3014
+ switch (sn.type) {
3015
+ case "VariableDeclarator":
3016
+ case "FunctionDeclaration":
3017
+ return (sn.attributes &
3018
+ (StateNodeAttributes.PRIVATE |
3019
+ StateNodeAttributes.PROTECTED));
3020
+ }
3021
+ return false;
3022
+ });
3023
+ })) {
3024
+ diagnostic(state, node, `The expression ${formatAst(node)} will fail at runtime using sdk-4.1.6`, compiler2DiagnosticType);
3025
+ }
3026
+ return undefined;
3027
+ }
3028
+ let nodeStr;
3029
+ if (state.inType) {
3030
+ if (!checkTypes || (nodeStr = formatAst(node)).match(/^Void|Null$/)) {
3031
+ return undefined;
3032
+ }
3033
+ }
3034
+ diagnostic(state, node, `Undefined symbol ${nodeStr || formatAst(node)}`, diagnosticType);
3035
+ return false;
3036
+ });
3037
+ };
3038
+ Object.values(state.fnMap).forEach((v) => v.ast && report(v.ast));
3039
+ state.rezAst && report(state.rezAst);
3040
+ }
3041
+ }
3042
+ function compareLiteralLike(a, b) {
3043
+ while (a.type === "BinaryExpression")
3044
+ a = a.left;
3045
+ while (b.type === "BinaryExpression")
3046
+ b = b.left;
3047
+ return a.type === "Literal" && b.type === "Literal" && a.value === b.value;
3048
+ }
3049
+ function getLiteralFromDecls(lookupDefns) {
3050
+ if (!lookupDefns.length)
3051
+ return null;
3052
+ let result = null;
3053
+ if (lookupDefns.every((lookupDefn) => lookupDefn.results.every((d) => {
3054
+ if (d.type === "EnumStringMember" ||
3055
+ (d.type === "VariableDeclarator" && d.node.kind === "const")) {
3056
+ const init = getLiteralNode(d.type === "EnumStringMember" ? d.init : d.node.init);
3057
+ if (!init)
3058
+ return false;
3059
+ if (!result) {
3060
+ result = init;
3061
+ return true;
3062
+ }
3063
+ else {
3064
+ return compareLiteralLike(init, result);
3065
+ }
3066
+ }
3067
+ return false;
3068
+ }))) {
3069
+ return result;
3070
+ }
3071
+ return null;
3072
+ }
3073
+ function optimizeNode(istate, node) {
3074
+ if (istate.state.inlining)
3075
+ return null;
3076
+ if (istate.state.inType) {
3077
+ return null;
3078
+ }
3079
+ switch (node.type) {
3080
+ case "UpdateExpression":
3081
+ // we only evaluated any subexpressions of the argument.
3082
+ evaluateNode(istate, node.argument);
3083
+ break;
3084
+ case "AssignmentExpression": {
3085
+ // we only evaluated any subexpressions of the lhs.
3086
+ const right = istate.stack.pop();
3087
+ evaluateNode(istate, node.left);
3088
+ istate.stack.push(right);
3089
+ break;
3090
+ }
3091
+ case "BinaryExpression":
3092
+ if (node.operator === "has" &&
3093
+ node.right.type === "UnaryExpression" &&
3094
+ node.right.operator === ":") {
3095
+ // we skipped this node, so evaluate it now...
3096
+ istate.stack.push(evaluate(istate, node.right));
3097
+ }
3098
+ break;
3099
+ }
3100
+ const before = beforeEvaluate(istate, node);
3101
+ if (before != null)
3102
+ return before;
3103
+ evaluateNode(istate, node);
3104
+ return afterEvaluate(istate, node);
3105
+ }
3106
+ function evaluateFunction(istate, func, args) {
3107
+ if (!func.body ||
3108
+ istate.state.inlining ||
3109
+ (args && args.length !== func.params.length)) {
3110
+ return false;
3111
+ }
3112
+ const paramValues = args &&
3113
+ Object.fromEntries(func.params.map((p, i) => [
3114
+ variableDeclarationName(p),
3115
+ args[i],
3116
+ ]));
3117
+ let ret = null;
3118
+ const body = args ? cloneDeep(func.body) : func.body;
3119
+ const depth = istate.stack.length;
3120
+ try {
3121
+ traverseAst(body, (node) => {
3122
+ switch (node.type) {
3123
+ case "BlockStatement":
3124
+ case "ReturnStatement":
3125
+ case "UnaryExpression":
3126
+ case "BinaryExpression":
3127
+ case "Literal":
3128
+ case "Identifier":
3129
+ return;
3130
+ default:
3131
+ throw new Error("Bad node type");
3132
+ }
3133
+ }, !args
3134
+ ? undefined
3135
+ : (node) => {
3136
+ switch (node.type) {
3137
+ case "ReturnStatement":
3138
+ ret = node.argument || null;
3139
+ return null;
3140
+ case "BlockStatement":
3141
+ return null;
3142
+ case "Identifier":
3143
+ if (hasProperty(paramValues, node.name)) {
3144
+ istate.stack.push(evaluate(istate, (node = paramValues[node.name])));
3145
+ return node;
3146
+ }
3147
+ // fall through;
3148
+ default: {
3149
+ const repl = optimizeNode(istate, node) || node;
3150
+ if (repl.type === "Literal")
3151
+ return repl;
3152
+ throw new Error("Didn't optimize");
3153
+ }
3154
+ }
3155
+ });
3156
+ delete istate.state.inlining;
3157
+ istate.stack.length = depth;
3158
+ return ret;
3159
+ }
3160
+ catch (e) {
3161
+ delete istate.state.inlining;
3162
+ istate.stack.length = depth;
3163
+ return false;
3164
+ }
3165
+ }
3166
+ function markFunctionCalled(state, func) {
3167
+ if (!hasProperty(state.calledFunctions, func.id.name)) {
3168
+ state.calledFunctions[func.id.name] = [func];
3169
+ return;
3170
+ }
3171
+ pushUnique(state.calledFunctions[func.id.name], func);
3172
+ }
3173
+ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3174
+ const state = (await analyze(fnMap, resourcesMap, manifestXML, config));
3175
+ state.localsStack = [{}];
3176
+ state.calledFunctions = {};
3177
+ state.usedByName = {};
3178
+ let again = false;
3179
+ const optimizeCallHelper = (istate, call, node) => {
3180
+ const result = optimizeCall(istate, call, node);
3181
+ if (result) {
3182
+ if (isExpression(result)) {
3183
+ istate.stack[istate.stack.length - 1].node = result;
3184
+ }
3185
+ again = true;
3186
+ }
3187
+ return result;
3188
+ };
3189
+ const topLocals = () => state.localsStack[state.localsStack.length - 1];
3190
+ /*
3191
+ * Might this function be called from somewhere, including
3192
+ * callbacks from the api (eg getSettingsView, etc).
3193
+ */
3194
+ const maybeCalled = (func) => {
3195
+ if (!func.body) {
3196
+ // this is an api.mir function. It can be called
3197
+ return true;
3198
+ }
3199
+ if (hasProperty(state.exposed, func.id.name))
3200
+ return true;
3201
+ if (func.attrs &&
3202
+ func.attrs.attributes &&
3203
+ func.attrs.attributes.elements.some((attr) => {
3204
+ if (attr.type !== "UnaryExpression")
3205
+ return false;
3206
+ if (attr.argument.type !== "Identifier")
3207
+ return false;
3208
+ return attr.argument.name === "test";
3209
+ })) {
3210
+ return true;
3211
+ }
3212
+ if (hasProperty(state.calledFunctions, func.id.name)) {
3213
+ return (state.calledFunctions[func.id.name].find((f) => f === func) !== null);
3214
+ }
3215
+ return false;
3216
+ };
3217
+ /*
3218
+ * Does elm (a class) have a maybeCalled function called name,
3219
+ * anywhere in its superClass chain.
3220
+ */
3221
+ const checkInherited = (elm, name) => elm.superClass === true ||
3222
+ (elm.superClass != null &&
3223
+ elm.superClass.some((sc) => (hasProperty(sc.decls, name) &&
3224
+ sc.decls[name].some((f) => isStateNode(f) &&
3225
+ f.type === "FunctionDeclaration" &&
3226
+ maybeCalled(f.node))) ||
3227
+ (sc.superClass && checkInherited(sc, name))));
3228
+ const renamer = (idnode) => {
3229
+ const ident = idnode.type === "Identifier" ? idnode : idnode.left;
3230
+ const locals = topLocals();
3231
+ const { map } = locals;
3232
+ if (map) {
3233
+ const declName = ident.name;
3234
+ const name = renameVariable(state, locals, declName);
3235
+ if (name) {
3236
+ const [, results] = state.lookupValue(ident);
3237
+ if (!results) {
3238
+ throw new Error(`Didn't find local ${declName} which needed renaming`);
3239
+ }
3240
+ if (results.length !== 1) {
3241
+ throw new Error(`Lookup of local ${declName} found more than one result`);
3242
+ }
3243
+ const parent = results[0].parent;
3244
+ if (!parent) {
3245
+ throw new Error(`No parent in lookup of local ${declName}`);
3246
+ }
3247
+ const decls = parent.decls;
3248
+ if (!decls || !hasProperty(decls, declName)) {
3249
+ throw new Error(`Missing decls in lookup of local ${declName}`);
3250
+ }
3251
+ if (hasProperty(decls, name)) {
3252
+ throw new Error(`While renaming ${declName} to ${name}, there was already a variable ${name}`);
3253
+ }
3254
+ if (decls[declName].length === 1) {
3255
+ decls[name] = decls[declName];
3256
+ delete decls[declName];
3257
+ }
3258
+ else {
3259
+ let i = decls[declName].length;
3260
+ while (i--) {
3261
+ const decl = decls[declName][i];
3262
+ if (decl === idnode ||
3263
+ (decl.type === "VariableDeclarator" && decl.node.id === idnode)) {
3264
+ decls[declName].splice(i, 1);
3265
+ decls[name] = [decl];
3266
+ break;
3267
+ }
3268
+ }
3269
+ if (i < 0) {
3270
+ throw new Error(`While renaming ${declName} to ${name}: Didn't find original declaration`);
3271
+ }
3272
+ }
3273
+ ident.name = name;
3274
+ }
3275
+ else {
3276
+ map[declName] = true;
3277
+ }
3278
+ }
3279
+ };
3280
+ // use this when optimizing initializer expressions,
3281
+ // outside of any function.
3282
+ const gistate = { state, stack: [] };
3283
+ if (state.config?.checkTypes !== "OFF" &&
3284
+ state.config?.trustDeclaredTypes &&
3285
+ state.config.propagateTypes) {
3286
+ gistate.typeChecker =
3287
+ state.config.typeCheckLevel?.toLowerCase() === "strict"
3288
+ ? subtypeOf
3289
+ : couldBeWeak;
3290
+ gistate.checkTypes = state.config?.checkTypes || "WARNING";
3291
+ }
3292
+ // use this when type inference is enabled, and we're
3293
+ // inside a function.
3294
+ let istate = gistate;
3295
+ state.pre = (node) => {
3296
+ const ret = preEvaluate(istate, node);
3297
+ switch (node.type) {
3298
+ case "EnumDeclaration":
3299
+ return [];
3300
+ case "ForStatement": {
3301
+ const map = topLocals().map;
3302
+ if (map) {
3303
+ state.localsStack.push({ node, map: { ...map } });
3304
+ }
3305
+ break;
3306
+ }
3307
+ case "VariableDeclarator": {
3308
+ renamer(node.id);
3309
+ break;
3310
+ }
3311
+ case "CatchClause":
3312
+ if (node.param) {
3313
+ state.localsStack.push({ node, map: { ...(topLocals().map || {}) } });
3314
+ renamer(node.param);
3315
+ }
3316
+ break;
3317
+ case "BinaryExpression":
3318
+ if (node.operator === "has" &&
3319
+ node.right.type === "UnaryExpression" &&
3320
+ node.right.operator === ":") {
3321
+ // Using `expr has :symbol` doesn't "expose"
3322
+ // symbol, and the rhs of an "as" isn't an
3323
+ // expression. In both cases, skip the rhs
3324
+ return ["left"];
3325
+ }
3326
+ break;
3327
+ case "Identifier": {
3328
+ const map = topLocals().map;
3329
+ if (map) {
3330
+ if (hasProperty(map, node.name)) {
3331
+ const name = map[node.name];
3332
+ if (typeof name === "string") {
3333
+ node.name = name;
3334
+ }
3335
+ const [, results] = state.lookupValue(node);
3336
+ if (results) {
3337
+ if (results.length !== 1 || results[0].results.length !== 1) {
3338
+ throw new Error(`Local ${node.name} had multiple lookup results`);
3339
+ }
3340
+ const parent = results[0].parent;
3341
+ if (!parent) {
3342
+ throw new Error(`Local ${node.name} had no parent`);
3343
+ }
3344
+ const decl = results[0].results[0];
3345
+ if (parent.type === "FunctionDeclaration" ||
3346
+ decl.type !== "VariableDeclarator") {
3347
+ // we can't optimize away function or catch parameters
3348
+ return [];
3349
+ }
3350
+ if (parent.type !== "BlockStatement") {
3351
+ throw new Error(`Local ${node.name} was not declared at block scope(??)`);
3352
+ }
3353
+ decl.used = true;
3354
+ }
3355
+ }
3356
+ }
3357
+ return [];
3358
+ }
3359
+ case "AssignmentExpression":
3360
+ case "UpdateExpression": {
3361
+ const lhs = node.type === "AssignmentExpression" ? node.left : node.argument;
3362
+ if (lhs.type === "Identifier") {
3363
+ const map = topLocals().map;
3364
+ if (map) {
3365
+ if (hasProperty(map, lhs.name)) {
3366
+ const name = map[lhs.name];
3367
+ if (typeof name === "string") {
3368
+ lhs.name = name;
3369
+ }
3370
+ }
3371
+ }
3372
+ }
3373
+ else if (lhs.type === "MemberExpression") {
3374
+ const object = state.traverse(lhs.object);
3375
+ if (object) {
3376
+ lhs.object = object;
3377
+ }
3378
+ if (!isLookupCandidate(lhs)) {
3379
+ const property = state.traverse(lhs.property);
3380
+ if (property) {
3381
+ lhs.property = property;
3382
+ }
3383
+ }
3384
+ }
3385
+ return node.type === "AssignmentExpression" ? ["right"] : [];
3386
+ }
3387
+ case "BlockStatement": {
3388
+ const map = topLocals().map;
3389
+ if (map) {
3390
+ state.localsStack.push({
3391
+ node,
3392
+ map: { ...map },
3393
+ });
3394
+ }
3395
+ break;
3396
+ }
3397
+ case "FunctionDeclaration": {
3398
+ const map = {};
3399
+ node.params &&
3400
+ node.params.forEach((p) => (map[variableDeclarationName(p)] = true));
3401
+ state.localsStack.push({ node, map });
3402
+ const [{ sn: parent }, { sn: self }] = state.stack.slice(-2);
3403
+ if (state.currentFunction) {
3404
+ throw new Error(`Nested functions: ${self.fullName} was activated during processing of ${state.currentFunction.fullName}`);
3405
+ }
3406
+ state.currentFunction = self;
3407
+ const is = !state.config?.propagateTypes ||
3408
+ node.attrs?.attributes?.elements.find((attr) => attr.type === "UnaryExpression" &&
3409
+ attr.argument.name === "noConstProp")
3410
+ ? null
3411
+ : buildTypeInfo(state, state.currentFunction, true);
3412
+ if (is) {
3413
+ /*
3414
+ * istate contains a copy of state, but we need the real
3415
+ * thing, because "state" is captured here.
3416
+ *
3417
+ * A better solution will be to separate out a
3418
+ * "lookup context", which will be a stack, plus a couple
3419
+ * of fields from state, and then pass that around.
3420
+ */
3421
+ is.state = state;
3422
+ if (state.config?.checkTypes !== "OFF" &&
3423
+ state.config?.trustDeclaredTypes) {
3424
+ is.typeChecker = gistate.typeChecker;
3425
+ is.checkTypes = state.config?.checkTypes || "WARNING";
3426
+ }
3427
+ istate = is;
3428
+ }
3429
+ if (parent.type === "ClassDeclaration" && !maybeCalled(node)) {
3430
+ let used = false;
3431
+ if (node.id.name === "initialize") {
3432
+ used = true;
3433
+ }
3434
+ else if (parent.superClass) {
3435
+ used = checkInherited(parent, node.id.name);
3436
+ }
3437
+ if (used) {
3438
+ markFunctionCalled(state, node);
3439
+ }
3440
+ }
3441
+ // We dont want to call evaluateNode on
3442
+ // id, args or returnType
3443
+ return ["body"];
3444
+ }
3445
+ case "ClassDeclaration":
3446
+ case "ModuleDeclaration":
3447
+ // We dont want to call evaluateNode on
3448
+ // id, or superClass
3449
+ return ["body"];
3450
+ }
3451
+ return ret;
3452
+ };
3453
+ state.post = (node) => {
3454
+ const locals = topLocals();
3455
+ if (locals.node === node) {
3456
+ state.localsStack.pop();
3457
+ }
3458
+ const opt = optimizeNode(istate, node);
3459
+ if (opt != null) {
3460
+ return opt;
3461
+ }
3462
+ switch (node.type) {
3463
+ case "FunctionDeclaration":
3464
+ if (node.body && evaluateFunction(istate, node, null) !== false) {
3465
+ node.optimizable = true;
3466
+ }
3467
+ if (!state.currentFunction) {
3468
+ throw new Error(`Finished function ${state.top().sn.fullName}, but it was not marked current`);
3469
+ }
3470
+ state.currentFunction.info = state.currentFunction.next_info || false;
3471
+ delete state.currentFunction.next_info;
3472
+ delete state.currentFunction;
3473
+ if (istate.stack.length) {
3474
+ throw new Error("Stack was not empty");
3475
+ }
3476
+ istate = gistate;
3477
+ if (again) {
3478
+ again = false;
3479
+ const top = state.stack.pop();
3480
+ state.traverse(node);
3481
+ state.stack.push(top);
3482
+ }
3483
+ break;
3484
+ case "BlockStatement":
3485
+ case "ForStatement":
3486
+ if (locals.map && cleanupUnusedVars(state, node)) {
3487
+ again = true;
3488
+ }
3489
+ break;
3490
+ case "IfStatement": {
3491
+ const call = inlinableSubExpression(node.test);
3492
+ if (call) {
3493
+ return optimizeCallHelper(istate, call, node);
3494
+ }
3495
+ break;
3496
+ }
3497
+ case "ReturnStatement":
3498
+ if (node.argument && node.argument.type === "CallExpression") {
3499
+ return optimizeCallHelper(istate, node.argument, node);
3500
+ }
3501
+ break;
3502
+ case "Identifier":
3503
+ if (hasProperty(state.index, node.name)) {
3504
+ state.usedByName[node.name] = true;
3505
+ }
3506
+ break;
3507
+ case "MemberExpression": {
3508
+ const property = isLookupCandidate(node);
3509
+ if (property) {
3510
+ if (hasProperty(state.index, property.name)) {
3511
+ state.usedByName[property.name] = true;
3512
+ }
3513
+ }
3514
+ break;
3515
+ }
3516
+ case "NewExpression":
3517
+ if (state.currentFunction) {
3518
+ const [, results] = state.lookup(node.callee);
3519
+ if (results) {
3520
+ recordCalledFuncs(state.currentFunction, findCalleesForNew(results));
3521
+ }
3522
+ else {
3523
+ recordModifiedUnknown(state.currentFunction);
3524
+ }
3525
+ }
3526
+ break;
3527
+ case "CallExpression": {
3528
+ return optimizeCallHelper(istate, node, null);
3529
+ }
3530
+ case "VariableDeclaration": {
3531
+ const locals = topLocals();
3532
+ if (locals.map &&
3533
+ locals.node &&
3534
+ locals.node.type === "BlockStatement") {
3535
+ let results;
3536
+ const declarations = node.declarations;
3537
+ let i = 0;
3538
+ let j = 0;
3539
+ while (i < node.declarations.length) {
3540
+ const decl = declarations[i++];
3541
+ if (!decl.init)
3542
+ continue;
3543
+ const call = inlinableSubExpression(decl.init);
3544
+ if (call) {
3545
+ const inlined = optimizeCallHelper(istate, call, decl);
3546
+ if (!inlined)
3547
+ continue;
3548
+ if (Array.isArray(inlined) || inlined.type !== "BlockStatement") {
3549
+ throw new Error("Unexpected inlined result");
3550
+ }
3551
+ if (!results) {
3552
+ results = [];
3553
+ }
3554
+ delete decl.init;
3555
+ results.push(withLoc({
3556
+ ...node,
3557
+ declarations: declarations.slice(j, i),
3558
+ }, j ? declarations[j] : null, decl.id));
3559
+ results.push(inlined);
3560
+ j = i;
3561
+ }
3562
+ }
3563
+ if (results) {
3564
+ if (j < i) {
3565
+ results.push({
3566
+ ...node,
3567
+ declarations: declarations.slice(j, i),
3568
+ });
3569
+ }
3570
+ return results;
3571
+ }
3572
+ }
3573
+ break;
3574
+ }
3575
+ case "ExpressionStatement":
3576
+ if (node.expression.type === "CallExpression") {
3577
+ return optimizeCallHelper(istate, node.expression, node);
3578
+ }
3579
+ else if (node.expression.type === "AssignmentExpression") {
3580
+ const call = inlinableSubExpression(node.expression.right);
3581
+ if (call) {
3582
+ let ok = false;
3583
+ if (node.expression.left.type === "Identifier") {
3584
+ if (hasProperty(topLocals().map, node.expression.left.type)) {
3585
+ ok = true;
3586
+ }
3587
+ }
3588
+ if (!ok && node.expression.operator === "=") {
3589
+ const [, result] = state.lookup(node.expression.left);
3590
+ ok = !!result;
3591
+ }
3592
+ if (ok) {
3593
+ return optimizeCallHelper(istate, call, node.expression);
3594
+ }
3595
+ }
3596
+ }
3597
+ else {
3598
+ return unused(state, node.expression, true);
3599
+ }
3600
+ break;
3601
+ case "AssignmentExpression":
3602
+ case "UpdateExpression":
3603
+ if (state.currentFunction) {
3604
+ const lhs = node.type === "AssignmentExpression" ? node.left : node.argument;
3605
+ const [, results] = state.lookup(lhs);
3606
+ if (results) {
3607
+ recordModifiedDecls(state.currentFunction, results);
3608
+ }
3609
+ else {
3610
+ const id = lhs.type === "Identifier" ? lhs : isLookupCandidate(lhs);
3611
+ if (id) {
3612
+ recordModifiedName(state.currentFunction, id.name);
3613
+ }
3614
+ else {
3615
+ recordModifiedUnknown(state.currentFunction);
3616
+ }
3617
+ }
3618
+ }
3619
+ break;
3620
+ }
3621
+ return null;
3622
+ };
3623
+ Object.values(fnMap).forEach((f) => {
3624
+ collectNamespaces(f.ast, state);
3625
+ });
3626
+ state.usedByName = {};
3627
+ state.calledFunctions = {};
3628
+ state.exposed = state.nextExposed;
3629
+ state.nextExposed = {};
3630
+ Object.values(fnMap).forEach((f) => {
3631
+ collectNamespaces(f.ast, state);
3632
+ });
3633
+ state.exposed = state.nextExposed;
3634
+ state.nextExposed = {};
3635
+ delete state.pre;
3636
+ delete state.post;
3637
+ Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
3638
+ const cleanup = (node) => {
3639
+ switch (node.type) {
3640
+ case "ThisExpression":
3641
+ node.text = "self";
3642
+ break;
3643
+ case "EnumStringBody":
3644
+ if (node.members.every((m) => {
3645
+ const name = "name" in m ? m.name : m.id.name;
3646
+ return (hasProperty(state.index, name) &&
3647
+ !hasProperty(state.exposed, name) &&
3648
+ !hasProperty(state.usedByName, name));
3649
+ })) {
3650
+ node.enumType = [
3651
+ ...new Set(node.members.map((m) => {
3652
+ if (!("init" in m))
3653
+ return "Number";
3654
+ const [node, type] = getNodeValue(m.init);
3655
+ if (!node) {
3656
+ throw new Error("Failed to get type for eliminated enum");
3657
+ }
3658
+ return type;
3659
+ })),
3660
+ ].join(" or ");
3661
+ node.members.splice(0);
3662
+ }
3663
+ break;
3664
+ case "EnumDeclaration":
3665
+ if (!node.body.members.length) {
3666
+ if (!node.id)
3667
+ return false;
3668
+ if (!node.body.enumType) {
3669
+ throw new Error("Missing enumType on optimized enum");
3670
+ }
3671
+ return {
3672
+ type: "TypedefDeclaration",
3673
+ id: node.id,
3674
+ ts: {
3675
+ type: "UnaryExpression",
3676
+ argument: {
3677
+ type: "TypeSpecList",
3678
+ ts: [
3679
+ node.body.enumType,
3680
+ ],
3681
+ },
3682
+ prefix: true,
3683
+ operator: " as",
3684
+ },
3685
+ };
3686
+ }
3687
+ break;
3688
+ case "VariableDeclaration": {
3689
+ node.declarations = node.declarations.filter((d) => {
3690
+ const name = variableDeclarationName(d.id);
3691
+ return (!hasProperty(state.index, name) ||
3692
+ hasProperty(state.exposed, name) ||
3693
+ hasProperty(state.usedByName, name));
3694
+ });
3695
+ if (!node.declarations.length) {
3696
+ return false;
3697
+ }
3698
+ break;
3699
+ }
3700
+ case "ClassElement":
3701
+ if (!node.item) {
3702
+ return false;
3703
+ }
3704
+ break;
3705
+ case "FunctionDeclaration":
3706
+ if (!maybeCalled(node)) {
3707
+ if (node.attrs &&
3708
+ node.attrs.attributes &&
3709
+ node.attrs.attributes.elements.some((attr) => attr.type === "UnaryExpression" && attr.argument.name === "keep")) {
3710
+ break;
3711
+ }
3712
+ return false;
3713
+ }
3714
+ break;
3715
+ case "ClassDeclaration":
3716
+ case "ModuleDeclaration":
3717
+ // none of the attributes means anything on classes and
3718
+ // modules, and the new compiler complains about some
3719
+ // of them. Just drop them all.
3720
+ if (node.attrs && node.attrs.access) {
3721
+ if (node.attrs.attributes) {
3722
+ delete node.attrs.access;
3723
+ }
3724
+ else {
3725
+ delete node.attrs;
3726
+ }
3727
+ }
3728
+ }
3729
+ return null;
3730
+ };
3731
+ Object.entries(fnMap).forEach(([, f]) => {
3732
+ traverseAst(f.ast, undefined, (node) => {
3733
+ const ret = cleanup(node);
3734
+ if (ret === false) {
3735
+ state.removeNodeComments(node, f.ast);
3736
+ }
3737
+ return ret;
3738
+ });
3739
+ });
3740
+ reportMissingSymbols(state, config);
3741
+ if (state.inlineDiagnostics) {
3742
+ if (!state.diagnostics) {
3743
+ state.diagnostics = state.inlineDiagnostics;
3744
+ }
3745
+ else {
3746
+ Object.entries(state.inlineDiagnostics).forEach(([key, diags]) => {
3747
+ if (!hasProperty(state.diagnostics, key)) {
3748
+ state.diagnostics[key] = diags;
3749
+ }
3750
+ else {
3751
+ state.diagnostics[key].push(...diags);
3752
+ }
3753
+ });
3754
+ }
3755
+ delete state.inlineDiagnostics;
3756
+ }
3757
+ Object.entries(fnMap).forEach(([name, f]) => {
3758
+ if (state.config && state.config.checkBuildPragmas) {
3759
+ pragmaChecker(state, f.ast, state.diagnostics?.[name]);
3760
+ }
3761
+ });
3762
+ return state.diagnostics;
3763
+ }
3764
+ function optimizeCall(istate, node, context) {
3765
+ const state = istate.state;
3766
+ const [name, results] = state.lookupNonlocal(node.callee);
3767
+ const callees = results ? findCallees(results) : null;
3768
+ if (!callees || !callees.length) {
3769
+ const n = name ||
3770
+ ("name" in node.callee && node.callee.name) ||
3771
+ ("property" in node.callee &&
3772
+ node.callee.property &&
3773
+ "name" in node.callee.property &&
3774
+ node.callee.property.name);
3775
+ if (n) {
3776
+ if (hasProperty(state.allFunctions, n)) {
3777
+ if (state.currentFunction) {
3778
+ recordCalledFuncs(state.currentFunction, state.allFunctions[n]);
3779
+ }
3780
+ state.allFunctions[n].forEach((fn) => markFunctionCalled(state, fn.node));
3781
+ }
3782
+ }
3783
+ else if (state.currentFunction) {
3784
+ // I don't think this can happen: foo[x](args)
3785
+ // doesn't parse, so you can't even do things like
3786
+ // $.Toybox.Lang[:format]("fmt", [])
3787
+ recordModifiedUnknown(state.currentFunction);
3788
+ }
3789
+ return null;
3790
+ }
3791
+ if (state.currentFunction) {
3792
+ recordCalledFuncs(state.currentFunction, callees);
3793
+ }
3794
+ if (callees.length === 1 && callees[0].type === "FunctionDeclaration") {
3795
+ const callee = callees[0].node;
3796
+ if (!context &&
3797
+ callee.optimizable &&
3798
+ !callee.hasOverride &&
3799
+ node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
3800
+ const ret = evaluateFunction(istate, callee, node.arguments);
3801
+ if (ret) {
3802
+ return withLoc(ret, node, node);
3803
+ }
3804
+ }
3805
+ if (shouldInline(state, callees[0], node, context)) {
3806
+ const ret = inlineFunction(state, callees[0], node, context);
3807
+ if (ret) {
3808
+ return ret;
3809
+ }
3810
+ }
3811
+ }
3812
+ callees.forEach((c) => markFunctionCalled(state, c.node));
3813
+ return null;
3814
+ }
3815
+
3816
+
2700
3817
  /***/ }),
2701
3818
 
2702
3819
  /***/ 4499:
@@ -2780,6 +3897,900 @@ var StateNodeAttributes;
2780
3897
  })(StateNodeAttributes || (StateNodeAttributes = {}));
2781
3898
 
2782
3899
 
3900
+ /***/ }),
3901
+
3902
+ /***/ 1851:
3903
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
3904
+
3905
+ "use strict";
3906
+ /* unused harmony export pragmaChecker */
3907
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
3908
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
3909
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
3910
+
3911
+
3912
+ function pragmaChecker(state, ast, diagnostics) {
3913
+ const comments = ast.comments;
3914
+ if (!comments)
3915
+ return;
3916
+ diagnostics = diagnostics
3917
+ ?.slice()
3918
+ .sort((d1, d2) => d1.loc.start.offset - d2.loc.start.offset);
3919
+ let diagIndex = 0;
3920
+ let index = -1;
3921
+ let comment;
3922
+ let matchers;
3923
+ const next = () => {
3924
+ while (++index < comments.length) {
3925
+ comment = comments[index];
3926
+ let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
3927
+ if (!match)
3928
+ continue;
3929
+ const kind = match[1];
3930
+ let str = match[2];
3931
+ const verCheck = checkCompilerVersion(str.replace(/\s.*/, ""), state.sdkVersion || 0);
3932
+ if (verCheck === false)
3933
+ continue;
3934
+ if (verCheck === true) {
3935
+ str = str.replace(/^\S+\s+/, "");
3936
+ }
3937
+ matchers = [];
3938
+ while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
3939
+ matchers.push({ kind, quote: match[1], needle: match[2] });
3940
+ str = str.substring(match[0].length);
3941
+ if (!str.length)
3942
+ break;
3943
+ }
3944
+ if (!str.length)
3945
+ break;
3946
+ if (!matchers.length) {
3947
+ match = str.match(/^(\S+)\s+$/);
3948
+ if (match) {
3949
+ matchers.push({ kind, quote: '"', needle: match[1] });
3950
+ break;
3951
+ }
3952
+ }
3953
+ diagnostic(state, comment, `Build pragma '${comment.value}' is invalid`, "ERROR");
3954
+ }
3955
+ };
3956
+ const matcher = (quote, needle, haystack) => {
3957
+ if (quote === '"') {
3958
+ return haystack.includes(needle);
3959
+ }
3960
+ const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/\W/g, "_")}(?:_\\d+)?)`));
3961
+ return re.test(haystack);
3962
+ };
3963
+ next();
3964
+ traverseAst(ast, (node) => {
3965
+ if (index >= comments.length ||
3966
+ node.type === "Line" ||
3967
+ node.type === "Block" ||
3968
+ node.type === "MultiLine") {
3969
+ return false;
3970
+ }
3971
+ if (node.start && node.start >= (comment.end || Infinity)) {
3972
+ const { kind, quote, needle } = matchers.shift();
3973
+ if (kind === "match") {
3974
+ const haystack = formatAst(node).replace(/([\r\n]|\s)+/g, " ");
3975
+ if (!matcher(quote, needle, haystack)) {
3976
+ matcher(quote, needle, haystack);
3977
+ diagnostic(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
3978
+ }
3979
+ }
3980
+ else if (kind === "expect") {
3981
+ const locCmp = (a, b) => {
3982
+ if (!b)
3983
+ return -1;
3984
+ if (a.start.line < b.start.line)
3985
+ return -1;
3986
+ if (a.start.line === b.start.line &&
3987
+ a.start.column < b.start.column) {
3988
+ return -1;
3989
+ }
3990
+ if (a.end.line > b.end.line)
3991
+ return 1;
3992
+ if (a.end.line === b.end.line && a.end.column >= b.end.column) {
3993
+ return 1;
3994
+ }
3995
+ return 0;
3996
+ };
3997
+ let found = false;
3998
+ if (diagnostics) {
3999
+ while (true) {
4000
+ if (diagIndex >= diagnostics.length) {
4001
+ diagnostics = null;
4002
+ break;
4003
+ }
4004
+ const diag = diagnostics[diagIndex];
4005
+ const cmp = locCmp(diag.loc, node.loc);
4006
+ if (cmp > 0) {
4007
+ break;
4008
+ }
4009
+ diagIndex++;
4010
+ if (cmp < 0)
4011
+ continue;
4012
+ if (matcher(quote, needle, diag.message)) {
4013
+ found = true;
4014
+ diag.type = "INFO";
4015
+ }
4016
+ }
4017
+ }
4018
+ if (!found) {
4019
+ diagnostic(state, comment, `Missing error message '${needle}`, "ERROR");
4020
+ }
4021
+ }
4022
+ if (matchers.length) {
4023
+ // if we're checking a series of nodes, we need
4024
+ // to skip over this one.
4025
+ return false;
4026
+ }
4027
+ next();
4028
+ }
4029
+ return null;
4030
+ });
4031
+ }
4032
+
4033
+
4034
+ /***/ }),
4035
+
4036
+ /***/ 9910:
4037
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4038
+
4039
+ "use strict";
4040
+ /* unused harmony export sizeBasedPRE */
4041
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
4042
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
4043
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
4044
+ /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5101);
4045
+ /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8180);
4046
+ /* harmony import */ var _function_info__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(819);
4047
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6906);
4048
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_5__);
4049
+
4050
+
4051
+
4052
+
4053
+
4054
+
4055
+ /**
4056
+ * This implements a pseudo Partial Redundancy Elimination
4057
+ * pass. It isn't quite like traditional PRE because we're
4058
+ * aiming to minimize size, not dynamic instructions. So
4059
+ * for us, its worthwhile to take something like:
4060
+ *
4061
+ * switch (x) {
4062
+ * case 1: foo(A.B); break;
4063
+ * case 2: foo(C); break;
4064
+ * case 3: bar(A.B); break;
4065
+ * }
4066
+ *
4067
+ * and rewrite it as
4068
+ *
4069
+ * var tmp = A.B;
4070
+ * switch (x) {
4071
+ * case 1: foo(tmp); break;
4072
+ * case 2: foo(C); break;
4073
+ * case 3: bar(tmp); break;
4074
+ * }
4075
+ *
4076
+ * because even though A.B wasn't used on all paths where we
4077
+ * inserted the temporary, we still reduced the code size.
4078
+ */
4079
+ const logging = false;
4080
+ function logAntState(s, decl) {
4081
+ const defs = Array.from(s.ant).reduce((defs, event) => {
4082
+ if (event.type === "def" || event.type === "mod")
4083
+ defs++;
4084
+ return defs;
4085
+ }, 0);
4086
+ console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
4087
+ console.log(` - members: ${Array.from(s.members)
4088
+ .map(([block, live]) => block.order + (live ? "t" : "f"))
4089
+ .join(", ")}`);
4090
+ }
4091
+ function logAntDecls(antDecls) {
4092
+ antDecls.forEach(logAntState);
4093
+ }
4094
+ function sizeBasedPRE(state, func) {
4095
+ if (!func.node.body)
4096
+ return;
4097
+ if (!state.config ||
4098
+ !state.config.sizeBasedPRE ||
4099
+ (typeof state.config.sizeBasedPRE === "string" &&
4100
+ state.config.sizeBasedPRE !== func.fullName)) {
4101
+ return;
4102
+ }
4103
+ const { graph: head, identifiers } = buildPREGraph(state, func);
4104
+ const candidates = computeAttributes(state, head);
4105
+ if (candidates) {
4106
+ if (logging) {
4107
+ console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
4108
+ logAntDecls(candidates);
4109
+ }
4110
+ const nodeMap = new Map();
4111
+ const declMap = new Map();
4112
+ const variableDecl = withLoc({
4113
+ type: "VariableDeclaration",
4114
+ declarations: [],
4115
+ kind: "var",
4116
+ }, func.node.body);
4117
+ variableDecl.end = variableDecl.start;
4118
+ variableDecl.loc.end = variableDecl.loc.start;
4119
+ Array.from(candidates.keys())
4120
+ .map((decl) => [declFullName(decl), decl])
4121
+ .sort()
4122
+ .forEach(([, decl]) => {
4123
+ let name;
4124
+ let i = 0;
4125
+ do {
4126
+ name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
4127
+ if (!identifiers.has(name)) {
4128
+ identifiers.add(name);
4129
+ break;
4130
+ }
4131
+ i++;
4132
+ } while (true);
4133
+ declMap.set(decl, name);
4134
+ const s = candidates.get(decl);
4135
+ variableDecl.declarations.push(withLoc({
4136
+ type: "VariableDeclarator",
4137
+ id: withLoc({ type: "Identifier", name }, variableDecl),
4138
+ kind: "var",
4139
+ }, variableDecl));
4140
+ s.ant.forEach((event) => {
4141
+ const events = nodeMap.get(event.node);
4142
+ if (!events) {
4143
+ nodeMap.set(event.node, [event]);
4144
+ }
4145
+ else {
4146
+ events.push(event);
4147
+ }
4148
+ });
4149
+ });
4150
+ applyReplacements(func.node, nodeMap, declMap);
4151
+ func.node.body.body.unshift(variableDecl);
4152
+ }
4153
+ }
4154
+ function buildPREGraph(state, func) {
4155
+ const result = buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
4156
+ // Split blocks that contains refs and defs to the same thing,
4157
+ // to make it easier to pick and choose which refs are converted
4158
+ postOrderTraverse(result.graph, (block) => {
4159
+ if (!block.events) {
4160
+ return;
4161
+ }
4162
+ let modSeen = false;
4163
+ const refs = new Set();
4164
+ const defs = new Set();
4165
+ const splitBlock = (eventIndex) => {
4166
+ const newBlock = { ...block };
4167
+ delete newBlock.node;
4168
+ newBlock.events = block.events?.splice(eventIndex);
4169
+ newBlock.succs?.forEach((succ) => {
4170
+ const i = succ.preds.findIndex((b) => b === block);
4171
+ succ.preds[i] = newBlock;
4172
+ if (succ.expreds?.includes(block)) {
4173
+ succ.expreds.push(newBlock);
4174
+ }
4175
+ });
4176
+ block.succs = [newBlock];
4177
+ newBlock.preds = [block];
4178
+ delete newBlock.expreds;
4179
+ modSeen = false;
4180
+ refs.clear();
4181
+ defs.clear();
4182
+ };
4183
+ for (let i = block.events.length; i--;) {
4184
+ const event = block.events[i];
4185
+ switch (event.type) {
4186
+ case "ref":
4187
+ if (some(event.decl, (decl) => decl.type === "Literal" ||
4188
+ (decl.type === "VariableDeclarator" &&
4189
+ decl.node.kind === "const"))) {
4190
+ break;
4191
+ }
4192
+ if (modSeen || defs.has(event.decl)) {
4193
+ splitBlock(i + 1);
4194
+ }
4195
+ refs.add(event.decl);
4196
+ break;
4197
+ case "def":
4198
+ if (refs.has(event.decl)) {
4199
+ splitBlock(i + 1);
4200
+ }
4201
+ defs.add(event.decl);
4202
+ break;
4203
+ case "mod":
4204
+ if (event.callees &&
4205
+ every(event.callees, (callee) => callee.info === false)) {
4206
+ // calls known to have no side effects can be
4207
+ // dropped.
4208
+ block.events.splice(i, 1);
4209
+ break;
4210
+ }
4211
+ if (refs.size) {
4212
+ splitBlock(i + 1);
4213
+ }
4214
+ modSeen = true;
4215
+ break;
4216
+ }
4217
+ }
4218
+ });
4219
+ return result;
4220
+ }
4221
+ function anticipatedDecls() {
4222
+ return new Map();
4223
+ }
4224
+ function equalSet(a, b) {
4225
+ if (a.size !== b.size)
4226
+ return false;
4227
+ for (const item of a) {
4228
+ if (!b.has(item))
4229
+ return false;
4230
+ }
4231
+ return true;
4232
+ }
4233
+ function equalMap(a, b) {
4234
+ if (a.size !== b.size)
4235
+ return false;
4236
+ for (const [item, value] of a) {
4237
+ if (b.get(item) !== value)
4238
+ return false;
4239
+ }
4240
+ return true;
4241
+ }
4242
+ function anticipatedState(node, events) {
4243
+ return { ant: events || new Set(), live: true, node, members: new Map() };
4244
+ }
4245
+ function cloneAnticipatedState(as) {
4246
+ return {
4247
+ ant: cloneSet(as.ant),
4248
+ live: as.live,
4249
+ node: as.node,
4250
+ members: new Map(as.members),
4251
+ };
4252
+ }
4253
+ function mergeAnticipatedState(ae, be) {
4254
+ mergeSet(ae.ant, be.ant);
4255
+ be.members.forEach((live, block) => ae.members.set(block, live));
4256
+ if (be.live)
4257
+ ae.live = true;
4258
+ }
4259
+ function cloneAnticipatedDecls(ad) {
4260
+ const copy = anticipatedDecls();
4261
+ for (const [k, v] of ad) {
4262
+ if (!v.isIsolated) {
4263
+ copy.set(k, cloneAnticipatedState(v));
4264
+ }
4265
+ }
4266
+ return copy;
4267
+ }
4268
+ function mergeAnticipatedDecls(a, b) {
4269
+ for (const [k, v] of b) {
4270
+ if (v.isIsolated)
4271
+ continue;
4272
+ const ae = a.get(k);
4273
+ if (ae) {
4274
+ mergeAnticipatedState(ae, v);
4275
+ }
4276
+ else {
4277
+ a.set(k, cloneAnticipatedState(v));
4278
+ }
4279
+ }
4280
+ }
4281
+ function equalStates(a, b) {
4282
+ if (a.size !== b.size)
4283
+ return false;
4284
+ for (const [k, ae] of a) {
4285
+ const be = b.get(k);
4286
+ if (!be ||
4287
+ be.live !== ae.live ||
4288
+ be.isIsolated !== ae.isIsolated ||
4289
+ !equalSet(ae.ant, be.ant) ||
4290
+ !equalMap(ae.members, be.members)) {
4291
+ return false;
4292
+ }
4293
+ }
4294
+ return true;
4295
+ }
4296
+ const LocalRefCost = 2;
4297
+ function refCost(node) {
4298
+ if (node.type === "Literal") {
4299
+ switch (typeof node.value) {
4300
+ case "string":
4301
+ return 5;
4302
+ case "bigint":
4303
+ case "number":
4304
+ return 5;
4305
+ case "boolean":
4306
+ return 2;
4307
+ default:
4308
+ if (node.value === null) {
4309
+ return 2;
4310
+ }
4311
+ return 0;
4312
+ }
4313
+ }
4314
+ // A read from a non-local identifier takes 8 bytes
4315
+ let cost = 8;
4316
+ if (node.type === "Identifier")
4317
+ return cost;
4318
+ while (true) {
4319
+ const next = node.object;
4320
+ if (next.type !== "MemberExpression") {
4321
+ if (next.type !== "ThisExpression") {
4322
+ cost += next.type === "Identifier" && next.name === "$" ? 4 : 6;
4323
+ }
4324
+ return cost;
4325
+ }
4326
+ node = next;
4327
+ cost += 6;
4328
+ }
4329
+ }
4330
+ function defCost(node) {
4331
+ return refCost(node) + 2;
4332
+ }
4333
+ function candidateBoundary(candState) {
4334
+ const boundary = new Set();
4335
+ candState.members.forEach((live, block) => {
4336
+ if (live && block !== candState.head) {
4337
+ if (block.preds) {
4338
+ block.preds.forEach((pred) => candState.members.has(pred) || boundary.add(pred));
4339
+ }
4340
+ }
4341
+ });
4342
+ if (candState.live) {
4343
+ if (!candState.head) {
4344
+ throw new Error(`Missing head`);
4345
+ }
4346
+ boundary.add(candState.head);
4347
+ }
4348
+ return boundary;
4349
+ }
4350
+ function candidateCost(candState) {
4351
+ let cost = 0;
4352
+ candState.ant.forEach((event) => {
4353
+ if (event.type === "ref") {
4354
+ cost -= refCost(candState.node) - LocalRefCost;
4355
+ }
4356
+ else {
4357
+ cost += defCost(candState.node);
4358
+ }
4359
+ });
4360
+ const boundarySize = candidateBoundary(candState).size;
4361
+ cost += defCost(candState.node) * boundarySize;
4362
+ return cost;
4363
+ }
4364
+ function computeAttributes(state, head) {
4365
+ const order = getPostOrder(head);
4366
+ order.forEach((block, i) => {
4367
+ block.order = i;
4368
+ });
4369
+ if (logging) {
4370
+ order.forEach((block) => {
4371
+ console.log(block.order, `(${block.node ? block.node.loc?.start.line : "??"})`, `Preds: ${(block.preds || [])
4372
+ .map((block) => block.order)
4373
+ .join(", ")}`);
4374
+ if (block.events) {
4375
+ block.events.forEach((event) => event.type !== "exn" &&
4376
+ console.log(` ${event.type}: ${event.decl
4377
+ ? declFullName(event.decl)
4378
+ : event.node
4379
+ ? formatAst(event.node)
4380
+ : "??"}`));
4381
+ }
4382
+ console.log(`Succs: ${(block.succs || [])
4383
+ .map((block) => block.order)
4384
+ .join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
4385
+ });
4386
+ }
4387
+ const queue = new DataflowQueue();
4388
+ const blockStates = [];
4389
+ /*
4390
+ Algorithm
4391
+ =========
4392
+
4393
+ Process blocks in post-order, and the events in reverse
4394
+ order to collect the AnticipatedState at the start of each
4395
+ Block.
4396
+
4397
+ Then for each EventDecl find the best starting block.
4398
+ */
4399
+ const modMap = new Map();
4400
+ const getMod = (event, decl, id) => {
4401
+ if (id.type !== "Identifier" && id.type !== "MemberExpression") {
4402
+ throw new Error("Trying to modify a non-variable");
4403
+ }
4404
+ let eventMap = modMap.get(event);
4405
+ if (!eventMap) {
4406
+ modMap.set(event, (eventMap = new Map()));
4407
+ }
4408
+ let result = eventMap.get(decl);
4409
+ if (!result) {
4410
+ result = {
4411
+ type: "mod",
4412
+ node: event.node,
4413
+ decl,
4414
+ id,
4415
+ mayThrow: event.mayThrow,
4416
+ };
4417
+ eventMap.set(decl, result);
4418
+ }
4419
+ return result;
4420
+ };
4421
+ order.forEach((block) => queue.enqueue(block));
4422
+ while (!queue.empty()) {
4423
+ const top = queue.dequeue();
4424
+ if (top.order === undefined) {
4425
+ throw new Error(`Unreachable block was visited!`);
4426
+ }
4427
+ const curState = (top.succs &&
4428
+ top.succs.reduce((blockState, succ) => {
4429
+ const succState = blockStates[succ.order];
4430
+ if (succState) {
4431
+ if (!blockState) {
4432
+ blockState = cloneAnticipatedDecls(succState);
4433
+ }
4434
+ else {
4435
+ mergeAnticipatedDecls(blockState, succState);
4436
+ }
4437
+ }
4438
+ return blockState;
4439
+ }, null)) ||
4440
+ anticipatedDecls();
4441
+ if (top.events) {
4442
+ for (let i = top.events.length; i--;) {
4443
+ const event = top.events[i];
4444
+ if (event.mayThrow && top.exsucc) {
4445
+ const succState = blockStates[top.exsucc.order];
4446
+ if (succState) {
4447
+ mergeAnticipatedDecls(curState, succState);
4448
+ }
4449
+ }
4450
+ switch (event.type) {
4451
+ case "ref": {
4452
+ let candidates = curState.get(event.decl);
4453
+ if (!candidates) {
4454
+ candidates = anticipatedState(event.node);
4455
+ curState.set(event.decl, candidates);
4456
+ }
4457
+ candidates.ant.add(event);
4458
+ candidates.live = true;
4459
+ break;
4460
+ }
4461
+ case "mod": {
4462
+ curState.forEach((candidates, decls) => {
4463
+ if (some(decls, (decl) => decl.type === "VariableDeclarator" &&
4464
+ decl.node.kind === "var" &&
4465
+ candidates.live &&
4466
+ (!event.callees ||
4467
+ event.callees.some((callee) => functionMayModify(state, callee, decl))))) {
4468
+ candidates.ant.add(getMod(event, decls, candidates.node));
4469
+ candidates.live = false;
4470
+ }
4471
+ });
4472
+ break;
4473
+ }
4474
+ case "def": {
4475
+ let candidates = curState.get(event.decl);
4476
+ const isUpdate = event.node.type === "UpdateExpression" ||
4477
+ (event.node.type === "AssignmentExpression" &&
4478
+ event.node.operator !== "=");
4479
+ if (!candidates) {
4480
+ const target = event.node.type === "AssignmentExpression"
4481
+ ? event.node.left
4482
+ : event.node.type === "UpdateExpression"
4483
+ ? event.node.argument
4484
+ : event.node.id.type === "BinaryExpression"
4485
+ ? event.node.id.left
4486
+ : event.node.id;
4487
+ candidates = anticipatedState(target);
4488
+ curState.set(event.decl, candidates);
4489
+ }
4490
+ if (isUpdate || candidates.live) {
4491
+ candidates.ant.add(event);
4492
+ }
4493
+ candidates.live = isUpdate;
4494
+ break;
4495
+ }
4496
+ }
4497
+ }
4498
+ }
4499
+ curState.forEach((antState) => {
4500
+ antState.head = top;
4501
+ antState.members.set(top, antState.live);
4502
+ if (!antState.live && candidateBoundary(antState).size === 0) {
4503
+ // we found a group that's isolated from the rest
4504
+ // of the function. Don't merge it with earlier
4505
+ // refs and defs, because we can take it or leave
4506
+ // it based on its own cost.
4507
+ antState.isIsolated = true;
4508
+ }
4509
+ });
4510
+ const oldState = blockStates[top.order];
4511
+ if (oldState && equalStates(oldState, curState)) {
4512
+ continue;
4513
+ }
4514
+ blockStates[top.order] = curState;
4515
+ if (logging) {
4516
+ console.log(`Updated block ${top.order}`);
4517
+ logAntDecls(curState);
4518
+ }
4519
+ if (top.preds) {
4520
+ top.preds.forEach((pred) => queue.enqueue(pred));
4521
+ }
4522
+ }
4523
+ const candidateDecls = anticipatedDecls();
4524
+ blockStates.forEach((blockState, i) => {
4525
+ blockState &&
4526
+ blockState.forEach((events, decl) => {
4527
+ const cost = candidateCost(events);
4528
+ if (cost >= 0)
4529
+ return;
4530
+ const existing = candidateDecls.get(decl);
4531
+ if (!existing ||
4532
+ existing.isIsolated ||
4533
+ candidateCost(existing) > cost) {
4534
+ const boundary = candidateBoundary(events);
4535
+ if (!Array.from(boundary).every((block) => {
4536
+ if (block !== events.head && block.events) {
4537
+ if (events.node.type === "Literal") {
4538
+ return false;
4539
+ }
4540
+ let i = block.events.length;
4541
+ while (i--) {
4542
+ const event = block.events[i];
4543
+ if (event.type === "def" || event.type === "mod") {
4544
+ events.ant.add({
4545
+ type: "mod",
4546
+ node: event.node,
4547
+ decl,
4548
+ id: events.node,
4549
+ mayThrow: false,
4550
+ });
4551
+ events.members.set(block, false);
4552
+ return true;
4553
+ }
4554
+ }
4555
+ }
4556
+ const node = block.node;
4557
+ if (!node)
4558
+ return false;
4559
+ events.ant.add({
4560
+ type: "mod",
4561
+ node: node.type === "FunctionDeclaration" ? node.body : node,
4562
+ before: true,
4563
+ decl,
4564
+ id: events.node,
4565
+ mayThrow: false,
4566
+ });
4567
+ events.members.set(block, false);
4568
+ return true;
4569
+ })) {
4570
+ return;
4571
+ }
4572
+ events.live = false;
4573
+ if (existing && existing.isIsolated) {
4574
+ delete existing.isIsolated;
4575
+ mergeAnticipatedState(events, existing);
4576
+ }
4577
+ else if (candidateCost(events) !== cost) {
4578
+ throw new Error(`cost of block ${i} changed`);
4579
+ }
4580
+ candidateDecls.set(decl, events);
4581
+ }
4582
+ });
4583
+ });
4584
+ if (candidateDecls.size) {
4585
+ return candidateDecls;
4586
+ }
4587
+ return null;
4588
+ }
4589
+ /*
4590
+ * Determine the cost of fixing a def under a statement.
4591
+ *
4592
+ * eg:
4593
+ *
4594
+ * if (foo()) {
4595
+ * bar(X.y);
4596
+ * } else {
4597
+ * baz(X.y);
4598
+ * }
4599
+ *
4600
+ * Here, we could pull out X.y as a local, but if foo might modify
4601
+ * X.y, we have nowhere to insert the temporary. But we can rewrite
4602
+ * it as:
4603
+ *
4604
+ * var tmp = foo();
4605
+ * if (tmp) {
4606
+ * bar(X.y);
4607
+ * } else {
4608
+ * baz(X.y);
4609
+ * }
4610
+ *
4611
+ * and now we can insert a temporary before the if, but it costs
4612
+ * 4 bytes to do so.
4613
+ *
4614
+ * We can do the same for switch statements unless (ugh!)
4615
+ * the cases might modify the decl too.
4616
+ *
4617
+ * eg
4618
+ *
4619
+ * switch (foo()) {
4620
+ * case bar(): ...
4621
+ * }
4622
+ *
4623
+ */
4624
+ function _isFixableStmt(node) {
4625
+ switch (node.type) {
4626
+ case "IfStatement":
4627
+ return 4;
4628
+ case "SwitchStatement":
4629
+ if (node.cases.every((c) => !c.test ||
4630
+ c.test.type === "Literal" ||
4631
+ c.test.type === "Identifier" ||
4632
+ c.test.type === "InstanceOfCase" ||
4633
+ (c.test.type === "UnaryExpression" && c.test.operator === ":"))) {
4634
+ return 4;
4635
+ }
4636
+ break;
4637
+ }
4638
+ return false;
4639
+ }
4640
+ function applyReplacements(func, nodeMap, declMap) {
4641
+ const ident = (name, node) => {
4642
+ return withLoc({ type: "Identifier", name }, node);
4643
+ };
4644
+ const pendingMap = new Map();
4645
+ const stmtStack = [func];
4646
+ traverseAst(func, (node) => {
4647
+ if (isStatement(node)) {
4648
+ stmtStack.push(node);
4649
+ }
4650
+ }, (node) => {
4651
+ const stmt = stmtStack[stmtStack.length - 1];
4652
+ if (stmt === node)
4653
+ stmtStack.pop();
4654
+ const events = nodeMap.get(node);
4655
+ if (events) {
4656
+ const ret = events.reduce((ret, event) => {
4657
+ if (event.type === "ref") {
4658
+ if (ret) {
4659
+ throw new Error(`ref found when there was already a replacement for this node`);
4660
+ }
4661
+ if (node.type !== "Identifier" &&
4662
+ node.type !== "MemberExpression" &&
4663
+ node.type !== "Literal") {
4664
+ throw new Error(`Ref found, but wrong type of node: ${node.type}`);
4665
+ }
4666
+ const name = declMap.get(event.decl);
4667
+ if (!name) {
4668
+ throw new Error(`No replacement found for "${formatAst(node)}"`);
4669
+ }
4670
+ return ident(name, node);
4671
+ }
4672
+ if (event.type === "def") {
4673
+ if (ret) {
4674
+ throw new Error(`def found when there was already a replacement for this node`);
4675
+ }
4676
+ if (node.type !== "AssignmentExpression" &&
4677
+ node.type !== "UpdateExpression") {
4678
+ throw new Error(`Def found, but wrong type of node: ${node.type}`);
4679
+ }
4680
+ const target = node.type === "AssignmentExpression"
4681
+ ? node.left
4682
+ : node.argument;
4683
+ const name = declMap.get(event.decl);
4684
+ if (!name) {
4685
+ throw new Error(`No replacement found for "${formatAst(target)}"`);
4686
+ }
4687
+ const id = ident(name, target);
4688
+ const assign = withLoc({
4689
+ type: "AssignmentExpression",
4690
+ left: target,
4691
+ right: { ...id },
4692
+ operator: "=",
4693
+ }, node);
4694
+ if (node.type === "AssignmentExpression") {
4695
+ node.left = id;
4696
+ }
4697
+ else {
4698
+ node.argument = id;
4699
+ }
4700
+ return withLoc({ type: "SequenceExpression", expressions: [node, assign] }, node);
4701
+ }
4702
+ if (event.type === "mod") {
4703
+ if (!event.decl) {
4704
+ throw new Error(`Unexpected null decl on mod event`);
4705
+ }
4706
+ let pending = pendingMap.get(stmt);
4707
+ if (!pending) {
4708
+ pendingMap.set(stmt, (pending = new Set()));
4709
+ }
4710
+ pending.add(event);
4711
+ }
4712
+ else {
4713
+ throw new Error(`Unexpected ${event.type} found`);
4714
+ }
4715
+ return ret;
4716
+ }, null);
4717
+ if (ret) {
4718
+ return ret;
4719
+ }
4720
+ }
4721
+ const pending = pendingMap.get(node);
4722
+ if (node.type === "SequenceExpression") {
4723
+ if (pending) {
4724
+ throw new Error(`Unexpected pending list at SequenceExpression`);
4725
+ }
4726
+ for (let i = node.expressions.length; i--;) {
4727
+ const ni = node.expressions[i];
4728
+ if (ni.type === "SequenceExpression") {
4729
+ node.expressions.splice(i, 1, ...ni.expressions);
4730
+ }
4731
+ }
4732
+ }
4733
+ const applyPending = (results, locNode) => {
4734
+ const target = results.length === 1 && results[0].type === "BlockStatement"
4735
+ ? results[0]
4736
+ : null;
4737
+ pendingMap.delete(node);
4738
+ pending.forEach((event) => {
4739
+ const decl = event.decl;
4740
+ const name = declMap.get(decl);
4741
+ if (!name) {
4742
+ throw new Error(`No replacement found for "${declFullName(decl)}"`);
4743
+ }
4744
+ if (!event.id) {
4745
+ throw new Error(`Missing id for mod event for "${declFullName(decl)}"`);
4746
+ }
4747
+ const rhs = withLocDeep(event.id, locNode, locNode);
4748
+ rhs.end = rhs.start;
4749
+ if (rhs.loc) {
4750
+ rhs.loc.end = rhs.loc.start;
4751
+ }
4752
+ const insertion = withLoc({
4753
+ type: "ExpressionStatement",
4754
+ expression: withLoc({
4755
+ type: "AssignmentExpression",
4756
+ left: ident(name, rhs),
4757
+ right: rhs,
4758
+ operator: "=",
4759
+ }, rhs),
4760
+ }, rhs);
4761
+ if (event.type === "mod" && event.before) {
4762
+ if (target) {
4763
+ target.body.unshift(insertion);
4764
+ }
4765
+ else {
4766
+ results.unshift(insertion);
4767
+ }
4768
+ }
4769
+ else {
4770
+ results.push(insertion);
4771
+ }
4772
+ });
4773
+ return results.length === 1 ? null : results;
4774
+ };
4775
+ if (node.type === "ExpressionStatement" &&
4776
+ node.expression.type === "SequenceExpression") {
4777
+ const results = [];
4778
+ node.expression.expressions.forEach((expression) => {
4779
+ results.push({ ...node, expression });
4780
+ });
4781
+ if (!pending) {
4782
+ return results;
4783
+ }
4784
+ return applyPending(results, node);
4785
+ }
4786
+ if (pending) {
4787
+ return applyPending([node], node);
4788
+ }
4789
+ return null;
4790
+ });
4791
+ }
4792
+
4793
+
2783
4794
  /***/ }),
2784
4795
 
2785
4796
  /***/ 4859:
@@ -3089,7 +5100,7 @@ function filterDecls(decls, possible, name) {
3089
5100
  const stack = d.stack;
3090
5101
  possible.forEach((poss) => {
3091
5102
  for (let i = stack.length; i--;) {
3092
- const sn = stack[i];
5103
+ const sn = stack[i].sn;
3093
5104
  if (sn.decls === poss.decls) {
3094
5105
  if (!cur[0]) {
3095
5106
  cur = [new Set(), new Set()];
@@ -3310,9 +5321,21 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
3310
5321
  if (Array.isArray(decl) ||
3311
5322
  (decl.type !== "MemberDecl" && decl.type !== "Unknown")) {
3312
5323
  if (!clearEquiv) {
5324
+ /*
5325
+ * If we're not clearing the equivalencies then this update
5326
+ * must be applied to every element of the set
5327
+ */
3313
5328
  const v = blockState.get(decl);
3314
5329
  if (v?.equivSet) {
3315
- blockState.set(decl, { ...v, curType: value });
5330
+ let s = decl;
5331
+ do {
5332
+ const next = blockState.get(s);
5333
+ if (!next || !next.equivSet) {
5334
+ throw new Error(`Inconsistent equivSet for ${tsKey(decl)}: missing value for ${tsKey(s)}`);
5335
+ }
5336
+ blockState.set(s, { ...next, curType: value });
5337
+ s = next.equivSet.next;
5338
+ } while (s !== decl);
3316
5339
  return;
3317
5340
  }
3318
5341
  }
@@ -3418,7 +5441,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
3418
5441
  return tmpState;
3419
5442
  }
3420
5443
  if (isExact(right) &&
3421
- right.type & SingleTonTypeTagsConst &&
5444
+ right.type & SingletonTypeTagsConst &&
3422
5445
  left.type & right.type) {
3423
5446
  // left is not equal to right, and right is one of the
3424
5447
  // singleton types; so we can remove that type from left.
@@ -4336,7 +6359,7 @@ function common_types(left, right, allowed) {
4336
6359
  }
4337
6360
  if (lt & 8 /* TypeTag.Number */) {
4338
6361
  result |=
4339
- rt & 6 /* TypeTag.Boolean */ ? 6 /* TypeTag.Boolean */ : rt & ~SingleTonTypeTagsConst;
6362
+ rt & 6 /* TypeTag.Boolean */ ? 6 /* TypeTag.Boolean */ : rt & ~SingletonTypeTagsConst;
4340
6363
  }
4341
6364
  if (lt & 16 /* TypeTag.Long */) {
4342
6365
  if (rt & 6 /* TypeTag.Boolean */) {
@@ -4746,7 +6769,7 @@ function calleeObjectType(istate, callee) {
4746
6769
  }
4747
6770
  if (callee.type === "Identifier" && istate.func) {
4748
6771
  const func = istate.func;
4749
- const [self] = func.stack.slice(-1);
6772
+ const [{ sn: self }] = func.stack.slice(-1);
4750
6773
  return typeFromTypeStateNode(istate.state, self, (func.attributes & StateNodeAttributes.STATIC) !== 0 ||
4751
6774
  self.type !== "ClassDeclaration");
4752
6775
  }
@@ -4878,14 +6901,14 @@ function checkCallArgs(istate, node, callees, args) {
4878
6901
  return resultType;
4879
6902
  }
4880
6903
  function isOverride(cur, funcs) {
4881
- const cls = cur.stack?.[cur.stack.length - 1];
6904
+ const cls = cur.stack?.[cur.stack.length - 1]?.sn;
4882
6905
  if (cls?.type === "ClassDeclaration" && cls.superClasses) {
4883
6906
  const supers = getSuperClasses(cls);
4884
6907
  if (supers &&
4885
6908
  some(funcs, (func) => {
4886
6909
  if (func === cur)
4887
6910
  return false;
4888
- const fcls = func.stack?.[func.stack.length - 1];
6911
+ const fcls = func.stack?.[func.stack.length - 1].sn;
4889
6912
  return fcls ? supers.has(fcls) : false;
4890
6913
  })) {
4891
6914
  return true;
@@ -5659,7 +7682,7 @@ function evaluateNode(istate, node) {
5659
7682
  case "ThisExpression": {
5660
7683
  const self = (() => {
5661
7684
  for (let i = state.stack.length; i--;) {
5662
- const si = state.stack[i];
7685
+ const si = state.stack[i].sn;
5663
7686
  if (si.type === "ClassDeclaration") {
5664
7687
  const klass = { type: 16384 /* TypeTag.Class */, value: si };
5665
7688
  if ((istate.func?.attributes || 0) & StateNodeAttributes.STATIC) {
@@ -5869,7 +7892,7 @@ function evaluateNode(istate, node) {
5869
7892
  if (node.init) {
5870
7893
  const init = popIstate(istate, node.init);
5871
7894
  if (node.id.type === "BinaryExpression" && istate.typeChecker) {
5872
- const top = istate.state.stack[istate.state.stack.length - 1];
7895
+ const top = istate.state.top().sn;
5873
7896
  if (top.type !== "BlockStatement") {
5874
7897
  const declType = typeFromTypespec(istate.state, node.id.right);
5875
7898
  if (!istate.typeChecker(init.value, declType)) {
@@ -6458,58 +8481,692 @@ function restrictExactTypesByEquality(a, b) {
6458
8481
  default:
6459
8482
  unhandledType(a);
6460
8483
  }
6461
- return { type: 0 /* TypeTag.Never */ };
8484
+ return { type: 0 /* TypeTag.Never */ };
8485
+ }
8486
+ function restrictByEqualityByComponent(a, b) {
8487
+ let bits = a.type;
8488
+ if (a.value == null && (b.type & bits) === b.type) {
8489
+ // shortcut:
8490
+ // if b.type is contained in a.type, and a has no
8491
+ // specialization, the result is just b.
8492
+ return b;
8493
+ }
8494
+ let br = null;
8495
+ do {
8496
+ const next = bits & (bits - 1);
8497
+ const bit = bits - next;
8498
+ const brt = restrictExactTypesByEquality({
8499
+ type: bit,
8500
+ value: getUnionComponent(a, bit) || undefined,
8501
+ }, b);
8502
+ if (brt.type !== 0 /* TypeTag.Never */) {
8503
+ if (!br) {
8504
+ br = cloneType(brt);
8505
+ }
8506
+ else {
8507
+ unionInto(br, brt);
8508
+ }
8509
+ }
8510
+ bits = next;
8511
+ } while (bits);
8512
+ if (!br) {
8513
+ return { type: 0 /* TypeTag.Never */ };
8514
+ }
8515
+ return br;
8516
+ }
8517
+ /*
8518
+ * Given that a == b, reutnr what we can deduce about b's
8519
+ * type.
8520
+ *
8521
+ * Note that this is similar to intersection. In many cases, it
8522
+ * is intersection. eg if a is the type (Null or "Hello" or Menu)
8523
+ * then we know b's type must be a subtype of intersection(a, b).
8524
+ *
8525
+ * But eg if it was a == 5, and a is known to be Char, String,
8526
+ * Number or Float, we can only eliminate String, because
8527
+ * 5.0 == 5, and 5.toChar() == 5.
8528
+ */
8529
+ function restrictByEquality(a, b) {
8530
+ if (a.type === 0 /* TypeTag.Never */)
8531
+ return a;
8532
+ if (isExact(a)) {
8533
+ return restrictExactTypesByEquality(a, b);
8534
+ }
8535
+ return restrictByEqualityByComponent(a, b);
8536
+ }
8537
+
8538
+
8539
+ /***/ }),
8540
+
8541
+ /***/ 3687:
8542
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
8543
+
8544
+ "use strict";
8545
+ /* unused harmony exports optimizeFunction, beforeEvaluate, afterEvaluate, tryDeEnumerate */
8546
+ /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(333);
8547
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
8548
+ /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4859);
8549
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6906);
8550
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_3__);
8551
+ /* harmony import */ var _interp__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7161);
8552
+ /* harmony import */ var _interp_binary__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4706);
8553
+ /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7255);
8554
+
8555
+
8556
+
8557
+
8558
+
8559
+
8560
+
8561
+ function optimizeFunction(state, func) {
8562
+ const istate = buildTypeInfo(state, func, true);
8563
+ if (!istate)
8564
+ return;
8565
+ evaluate({
8566
+ ...istate,
8567
+ pre(node) {
8568
+ return beforeEvaluate(this, node);
8569
+ },
8570
+ post(node) {
8571
+ return afterEvaluate(this, node);
8572
+ },
8573
+ }, func.node.body);
8574
+ }
8575
+ function beforeEvaluate(istate, node) {
8576
+ switch (node.type) {
8577
+ case "ConditionalExpression": {
8578
+ let alternate = tryPop(istate, node.alternate);
8579
+ let consequent = tryPop(istate, node.consequent);
8580
+ const test = popIstate(istate, node.test);
8581
+ const result = mustBeTrue(test.value)
8582
+ ? true
8583
+ : mustBeFalse(test.value)
8584
+ ? false
8585
+ : null;
8586
+ if (result !== null) {
8587
+ if (!test.embeddedEffects) {
8588
+ const arg = result ? consequent : alternate;
8589
+ istate.stack.push(arg);
8590
+ return result ? node.consequent : node.alternate;
8591
+ }
8592
+ }
8593
+ if (node.alternate &&
8594
+ node.test.type === "UnaryExpression" &&
8595
+ node.test.operator === "!" &&
8596
+ test.value.type === 6 /* TypeTag.Boolean */) {
8597
+ const alternateNode = node.alternate;
8598
+ node.alternate = node.consequent;
8599
+ node.consequent = alternateNode;
8600
+ const tmp = alternate;
8601
+ alternate = consequent;
8602
+ consequent = tmp;
8603
+ test.node = node.test = node.test.argument;
8604
+ }
8605
+ if (test.value.type === 6 /* TypeTag.Boolean */ &&
8606
+ ((consequent.value.type === 4 /* TypeTag.True */ &&
8607
+ alternate.value.type === 2 /* TypeTag.False */) ||
8608
+ (consequent.value.type === 2 /* TypeTag.False */ &&
8609
+ alternate.value.type === 4 /* TypeTag.True */)) &&
8610
+ !consequent.embeddedEffects &&
8611
+ !alternate.embeddedEffects) {
8612
+ if (consequent.value.type === 2 /* TypeTag.False */) {
8613
+ test.node = wrap({
8614
+ type: "UnaryExpression",
8615
+ operator: "!",
8616
+ argument: node.test,
8617
+ prefix: true,
8618
+ }, test.node.loc);
8619
+ }
8620
+ istate.stack.push(test);
8621
+ return test.node;
8622
+ }
8623
+ istate.stack.push(test, consequent, alternate);
8624
+ break;
8625
+ }
8626
+ case "IfStatement": {
8627
+ if (node.alternate &&
8628
+ node.alternate.type === "BlockStatement" &&
8629
+ !node.alternate.body.length) {
8630
+ delete node.alternate;
8631
+ }
8632
+ const test = popIstate(istate, node.test);
8633
+ if (!node.alternate &&
8634
+ node.consequent.type === "BlockStatement" &&
8635
+ !node.consequent.body.length) {
8636
+ const ret = withLoc(node.consequent, node.test, node.test);
8637
+ const u = test.embeddedEffects && unused(istate.state, node.test);
8638
+ if (u) {
8639
+ node.consequent.body = u;
8640
+ }
8641
+ return ret;
8642
+ }
8643
+ const result = mustBeTrue(test.value)
8644
+ ? true
8645
+ : mustBeFalse(test.value)
8646
+ ? false
8647
+ : null;
8648
+ if (result !== null) {
8649
+ const rep = result ? node.consequent : node.alternate || false;
8650
+ if (!test.embeddedEffects) {
8651
+ return rep;
8652
+ }
8653
+ const estmt = wrap({ type: "ExpressionStatement", expression: node.test }, node.loc);
8654
+ if (!rep) {
8655
+ return estmt;
8656
+ }
8657
+ if (rep.type === "BlockStatement") {
8658
+ rep.body.unshift(estmt);
8659
+ return rep;
8660
+ }
8661
+ }
8662
+ if (node.alternate &&
8663
+ node.test.type === "UnaryExpression" &&
8664
+ node.test.operator === "!" &&
8665
+ test.value.type === 6 /* TypeTag.Boolean */) {
8666
+ const alternate = node.alternate;
8667
+ node.alternate = node.consequent;
8668
+ node.consequent = alternate;
8669
+ test.node = node.test = node.test.argument;
8670
+ }
8671
+ istate.stack.push(test);
8672
+ break;
8673
+ }
8674
+ case "WhileStatement":
8675
+ case "DoWhileStatement": {
8676
+ const test = popIstate(istate, node.test);
8677
+ if (!test.embeddedEffects) {
8678
+ if (mustBeFalse(test.value)) {
8679
+ return node.type === "WhileStatement" ? false : node.body;
8680
+ }
8681
+ }
8682
+ istate.stack.push(test);
8683
+ break;
8684
+ }
8685
+ case "BinaryExpression":
8686
+ if (node.operator === "has" &&
8687
+ node.right.type === "UnaryExpression" &&
8688
+ node.right.operator === ":") {
8689
+ const [left, right] = istate.stack.slice(-2);
8690
+ if (left.embeddedEffects ||
8691
+ right.embeddedEffects ||
8692
+ !hasValue(left.value) ||
8693
+ !hasValue(right.value) ||
8694
+ !(left.value.type & (4096 /* TypeTag.Module */ | 16384 /* TypeTag.Class */))) {
8695
+ break;
8696
+ }
8697
+ const id = node.right.argument;
8698
+ if (every(left.value.value, (m) => {
8699
+ if (hasProperty(m.decls, id.name))
8700
+ return false;
8701
+ // This is overkill, since we've already looked up
8702
+ // node.left, but the actual lookup rules are complicated,
8703
+ // and embedded within state.lookup; so just defer to that.
8704
+ return (istate.state.lookup({
8705
+ type: "MemberExpression",
8706
+ object: node.left,
8707
+ property: id,
8708
+ computed: false,
8709
+ })[1] == null);
8710
+ })) {
8711
+ popIstate(istate, node.right);
8712
+ popIstate(istate, node.left);
8713
+ const rep = wrap({ type: "Literal", value: false, raw: "false" }, node.loc);
8714
+ istate.stack.push({
8715
+ value: { type: 2 /* TypeTag.False */ },
8716
+ embeddedEffects: false,
8717
+ node: rep,
8718
+ });
8719
+ return rep;
8720
+ }
8721
+ }
8722
+ else {
8723
+ if (node.operator !== "as") {
8724
+ const left = tryDeEnumerate(istate, node.left, -2);
8725
+ if (left)
8726
+ node.left = left;
8727
+ const right = tryDeEnumerate(istate, node.right, -1);
8728
+ if (right)
8729
+ node.right = right;
8730
+ }
8731
+ const rep = tryCommuteAndAssociate(istate, node);
8732
+ if (rep)
8733
+ return rep;
8734
+ }
8735
+ break;
8736
+ case "LogicalExpression": {
8737
+ const right = tryPop(istate, node.right);
8738
+ const left = popIstate(istate, node.left);
8739
+ const isAnd = node.operator === "&&" || node.operator === "and";
8740
+ if (isAnd ? mustBeFalse(left.value) : mustBeTrue(left.value)) {
8741
+ istate.stack.push(left);
8742
+ return node.left;
8743
+ }
8744
+ if (
8745
+ // bail if left could be anything other than bool/integer
8746
+ (left.value.type &
8747
+ (6 /* TypeTag.Boolean */ | 8 /* TypeTag.Number */ | 16 /* TypeTag.Long */)) !==
8748
+ left.value.type ||
8749
+ // bail if left could be boolean AND it could be integer
8750
+ (left.value.type & 6 /* TypeTag.Boolean */ &&
8751
+ left.value.type & (8 /* TypeTag.Number */ | 16 /* TypeTag.Long */)) ||
8752
+ // bail if right doesn't match left
8753
+ (right.value.type &
8754
+ (left.value.type & 6 /* TypeTag.Boolean */
8755
+ ? 6 /* TypeTag.Boolean */
8756
+ : 8 /* TypeTag.Number */ | 16 /* TypeTag.Long */)) !==
8757
+ right.value.type) {
8758
+ istate.stack.push(left);
8759
+ istate.stack.push(right);
8760
+ break;
8761
+ }
8762
+ if (right.value.type === (isAnd ? 4 /* TypeTag.True */ : 2 /* TypeTag.False */) &&
8763
+ !right.embeddedEffects &&
8764
+ (left.value.type & 6 /* TypeTag.Boolean */) === left.value.type) {
8765
+ istate.stack.push(left);
8766
+ return node.left;
8767
+ }
8768
+ if (right.value.type === (isAnd ? 2 /* TypeTag.False */ : 4 /* TypeTag.True */) &&
8769
+ !left.embeddedEffects &&
8770
+ (left.value.type & 6 /* TypeTag.Boolean */) === left.value.type) {
8771
+ istate.stack.push(right);
8772
+ return node.right;
8773
+ }
8774
+ istate.stack.push(left);
8775
+ istate.stack.push(right);
8776
+ if (isAnd ? !mustBeTrue(left.value) : !mustBeFalse(left.value)) {
8777
+ break;
8778
+ }
8779
+ if (!(left.value.type & ~6 /* TypeTag.Boolean */)) {
8780
+ // the left type is boolean, so the
8781
+ // `&` or `|` would be a no-op. We
8782
+ // need to check that its side-effect
8783
+ // free. Just cheap checks for now.
8784
+ if (!left.embeddedEffects) {
8785
+ istate.stack.splice(-2, 2, right);
8786
+ return node.right;
8787
+ }
8788
+ }
8789
+ const rep = node;
8790
+ rep.type = "BinaryExpression";
8791
+ rep.operator = isAnd ? "&" : "|";
8792
+ break;
8793
+ }
8794
+ case "ForStatement": {
8795
+ if (node.update?.type === "Literal" ||
8796
+ (node.update?.type === "SequenceExpression" &&
8797
+ node.update.expressions.length === 0)) {
8798
+ popIstate(istate, node.update);
8799
+ delete node.update;
8800
+ }
8801
+ if (node.init?.type === "Literal" ||
8802
+ (node.init?.type === "SequenceExpression" &&
8803
+ node.init.expressions.length === 0)) {
8804
+ delete node.init;
8805
+ const depth = -1 - (node.update ? 1 : 0) - (node.test ? 1 : 0);
8806
+ istate.stack.splice(depth, 1);
8807
+ }
8808
+ break;
8809
+ }
8810
+ case "BlockStatement": {
8811
+ for (let i = node.body.length; i--;) {
8812
+ const stmt = node.body[i];
8813
+ if (stmt.type === "VariableDeclaration" && !stmt.declarations.length) {
8814
+ node.body.splice(i, 1);
8815
+ }
8816
+ else if (stmt.type === "BlockStatement" &&
8817
+ stmt.body.every((s) => s.type !== "VariableDeclaration")) {
8818
+ node.body.splice(i, 1, ...stmt.body);
8819
+ }
8820
+ }
8821
+ break;
8822
+ }
8823
+ case "SequenceExpression": {
8824
+ for (let i = node.expressions.length; i--;) {
8825
+ const expr = node.expressions[i];
8826
+ if (expr.type === "Literal") {
8827
+ istate.stack.splice(i - node.expressions.length, 1);
8828
+ node.expressions.splice(i, 1);
8829
+ }
8830
+ }
8831
+ break;
8832
+ }
8833
+ case "AssignmentExpression": {
8834
+ if (node.operator === "=") {
8835
+ let selfAssign = false;
8836
+ if (node.left.type === "Identifier" &&
8837
+ node.right.type === "Identifier" &&
8838
+ node.left.name === node.right.name) {
8839
+ selfAssign = true;
8840
+ }
8841
+ else {
8842
+ const [left, right] = istate.stack.slice(-2);
8843
+ if (!left.embeddedEffects &&
8844
+ !right.embeddedEffects &&
8845
+ mustBeIdentical(left.value, right.value)) {
8846
+ selfAssign = true;
8847
+ }
8848
+ }
8849
+ if (selfAssign) {
8850
+ popIstate(istate, node.right);
8851
+ popIstate(istate, node.left);
8852
+ const rep = withLoc({ type: "Literal", value: null, raw: "null" }, node, node);
8853
+ istate.stack.push({
8854
+ value: { type: 1 /* TypeTag.Null */ },
8855
+ embeddedEffects: false,
8856
+ node: rep,
8857
+ });
8858
+ return rep;
8859
+ }
8860
+ }
8861
+ break;
8862
+ }
8863
+ }
8864
+ return null;
8865
+ }
8866
+ function afterEvaluate(istate, node) {
8867
+ if (isExpression(node) && node.type !== "Literal") {
8868
+ const top = istate.stack[istate.stack.length - 1];
8869
+ if (!top.embeddedEffects && hasValue(top.value)) {
8870
+ const rep = mcExprFromType(top.value);
8871
+ if (rep) {
8872
+ top.node = rep;
8873
+ return withLoc(rep, node, node);
8874
+ }
8875
+ }
8876
+ }
8877
+ return null;
8878
+ }
8879
+ function identity(istate, node, left, right, allowedTypes, target) {
8880
+ if (hasValue(right.value) &&
8881
+ right.value.type & allowedTypes &&
8882
+ !(left.value.type & ~allowedTypes) &&
8883
+ Number(right.value.value) === target) {
8884
+ // a +/- 0 => a
8885
+ // but we still need to check that the type of the zero
8886
+ // doesn't change the type of the result.
8887
+ if (right.value.type === 8 /* TypeTag.Number */ ||
8888
+ (right.value.type === 16 /* TypeTag.Long */ &&
8889
+ !(left.value.type & ~(16 /* TypeTag.Long */ | 64 /* TypeTag.Double */))) ||
8890
+ (right.value.type === 32 /* TypeTag.Float */ &&
8891
+ !(left.value.type & ~(32 /* TypeTag.Float */ | 64 /* TypeTag.Double */))) ||
8892
+ (right.value.type === 64 /* TypeTag.Double */ &&
8893
+ left.value.type === 64 /* TypeTag.Double */)) {
8894
+ istate.stack.pop();
8895
+ return node.left;
8896
+ }
8897
+ }
8898
+ return null;
8899
+ }
8900
+ function zero(istate, node, left, right, allowedTypes, target) {
8901
+ if (hasValue(right.value) &&
8902
+ right.value.type & allowedTypes &&
8903
+ !(left.value.type & ~allowedTypes) &&
8904
+ Number(right.value.value) === target) {
8905
+ // a * 0 => 0
8906
+ // but we still need to check that the type of a
8907
+ // doesn't change the type of the zero.
8908
+ if ((right.value.type === 8 /* TypeTag.Number */ &&
8909
+ left.value.type === 8 /* TypeTag.Number */) ||
8910
+ (right.value.type === 16 /* TypeTag.Long */ &&
8911
+ !(left.value.type & ~(16 /* TypeTag.Long */ | 8 /* TypeTag.Number */))) ||
8912
+ (right.value.type === 32 /* TypeTag.Float */ &&
8913
+ !(left.value.type & ~(32 /* TypeTag.Float */ | 8 /* TypeTag.Number */))) ||
8914
+ right.value.type === 64 /* TypeTag.Double */) {
8915
+ istate.stack.splice(-2, 1);
8916
+ return node.right;
8917
+ }
8918
+ }
8919
+ return null;
8920
+ }
8921
+ function tryIdentity(istate, node, left, right) {
8922
+ switch (node.operator) {
8923
+ case "+":
8924
+ case "-": {
8925
+ const rep = identity(istate, node, left, right, 120 /* TypeTag.Numeric */, 0);
8926
+ if (rep)
8927
+ return rep;
8928
+ if (node.right.type === "UnaryExpression" &&
8929
+ node.right.operator === "-") {
8930
+ // We can convert a +/- -b to a -/+ b, but we have to know
8931
+ // something about the types. eg if b is Number, with the
8932
+ // value -2^31, negating b will leave the value as -2^31.
8933
+ // This doesn't matter if the a is also Number, but if
8934
+ // a might be Long, Float or Double, we would change the
8935
+ // result. Similarly for Long and -2^63
8936
+ if (!((left.value.type | right.value.type) & ~120 /* TypeTag.Numeric */) &&
8937
+ (right.value.type & 8 /* TypeTag.Number */ // Negating -2^31 goes wrong if left is a wider type
8938
+ ? !(left.value.type &
8939
+ (16 /* TypeTag.Long */ | 32 /* TypeTag.Float */ | 64 /* TypeTag.Double */))
8940
+ : right.value.type & 16 /* TypeTag.Long */ // Negating -2^63 goes wrong if left is a float/double
8941
+ ? !(left.value.type & (32 /* TypeTag.Float */ | 64 /* TypeTag.Double */))
8942
+ : true)) {
8943
+ right.value = evaluateBinaryTypes("-", { type: 8 /* TypeTag.Number */, value: 0 }, right.value);
8944
+ right.node = node.right.argument;
8945
+ node.right = right.node;
8946
+ node.operator = node.operator === "+" ? "-" : "+";
8947
+ }
8948
+ }
8949
+ break;
8950
+ }
8951
+ case "*": {
8952
+ const rep = zero(istate, node, left, right, 120 /* TypeTag.Numeric */, 0);
8953
+ if (rep)
8954
+ return rep;
8955
+ // fall through
8956
+ }
8957
+ case "/": {
8958
+ const rep = identity(istate, node, left, right, 120 /* TypeTag.Numeric */, 1);
8959
+ if (rep)
8960
+ return rep;
8961
+ break;
8962
+ }
8963
+ case "|": {
8964
+ const rep = zero(istate, node, left, right, 8 /* TypeTag.Number */ | 16 /* TypeTag.Long */, -1);
8965
+ if (rep)
8966
+ return rep;
8967
+ // fall through
8968
+ }
8969
+ case "^": {
8970
+ const rep = identity(istate, node, left, right, 8 /* TypeTag.Number */ | 16 /* TypeTag.Long */, 0);
8971
+ if (rep)
8972
+ return rep;
8973
+ break;
8974
+ }
8975
+ case "&": {
8976
+ const rep = zero(istate, node, left, right, 8 /* TypeTag.Number */ | 16 /* TypeTag.Long */, 0) ||
8977
+ identity(istate, node, left, right, 8 /* TypeTag.Number */ | 16 /* TypeTag.Long */, -1);
8978
+ if (rep)
8979
+ return rep;
8980
+ break;
8981
+ }
8982
+ }
8983
+ return null;
6462
8984
  }
6463
- function restrictByEqualityByComponent(a, b) {
6464
- let bits = a.type;
6465
- if (a.value == null && (b.type & bits) === b.type) {
6466
- // shortcut:
6467
- // if b.type is contained in a.type, and a has no
6468
- // specialization, the result is just b.
6469
- return b;
8985
+ function tryCommuteAndAssociate(istate, node) {
8986
+ let [left, right] = istate.stack.slice(-2);
8987
+ // no need to do anything if both sides are constants
8988
+ if (!right || (hasValue(left.value) && hasValue(right.value))) {
8989
+ return null;
6470
8990
  }
6471
- let br = null;
6472
- do {
6473
- const next = bits & (bits - 1);
6474
- const bit = bits - next;
6475
- const brt = restrictExactTypesByEquality({
6476
- type: bit,
6477
- value: getUnionComponent(a, bit) || undefined,
6478
- }, b);
6479
- if (brt.type !== 0 /* TypeTag.Never */) {
6480
- if (!br) {
6481
- br = cloneType(brt);
8991
+ switch (node.operator) {
8992
+ case "+":
8993
+ // Addition is only commutative/associative if both arguments
8994
+ // are numeric, or one argument is Number, and the other is Char
8995
+ if (left.value.type & ~(120 /* TypeTag.Numeric */ | 128 /* TypeTag.Char */) ||
8996
+ right.value.type & ~(120 /* TypeTag.Numeric */ | 128 /* TypeTag.Char */) ||
8997
+ left.value.type & right.value.type & 128 /* TypeTag.Char */) {
8998
+ break;
6482
8999
  }
6483
- else {
6484
- unionInto(br, brt);
9000
+ // fallthrough
9001
+ case "*":
9002
+ case "&":
9003
+ case "|":
9004
+ case "^":
9005
+ // flip the left argument to the right if the left has
9006
+ // a known value, but the right does not, or if the
9007
+ // top operator is additive, and the left operand is
9008
+ // negated, and the right operand is not.
9009
+ if (!left.embeddedEffects &&
9010
+ (hasValue(left.value) ||
9011
+ (!right.embeddedEffects &&
9012
+ node.operator === "+" &&
9013
+ node.left.type === "UnaryExpression" &&
9014
+ node.left.operator === "-" &&
9015
+ (node.right.type !== "UnaryExpression" ||
9016
+ node.right.operator !== "-")))) {
9017
+ const l = node.left;
9018
+ node.left = node.right;
9019
+ node.right = l;
9020
+ istate.stack.splice(-2, 2, right, left);
9021
+ const r = right;
9022
+ right = left;
9023
+ left = r;
9024
+ }
9025
+ // fallthrough
9026
+ case "-":
9027
+ if (tryReAssociate(istate, node, left, right)) {
9028
+ [left, right] = istate.stack.slice(-2);
6485
9029
  }
6486
- }
6487
- bits = next;
6488
- } while (bits);
6489
- if (!br) {
6490
- return { type: 0 /* TypeTag.Never */ };
6491
9030
  }
6492
- return br;
9031
+ return tryIdentity(istate, node, left, right);
6493
9032
  }
6494
9033
  /*
6495
- * Given that a == b, reutnr what we can deduce about b's
6496
- * type.
9034
+ * Try to reorder (a op K1) op K2 => a op (K1 op K2),
9035
+ * and fold K1 op K2.
6497
9036
  *
6498
- * Note that this is similar to intersection. In many cases, it
6499
- * is intersection. eg if a is the type (Null or "Hello" or Menu)
6500
- * then we know b's type must be a subtype of intersection(a, b).
9037
+ * Failing that,
9038
+ * Try to reorder (a op K1) op (b op K2) as
9039
+ * (a op b) op (K1 op K2), and fold K1 op K2.
6501
9040
  *
6502
- * But eg if it was a == 5, and a is known to be Char, String,
6503
- * Number or Float, we can only eliminate String, because
6504
- * 5.0 == 5, and 5.toChar() == 5.
9041
+ * Failing that,
9042
+ * Try to reorder (a op K) op b => (a op b) op K
9043
+ * so that constants float up and to the right.
9044
+ * This helps because now ((a op K1) op b) op K2
9045
+ * becomes ((a op b) op K1) op K2, and we can
9046
+ * fold K1 op K2 by the first transformation.
9047
+ *
9048
+ * Floating point arithmetic isn't really associative
9049
+ * though, so we mostly suppress this when Floats
9050
+ * and Doubles may be involved; except that
9051
+ * (a + K1) + K2 can be safely converted to
9052
+ * a + (K1 + K2) if K1 and K2 have the same sign.
6505
9053
  */
6506
- function restrictByEquality(a, b) {
6507
- if (a.type === 0 /* TypeTag.Never */)
6508
- return a;
6509
- if (isExact(a)) {
6510
- return restrictExactTypesByEquality(a, b);
9054
+ function tryReAssociate(istate, node, left, right) {
9055
+ if (node.left.type !== "BinaryExpression" ||
9056
+ (node.left.operator !== node.operator &&
9057
+ !(node.operator === "+" && node.left.operator === "-") &&
9058
+ !(node.operator === "-" && node.left.operator === "+"))) {
9059
+ return false;
6511
9060
  }
6512
- return restrictByEqualityByComponent(a, b);
9061
+ const lr = getLiteralNode(node.left.right);
9062
+ if (!lr)
9063
+ return false;
9064
+ const leftRight = evaluate(istate, lr);
9065
+ if (!hasValue(leftRight.value))
9066
+ return false;
9067
+ if (hasValue(right.value)) {
9068
+ // (ll + lr) + r => ll + (r + lr)
9069
+ // (ll - lr) - r => ll - (r + lr)
9070
+ // (ll + lr) - r => ll + (r - lr)
9071
+ // (ll - lr) + r => ll - (r - lr)
9072
+ const tmpNode = {
9073
+ type: "BinaryExpression",
9074
+ operator: node.operator === "+" || node.operator === "-"
9075
+ ? node.operator === node.left.operator
9076
+ ? "+"
9077
+ : "-"
9078
+ : node.operator,
9079
+ left: node.right,
9080
+ right: node.left.right,
9081
+ };
9082
+ if (tmpNode.operator === "+" || tmpNode.operator === "-") {
9083
+ if (leftRight.value.type & (32 /* TypeTag.Float */ | 64 /* TypeTag.Double */) ||
9084
+ right.value.type & (32 /* TypeTag.Float */ | 64 /* TypeTag.Double */)) {
9085
+ // we don't want to fold "a + 1.0 - 1.0" because
9086
+ // it could be there for rounding purposes
9087
+ const lsign = right.value.value < 0;
9088
+ const rsign = leftRight.value.value < 0 === (tmpNode.operator === "+");
9089
+ if (lsign !== rsign)
9090
+ return false;
9091
+ }
9092
+ }
9093
+ const repType = evaluate(istate, tmpNode);
9094
+ if (!hasValue(repType.value))
9095
+ return false;
9096
+ const repNode = mcExprFromType(repType.value);
9097
+ if (!repNode)
9098
+ return false;
9099
+ left.node = node.left = node.left.left;
9100
+ node.right = repNode;
9101
+ istate.stack.splice(-1, 1, repType);
9102
+ repType.node = repNode;
9103
+ return true;
9104
+ }
9105
+ if (leftRight.value.type !== left.value.type ||
9106
+ leftRight.value.type !== right.value.type ||
9107
+ leftRight.value.type & (32 /* TypeTag.Float */ | 64 /* TypeTag.Double */)) {
9108
+ return false;
9109
+ }
9110
+ if (node.right.type === "BinaryExpression" &&
9111
+ (node.right.operator === node.operator ||
9112
+ ((node.operator === "+" || node.operator === "-") &&
9113
+ (node.right.operator === "+" || node.right.operator === "-")))) {
9114
+ // (a + K1) + (b + K2) => (a + b) + (K1 + K2)
9115
+ const rr = getLiteralNode(node.right.right);
9116
+ if (!rr)
9117
+ return false;
9118
+ const rightRight = evaluate(istate, rr);
9119
+ if (!hasValue(rightRight.value))
9120
+ return false;
9121
+ const rightOp = node.operator === "+" || node.operator === "-"
9122
+ ? ((node.left.operator === "+") === (node.right.operator === "+")) ===
9123
+ (node.operator === "+")
9124
+ ? "+"
9125
+ : "-"
9126
+ : node.operator;
9127
+ const topOp = node.left.operator;
9128
+ const leftOp = node.operator;
9129
+ const rightType = evaluateBinaryTypes(rightOp, leftRight.value, rightRight.value);
9130
+ if (!hasValue(rightType))
9131
+ return false;
9132
+ const repNode = mcExprFromType(rightType);
9133
+ if (!repNode)
9134
+ return false;
9135
+ node.left.right = node.right.left;
9136
+ node.right = repNode;
9137
+ node.left.operator = leftOp;
9138
+ node.operator = topOp;
9139
+ istate.stack.splice(-1, 1, {
9140
+ value: rightType,
9141
+ node: repNode,
9142
+ embeddedEffects: false,
9143
+ });
9144
+ return true;
9145
+ }
9146
+ const op = node.operator;
9147
+ node.operator = node.left.operator;
9148
+ node.left.operator = op;
9149
+ leftRight.node = node.left.right;
9150
+ node.left.right = node.right;
9151
+ node.right = leftRight.node;
9152
+ istate.stack.splice(-1, 1, leftRight);
9153
+ return true;
9154
+ }
9155
+ function tryDeEnumerate(istate, node, elem) {
9156
+ if (node.type === "BinaryExpression" &&
9157
+ node.operator === "as" &&
9158
+ node.right.ts.length === 1 &&
9159
+ typeof node.right.ts[0] === "string") {
9160
+ elem += istate.stack.length;
9161
+ const item = istate.stack[elem];
9162
+ istate.stack[elem] = {
9163
+ value: deEnumerate(item.value),
9164
+ embeddedEffects: item.embeddedEffects,
9165
+ node: node.left,
9166
+ };
9167
+ return node.left;
9168
+ }
9169
+ return null;
6513
9170
  }
6514
9171
 
6515
9172
 
@@ -6755,7 +9412,7 @@ function printBlockTrailer(block) {
6755
9412
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
6756
9413
  /* harmony export */ "iX": () => (/* binding */ getStateNodeDeclsFromType)
6757
9414
  /* harmony export */ });
6758
- /* unused harmony exports typeTagName, LastTypeTag, SingleTonTypeTagsConst, UnionDataTypeTagsConst, ValueTypeTagsConst, ObjectLikeTagsConst, EnumTagsConst, isExact, isUnion, isSingleton, hasValue, hasNoData, lookupByFullName, cloneType, typeFromTypeStateNode, typeFromTypeStateNodes, typeFromSingleTypeSpec, typeFromTypespec, typeFromLiteral, mcExprFromType, castType, TruthyTypes, mustBeTrue, mustBeFalse, display, hasUnionData, getObjectValue, forEachUnionComponent, getUnionComponent, setUnionComponent */
9415
+ /* unused harmony exports typeTagName, LastTypeTag, SingletonTypeTagsConst, UnionDataTypeTagsConst, ValueTypeTagsConst, ObjectLikeTagsConst, EnumTagsConst, isExact, isUnion, isSingleton, hasValue, hasNoData, cloneType, typeFromTypeStateNode, typeFromTypeStateNodes, typeFromSingleTypeSpec, typeFromTypespec, typeFromLiteral, mcExprFromType, castType, TruthyTypes, mustBeTrue, mustBeFalse, display, hasUnionData, getObjectValue, forEachUnionComponent, getUnionComponent, setUnionComponent */
6759
9416
  /* harmony import */ var _markw65_prettier_plugin_monkeyc__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9642);
6760
9417
  /* harmony import */ var _markw65_prettier_plugin_monkeyc__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_markw65_prettier_plugin_monkeyc__WEBPACK_IMPORTED_MODULE_0__);
6761
9418
  /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8180);
@@ -6830,7 +9487,7 @@ function typeTagName(tag) {
6830
9487
  }
6831
9488
  }
6832
9489
  const LastTypeTag = 262144 /* TypeTag.Typedef */;
6833
- const SingleTonTypeTagsConst = 1 /* TypeTag.Null */ | 2 /* TypeTag.False */ | 4 /* TypeTag.True */;
9490
+ const SingletonTypeTagsConst = 1 /* TypeTag.Null */ | 2 /* TypeTag.False */ | 4 /* TypeTag.True */;
6834
9491
  const UnionDataTypeTagsConst = 512 /* TypeTag.Array */ |
6835
9492
  1024 /* TypeTag.Dictionary */ |
6836
9493
  2048 /* TypeTag.Method */ |
@@ -6853,7 +9510,7 @@ const ObjectLikeTagsConst = 6 /* TypeTag.Boolean */ |
6853
9510
  1024 /* TypeTag.Dictionary */ |
6854
9511
  2048 /* TypeTag.Method */ |
6855
9512
  65536 /* TypeTag.Enum */;
6856
- const EnumTagsConst = SingleTonTypeTagsConst | (ValueTypeTagsConst & ~131072 /* TypeTag.Symbol */);
9513
+ const EnumTagsConst = SingletonTypeTagsConst | (ValueTypeTagsConst & ~131072 /* TypeTag.Symbol */);
6857
9514
  function isExact(v) {
6858
9515
  // check that there is exactly one bit set
6859
9516
  return v.type !== 0 && !(v.type & (v.type - 1));
@@ -6862,27 +9519,18 @@ function isUnion(v) {
6862
9519
  return v.type !== 0 && !isExact(v);
6863
9520
  }
6864
9521
  function isSingleton(v) {
6865
- return isExact(v) && (v.type & SingleTonTypeTagsConst) !== 0;
9522
+ return isExact(v) && (v.type & SingletonTypeTagsConst) !== 0;
6866
9523
  }
6867
9524
  function hasValue(v) {
6868
9525
  return (isExact(v) &&
6869
- ((v.type & SingleTonTypeTagsConst) !== 0 || v.value !== undefined));
9526
+ ((v.type & SingletonTypeTagsConst) !== 0 || v.value !== undefined));
6870
9527
  }
6871
9528
  function hasNoData(v, t) {
6872
9529
  if (v.value == null)
6873
9530
  return true;
6874
9531
  return ((hasUnionData(v.type)
6875
9532
  ? v.value.mask & t
6876
- : v.type & t & ~SingleTonTypeTagsConst) === 0);
6877
- }
6878
- function lookupByFullName(state, fullName) {
6879
- return fullName.split(".").reduce((results, part) => {
6880
- return results
6881
- .flatMap((result) => (0,_api__WEBPACK_IMPORTED_MODULE_2__.isStateNode)(result)
6882
- ? result.decls?.[part] || result.type_decls?.[part]
6883
- : null)
6884
- .filter((sn) => !!sn);
6885
- }, [state.stack[0]]);
9533
+ : v.type & t & ~SingletonTypeTagsConst) === 0);
6886
9534
  }
6887
9535
  function cloneType(t) {
6888
9536
  return { ...t };
@@ -7451,7 +10099,7 @@ function getObjectValue(t) {
7451
10099
  }
7452
10100
  function forEachUnionComponent(v, bits, fn) {
7453
10101
  // never iterate the singleton bits, because they don't have data
7454
- bits &= ~SingleTonTypeTagsConst;
10102
+ bits &= ~SingletonTypeTagsConst;
7455
10103
  if (!bits)
7456
10104
  return;
7457
10105
  if ((v.type | bits) & UnionDataTypeTagsConst) {
@@ -7481,7 +10129,7 @@ function forEachUnionComponent(v, bits, fn) {
7481
10129
  function getUnionComponent(v, tag) {
7482
10130
  if (v.value == null)
7483
10131
  return null;
7484
- let bits = v.type & ~SingleTonTypeTagsConst;
10132
+ let bits = v.type & ~SingletonTypeTagsConst;
7485
10133
  if (!bits)
7486
10134
  return null;
7487
10135
  if (bits & (bits - 1)) {
@@ -7555,7 +10203,7 @@ function getStateNodeDeclsFromType(state, object) {
7555
10203
  next &= ~6 /* TypeTag.Boolean */;
7556
10204
  }
7557
10205
  const name = `Toybox.Lang.${typeTagName(bit)}`;
7558
- const sns = lookupByFullName(state, name);
10206
+ const sns = (0,_api__WEBPACK_IMPORTED_MODULE_2__.lookupByFullName)(state, name);
7559
10207
  sns.forEach((sn) => (0,_api__WEBPACK_IMPORTED_MODULE_2__.isStateNode)(sn) && decls.push(sn));
7560
10208
  bits = next;
7561
10209
  } while (bits);
@@ -7596,7 +10244,7 @@ function unionInto(to, from) {
7596
10244
  return true;
7597
10245
  }
7598
10246
  const newTags = to.type | from.type;
7599
- if (!(from.type & ~SingleTonTypeTagsConst)) {
10247
+ if (!(from.type & ~SingletonTypeTagsConst)) {
7600
10248
  // - Adding singletons never affects the data.
7601
10249
  if (newTags === to.type)
7602
10250
  return false;
@@ -7858,7 +10506,7 @@ function clearValuesUnder(v, tag, clearTag = false) {
7858
10506
  const newTag = clearTag ? v.type & ~tag : v.type | tag;
7859
10507
  // If the incoming type consists of singletons,
7860
10508
  // we can always merge it without affecting our data.
7861
- tag &= ~SingleTonTypeTagsConst;
10509
+ tag &= ~SingletonTypeTagsConst;
7862
10510
  if (!tag || v.value == null) {
7863
10511
  v.type = newTag;
7864
10512
  return;
@@ -7979,6 +10627,193 @@ function widenType(t) {
7979
10627
  }
7980
10628
 
7981
10629
 
10630
+ /***/ }),
10631
+
10632
+ /***/ 424:
10633
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
10634
+
10635
+ "use strict";
10636
+ /* unused harmony export cleanupUnusedVars */
10637
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
10638
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
10639
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
10640
+ /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(333);
10641
+
10642
+
10643
+
10644
+ function cleanupUnusedVars(state, node) {
10645
+ const parent = state.stack.slice(-1).pop().sn;
10646
+ if (parent.node !== node) {
10647
+ return false;
10648
+ }
10649
+ if (parent.type !== "BlockStatement") {
10650
+ throw new Error(`Unexpected parent type '${parent.type}' for local declaration`);
10651
+ }
10652
+ if (!parent.decls)
10653
+ return false;
10654
+ let toRemove = null;
10655
+ Object.values(parent.decls).forEach((decls) => {
10656
+ if (decls.length === 1 &&
10657
+ decls[0].type === "VariableDeclarator" &&
10658
+ !decls[0].used) {
10659
+ if (!toRemove)
10660
+ toRemove = {};
10661
+ toRemove[decls[0].name] = decls[0];
10662
+ }
10663
+ });
10664
+ if (!toRemove)
10665
+ return false;
10666
+ const varDeclarations = new Map();
10667
+ const stack = [];
10668
+ let changes = false;
10669
+ traverseAst(node, (node) => {
10670
+ switch (node.type) {
10671
+ case "SwitchCase":
10672
+ stack.push(node.consequent);
10673
+ break;
10674
+ case "BlockStatement":
10675
+ stack.push(node.body);
10676
+ break;
10677
+ }
10678
+ }, (node) => {
10679
+ switch (node.type) {
10680
+ case "SwitchCase":
10681
+ case "BlockStatement":
10682
+ stack.pop();
10683
+ break;
10684
+ case "VariableDeclaration": {
10685
+ node.declarations.forEach((decl, i) => {
10686
+ const name = variableDeclarationName(decl.id);
10687
+ if (hasProperty(toRemove, name)) {
10688
+ const info = varDeclarations.get(node);
10689
+ if (info) {
10690
+ info.indices.push(i);
10691
+ }
10692
+ else {
10693
+ varDeclarations.set(node, {
10694
+ parent: stack[stack.length - 1],
10695
+ indices: [i],
10696
+ });
10697
+ }
10698
+ }
10699
+ });
10700
+ break;
10701
+ }
10702
+ case "ExpressionStatement":
10703
+ if (node.expression.type === "AssignmentExpression") {
10704
+ if (node.expression.left.type === "Identifier" &&
10705
+ hasProperty(toRemove, node.expression.left.name)) {
10706
+ changes = true;
10707
+ return unused(state, node.expression.right);
10708
+ }
10709
+ }
10710
+ else if (node.expression.type === "UpdateExpression" &&
10711
+ node.expression.argument.type === "Identifier" &&
10712
+ hasProperty(toRemove, node.expression.argument.name)) {
10713
+ return false;
10714
+ }
10715
+ break;
10716
+ case "SequenceExpression": {
10717
+ for (let i = node.expressions.length; i--;) {
10718
+ const expr = node.expressions[i];
10719
+ if (expr.type === "AssignmentExpression") {
10720
+ if (expr.left.type === "Identifier" &&
10721
+ hasProperty(toRemove, expr.left.name)) {
10722
+ const rep = unused(state, expr.right);
10723
+ if (!rep.length) {
10724
+ changes = true;
10725
+ node.expressions.splice(i, 1);
10726
+ }
10727
+ else {
10728
+ // Sequence expressions can only be assignments
10729
+ // or update expressions. Even calls aren't allowed
10730
+ toRemove[expr.left.name] = null;
10731
+ expr.operator = "=";
10732
+ }
10733
+ }
10734
+ }
10735
+ else if (expr.type === "UpdateExpression" &&
10736
+ expr.argument.type === "Identifier" &&
10737
+ hasProperty(toRemove, expr.argument.name)) {
10738
+ changes = true;
10739
+ node.expressions.splice(i, 1);
10740
+ }
10741
+ }
10742
+ break;
10743
+ }
10744
+ }
10745
+ return null;
10746
+ });
10747
+ varDeclarations.forEach((info, decl) => {
10748
+ let index = -1;
10749
+ for (let ii = info.indices.length, j = decl.declarations.length; ii--;) {
10750
+ const i = info.indices[ii];
10751
+ const vdecl = decl.declarations[i];
10752
+ const name = variableDeclarationName(vdecl.id);
10753
+ if (hasProperty(toRemove, name)) {
10754
+ const rep = vdecl.init ? unused(state, vdecl.init) : [];
10755
+ if (rep.length) {
10756
+ if ((state.sdkVersion || 0) < 4001007 &&
10757
+ rep.find((s) => s.type === "ExpressionStatement" &&
10758
+ (s.expression.type === "NewExpression" ||
10759
+ (s.expression.type === "MemberExpression" &&
10760
+ !s.expression.computed &&
10761
+ s.expression.object.type === "NewExpression")))) {
10762
+ // prior to 4.1.7 vanilla new expressions were discarded,
10763
+ // so don't create top level new expressions.
10764
+ continue;
10765
+ }
10766
+ if (parent.node.type === "ForStatement") {
10767
+ // declarations whose inits have side effects
10768
+ // can't be deleted from for statements.
10769
+ continue;
10770
+ }
10771
+ changes = true;
10772
+ if (index < 0) {
10773
+ index = info.parent.findIndex((s) => s === decl);
10774
+ if (index < 0) {
10775
+ throw new Error(`Failed to find variable declaration for ${variableDeclarationName(vdecl.id)}`);
10776
+ }
10777
+ }
10778
+ if (j > i + 1) {
10779
+ const tail = {
10780
+ ...decl,
10781
+ declarations: decl.declarations.slice(i + 1, j),
10782
+ };
10783
+ if (decl.loc && vdecl.loc) {
10784
+ tail.loc = { ...decl.loc, start: vdecl.loc.end };
10785
+ tail.start = vdecl.end;
10786
+ }
10787
+ rep.push(tail);
10788
+ }
10789
+ if (decl.loc && vdecl.loc) {
10790
+ decl.loc = { ...decl.loc, end: vdecl.loc.start };
10791
+ decl.end = vdecl.start;
10792
+ }
10793
+ decl.declarations.splice(i);
10794
+ info.parent.splice(index + 1, 0, ...rep);
10795
+ j = i;
10796
+ continue;
10797
+ }
10798
+ if (toRemove[name]) {
10799
+ changes = true;
10800
+ j--;
10801
+ decl.declarations.splice(i, 1);
10802
+ if (i === j && decl.loc && vdecl.loc) {
10803
+ decl.loc = { ...decl.loc, end: vdecl.loc.start };
10804
+ decl.end = vdecl.start;
10805
+ }
10806
+ }
10807
+ else {
10808
+ delete vdecl.init;
10809
+ }
10810
+ }
10811
+ }
10812
+ });
10813
+ return changes;
10814
+ }
10815
+
10816
+
7982
10817
  /***/ }),
7983
10818
 
7984
10819
  /***/ 4405:
@@ -8028,7 +10863,7 @@ function renameVariable(state, locals, declName) {
8028
10863
  let ok = false;
8029
10864
  let i;
8030
10865
  for (i = state.stack.length; i--;) {
8031
- const elm = state.stack[i];
10866
+ const elm = state.stack[i].sn;
8032
10867
  if (ok) {
8033
10868
  if (hasProperty(elm.decls, name)) {
8034
10869
  break;
@@ -8163,10 +10998,13 @@ __webpack_require__.r(__webpack_exports__);
8163
10998
  __webpack_require__.d(__webpack_exports__, {
8164
10999
  "checkCompilerVersion": () => (/* binding */ checkCompilerVersion),
8165
11000
  "collectNamespaces": () => (/* binding */ collectNamespaces),
11001
+ "createDocumentationMap": () => (/* binding */ createDocumentationMap),
8166
11002
  "diagnostic": () => (/* binding */ diagnostic),
8167
11003
  "diagnosticHelper": () => (/* binding */ diagnosticHelper),
11004
+ "findNamesInScope": () => (/* binding */ findNamesInScope),
8168
11005
  "findUsingForNode": () => (/* binding */ findUsingForNode),
8169
11006
  "formatAst": () => (/* binding */ formatAst),
11007
+ "formatAstLongLines": () => (/* binding */ formatAstLongLines),
8170
11008
  "getApiFunctionInfo": () => (/* binding */ getApiFunctionInfo),
8171
11009
  "getApiMapping": () => (/* binding */ getApiMapping),
8172
11010
  "getSuperClasses": () => (/* binding */ getSuperClasses),
@@ -8174,7 +11012,12 @@ __webpack_require__.d(__webpack_exports__, {
8174
11012
  "isLocal": () => (/* binding */ isLocal),
8175
11013
  "isLookupCandidate": () => (/* binding */ isLookupCandidate),
8176
11014
  "isStateNode": () => (/* binding */ isStateNode),
11015
+ "lookupByFullName": () => (/* binding */ lookupByFullName),
8177
11016
  "lookupNext": () => (/* binding */ lookupNext),
11017
+ "lookupResultContains": () => (/* binding */ lookupResultContains),
11018
+ "lookupWithType": () => (/* binding */ lookupWithType),
11019
+ "makeToyboxLink": () => (/* binding */ makeToyboxLink),
11020
+ "mapVarDeclsByType": () => (/* binding */ mapVarDeclsByType),
8178
11021
  "markInvokeClassMethod": () => (/* binding */ markInvokeClassMethod),
8179
11022
  "parseSdkVersion": () => (/* binding */ parseSdkVersion),
8180
11023
  "sameLookupResult": () => (/* binding */ sameLookupResult),
@@ -8194,6 +11037,8 @@ var promises_ = __webpack_require__(560);
8194
11037
  const external_prettier_namespaceObject = require("prettier");
8195
11038
  // EXTERNAL MODULE: ./src/ast.ts
8196
11039
  var src_ast = __webpack_require__(6652);
11040
+ // EXTERNAL MODULE: ./src/mc-rewrite.ts
11041
+ var mc_rewrite = __webpack_require__(5530);
8197
11042
  // EXTERNAL MODULE: ./src/negative-fixups.ts
8198
11043
  var negative_fixups = __webpack_require__(4499);
8199
11044
  // EXTERNAL MODULE: ./src/optimizer-types.ts
@@ -8717,13 +11562,14 @@ function add_one_resource(state, doc, module, e) {
8717
11562
  }
8718
11563
  }
8719
11564
 
8720
- // EXTERNAL MODULE: external "./util.cjs"
8721
- var external_util_cjs_ = __webpack_require__(6906);
8722
11565
  // EXTERNAL MODULE: ./src/type-flow.ts
8723
11566
  var type_flow = __webpack_require__(4859);
11567
+ // EXTERNAL MODULE: ./src/type-flow/types.ts
11568
+ var types = __webpack_require__(7255);
11569
+ // EXTERNAL MODULE: external "./util.cjs"
11570
+ var external_util_cjs_ = __webpack_require__(6906);
8724
11571
  ;// CONCATENATED MODULE: ./src/visitor.ts
8725
11572
 
8726
-
8727
11573
  function visitorNode(node) {
8728
11574
  if (node.type === "Identifier") {
8729
11575
  return node;
@@ -8742,28 +11588,11 @@ function visitorNode(node) {
8742
11588
  }
8743
11589
  return node;
8744
11590
  }
8745
- function visitReferences(state, ast, name, defn, callback, includeDefs = false, filter = null, typeMap = null) {
8746
- const lookup = (node, nonLocal = false) => {
8747
- const results = nonLocal ? state.lookupNonlocal(node) : state.lookup(node);
8748
- if (results[1] || !typeMap)
8749
- return results;
8750
- if (node.type === "MemberExpression" && !node.computed) {
8751
- const objectType = typeMap.get(node.object);
8752
- if (!objectType)
8753
- return results;
8754
- const [, decls] = (0,type_flow/* findObjectDeclsByProperty */.nK)(state, objectType, node);
8755
- if (decls) {
8756
- const next = (0,external_api_cjs_.lookupNext)(state, [{ parent: null, results: decls }], "decls", node.property);
8757
- if (next) {
8758
- return [node.property.name, next];
8759
- }
8760
- }
8761
- }
8762
- return results;
8763
- };
11591
+ function visitReferences(state, ast, name, defn, callback, includeDefs = false, filter = null, typeMap = null, findSingleDefinition = false) {
11592
+ const lookup = (node, nonLocal = false) => (0,external_api_cjs_.lookupWithType)(state, node, typeMap, nonLocal);
8764
11593
  const checkResults = ([name, results], node) => {
8765
11594
  if (name && results) {
8766
- if (!defn || (0,external_api_cjs_.sameLookupResult)(results, defn)) {
11595
+ if (!defn || (0,external_api_cjs_.lookupResultContains)(results, defn)) {
8767
11596
  if (callback(node, results, false) === false) {
8768
11597
  return [];
8769
11598
  }
@@ -8776,6 +11605,35 @@ function visitReferences(state, ast, name, defn, callback, includeDefs = false,
8776
11605
  }
8777
11606
  return null;
8778
11607
  };
11608
+ const visitDef = (node, def, decls = "decls") => {
11609
+ const id = node.type === "BinaryExpression" ? node.left : node;
11610
+ if (filter && !filter(id))
11611
+ return;
11612
+ let [scope, parent] = state.stack.slice(-2).reverse();
11613
+ let results;
11614
+ if (def) {
11615
+ if (scope.sn.node !== def) {
11616
+ parent = scope;
11617
+ }
11618
+ results = parent.sn[decls]?.[id.name];
11619
+ if (!results)
11620
+ return;
11621
+ const thisDefn = results.find((decl) => decl.node === def);
11622
+ if (!thisDefn) {
11623
+ return;
11624
+ }
11625
+ if (findSingleDefinition) {
11626
+ results = [thisDefn];
11627
+ }
11628
+ }
11629
+ else {
11630
+ if (!parent) {
11631
+ return;
11632
+ }
11633
+ results = [scope.sn];
11634
+ }
11635
+ checkResults([id.name, [{ parent: parent.sn, results }]], id);
11636
+ };
8779
11637
  state.pre = (node) => {
8780
11638
  if (filter && !filter(node))
8781
11639
  return [];
@@ -8812,7 +11670,8 @@ function visitReferences(state, ast, name, defn, callback, includeDefs = false,
8812
11670
  // it will be ignored, and the lookup will start as if the
8813
11671
  // call had been written self.foo() rather than foo().
8814
11672
  if (node.callee.type === "Identifier") {
8815
- if (!name || node.callee.name === name) {
11673
+ if ((!name || node.callee.name === name) &&
11674
+ (!filter || filter(node.callee))) {
8816
11675
  /* ignore return value */
8817
11676
  checkResults(lookup(node.callee, true), node.callee);
8818
11677
  }
@@ -8848,29 +11707,47 @@ function visitReferences(state, ast, name, defn, callback, includeDefs = false,
8848
11707
  return ["returnType"];
8849
11708
  }
8850
11709
  case "ModuleDeclaration":
8851
- if (includeDefs)
8852
- break;
11710
+ if (includeDefs) {
11711
+ visitDef(node.id);
11712
+ }
8853
11713
  return ["body"];
8854
11714
  case "ClassDeclaration":
8855
- if (includeDefs)
8856
- break;
11715
+ if (includeDefs) {
11716
+ visitDef(node.id, node);
11717
+ }
8857
11718
  return ["body", "superClass"];
8858
11719
  case "FunctionDeclaration":
8859
- if (includeDefs)
8860
- break;
11720
+ if (includeDefs) {
11721
+ visitDef(node.id, node);
11722
+ }
8861
11723
  return ["params", "returnType", "body"];
8862
11724
  case "TypedefDeclaration":
8863
- if (includeDefs)
8864
- break;
11725
+ if (includeDefs) {
11726
+ visitDef(node.id, node, "type_decls");
11727
+ }
8865
11728
  return ["ts"];
8866
11729
  case "VariableDeclarator":
8867
- if (includeDefs)
8868
- break;
11730
+ if (includeDefs) {
11731
+ visitDef(node.id, node);
11732
+ }
11733
+ if (node.id.type === "BinaryExpression") {
11734
+ state.traverse(node.id.right);
11735
+ }
8869
11736
  return ["init"];
8870
11737
  case "EnumDeclaration":
8871
- if (includeDefs)
11738
+ if (includeDefs) {
11739
+ if (node.id) {
11740
+ visitDef(node.id, node, "type_decls");
11741
+ }
8872
11742
  break;
11743
+ }
8873
11744
  return [];
11745
+ case "EnumStringMember": {
11746
+ if (!filter || filter(node.id)) {
11747
+ checkResults([node.id.name, [{ parent: state.top().sn, results: [node] }]], node);
11748
+ }
11749
+ break;
11750
+ }
8874
11751
  case "CatchClause":
8875
11752
  if (includeDefs)
8876
11753
  break;
@@ -8897,6 +11774,9 @@ function visitReferences(state, ast, name, defn, callback, includeDefs = false,
8897
11774
 
8898
11775
 
8899
11776
 
11777
+
11778
+
11779
+
8900
11780
  /*
8901
11781
  * This is an unfortunate hack. I want to be able to extract things
8902
11782
  * like the types of all of a Class's variables (in particular the type
@@ -9101,6 +11981,19 @@ function sameLookupDefinition(a, b) {
9101
11981
  function sameLookupResult(a, b) {
9102
11982
  return (0,external_util_cjs_.sameArrays)(a, b, sameLookupDefinition);
9103
11983
  }
11984
+ function declKey(decl) {
11985
+ return isStateNode(decl)
11986
+ ? decl.type === "ModuleDeclaration"
11987
+ ? decl.fullName
11988
+ : decl.node
11989
+ : decl;
11990
+ }
11991
+ function lookupResultContains(a, b) {
11992
+ if (!b.length)
11993
+ return false;
11994
+ const bs = new Set(b.flatMap((bdef) => bdef.results.map(declKey)));
11995
+ return a.some((adef) => adef.results.some((adecl) => bs.has(declKey(adecl))));
11996
+ }
9104
11997
  function isLookupCandidate(node) {
9105
11998
  return node.computed
9106
11999
  ? node.property.type === "UnaryExpression" &&
@@ -9177,26 +12070,26 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
9177
12070
  }
9178
12071
  case "ThisExpression": {
9179
12072
  for (let i = stack.length;;) {
9180
- const si = stack[--i];
12073
+ const si = stack[--i].sn;
9181
12074
  if (si.type === "ModuleDeclaration" ||
9182
12075
  si.type === "ClassDeclaration" ||
9183
12076
  !i) {
9184
12077
  return [
9185
12078
  name || si.name,
9186
- [{ parent: i ? stack[i - 1] : null, results: [si] }],
12079
+ [{ parent: i ? stack[i - 1].sn : null, results: [si] }],
9187
12080
  ];
9188
12081
  }
9189
12082
  }
9190
12083
  }
9191
12084
  case "Identifier": {
9192
12085
  if (node.name === "$") {
9193
- return [name || node.name, [{ parent: null, results: [stack[0]] }]];
12086
+ return [name || node.name, [{ parent: null, results: [stack[0].sn] }]];
9194
12087
  }
9195
12088
  let inStatic = false;
9196
12089
  let checkedImports = ignoreImports;
9197
12090
  let imports = null;
9198
12091
  for (let i = stack.length; i--;) {
9199
- const si = stack[i];
12092
+ const si = stack[i].sn;
9200
12093
  switch (si.type) {
9201
12094
  case "ClassDeclaration":
9202
12095
  if (inStatic && state.config?.enforceStatic !== "NO") {
@@ -9293,6 +12186,26 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
9293
12186
  }
9294
12187
  return [false, false];
9295
12188
  }
12189
+ function lookupWithType(state, node, typeMap, nonLocal = false, stack = null) {
12190
+ const results = nonLocal
12191
+ ? state.lookupNonlocal(node, null, stack)
12192
+ : state.lookup(node, null, stack);
12193
+ if (results[1] || !typeMap)
12194
+ return results;
12195
+ if (node.type === "MemberExpression" && !node.computed) {
12196
+ const objectType = typeMap.get(node.object);
12197
+ if (!objectType)
12198
+ return results;
12199
+ const [, decls] = (0,type_flow/* findObjectDeclsByProperty */.nK)(state, objectType, node);
12200
+ if (decls) {
12201
+ const next = lookupNext(state, [{ parent: null, results: decls }], "decls", node.property);
12202
+ if (next) {
12203
+ return [node.property.name, next];
12204
+ }
12205
+ }
12206
+ }
12207
+ return results;
12208
+ }
9296
12209
  function stateFuncs() {
9297
12210
  let currentEnum = null;
9298
12211
  return {
@@ -9330,9 +12243,10 @@ function stateFuncs() {
9330
12243
  return lookup(this, "type_decls", node, name, stack);
9331
12244
  },
9332
12245
  stackClone() {
9333
- return this.stack.map((elm) => elm.type === "ModuleDeclaration" || elm.type === "Program"
9334
- ? { ...elm }
9335
- : elm);
12246
+ return this.stack.slice();
12247
+ },
12248
+ top() {
12249
+ return this.stack[this.stack.length - 1];
9336
12250
  },
9337
12251
  traverse(root) {
9338
12252
  return (0,src_ast/* traverseAst */.lA)(root, (node) => {
@@ -9359,7 +12273,7 @@ function stateFuncs() {
9359
12273
  if (this.stack.length !== 1) {
9360
12274
  throw new Error("Unexpected stack length for Program node");
9361
12275
  }
9362
- this.stack[0].node = node;
12276
+ this.stack[0].sn.node = node;
9363
12277
  break;
9364
12278
  case "TypeSpecList":
9365
12279
  case "TypeSpecPart":
@@ -9367,10 +12281,9 @@ function stateFuncs() {
9367
12281
  break;
9368
12282
  case "ImportModule":
9369
12283
  case "Using": {
9370
- const [parent] = this.stack.slice(-1);
9371
- if (!parent.usings) {
9372
- parent.usings = {};
9373
- }
12284
+ const parent = { ...this.stack.pop() };
12285
+ this.stack.push(parent);
12286
+ parent.usings = parent.usings ? { ...parent.usings } : {};
9374
12287
  const name = (node.type === "Using" && node.as && node.as.name) ||
9375
12288
  (node.id.type === "Identifier"
9376
12289
  ? node.id.name
@@ -9382,6 +12295,7 @@ function stateFuncs() {
9382
12295
  parent.imports = [using];
9383
12296
  }
9384
12297
  else {
12298
+ parent.imports = parent.imports.slice();
9385
12299
  const index = parent.imports.findIndex((using) => (using.node.id.type === "Identifier"
9386
12300
  ? using.node.id.name
9387
12301
  : using.node.id.property.name) === name);
@@ -9394,35 +12308,39 @@ function stateFuncs() {
9394
12308
  }
9395
12309
  case "CatchClause":
9396
12310
  if (node.param) {
9397
- const [parent] = this.stack.slice(-1);
12311
+ const parent = this.top().sn;
9398
12312
  if (!parent.decls)
9399
12313
  parent.decls = {};
9400
12314
  const id = node.param.type === "Identifier"
9401
12315
  ? node.param
9402
12316
  : node.param.left;
9403
12317
  this.stack.push({
9404
- type: "BlockStatement",
9405
- fullName: parent.fullName,
9406
- name: undefined,
9407
- node: node.body,
9408
- decls: { [id.name]: [id] },
9409
- attributes: 0,
12318
+ sn: {
12319
+ type: "BlockStatement",
12320
+ fullName: parent.fullName,
12321
+ name: undefined,
12322
+ node: node.body,
12323
+ decls: { [id.name]: [id] },
12324
+ attributes: 0,
12325
+ },
9410
12326
  });
9411
12327
  }
9412
12328
  break;
9413
12329
  case "ForStatement":
9414
12330
  if (node.init && node.init.type === "VariableDeclaration") {
9415
12331
  this.stack.push({
9416
- type: "BlockStatement",
9417
- fullName: this.stack.slice(-1).pop().fullName,
9418
- name: undefined,
9419
- node: node,
9420
- attributes: 0,
12332
+ sn: {
12333
+ type: "BlockStatement",
12334
+ fullName: this.top().sn.fullName,
12335
+ name: undefined,
12336
+ node: node,
12337
+ attributes: 0,
12338
+ },
9421
12339
  });
9422
12340
  }
9423
12341
  break;
9424
12342
  case "BlockStatement": {
9425
- const [parent] = this.stack.slice(-1);
12343
+ const parent = this.top().sn;
9426
12344
  if (parent.node === node ||
9427
12345
  (parent.type !== "FunctionDeclaration" &&
9428
12346
  parent.type !== "BlockStatement")) {
@@ -9433,10 +12351,10 @@ function stateFuncs() {
9433
12351
  case "ClassDeclaration":
9434
12352
  case "FunctionDeclaration":
9435
12353
  case "ModuleDeclaration": {
9436
- const [parent] = this.stack.slice(-1);
12354
+ const parent = this.top().sn;
9437
12355
  const name = "id" in node ? node.id && node.id.name : undefined;
9438
12356
  const fullName = this.stack
9439
- .map((e) => e.name)
12357
+ .map((e) => e.sn.name)
9440
12358
  .concat(name)
9441
12359
  .filter((e) => e != null)
9442
12360
  .join(".");
@@ -9449,7 +12367,7 @@ function stateFuncs() {
9449
12367
  ? 0
9450
12368
  : stateNodeAttrs(node.attrs),
9451
12369
  };
9452
- this.stack.push(elm);
12370
+ this.stack.push({ sn: elm });
9453
12371
  if (name) {
9454
12372
  if (!parent.decls)
9455
12373
  parent.decls = {};
@@ -9458,7 +12376,7 @@ function stateFuncs() {
9458
12376
  const e = parent.decls[name].find((d) => isStateNode(d) && d[what] === elm[what]);
9459
12377
  if (e != null) {
9460
12378
  e.node = node;
9461
- this.stack.splice(-1, 1, e);
12379
+ this.top().sn = e;
9462
12380
  break;
9463
12381
  }
9464
12382
  }
@@ -9492,7 +12410,7 @@ function stateFuncs() {
9492
12410
  this.inType++;
9493
12411
  break;
9494
12412
  }
9495
- const [parent] = this.stack.slice(-1);
12413
+ const parent = this.top().sn;
9496
12414
  const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
9497
12415
  node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
9498
12416
  }
@@ -9500,7 +12418,7 @@ function stateFuncs() {
9500
12418
  case "TypedefDeclaration": {
9501
12419
  this.inType++;
9502
12420
  const name = node.id.name;
9503
- const [parent] = this.stack.slice(-1);
12421
+ const parent = this.top().sn;
9504
12422
  if (!parent.type_decls)
9505
12423
  parent.type_decls = {};
9506
12424
  if (!(0,src_ast/* hasProperty */.l$)(parent.type_decls, name)) {
@@ -9524,7 +12442,7 @@ function stateFuncs() {
9524
12442
  break;
9525
12443
  }
9526
12444
  case "VariableDeclaration": {
9527
- const [parent] = this.stack.slice(-1);
12445
+ const parent = this.top().sn;
9528
12446
  if (!parent.decls)
9529
12447
  parent.decls = {};
9530
12448
  const decls = parent.decls;
@@ -9560,7 +12478,7 @@ function stateFuncs() {
9560
12478
  throw new Error(`Expected inType to be 1 at EnumStringBody. Got ${this.inType}.`);
9561
12479
  }
9562
12480
  this.inType--;
9563
- const [parent] = this.stack.slice(-1);
12481
+ const parent = this.top().sn;
9564
12482
  const values = parent.decls || (parent.decls = {});
9565
12483
  let prev = -1;
9566
12484
  node.members.forEach((m, i) => {
@@ -9652,17 +12570,19 @@ function stateFuncs() {
9652
12570
  this.inType++;
9653
12571
  break;
9654
12572
  }
9655
- const [parent] = this.stack.slice(-1);
9656
- if (parent.node === node ||
12573
+ const parent = this.top();
12574
+ if (parent.sn.node === node ||
9657
12575
  // The pre function might cause node.body to be skipped,
9658
12576
  // so we need to check here, just in case.
9659
12577
  // (this actually happens with prettier-extenison-monkeyc's
9660
12578
  // findItemsByRange)
9661
- (node.type === "CatchClause" && parent.node === node.body)) {
9662
- delete parent.usings;
9663
- delete parent.imports;
9664
- if (node.type !== "Program") {
9665
- this.stack.pop();
12579
+ (node.type === "CatchClause" && parent.sn.node === node.body)) {
12580
+ let top = this.stack.pop();
12581
+ if (node.type === "Program") {
12582
+ top = { ...top };
12583
+ delete top.usings;
12584
+ delete top.imports;
12585
+ this.stack.push(top);
9666
12586
  }
9667
12587
  }
9668
12588
  }
@@ -9688,11 +12608,13 @@ function collectNamespaces(ast, stateIn) {
9688
12608
  if (!state.stack) {
9689
12609
  state.stack = [
9690
12610
  {
9691
- type: "Program",
9692
- name: "$",
9693
- fullName: "$",
9694
- node: undefined,
9695
- attributes: 0,
12611
+ sn: {
12612
+ type: "Program",
12613
+ name: "$",
12614
+ fullName: "$",
12615
+ node: undefined,
12616
+ attributes: 0,
12617
+ },
9696
12618
  },
9697
12619
  ];
9698
12620
  }
@@ -9717,10 +12639,10 @@ function collectNamespaces(ast, stateIn) {
9717
12639
  if (state.stack.length !== 1) {
9718
12640
  throw new Error("Invalid AST!");
9719
12641
  }
9720
- if (state.stack[0].type !== "Program") {
12642
+ if (state.stack[0].sn.type !== "Program") {
9721
12643
  throw new Error("Bottom of stack was not a Program!");
9722
12644
  }
9723
- return state.stack[0];
12645
+ return state.stack[0].sn;
9724
12646
  }
9725
12647
  function formatAst(node, monkeyCSource = null, options = null) {
9726
12648
  /*
@@ -9759,10 +12681,152 @@ function formatAst(node, monkeyCSource = null, options = null) {
9759
12681
  endOfLine: "lf",
9760
12682
  });
9761
12683
  }
12684
+ function findNamesInExactScope(decl, regexp) {
12685
+ if (!decl.decls)
12686
+ return [];
12687
+ return Object.entries(decl.decls).flatMap(([key, value]) => regexp.test(key) ? value : []);
12688
+ }
12689
+ function findNamesInScope(declStack, pattern) {
12690
+ const regex = typeof pattern === "string"
12691
+ ? new RegExp(pattern.replace(/\W/g, "").split("").join(".*"), "i")
12692
+ : pattern;
12693
+ const results = new Map();
12694
+ const helper = (decls, depth) => {
12695
+ decls.forEach((parent) => {
12696
+ if (parent.type === "ClassDeclaration") {
12697
+ if (parent.superClass && parent.superClass !== true) {
12698
+ helper(parent.superClass, depth + 1);
12699
+ }
12700
+ }
12701
+ findNamesInExactScope(parent, regex).forEach((sn) => {
12702
+ results.set(sn, { parent, depth });
12703
+ });
12704
+ });
12705
+ };
12706
+ let depth = 0;
12707
+ while (depth < declStack.length) {
12708
+ helper(declStack[declStack.length - 1 - depth], depth);
12709
+ depth++;
12710
+ }
12711
+ return Array.from(results);
12712
+ }
12713
+ function mapVarDeclsByType(state, decls, node, typeMap) {
12714
+ return decls.flatMap((decl) => {
12715
+ if (decl.type === "VariableDeclarator" ||
12716
+ decl.type === "Identifier" ||
12717
+ decl.type === "BinaryExpression") {
12718
+ const type = typeMap?.get(node);
12719
+ return type ? (0,types/* getStateNodeDeclsFromType */.iX)(state, type) : [];
12720
+ }
12721
+ return decl;
12722
+ });
12723
+ }
12724
+ function formatAstLongLines(node) {
12725
+ return formatAst(node, null, { printWidth: 10000 });
12726
+ }
12727
+ async function createDocumentationMap(functionDocumentation) {
12728
+ const docMap = new Map();
12729
+ const state = await (0,mc_rewrite/* analyze */.BJ)({}, {}, undefined, {});
12730
+ functionDocumentation.forEach((info) => {
12731
+ state.allFunctions[info.name]?.forEach((decl) => decl.node?.loc?.source === "api.mir" &&
12732
+ decl.fullName.endsWith(`.${info.parent}.${info.name}`) &&
12733
+ docMap.set(decl.fullName, info.doc
12734
+ .replace(/(\*.*?)\s*<br\/>\s*(?!\s*\*)/g, "$1\n\n")
12735
+ .replace(/@example(.*?)(@|$)/g, (match, m1, m2) => `\n#### Example\n\`\`\`${m1.replace(/<br\/>/g, "\n")}\`\`\`${m2}`)
12736
+ .replace(/@note/g, "\n#### Note\n")
12737
+ .replace(/@see/, "\n#### See Also:\n$&")
12738
+ .replace(/@see\s+(.*?)(?=<br\/>)/g, "\n * {$1}")
12739
+ .replace(/@throws/, "\n#### Throws:\n$&")
12740
+ .replace(/@throws\s+(.*?)(?=<br\/>)/g, "\n * $1")
12741
+ .replace(/@since\s+(.*?)(?=<br\/>)/, "\n#### Since:\nAPI Level $1\n")
12742
+ .replace(/<div class="description">/, "### Description\n")
12743
+ .replace(/<div class="param">/, "\n#### Parameters\n$&")
12744
+ .replace(/<div class="param">/g, " \n*")
12745
+ .replace(/\s*<div[^>]*>/g, " \n\n")
12746
+ .replace(/\s*<br\/>\s*([@*])/g, "\n$1")
12747
+ //.replace(/\s\s\s(\s)*(?!\/\/)/g, " \n")
12748
+ .replace(/<[^>]*>/g, "")
12749
+ .replace(/@/g, " \n\n@")
12750
+ //.replace(/\s\*/g, " \n*")
12751
+ .replace(/\+(\w+)\+/g, "`$1`")
12752
+ .trim()
12753
+ .replace(/\[((\s*(\w+::)+\w+\s*,)*(\s*(\w+::)+\w+\s*))\]/g, (arg, a1) => {
12754
+ return a1
12755
+ .split(",")
12756
+ .map((s) => {
12757
+ const name = s.trim().replace(/::/g, ".");
12758
+ const decl = lookupByFullName(state, name);
12759
+ if (decl && decl.length === 1) {
12760
+ const sn = decl[0];
12761
+ const link = makeToyboxLink(sn);
12762
+ return `[${sn.name || name}](${link})`;
12763
+ }
12764
+ return s;
12765
+ })
12766
+ .join(" or ");
12767
+ })
12768
+ .replace(/\{(\s*(?:\w+::)+\w+(?:#\w+)?|https:\/\/\S+)\s*(\S.*?)?\s*\}/g, (arg, a1, a2) => {
12769
+ if (a1.startsWith("https://")) {
12770
+ return `[${a2 || a1}](${a1})`;
12771
+ }
12772
+ let name = a1.trim().replace(/::|#/g, ".");
12773
+ if (!name.startsWith("Toybox")) {
12774
+ name = `Toybox.${name}`;
12775
+ }
12776
+ const decl = lookupByFullName(state, name);
12777
+ if (decl && decl.length === 1) {
12778
+ const link = makeToyboxLink(decl[0]);
12779
+ return `[${a2 || a1}](${link})`;
12780
+ }
12781
+ return arg;
12782
+ })));
12783
+ });
12784
+ return docMap;
12785
+ }
12786
+ function makeToyboxLink(result) {
12787
+ const make_link = (fullName, fragment) => {
12788
+ const path = fullName.split(".");
12789
+ return (`https://developer.garmin.com/connect-iq/api-docs/${path
12790
+ .slice(1, fragment ? -1 : undefined)
12791
+ .join("/")}.html` +
12792
+ (fragment ? `#${path.slice(-1)[0]}-${fragment}` : ""));
12793
+ };
12794
+ switch (result.type) {
12795
+ case "ClassDeclaration":
12796
+ case "ModuleDeclaration":
12797
+ if (result.fullName.startsWith("$.Toybox")) {
12798
+ return make_link(result.fullName);
12799
+ }
12800
+ break;
12801
+ case "FunctionDeclaration":
12802
+ return make_link(result.fullName, "instance_function");
12803
+ case "EnumStringMember":
12804
+ if (result.init.enumType && typeof result.init.enumType === "string") {
12805
+ return make_link("$." + result.init.enumType, "module");
12806
+ }
12807
+ break;
12808
+ case "EnumDeclaration":
12809
+ return make_link(result.fullName, "module");
12810
+ case "TypedefDeclaration":
12811
+ return make_link(result.fullName, "named_type");
12812
+ case "VariableDeclarator":
12813
+ return make_link(result.fullName, "var");
12814
+ }
12815
+ return null;
12816
+ }
12817
+ function lookupByFullName(state, fullName) {
12818
+ return fullName.split(".").reduce((results, part) => {
12819
+ return results
12820
+ .flatMap((result) => isStateNode(result)
12821
+ ? result.decls?.[part] || result.type_decls?.[part]
12822
+ : null)
12823
+ .filter((sn) => !!sn);
12824
+ }, [state.stack[0].sn]);
12825
+ }
9762
12826
  function handleException(state, node, exception) {
9763
12827
  try {
9764
12828
  const fullName = state.stack
9765
- .map((e) => e.name)
12829
+ .map((e) => e.sn.name)
9766
12830
  .concat("name" in node && typeof node.name === "string" ? node.name : undefined)
9767
12831
  .filter((e) => e != null)
9768
12832
  .join(".");
@@ -9787,7 +12851,7 @@ function handleException(state, node, exception) {
9787
12851
  function findUsing(state, stack, using) {
9788
12852
  if (using.module)
9789
12853
  return using.module;
9790
- let module = stack[0];
12854
+ let module = stack[0].sn;
9791
12855
  const find = (node) => {
9792
12856
  let name;
9793
12857
  if (node.type === "Identifier") {
@@ -9835,7 +12899,7 @@ function findUsingForNode(state, stack, i, node) {
9835
12899
  imports = [];
9836
12900
  imports.push({
9837
12901
  name: `${module.fullName}.${node.name}`,
9838
- decls: { parent: si, results: module.type_decls[node.name] },
12902
+ decls: { parent: si.sn, results: module.type_decls[node.name] },
9839
12903
  });
9840
12904
  }
9841
12905
  }
@@ -9857,7 +12921,7 @@ function getApiFunctionInfo(state, func) {
9857
12921
  };
9858
12922
  }
9859
12923
  if (func.name === "initialize") {
9860
- const top = func.stack[func.stack.length - 1];
12924
+ const top = func.stack[func.stack.length - 1].sn;
9861
12925
  if (top.type === "ClassDeclaration") {
9862
12926
  top.hasInvoke = true;
9863
12927
  }
@@ -9870,7 +12934,7 @@ function markInvokeClassMethod(state, func) {
9870
12934
  func.info = state.invokeInfo;
9871
12935
  }
9872
12936
  function isLocal(v) {
9873
- return v.stack[v.stack.length - 1]?.type === "BlockStatement";
12937
+ return v.stack[v.stack.length - 1]?.sn.type === "BlockStatement";
9874
12938
  }
9875
12939
  function diagnostic(state, node, message, type = "INFO", extra) {
9876
12940
  if (!state.diagnostics)