@markw65/monkeyc-optimizer 1.0.44 → 1.0.45

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,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,hasProperty,isLookupCandidate,isStateNode,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
1
+ 0 && (module.exports = {checkCompilerVersion,collectNamespaces,findUsingForNode,formatAst,getApiFunctionInfo,getApiMapping,hasProperty,isLocal,isLookupCandidate,isStateNode,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
2
2
  /******/ (() => { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -265,6 +265,7 @@ __webpack_require__.d(__webpack_exports__, {
265
265
  "getApiFunctionInfo": () => (/* binding */ api_getApiFunctionInfo),
266
266
  "getApiMapping": () => (/* binding */ api_getApiMapping),
267
267
  "hasProperty": () => (/* reexport */ ast_hasProperty),
268
+ "isLocal": () => (/* binding */ api_isLocal),
268
269
  "isLookupCandidate": () => (/* binding */ api_isLookupCandidate),
269
270
  "isStateNode": () => (/* binding */ api_isStateNode),
270
271
  "markInvokeClassMethod": () => (/* binding */ api_markInvokeClassMethod),
@@ -533,6 +534,64 @@ function ast_getNodeValue(node) {
533
534
  }
534
535
  throw new Error(`Literal has unknown type '${type}'`);
535
536
  }
537
+ function wrap(node, loc) {
538
+ if (loc) {
539
+ node.loc = loc;
540
+ node.start = loc.start.offset;
541
+ node.end = loc.end.offset;
542
+ }
543
+ return node;
544
+ }
545
+ function locRange(start, end) {
546
+ return {
547
+ source: start.source || end.source,
548
+ start: start.start,
549
+ end: end.end,
550
+ };
551
+ }
552
+ function adjustLoc(loc, start = 1, end = -1) {
553
+ return {
554
+ source: loc.source,
555
+ start: {
556
+ offset: loc.start.offset + start,
557
+ line: loc.start.line,
558
+ column: loc.start.column + start,
559
+ },
560
+ end: {
561
+ offset: loc.end.offset + end,
562
+ line: loc.end.line,
563
+ column: loc.end.column + end,
564
+ },
565
+ };
566
+ }
567
+ function makeIdentifier(name, loc) {
568
+ return wrap({ type: "Identifier", name }, loc);
569
+ }
570
+ function makeMemberExpression(object, property) {
571
+ return wrap({
572
+ type: "MemberExpression",
573
+ object,
574
+ property,
575
+ computed: false,
576
+ }, object.loc && locRange(object.loc, property.loc));
577
+ }
578
+ function makeScopedName(dotted, l) {
579
+ const loc = l && adjustLoc(l, 0, l.start.offset - l.end.offset);
580
+ const result = dotted.split(/\s*\.\s*/).reduce(({ cur, offset }, next) => {
581
+ const id = makeIdentifier(next, loc && adjustLoc(loc, offset, offset + next.length));
582
+ if (!cur) {
583
+ cur = id;
584
+ }
585
+ else {
586
+ cur = makeMemberExpression(cur, id);
587
+ }
588
+ offset += next.length + 1;
589
+ return { cur, offset };
590
+ }, { cur: null, offset: 0 }).cur;
591
+ if (!result)
592
+ throw new Error("Failed to make a ScopedName");
593
+ return result;
594
+ }
536
595
 
537
596
  ;// CONCATENATED MODULE: external "./api.cjs"
538
597
  const external_api_cjs_namespaceObject = require("./api.cjs");
@@ -587,6 +646,8 @@ function function_info_recordCalledFuncs(func, callees) {
587
646
  }
588
647
  function function_info_functionMayModify(state, func, decl) {
589
648
  const info = func.info;
649
+ if (info === false)
650
+ return false;
590
651
  if (!info || info.modifiedUnknown)
591
652
  return true;
592
653
  if (info.resolvedDecls) {
@@ -599,7 +660,7 @@ function function_info_functionMayModify(state, func, decl) {
599
660
  const visited = new Set();
600
661
  const resolved = new Set();
601
662
  const resolveDecls = (f) => {
602
- if (visited.has(f))
663
+ if (f.info === false || visited.has(f))
603
664
  return true;
604
665
  if (!f.info)
605
666
  return false;
@@ -661,6 +722,16 @@ function function_info_findCalleesForNew(lookupDefs) {
661
722
  .flatMap(initializer)
662
723
  .filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
663
724
  }
725
+ function function_info_findCalleesByNode(state, callee) {
726
+ const name = callee.type === "Identifier"
727
+ ? callee.name
728
+ : callee.type === "MemberExpression" && !callee.computed
729
+ ? callee.property.name
730
+ : null;
731
+ if (!name)
732
+ return null;
733
+ return ((hasProperty(state.allFunctions, name) && state.allFunctions[name]) || null);
734
+ }
664
735
 
665
736
  ;// CONCATENATED MODULE: ./src/optimizer-types.ts
666
737
  var optimizer_types_StateNodeAttributes;
@@ -1624,13 +1695,17 @@ function pragma_checker_pragmaChecker(state, ast, diagnostics) {
1624
1695
  if (quote == '"') {
1625
1696
  return haystack.includes(needle);
1626
1697
  }
1627
- const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/[".]/g, "_")}(?:_\\d+)?)`));
1698
+ const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/\W/g, "_")}(?:_\\d+)?)`));
1628
1699
  return re.test(haystack);
1629
1700
  };
1630
1701
  next();
1631
1702
  traverseAst(ast, (node) => {
1632
- if (index >= comments.length)
1703
+ if (index >= comments.length ||
1704
+ node.type === "Line" ||
1705
+ node.type === "Block" ||
1706
+ node.type === "MultiLine") {
1633
1707
  return false;
1708
+ }
1634
1709
  if (node.start && node.start >= (comment.end || Infinity)) {
1635
1710
  const { kind, quote, needle } = matchers.shift();
1636
1711
  if (kind === "match") {
@@ -1778,7 +1853,7 @@ function control_flow_buildReducedGraph(state, func, notice) {
1778
1853
  try {
1779
1854
  const localState = new LocalState(func.node);
1780
1855
  const ret = localState.curBlock;
1781
- state.stack = func.stack;
1856
+ state.stack = [...func.stack];
1782
1857
  const stmtStack = [func.node];
1783
1858
  let tryActive = 0;
1784
1859
  state.pre = (node) => {
@@ -1793,6 +1868,8 @@ function control_flow_buildReducedGraph(state, func, notice) {
1793
1868
  stmtStack.push(node);
1794
1869
  }
1795
1870
  switch (node.type) {
1871
+ case "FunctionDeclaration":
1872
+ return ["body"];
1796
1873
  case "AttributeList":
1797
1874
  return [];
1798
1875
  case "SwitchStatement": {
@@ -2009,11 +2086,6 @@ function control_flow_buildReducedGraph(state, func, notice) {
2009
2086
  }
2010
2087
  case "VariableDeclarator":
2011
2088
  return ["init"];
2012
- case "MemberExpression":
2013
- if (!node.computed) {
2014
- return ["object"];
2015
- }
2016
- break;
2017
2089
  case "UnaryExpression":
2018
2090
  if (node.operator === ":") {
2019
2091
  return [];
@@ -2049,6 +2121,14 @@ function control_flow_buildReducedGraph(state, func, notice) {
2049
2121
  case "ContinueStatement":
2050
2122
  localState.terminal(node.type);
2051
2123
  return [];
2124
+ case "CallExpression":
2125
+ if (node.callee.type === "Identifier") {
2126
+ const extra = state.stack.splice(func.stack.length);
2127
+ state.traverse(node.callee);
2128
+ state.stack.push(...extra);
2129
+ return ["arguments"];
2130
+ }
2131
+ break;
2052
2132
  }
2053
2133
  return null;
2054
2134
  };
@@ -2210,142 +2290,94 @@ function getPreOrder(head) {
2210
2290
 
2211
2291
  // EXTERNAL MODULE: ./node_modules/priorityqueuejs/index.js
2212
2292
  var priorityqueuejs = __webpack_require__(2789);
2213
- ;// CONCATENATED MODULE: ./src/pre.ts
2293
+ ;// CONCATENATED MODULE: ./src/data-flow.ts
2214
2294
 
2215
2295
 
2216
2296
 
2217
2297
 
2218
2298
 
2219
- /**
2220
- * This implements a pseudo Partial Redundancy Elimination
2221
- * pass. It isn't quite like traditional PRE because we're
2222
- * aiming to minimize size, not dynamic instructions. So
2223
- * for us, its worthwhile to take something like:
2224
- *
2225
- * switch (x) {
2226
- * case 1: foo(A.B); break;
2227
- * case 2: foo(C); break;
2228
- * case 3: bar(A.B); break;
2229
- * }
2230
- *
2231
- * and rewrite it as
2232
- *
2233
- * var tmp = A.B;
2234
- * switch (x) {
2235
- * case 1: foo(tmp); break;
2236
- * case 2: foo(C); break;
2237
- * case 3: bar(tmp); break;
2238
- * }
2239
- *
2240
- * because even though A.B wasn't used on all paths where we
2241
- * inserted the temporary, we still reduced the code size.
2242
- */
2243
- const logging = false;
2244
- function declFullName(decl) {
2299
+
2300
+ function data_flow_declFullName(decl) {
2301
+ if (Array.isArray(decl)) {
2302
+ decl = decl[0];
2303
+ }
2304
+ if (decl.type === "Literal") {
2305
+ return decl.raw || decl.value?.toString() || "null";
2306
+ }
2307
+ if (isStateNode(decl))
2308
+ return decl.fullName;
2245
2309
  switch (decl.type) {
2246
- case "Literal":
2247
- return decl.raw || decl.value?.toString() || "null";
2248
- case "VariableDeclarator":
2249
- return decl.fullName;
2310
+ case "BinaryExpression":
2311
+ return decl.left.name;
2312
+ case "EnumStringMember":
2313
+ return decl.init
2314
+ ? `${decl.id.name}:${formatAst(decl.init)}`
2315
+ : decl.id.name;
2250
2316
  default:
2251
2317
  throw new Error(`Unexpected EventDecl type: ${decl.type}`);
2252
2318
  }
2253
2319
  }
2254
- function declName(decl) {
2320
+ function data_flow_declName(decl) {
2321
+ if (Array.isArray(decl)) {
2322
+ decl = decl[0];
2323
+ }
2324
+ if (decl.type === "Literal") {
2325
+ return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
2326
+ }
2327
+ if (isStateNode(decl))
2328
+ return decl.name;
2255
2329
  switch (decl.type) {
2256
- case "Literal":
2257
- return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
2258
- case "VariableDeclarator":
2259
- return decl.name;
2330
+ case "BinaryExpression":
2331
+ return decl.left.name;
2332
+ case "EnumStringMember":
2333
+ return decl.id.name;
2260
2334
  default:
2261
2335
  throw new Error(`Unexpected EventDecl type: ${decl.type}`);
2262
2336
  }
2263
2337
  }
2264
- function logAntState(s, decl) {
2265
- const defs = Array.from(s.ant).reduce((defs, event) => {
2266
- if (event.type === "def" || event.type === "mod")
2267
- defs++;
2268
- return defs;
2269
- }, 0);
2270
- console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
2271
- console.log(` - members: ${Array.from(s.members)
2272
- .map(([block, live]) => block.order + (live ? "t" : "f"))
2273
- .join(", ")}`);
2274
- }
2275
- function logAntDecls(antDecls) {
2276
- antDecls.forEach(logAntState);
2277
- }
2278
- function pre_sizeBasedPRE(state, func) {
2279
- if (!func.node.body)
2280
- return;
2281
- if (!state.config ||
2282
- !state.config.sizeBasedPRE ||
2283
- (typeof state.config.sizeBasedPRE === "string" &&
2284
- state.config.sizeBasedPRE !== func.fullName)) {
2285
- return;
2286
- }
2287
- const { graph: head, identifiers } = buildPREGraph(state, func);
2288
- const candidates = computeAttributes(state, head);
2289
- if (candidates) {
2290
- if (logging) {
2291
- console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
2292
- logAntDecls(candidates);
2293
- }
2294
- const nodeMap = new Map();
2295
- const declMap = new Map();
2296
- const variableDecl = withLoc({
2297
- type: "VariableDeclaration",
2298
- declarations: [],
2299
- kind: "var",
2300
- }, func.node.body);
2301
- variableDecl.end = variableDecl.start;
2302
- variableDecl.loc.end = variableDecl.loc.start;
2303
- candidates.forEach((s, decl) => {
2304
- let name;
2305
- let i = 0;
2306
- do {
2307
- name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
2308
- if (!identifiers.has(name)) {
2309
- identifiers.add(name);
2310
- break;
2311
- }
2312
- i++;
2313
- } while (true);
2314
- declMap.set(decl, name);
2315
- variableDecl.declarations.push(withLoc({
2316
- type: "VariableDeclarator",
2317
- id: withLoc({ type: "Identifier", name }, variableDecl),
2318
- kind: "var",
2319
- }, variableDecl));
2320
- s.ant.forEach((event) => {
2321
- const events = nodeMap.get(event.node);
2322
- if (!events) {
2323
- nodeMap.set(event.node, [event]);
2324
- }
2325
- else {
2326
- events.push(event);
2327
- }
2328
- });
2329
- });
2330
- applyReplacements(func.node, nodeMap, declMap);
2331
- func.node.body.body.unshift(variableDecl);
2332
- }
2333
- }
2334
2338
  function unhandledExpression(node) {
2335
2339
  throw new Error(`Unhandled expression type: ${node.type}`);
2336
2340
  }
2337
- function buildPREGraph(state, func) {
2341
+ function data_flow_buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wantsAllRefs) {
2342
+ const uniqueDeclMap = new Map();
2338
2343
  const findDecl = (node) => {
2339
2344
  if (node.type === "Identifier" ||
2340
2345
  (node.type === "MemberExpression" && !node.computed)) {
2341
2346
  const [, results] = state.lookup(node);
2342
- if (results &&
2343
- results.length === 1 &&
2344
- results[0].parent?.type != "BlockStatement" &&
2345
- results[0].results.length === 1 &&
2346
- results[0].results[0].type === "VariableDeclarator") {
2347
- return results[0].results[0];
2348
- }
2347
+ const decls = (results &&
2348
+ results.reduce((decls, result) => result.results.reduce((decls, result) => {
2349
+ if (!wantsAllRefs &&
2350
+ (result.type !== "VariableDeclarator" || isLocal(result))) {
2351
+ return decls;
2352
+ }
2353
+ if (!decls)
2354
+ return result;
2355
+ if (Array.isArray(decls)) {
2356
+ decls.push(result);
2357
+ return decls;
2358
+ }
2359
+ else {
2360
+ return [decls, result];
2361
+ }
2362
+ }, decls), null)) ||
2363
+ null;
2364
+ if (!Array.isArray(decls))
2365
+ return decls;
2366
+ // We use EventDecl as a Map key, so we need to
2367
+ // uniquify it. Note that from any given function,
2368
+ // if state.lookup finds a set of non locals, it will
2369
+ // always find the same set, so we can use the first
2370
+ // such as the unique identifier.
2371
+ const canon = uniqueDeclMap.get(decls[0]);
2372
+ if (!canon) {
2373
+ uniqueDeclMap.set(decls[0], decls);
2374
+ return decls;
2375
+ }
2376
+ if (canon.length != decls.length ||
2377
+ !canon.every((v, i) => v === decls[i])) {
2378
+ throw new Error(`Canonical representation of ${data_flow_declFullName(canon)} did not match`);
2379
+ }
2380
+ return canon;
2349
2381
  }
2350
2382
  return null;
2351
2383
  };
@@ -2353,18 +2385,22 @@ function buildPREGraph(state, func) {
2353
2385
  const identifiers = new Set();
2354
2386
  const liveDefs = new Map();
2355
2387
  const liveStmts = new Map();
2356
- const liveDef = (def, stmt) => {
2357
- let curNodes = liveDefs.get(def);
2358
- if (!curNodes) {
2359
- liveDefs.set(def, (curNodes = new Set()));
2360
- }
2361
- curNodes.add(stmt);
2362
- let defs = liveStmts.get(stmt);
2363
- if (!defs) {
2364
- liveStmts.set(stmt, (defs = new Map()));
2388
+ const liveDef = trackInsertionPoints
2389
+ ? (def, stmt) => {
2390
+ let curNodes = liveDefs.get(def);
2391
+ if (!curNodes) {
2392
+ liveDefs.set(def, (curNodes = new Set()));
2393
+ }
2394
+ curNodes.add(stmt);
2395
+ let defs = liveStmts.get(stmt);
2396
+ if (!defs) {
2397
+ liveStmts.set(stmt, (defs = new Map()));
2398
+ }
2399
+ defs.set(def, (defs.get(def) || 0) + 1);
2365
2400
  }
2366
- defs.set(def, (defs.get(def) || 0) + 1);
2367
- };
2401
+ : () => {
2402
+ /* do nothing */
2403
+ };
2368
2404
  return {
2369
2405
  identifiers,
2370
2406
  graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
@@ -2378,7 +2414,7 @@ function buildPREGraph(state, func) {
2378
2414
  }
2379
2415
  const v = liveDefs.get(def);
2380
2416
  if (!v || !v.has(node)) {
2381
- throw new Error(`No stmt in liveDef for ${def ? declFullName(def) : "null"}`);
2417
+ throw new Error(`No stmt in liveDef for ${def ? data_flow_declFullName(def) : "null"}`);
2382
2418
  }
2383
2419
  v.delete(node);
2384
2420
  if (!v.size) {
@@ -2399,7 +2435,7 @@ function buildPREGraph(state, func) {
2399
2435
  case "ParenthesizedExpression":
2400
2436
  break;
2401
2437
  case "Literal":
2402
- if (refCost(node) > LocalRefCost) {
2438
+ if (wantsLiteral(node)) {
2403
2439
  const result = getNodeValue(node);
2404
2440
  const key = result[1] +
2405
2441
  (result[0].value === null
@@ -2421,34 +2457,40 @@ function buildPREGraph(state, func) {
2421
2457
  case "Identifier":
2422
2458
  identifiers.add(node.name);
2423
2459
  // fall through
2424
- case "MemberExpression":
2425
- {
2426
- const decl = findDecl(node);
2427
- if (decl && decl.type === "VariableDeclarator") {
2428
- const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
2429
- liveDefs.get(decl);
2430
- if (defStmts) {
2431
- break;
2432
- /*
2433
- // hold off on this for now. we need to communicate
2434
- // which defs need to be fixed, which involves yet-another
2435
- // table.
2436
-
2437
- if (defStmts.size !== 1) break;
2438
- const fixable = isFixableStmt([...defStmts][0]);
2439
- if (fixable === false) break;
2440
- cost += fixable;
2441
- */
2460
+ case "MemberExpression": {
2461
+ const decls = findDecl(node);
2462
+ if (!decls)
2463
+ break;
2464
+ if (trackInsertionPoints &&
2465
+ some(decls, (decl) => {
2466
+ if (decl.type === "VariableDeclarator") {
2467
+ const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
2468
+ liveDefs.get(decl);
2469
+ if (defStmts) {
2470
+ return true;
2471
+ /*
2472
+ // hold off on this for now. we need to communicate
2473
+ // which defs need to be fixed, which involves yet-another
2474
+ // table.
2475
+
2476
+ if (defStmts.size !== 1) break;
2477
+ const fixable = isFixableStmt([...defStmts][0]);
2478
+ if (fixable === false) break;
2479
+ cost += fixable;
2480
+ */
2481
+ }
2442
2482
  }
2443
- return {
2444
- type: "ref",
2445
- node,
2446
- decl,
2447
- mayThrow,
2448
- };
2449
- }
2483
+ return false;
2484
+ })) {
2485
+ break;
2450
2486
  }
2451
- break;
2487
+ return {
2488
+ type: "ref",
2489
+ node,
2490
+ decl: decls,
2491
+ mayThrow,
2492
+ };
2493
+ }
2452
2494
  case "VariableDeclarator": {
2453
2495
  const decl = findDecl(node.id.type === "BinaryExpression" ? node.id.left : node.id);
2454
2496
  if (decl) {
@@ -2496,8 +2538,10 @@ function buildPREGraph(state, func) {
2496
2538
  }
2497
2539
  case "CallExpression": {
2498
2540
  liveDef(null, stmt);
2499
- const [, results] = state.lookup(node.callee);
2500
- const callees = results ? findCallees(results) : null;
2541
+ const [, results] = state.lookupNonlocal(node.callee);
2542
+ const callees = results
2543
+ ? findCallees(results)
2544
+ : findCalleesByNode(state, node.callee);
2501
2545
  return { type: "mod", node, mayThrow, callees };
2502
2546
  }
2503
2547
  default:
@@ -2512,67 +2556,193 @@ function buildPREGraph(state, func) {
2512
2556
  }),
2513
2557
  };
2514
2558
  }
2515
- function anticipatedDecls() {
2516
- return new Map();
2517
- }
2518
- function equalSet(a, b) {
2519
- if (a.size != b.size)
2520
- return false;
2521
- for (const item of a) {
2522
- if (!b.has(item))
2523
- return false;
2524
- }
2525
- return true;
2526
- }
2527
- function equalMap(a, b) {
2528
- if (a.size != b.size)
2529
- return false;
2530
- for (const [item, value] of a) {
2531
- if (b.get(item) !== value)
2532
- return false;
2559
+ class data_flow_DataflowQueue {
2560
+ constructor() {
2561
+ this.enqueued = new Set();
2562
+ this.queue = new PriorityQueue((b, a) => (a.order || 0) - (b.order || 0));
2533
2563
  }
2534
- return true;
2535
- }
2536
- function anticipatedState(node, events) {
2537
- return { ant: events || new Set(), live: true, node, members: new Map() };
2538
- }
2539
- function cloneAnticipatedState(as) {
2540
- return {
2541
- ant: cloneSet(as.ant),
2542
- live: as.live,
2543
- node: as.node,
2544
- members: new Map(as.members),
2545
- };
2546
- }
2547
- function mergeAnticipatedState(ae, be) {
2548
- mergeSet(ae.ant, be.ant);
2549
- be.members.forEach((live, block) => ae.members.set(block, live));
2550
- if (be.live)
2551
- ae.live = true;
2552
- }
2553
- function cloneAnticipatedDecls(ad) {
2554
- const copy = anticipatedDecls();
2555
- for (const [k, v] of ad) {
2556
- if (!v.isIsolated) {
2557
- copy.set(k, cloneAnticipatedState(v));
2564
+ enqueue(block) {
2565
+ if (!this.enqueued.has(block)) {
2566
+ this.enqueued.add(block);
2567
+ this.queue.enq(block);
2558
2568
  }
2559
2569
  }
2560
- return copy;
2561
- }
2562
- function mergeAnticipatedDecls(a, b) {
2563
- for (const [k, v] of b) {
2564
- if (v.isIsolated)
2565
- continue;
2566
- const ae = a.get(k);
2567
- if (ae) {
2568
- mergeAnticipatedState(ae, v);
2569
- }
2570
- else {
2571
- a.set(k, cloneAnticipatedState(v));
2572
- }
2570
+ dequeue() {
2571
+ const block = this.queue.deq();
2572
+ this.enqueued.delete(block);
2573
+ return block;
2574
+ }
2575
+ empty() {
2576
+ return this.queue.isEmpty();
2573
2577
  }
2574
2578
  }
2575
- function equalStates(a, b) {
2579
+
2580
+ ;// CONCATENATED MODULE: ./src/pre.ts
2581
+
2582
+
2583
+
2584
+
2585
+
2586
+
2587
+ /**
2588
+ * This implements a pseudo Partial Redundancy Elimination
2589
+ * pass. It isn't quite like traditional PRE because we're
2590
+ * aiming to minimize size, not dynamic instructions. So
2591
+ * for us, its worthwhile to take something like:
2592
+ *
2593
+ * switch (x) {
2594
+ * case 1: foo(A.B); break;
2595
+ * case 2: foo(C); break;
2596
+ * case 3: bar(A.B); break;
2597
+ * }
2598
+ *
2599
+ * and rewrite it as
2600
+ *
2601
+ * var tmp = A.B;
2602
+ * switch (x) {
2603
+ * case 1: foo(tmp); break;
2604
+ * case 2: foo(C); break;
2605
+ * case 3: bar(tmp); break;
2606
+ * }
2607
+ *
2608
+ * because even though A.B wasn't used on all paths where we
2609
+ * inserted the temporary, we still reduced the code size.
2610
+ */
2611
+ const logging = false;
2612
+ function logAntState(s, decl) {
2613
+ const defs = Array.from(s.ant).reduce((defs, event) => {
2614
+ if (event.type === "def" || event.type === "mod")
2615
+ defs++;
2616
+ return defs;
2617
+ }, 0);
2618
+ console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
2619
+ console.log(` - members: ${Array.from(s.members)
2620
+ .map(([block, live]) => block.order + (live ? "t" : "f"))
2621
+ .join(", ")}`);
2622
+ }
2623
+ function logAntDecls(antDecls) {
2624
+ antDecls.forEach(logAntState);
2625
+ }
2626
+ function pre_sizeBasedPRE(state, func) {
2627
+ if (!func.node.body)
2628
+ return;
2629
+ if (!state.config ||
2630
+ !state.config.sizeBasedPRE ||
2631
+ (typeof state.config.sizeBasedPRE === "string" &&
2632
+ state.config.sizeBasedPRE !== func.fullName)) {
2633
+ return;
2634
+ }
2635
+ const { graph: head, identifiers } = buildPREGraph(state, func);
2636
+ const candidates = computeAttributes(state, head);
2637
+ if (candidates) {
2638
+ if (logging) {
2639
+ console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
2640
+ logAntDecls(candidates);
2641
+ }
2642
+ const nodeMap = new Map();
2643
+ const declMap = new Map();
2644
+ const variableDecl = withLoc({
2645
+ type: "VariableDeclaration",
2646
+ declarations: [],
2647
+ kind: "var",
2648
+ }, func.node.body);
2649
+ variableDecl.end = variableDecl.start;
2650
+ variableDecl.loc.end = variableDecl.loc.start;
2651
+ candidates.forEach((s, decl) => {
2652
+ let name;
2653
+ let i = 0;
2654
+ do {
2655
+ name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
2656
+ if (!identifiers.has(name)) {
2657
+ identifiers.add(name);
2658
+ break;
2659
+ }
2660
+ i++;
2661
+ } while (true);
2662
+ declMap.set(decl, name);
2663
+ variableDecl.declarations.push(withLoc({
2664
+ type: "VariableDeclarator",
2665
+ id: withLoc({ type: "Identifier", name }, variableDecl),
2666
+ kind: "var",
2667
+ }, variableDecl));
2668
+ s.ant.forEach((event) => {
2669
+ const events = nodeMap.get(event.node);
2670
+ if (!events) {
2671
+ nodeMap.set(event.node, [event]);
2672
+ }
2673
+ else {
2674
+ events.push(event);
2675
+ }
2676
+ });
2677
+ });
2678
+ applyReplacements(func.node, nodeMap, declMap);
2679
+ func.node.body.body.unshift(variableDecl);
2680
+ }
2681
+ }
2682
+ function buildPREGraph(state, func) {
2683
+ return buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
2684
+ }
2685
+ function anticipatedDecls() {
2686
+ return new Map();
2687
+ }
2688
+ function equalSet(a, b) {
2689
+ if (a.size != b.size)
2690
+ return false;
2691
+ for (const item of a) {
2692
+ if (!b.has(item))
2693
+ return false;
2694
+ }
2695
+ return true;
2696
+ }
2697
+ function equalMap(a, b) {
2698
+ if (a.size != b.size)
2699
+ return false;
2700
+ for (const [item, value] of a) {
2701
+ if (b.get(item) !== value)
2702
+ return false;
2703
+ }
2704
+ return true;
2705
+ }
2706
+ function anticipatedState(node, events) {
2707
+ return { ant: events || new Set(), live: true, node, members: new Map() };
2708
+ }
2709
+ function cloneAnticipatedState(as) {
2710
+ return {
2711
+ ant: cloneSet(as.ant),
2712
+ live: as.live,
2713
+ node: as.node,
2714
+ members: new Map(as.members),
2715
+ };
2716
+ }
2717
+ function mergeAnticipatedState(ae, be) {
2718
+ mergeSet(ae.ant, be.ant);
2719
+ be.members.forEach((live, block) => ae.members.set(block, live));
2720
+ if (be.live)
2721
+ ae.live = true;
2722
+ }
2723
+ function cloneAnticipatedDecls(ad) {
2724
+ const copy = anticipatedDecls();
2725
+ for (const [k, v] of ad) {
2726
+ if (!v.isIsolated) {
2727
+ copy.set(k, cloneAnticipatedState(v));
2728
+ }
2729
+ }
2730
+ return copy;
2731
+ }
2732
+ function mergeAnticipatedDecls(a, b) {
2733
+ for (const [k, v] of b) {
2734
+ if (v.isIsolated)
2735
+ continue;
2736
+ const ae = a.get(k);
2737
+ if (ae) {
2738
+ mergeAnticipatedState(ae, v);
2739
+ }
2740
+ else {
2741
+ a.set(k, cloneAnticipatedState(v));
2742
+ }
2743
+ }
2744
+ }
2745
+ function equalStates(a, b) {
2576
2746
  if (a.size !== b.size)
2577
2747
  return false;
2578
2748
  for (const [k, ae] of a) {
@@ -2667,26 +2837,18 @@ function computeAttributes(state, head) {
2667
2837
  .join(", ")}`);
2668
2838
  if (block.events) {
2669
2839
  block.events.forEach((event) => event.type !== "exn" &&
2670
- console.log(` ${event.type}: ${event.decl ? declFullName(event.decl) : "??"}`));
2840
+ console.log(` ${event.type}: ${event.decl
2841
+ ? declFullName(event.decl)
2842
+ : event.node
2843
+ ? formatAst(event.node)
2844
+ : "??"}`));
2671
2845
  }
2672
2846
  console.log(`Succs: ${(block.succs || [])
2673
2847
  .map((block) => block.order)
2674
2848
  .join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
2675
2849
  });
2676
2850
  }
2677
- const enqueued = new Set();
2678
- const queue = new PriorityQueue((b, a) => (a.order || 0) - (b.order || 0));
2679
- const enqueue = (block) => {
2680
- if (!enqueued.has(block)) {
2681
- enqueued.add(block);
2682
- queue.enq(block);
2683
- }
2684
- };
2685
- const dequeue = () => {
2686
- const block = queue.deq();
2687
- enqueued.delete(block);
2688
- return block;
2689
- };
2851
+ const queue = new DataflowQueue();
2690
2852
  const blockStates = [];
2691
2853
  /*
2692
2854
  Algorithm
@@ -2720,9 +2882,9 @@ function computeAttributes(state, head) {
2720
2882
  }
2721
2883
  return result;
2722
2884
  };
2723
- order.forEach((block) => enqueue(block));
2724
- while (queue.size()) {
2725
- const top = dequeue();
2885
+ order.forEach((block) => queue.enqueue(block));
2886
+ while (!queue.empty()) {
2887
+ const top = queue.dequeue();
2726
2888
  if (top.order === undefined) {
2727
2889
  throw new Error(`Unreachable block was visited!`);
2728
2890
  }
@@ -2761,13 +2923,13 @@ function computeAttributes(state, head) {
2761
2923
  break;
2762
2924
  }
2763
2925
  case "mod": {
2764
- curState.forEach((candidates, decl) => {
2765
- if (decl.type === "VariableDeclarator" &&
2926
+ curState.forEach((candidates, decls) => {
2927
+ if (some(decls, (decl) => decl.type === "VariableDeclarator" &&
2766
2928
  decl.node.kind === "var" &&
2767
2929
  candidates.live &&
2768
2930
  (!event.callees ||
2769
- event.callees.some((callee) => functionMayModify(state, callee, decl)))) {
2770
- candidates.ant.add(getMod(event, decl, candidates.node));
2931
+ event.callees.some((callee) => functionMayModify(state, callee, decl))))) {
2932
+ candidates.ant.add(getMod(event, decls, candidates.node));
2771
2933
  candidates.live = false;
2772
2934
  }
2773
2935
  });
@@ -2819,7 +2981,7 @@ function computeAttributes(state, head) {
2819
2981
  logAntDecls(curState);
2820
2982
  }
2821
2983
  if (top.preds) {
2822
- top.preds.forEach((pred) => enqueue(pred));
2984
+ top.preds.forEach((pred) => queue.enqueue(pred));
2823
2985
  }
2824
2986
  }
2825
2987
  const candidateDecls = anticipatedDecls();
@@ -3658,8 +3820,21 @@ function replacementLiteral(arg, value, type) {
3658
3820
  else if (type === "Double") {
3659
3821
  raw += "d";
3660
3822
  }
3661
- else if (type === "Float" && prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
3662
- raw += "f";
3823
+ else if (type === "Float") {
3824
+ if (prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
3825
+ raw += "f";
3826
+ }
3827
+ else {
3828
+ const match = raw.match(/^(-)?(\d*)\.(\d+)(e\d+)?/);
3829
+ if (match && match[2].length + match[3].length > 9) {
3830
+ for (let l = 9 - match[2].length; l > 0; l--) {
3831
+ const s = `${match[1] || ""}${match[2]}.${match[3].substring(0, l)}${match[4] || ""}`;
3832
+ if (value !== roundToFloat(parseFloat(s)))
3833
+ break;
3834
+ raw = s;
3835
+ }
3836
+ }
3837
+ }
3663
3838
  }
3664
3839
  const { start, end, loc } = arg;
3665
3840
  return {
@@ -3747,6 +3922,20 @@ function shift_mod_types(left, right) {
3747
3922
  }
3748
3923
  return result;
3749
3924
  }
3925
+ function equalsFn(left, right) {
3926
+ const lt = typeof left;
3927
+ const rt = typeof right;
3928
+ return lt === "string" || rt === "string"
3929
+ ? // two string literals will compare unequal, becuase string
3930
+ // equality is object equality.
3931
+ false
3932
+ : (lt === "number" || lt === "bigint") &&
3933
+ (rt === "number" || rt === "bigint")
3934
+ ? // numeric types are compared for value equality
3935
+ left == right
3936
+ : // otherwise types and values must match
3937
+ left === right;
3938
+ }
3750
3939
  const operators = {
3751
3940
  "+": {
3752
3941
  typeFn: plus_types,
@@ -3798,14 +3987,11 @@ const operators = {
3798
3987
  },
3799
3988
  "==": {
3800
3989
  typeFn: () => ["Boolean", (v) => v],
3801
- valueFn: (left, right) =>
3802
- // two string literals will compare unequal, becuase string
3803
- // equality is object equality.
3804
- typeof left === "string" ? false : left === right,
3990
+ valueFn: equalsFn,
3805
3991
  },
3806
3992
  "!=": {
3807
3993
  typeFn: () => ["Boolean", (v) => v],
3808
- valueFn: (left, right) => typeof left === "string" ? true : left !== right,
3994
+ valueFn: (left, right) => !equalsFn(left, right),
3809
3995
  },
3810
3996
  "<=": {
3811
3997
  typeFn: common_arith_types,
@@ -4332,7 +4518,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
4332
4518
  if (!state.currentFunction) {
4333
4519
  throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
4334
4520
  }
4335
- state.currentFunction.info = state.currentFunction.next_info;
4521
+ state.currentFunction.info = state.currentFunction.next_info || false;
4336
4522
  delete state.currentFunction.next_info;
4337
4523
  delete state.currentFunction;
4338
4524
  break;
@@ -4987,31 +5173,6 @@ function add_resources_to_ast(state, ast, resources, manifestXML) {
4987
5173
  });
4988
5174
  });
4989
5175
  }
4990
- function makeIdentifier(name, loc) {
4991
- return wrap({ type: "Identifier", name }, loc);
4992
- }
4993
- function makeMemberExpression(object, property) {
4994
- return wrap({
4995
- type: "MemberExpression",
4996
- object,
4997
- property,
4998
- computed: false,
4999
- }, object.loc && locRange(object.loc, property.loc));
5000
- }
5001
- function makeScopedName(dotted, l) {
5002
- const loc = l && adjustLoc(l, 0, l.start.offset - l.end.offset);
5003
- return dotted.split(/\s*\.\s*/).reduce(({ cur, offset }, next) => {
5004
- const id = makeIdentifier(next, loc && adjustLoc(loc, offset, offset + next.length));
5005
- if (!cur) {
5006
- cur = id;
5007
- }
5008
- else {
5009
- cur = makeMemberExpression(cur, id);
5010
- }
5011
- offset += next.length + 1;
5012
- return { cur, offset };
5013
- }, { cur: null, offset: 0 }).cur;
5014
- }
5015
5176
  const drawableSkips = {
5016
5177
  x: { center: true, left: true, right: true, start: true },
5017
5178
  y: { center: true, top: true, bottom: true, start: true },
@@ -5051,10 +5212,8 @@ function visit_resource_refs(state, doc, e) {
5051
5212
  if (ast_hasProperty(skip, name)) {
5052
5213
  return;
5053
5214
  }
5054
- if (/^([\w_$]+\s*\.\s*)*[\w_$]+$/.test(name)) {
5055
- const dn = makeScopedName(name, loc);
5056
- if (dn)
5057
- result.push(dn);
5215
+ if (/^([-\w_$]+\s*\.\s*)*[-\w_$]+$/.test(name)) {
5216
+ result.push(makeScopedName(name, loc));
5058
5217
  return;
5059
5218
  }
5060
5219
  // We wrap the expression in parentheses, so adjust
@@ -5154,37 +5313,6 @@ function visit_resource_refs(state, doc, e) {
5154
5313
  });
5155
5314
  return result;
5156
5315
  }
5157
- function wrap(node, loc) {
5158
- if (loc) {
5159
- node.loc = loc;
5160
- node.start = loc.start.offset;
5161
- node.end = loc.end.offset;
5162
- }
5163
- return node;
5164
- }
5165
- function locRange(start, end) {
5166
- return {
5167
- source: start.source || end.source,
5168
- start: start.start,
5169
- end: end.end,
5170
- };
5171
- }
5172
- function adjustLoc(loc, start = 1, end = -1) {
5173
- /* Attributes are quoted, so skip the quotes */
5174
- return {
5175
- source: loc.source,
5176
- start: {
5177
- offset: loc.start.offset + start,
5178
- line: loc.start.line,
5179
- column: loc.start.column + start,
5180
- },
5181
- end: {
5182
- offset: loc.end.offset + end,
5183
- line: loc.end.line,
5184
- column: loc.end.column + end,
5185
- },
5186
- };
5187
- }
5188
5316
  function add_one_resource(state, doc, module, e) {
5189
5317
  let id;
5190
5318
  let func;
@@ -5196,7 +5324,20 @@ function add_one_resource(state, doc, module, e) {
5196
5324
  wrap({
5197
5325
  type: "VariableDeclarator",
5198
5326
  kind: "var",
5199
- id: makeIdentifier(id ? id.value.value : "*invalid*", loc),
5327
+ id: {
5328
+ type: "BinaryExpression",
5329
+ operator: "as",
5330
+ left: makeIdentifier(id ? id.value.value : "*invalid*", loc),
5331
+ right: {
5332
+ type: "TypeSpecList",
5333
+ ts: [
5334
+ {
5335
+ type: "TypeSpecPart",
5336
+ name: makeIdentifier("Symbol"),
5337
+ },
5338
+ ],
5339
+ },
5340
+ },
5200
5341
  init,
5201
5342
  }, e.loc),
5202
5343
  ],
@@ -5218,19 +5359,75 @@ function add_one_resource(state, doc, module, e) {
5218
5359
  loc: e.loc,
5219
5360
  };
5220
5361
  };
5362
+ const layoutDecl = () => {
5363
+ if (!id)
5364
+ return null;
5365
+ const loc = id.value.loc;
5366
+ const items = init ? [varDecl()] : [];
5367
+ return {
5368
+ type: "FunctionDeclaration",
5369
+ body: { type: "BlockStatement", body: items, loc: e.loc },
5370
+ id: makeIdentifier(id.value.value, loc),
5371
+ params: [
5372
+ {
5373
+ type: "BinaryExpression",
5374
+ operator: "as",
5375
+ left: makeIdentifier("dc"),
5376
+ right: {
5377
+ type: "TypeSpecList",
5378
+ ts: [
5379
+ {
5380
+ type: "TypeSpecPart",
5381
+ name: makeScopedName("Graphics.Dc"),
5382
+ },
5383
+ ],
5384
+ },
5385
+ },
5386
+ ],
5387
+ returnType: {
5388
+ type: "UnaryExpression",
5389
+ operator: " as",
5390
+ prefix: true,
5391
+ argument: {
5392
+ type: "TypeSpecList",
5393
+ ts: [
5394
+ {
5395
+ type: "TypeSpecPart",
5396
+ name: makeScopedName("$.Toybox.Lang.Array"),
5397
+ generics: [
5398
+ {
5399
+ type: "TypeSpecList",
5400
+ ts: [
5401
+ {
5402
+ type: "TypeSpecPart",
5403
+ name: makeScopedName("$.Toybox.WatchUi.Drawable"),
5404
+ },
5405
+ ],
5406
+ },
5407
+ ],
5408
+ },
5409
+ ],
5410
+ },
5411
+ },
5412
+ loc: e.loc,
5413
+ };
5414
+ };
5221
5415
  switch (e.name) {
5222
5416
  case "font":
5223
5417
  case "string":
5224
5418
  case "jsonData":
5225
5419
  case "animation":
5226
5420
  case "bitmap":
5227
- case "layout":
5228
5421
  case "drawable-list":
5229
5422
  case "property":
5230
5423
  case "fitField":
5231
5424
  id = e.attr.id;
5232
5425
  func = varDecl;
5233
5426
  break;
5427
+ case "layout":
5428
+ id = e.attr.id;
5429
+ func = layoutDecl;
5430
+ break;
5234
5431
  case "menu":
5235
5432
  id = e.attr.id;
5236
5433
  func = () => classDecl("Ui.Menu");
@@ -5820,387 +6017,423 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
5820
6017
  }
5821
6018
  return [false, false];
5822
6019
  }
5823
- function api_collectNamespaces(ast, stateIn) {
5824
- const state = (stateIn || {});
5825
- if (!state.nextExposed)
5826
- state.nextExposed = {};
5827
- if (!state.index)
5828
- state.index = {};
5829
- if (!state.stack) {
5830
- state.stack = [
5831
- {
5832
- type: "Program",
5833
- name: "$",
5834
- fullName: "$",
5835
- node: undefined,
5836
- attributes: 0,
5837
- },
5838
- ];
5839
- }
5840
- if (!state.lookupRules) {
5841
- const rules = state?.config?.compilerLookupRules || "DEFAULT";
5842
- if (rules !== "COMPILER1" && rules !== "COMPILER2") {
5843
- const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
5844
- if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
5845
- state.lookupRules = "COMPILER2";
5846
- }
5847
- else {
5848
- state.lookupRules = "COMPILER1";
5849
- }
5850
- }
5851
- }
5852
- state.removeNodeComments = (node, ast) => {
5853
- if (node.start && node.end && ast.comments && ast.comments.length) {
5854
- let low = 0, high = ast.comments.length;
5855
- while (high > low) {
5856
- const mid = (low + high) >> 1;
5857
- if ((ast.comments[mid].start || 0) < node.start) {
5858
- low = mid + 1;
6020
+ function stateFuncs() {
6021
+ let currentEnum = null;
6022
+ return {
6023
+ removeNodeComments(node, ast) {
6024
+ if (node.start && node.end && ast.comments && ast.comments.length) {
6025
+ let low = 0, high = ast.comments.length;
6026
+ while (high > low) {
6027
+ const mid = (low + high) >> 1;
6028
+ if ((ast.comments[mid].start || 0) < node.start) {
6029
+ low = mid + 1;
6030
+ }
6031
+ else {
6032
+ high = mid;
6033
+ }
5859
6034
  }
5860
- else {
5861
- high = mid;
6035
+ while (high < ast.comments.length &&
6036
+ (ast.comments[high].end || 0) < node.end) {
6037
+ high++;
6038
+ }
6039
+ if (high > low) {
6040
+ ast.comments.splice(low, high - low);
5862
6041
  }
5863
6042
  }
5864
- while (high < ast.comments.length &&
5865
- (ast.comments[high].end || 0) < node.end) {
5866
- high++;
5867
- }
5868
- if (high > low) {
5869
- ast.comments.splice(low, high - low);
5870
- }
5871
- }
5872
- };
5873
- state.lookup = (node, name, stack) => lookup(state, state.inType ? "type_decls" : "decls", node, name, stack);
5874
- state.lookupNonlocal = (node, name, stack) => lookup(state, "decls", node, name, stack, true);
5875
- state.lookupValue = (node, name, stack) => lookup(state, "decls", node, name, stack);
5876
- state.lookupType = (node, name, stack) => lookup(state, "type_decls", node, name, stack);
5877
- state.stackClone = () => state.stack.map((elm) => elm.type === "ModuleDeclaration" || elm.type === "Program"
5878
- ? { ...elm }
5879
- : elm);
5880
- state.inType = 0;
5881
- state.traverse = (root) => ast_traverseAst(root, (node) => {
5882
- try {
5883
- if (state.shouldExclude && state.shouldExclude(node)) {
5884
- // don't visit any children, but do call post
5885
- return [];
5886
- }
5887
- switch (node.type) {
5888
- case "UnaryExpression":
5889
- if (node.operator === ":" && !state.inType) {
5890
- state.nextExposed[node.argument.name] = true;
5891
- }
5892
- break;
5893
- case "AttributeList":
5894
- return [];
5895
- case "Program":
5896
- if (state.stack.length != 1) {
5897
- throw new Error("Unexpected stack length for Program node");
6043
+ },
6044
+ lookup(node, name, stack) {
6045
+ return lookup(this, this.inType ? "type_decls" : "decls", node, name, stack);
6046
+ },
6047
+ lookupNonlocal(node, name, stack) {
6048
+ return lookup(this, "decls", node, name, stack, true);
6049
+ },
6050
+ lookupValue(node, name, stack) {
6051
+ return lookup(this, "decls", node, name, stack);
6052
+ },
6053
+ lookupType(node, name, stack) {
6054
+ return lookup(this, "type_decls", node, name, stack);
6055
+ },
6056
+ stackClone() {
6057
+ return this.stack.map((elm) => elm.type === "ModuleDeclaration" || elm.type === "Program"
6058
+ ? { ...elm }
6059
+ : elm);
6060
+ },
6061
+ traverse(root) {
6062
+ return ast_traverseAst(root, (node) => {
6063
+ try {
6064
+ if (this.shouldExclude && this.shouldExclude(node)) {
6065
+ // don't visit any children, but do call post
6066
+ return [];
5898
6067
  }
5899
- state.stack[0].node = node;
5900
- break;
5901
- case "TypeSpecList":
5902
- case "TypeSpecPart":
5903
- state.inType++;
5904
- break;
5905
- case "ImportModule":
5906
- case "Using": {
5907
- const [parent] = state.stack.slice(-1);
5908
- if (!parent.usings) {
5909
- parent.usings = {};
5910
- }
5911
- const name = (node.type === "Using" && node.as && node.as.name) ||
5912
- (node.id.type === "Identifier"
5913
- ? node.id.name
5914
- : node.id.property.name);
5915
- const using = { node };
5916
- parent.usings[name] = using;
5917
- if (node.type == "ImportModule") {
5918
- if (!parent.imports) {
5919
- parent.imports = [using];
6068
+ switch (node.type) {
6069
+ case "MemberExpression": {
6070
+ if (api_isLookupCandidate(node)) {
6071
+ return (this.pre && this.pre(node, this)) || ["object"];
6072
+ }
6073
+ break;
5920
6074
  }
5921
- else {
5922
- const index = parent.imports.findIndex((using) => (using.node.id.type === "Identifier"
5923
- ? using.node.id.name
5924
- : using.node.id.property.name) === name);
5925
- if (index >= 0)
5926
- parent.imports.splice(index, 1);
5927
- parent.imports.push(using);
6075
+ case "UnaryExpression":
6076
+ if (node.operator === ":" && !this.inType) {
6077
+ this.nextExposed[node.argument.name] = true;
6078
+ }
6079
+ break;
6080
+ case "AttributeList":
6081
+ return [];
6082
+ case "Program":
6083
+ if (this.stack.length != 1) {
6084
+ throw new Error("Unexpected stack length for Program node");
6085
+ }
6086
+ this.stack[0].node = node;
6087
+ break;
6088
+ case "TypeSpecList":
6089
+ case "TypeSpecPart":
6090
+ this.inType++;
6091
+ break;
6092
+ case "ImportModule":
6093
+ case "Using": {
6094
+ const [parent] = this.stack.slice(-1);
6095
+ if (!parent.usings) {
6096
+ parent.usings = {};
6097
+ }
6098
+ const name = (node.type === "Using" && node.as && node.as.name) ||
6099
+ (node.id.type === "Identifier"
6100
+ ? node.id.name
6101
+ : node.id.property.name);
6102
+ const using = { node };
6103
+ parent.usings[name] = using;
6104
+ if (node.type == "ImportModule") {
6105
+ if (!parent.imports) {
6106
+ parent.imports = [using];
6107
+ }
6108
+ else {
6109
+ const index = parent.imports.findIndex((using) => (using.node.id.type === "Identifier"
6110
+ ? using.node.id.name
6111
+ : using.node.id.property.name) === name);
6112
+ if (index >= 0)
6113
+ parent.imports.splice(index, 1);
6114
+ parent.imports.push(using);
6115
+ }
6116
+ }
6117
+ break;
5928
6118
  }
5929
- }
5930
- break;
5931
- }
5932
- case "CatchClause":
5933
- if (node.param) {
5934
- const [parent] = state.stack.slice(-1);
5935
- if (!parent.decls)
5936
- parent.decls = {};
5937
- const id = node.param.type === "Identifier"
5938
- ? node.param
5939
- : node.param.left;
5940
- state.stack.push({
5941
- type: "BlockStatement",
5942
- fullName: undefined,
5943
- name: undefined,
5944
- node: node.body,
5945
- decls: { [id.name]: [id] },
5946
- attributes: 0,
5947
- });
5948
- }
5949
- break;
5950
- case "ForStatement":
5951
- if (node.init && node.init.type === "VariableDeclaration") {
5952
- state.stack.push({
5953
- type: "BlockStatement",
5954
- fullName: undefined,
5955
- name: undefined,
5956
- node: node,
5957
- attributes: 0,
5958
- });
5959
- }
5960
- break;
5961
- case "BlockStatement": {
5962
- const [parent] = state.stack.slice(-1);
5963
- if (parent.node === node ||
5964
- (parent.type != "FunctionDeclaration" &&
5965
- parent.type != "BlockStatement")) {
5966
- break;
5967
- }
5968
- // fall through
5969
- }
5970
- case "ClassDeclaration":
5971
- case "FunctionDeclaration":
5972
- case "ModuleDeclaration": {
5973
- const [parent] = state.stack.slice(-1);
5974
- const name = "id" in node ? node.id && node.id.name : undefined;
5975
- const fullName = state.stack
5976
- .map((e) => e.name)
5977
- .concat(name)
5978
- .filter((e) => e != null)
5979
- .join(".");
5980
- const elm = {
5981
- type: node.type,
5982
- name,
5983
- fullName,
5984
- node,
5985
- attributes: node.type === "BlockStatement"
5986
- ? 0
5987
- : stateNodeAttrs(node.attrs),
5988
- };
5989
- state.stack.push(elm);
5990
- if (name) {
5991
- if (!parent.decls)
5992
- parent.decls = {};
5993
- if (ast_hasProperty(parent.decls, name)) {
5994
- const what = node.type == "ModuleDeclaration" ? "type" : "node";
5995
- const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
5996
- if (e != null) {
5997
- e.node = node;
5998
- state.stack.splice(-1, 1, e);
6119
+ case "CatchClause":
6120
+ if (node.param) {
6121
+ const [parent] = this.stack.slice(-1);
6122
+ if (!parent.decls)
6123
+ parent.decls = {};
6124
+ const id = node.param.type === "Identifier"
6125
+ ? node.param
6126
+ : node.param.left;
6127
+ this.stack.push({
6128
+ type: "BlockStatement",
6129
+ fullName: undefined,
6130
+ name: undefined,
6131
+ node: node.body,
6132
+ decls: { [id.name]: [id] },
6133
+ attributes: 0,
6134
+ });
6135
+ }
6136
+ break;
6137
+ case "ForStatement":
6138
+ if (node.init && node.init.type === "VariableDeclaration") {
6139
+ this.stack.push({
6140
+ type: "BlockStatement",
6141
+ fullName: undefined,
6142
+ name: undefined,
6143
+ node: node,
6144
+ attributes: 0,
6145
+ });
6146
+ }
6147
+ break;
6148
+ case "BlockStatement": {
6149
+ const [parent] = this.stack.slice(-1);
6150
+ if (parent.node === node ||
6151
+ (parent.type != "FunctionDeclaration" &&
6152
+ parent.type != "BlockStatement")) {
5999
6153
  break;
6000
6154
  }
6155
+ // fall through
6001
6156
  }
6002
- else {
6003
- parent.decls[name] = [];
6157
+ case "ClassDeclaration":
6158
+ case "FunctionDeclaration":
6159
+ case "ModuleDeclaration": {
6160
+ const [parent] = this.stack.slice(-1);
6161
+ const name = "id" in node ? node.id && node.id.name : undefined;
6162
+ const fullName = this.stack
6163
+ .map((e) => e.name)
6164
+ .concat(name)
6165
+ .filter((e) => e != null)
6166
+ .join(".");
6167
+ const elm = {
6168
+ type: node.type,
6169
+ name,
6170
+ fullName,
6171
+ node,
6172
+ attributes: node.type === "BlockStatement"
6173
+ ? 0
6174
+ : stateNodeAttrs(node.attrs),
6175
+ };
6176
+ this.stack.push(elm);
6177
+ if (name) {
6178
+ if (!parent.decls)
6179
+ parent.decls = {};
6180
+ if (ast_hasProperty(parent.decls, name)) {
6181
+ const what = node.type == "ModuleDeclaration" ? "type" : "node";
6182
+ const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
6183
+ if (e != null) {
6184
+ e.node = node;
6185
+ this.stack.splice(-1, 1, e);
6186
+ break;
6187
+ }
6188
+ }
6189
+ else {
6190
+ parent.decls[name] = [];
6191
+ }
6192
+ if (node.type === "FunctionDeclaration" &&
6193
+ node.params &&
6194
+ node.params.length) {
6195
+ const decls = (elm.decls = {});
6196
+ node.params.forEach((p) => (decls[api_variableDeclarationName(p)] = [p]));
6197
+ }
6198
+ parent.decls[name].push(elm);
6199
+ if (node.type == "ModuleDeclaration" ||
6200
+ node.type == "ClassDeclaration") {
6201
+ if (!parent.type_decls)
6202
+ parent.type_decls = {};
6203
+ if (!ast_hasProperty(parent.type_decls, name)) {
6204
+ parent.type_decls[name] = [];
6205
+ }
6206
+ parent.type_decls[name].push(elm);
6207
+ }
6208
+ break;
6209
+ }
6210
+ break;
6004
6211
  }
6005
- if (node.type === "FunctionDeclaration" &&
6006
- node.params &&
6007
- node.params.length) {
6008
- const decls = (elm.decls = {});
6009
- node.params.forEach((p) => (decls[api_variableDeclarationName(p)] = [p]));
6212
+ // an EnumDeclaration doesn't create a scope, but
6213
+ // it does create a type (if it has a name)
6214
+ case "EnumDeclaration": {
6215
+ if (!node.id) {
6216
+ this.inType++;
6217
+ break;
6218
+ }
6219
+ const [parent] = this.stack.slice(-1);
6220
+ const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
6221
+ node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
6010
6222
  }
6011
- parent.decls[name].push(elm);
6012
- if (node.type == "ModuleDeclaration" ||
6013
- node.type == "ClassDeclaration") {
6223
+ // fall through
6224
+ case "TypedefDeclaration": {
6225
+ this.inType++;
6226
+ const name = node.id.name;
6227
+ const [parent] = this.stack.slice(-1);
6014
6228
  if (!parent.type_decls)
6015
6229
  parent.type_decls = {};
6016
6230
  if (!ast_hasProperty(parent.type_decls, name)) {
6017
6231
  parent.type_decls[name] = [];
6018
6232
  }
6019
- parent.type_decls[name].push(elm);
6233
+ else if (parent.type_decls[name].find((n) => (api_isStateNode(n) ? n.node : n) === node)) {
6234
+ break;
6235
+ }
6236
+ const decl = {
6237
+ type: node.type,
6238
+ node,
6239
+ name,
6240
+ fullName: parent.fullName + "." + name,
6241
+ attributes: stateNodeAttrs(node.attrs),
6242
+ stack: this.stack.slice(),
6243
+ };
6244
+ parent.type_decls[name].push(decl);
6245
+ if (decl.type === "EnumDeclaration") {
6246
+ currentEnum = decl;
6247
+ }
6248
+ break;
6249
+ }
6250
+ case "VariableDeclaration": {
6251
+ const [parent] = this.stack.slice(-1);
6252
+ if (!parent.decls)
6253
+ parent.decls = {};
6254
+ const decls = parent.decls;
6255
+ const stack = this.stackClone();
6256
+ node.declarations.forEach((decl) => {
6257
+ const name = api_variableDeclarationName(decl.id);
6258
+ if (!ast_hasProperty(decls, name)) {
6259
+ decls[name] = [];
6260
+ }
6261
+ else if (decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == decl)) {
6262
+ return;
6263
+ }
6264
+ decl.kind = node.kind;
6265
+ decls[name].push({
6266
+ type: "VariableDeclarator",
6267
+ node: decl,
6268
+ name,
6269
+ fullName: parent.fullName + "." + name,
6270
+ stack,
6271
+ attributes: stateNodeAttrs(node.attrs),
6272
+ });
6273
+ if (node.kind == "const") {
6274
+ if (!ast_hasProperty(this.index, name)) {
6275
+ this.index[name] = [];
6276
+ }
6277
+ (0,external_util_cjs_namespaceObject.pushUnique)(this.index[name], parent);
6278
+ }
6279
+ });
6280
+ break;
6281
+ }
6282
+ case "EnumStringBody": {
6283
+ if (this.inType !== 1) {
6284
+ throw new Error(`Expected inType to be 1 at EnumStringBody. Got ${this.inType}.`);
6285
+ }
6286
+ this.inType--;
6287
+ const [parent] = this.stack.slice(-1);
6288
+ const values = parent.decls || (parent.decls = {});
6289
+ let prev = -1;
6290
+ node.members.forEach((m, i) => {
6291
+ if (m.type == "Identifier") {
6292
+ if (typeof prev === "bigint") {
6293
+ prev += 1n;
6294
+ }
6295
+ else {
6296
+ prev += 1;
6297
+ }
6298
+ m = node.members[i] = {
6299
+ type: "EnumStringMember",
6300
+ loc: m.loc,
6301
+ start: m.start,
6302
+ end: m.end,
6303
+ id: m,
6304
+ init: {
6305
+ type: "Literal",
6306
+ value: prev,
6307
+ raw: prev.toString() +
6308
+ (typeof prev === "bigint" ? "l" : ""),
6309
+ enumType: m.enumType,
6310
+ loc: m.loc,
6311
+ start: m.start,
6312
+ end: m.end,
6313
+ },
6314
+ };
6315
+ }
6316
+ const name = m.id.name;
6317
+ const init = getLiteralNode(m.init);
6318
+ if (!init) {
6319
+ throw new Error("Unexpected enum initializer");
6320
+ }
6321
+ if (init != m.init) {
6322
+ if (m.init.enumType) {
6323
+ init.enumType = m.init.enumType;
6324
+ }
6325
+ m.init = init;
6326
+ }
6327
+ if (init.type == "Literal" &&
6328
+ init.raw &&
6329
+ prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
6330
+ prev = init.value;
6331
+ }
6332
+ if (!ast_hasProperty(values, name)) {
6333
+ values[name] = [];
6334
+ }
6335
+ if ((0,external_util_cjs_namespaceObject.pushUnique)(values[name], m) && currentEnum) {
6336
+ if (!this.enumMap)
6337
+ this.enumMap = new Map();
6338
+ this.enumMap.set(m, currentEnum);
6339
+ }
6340
+ if (!ast_hasProperty(this.index, name)) {
6341
+ this.index[name] = [];
6342
+ }
6343
+ (0,external_util_cjs_namespaceObject.pushUnique)(this.index[name], parent);
6344
+ });
6345
+ break;
6020
6346
  }
6021
6347
  }
6022
- break;
6348
+ if (this.pre)
6349
+ return this.pre(node, this);
6023
6350
  }
6024
- // an EnumDeclaration doesn't create a scope, but
6025
- // it does create a type (if it has a name)
6026
- case "EnumDeclaration": {
6027
- if (!node.id) {
6028
- state.inType++;
6029
- break;
6030
- }
6031
- const [parent] = state.stack.slice(-1);
6032
- const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
6033
- node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
6351
+ catch (e) {
6352
+ handleException(this, node, e);
6034
6353
  }
6035
- // fall through
6036
- case "TypedefDeclaration": {
6037
- state.inType++;
6038
- const name = node.id.name;
6039
- const [parent] = state.stack.slice(-1);
6040
- if (!parent.type_decls)
6041
- parent.type_decls = {};
6042
- if (!ast_hasProperty(parent.type_decls, name)) {
6043
- parent.type_decls[name] = [];
6044
- }
6045
- else if (parent.type_decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == node)) {
6046
- break;
6354
+ return null;
6355
+ }, (node) => {
6356
+ try {
6357
+ let ret;
6358
+ if (this.shouldExclude && this.shouldExclude(node)) {
6359
+ // delete the node.
6360
+ ret = false;
6047
6361
  }
6048
- parent.type_decls[name].push(node.type === "EnumDeclaration"
6049
- ? node
6050
- : {
6051
- type: "TypedefDeclaration",
6052
- node,
6053
- name,
6054
- fullName: parent.fullName + "." + name,
6055
- attributes: stateNodeAttrs(node.attrs),
6056
- });
6057
- break;
6058
- }
6059
- case "VariableDeclaration": {
6060
- const [parent] = state.stack.slice(-1);
6061
- if (!parent.decls)
6062
- parent.decls = {};
6063
- const decls = parent.decls;
6064
- const stack = state.stackClone();
6065
- node.declarations.forEach((decl) => {
6066
- const name = api_variableDeclarationName(decl.id);
6067
- if (!ast_hasProperty(decls, name)) {
6068
- decls[name] = [];
6069
- }
6070
- else if (decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == decl)) {
6071
- return;
6362
+ else {
6363
+ const type = node.type;
6364
+ if (this.post)
6365
+ ret = this.post(node, this);
6366
+ switch (type) {
6367
+ case "EnumDeclaration":
6368
+ currentEnum = null;
6369
+ // fall through
6370
+ case "TypeSpecPart":
6371
+ case "TypeSpecList":
6372
+ case "TypedefDeclaration":
6373
+ this.inType--;
6374
+ break;
6375
+ case "EnumStringBody":
6376
+ this.inType++;
6377
+ break;
6072
6378
  }
6073
- decl.kind = node.kind;
6074
- decls[name].push({
6075
- type: "VariableDeclarator",
6076
- node: decl,
6077
- name,
6078
- fullName: parent.fullName + "." + name,
6079
- stack,
6080
- attributes: stateNodeAttrs(node.attrs),
6081
- });
6082
- if (node.kind == "const") {
6083
- if (!ast_hasProperty(state.index, name)) {
6084
- state.index[name] = [];
6379
+ const [parent] = this.stack.slice(-1);
6380
+ if (parent.node === node ||
6381
+ // The pre function might cause node.body to be skipped,
6382
+ // so we need to check here, just in case.
6383
+ // (this actually happens with prettier-extenison-monkeyc's
6384
+ // findItemsByRange)
6385
+ (node.type === "CatchClause" && parent.node === node.body)) {
6386
+ delete parent.usings;
6387
+ delete parent.imports;
6388
+ if (node.type != "Program") {
6389
+ this.stack.pop();
6085
6390
  }
6086
- (0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
6087
6391
  }
6088
- });
6089
- break;
6392
+ }
6393
+ if (ret != null && node.loc && node.loc.source && this.fnMap) {
6394
+ const fnInfo = this.fnMap[node.loc.source];
6395
+ fnInfo && fnInfo.ast && this.removeNodeComments(node, fnInfo.ast);
6396
+ }
6397
+ return ret;
6090
6398
  }
6091
- case "EnumStringBody": {
6092
- if (state.inType !== 1) {
6093
- throw new Error(`Expected inType to be 1 at EnumStringBody. Got ${state.inType}.`);
6094
- }
6095
- state.inType--;
6096
- const [parent] = state.stack.slice(-1);
6097
- const values = parent.decls || (parent.decls = {});
6098
- let prev = -1;
6099
- node.members.forEach((m, i) => {
6100
- if (m.type == "Identifier") {
6101
- if (typeof prev === "bigint") {
6102
- prev += 1n;
6103
- }
6104
- else {
6105
- prev += 1;
6106
- }
6107
- m = node.members[i] = {
6108
- type: "EnumStringMember",
6109
- loc: m.loc,
6110
- start: m.start,
6111
- end: m.end,
6112
- id: m,
6113
- init: {
6114
- type: "Literal",
6115
- value: prev,
6116
- raw: prev.toString() + (typeof prev === "bigint" ? "l" : ""),
6117
- enumType: m.enumType,
6118
- loc: m.loc,
6119
- start: m.start,
6120
- end: m.end,
6121
- },
6122
- };
6123
- }
6124
- const name = m.id.name;
6125
- const init = getLiteralNode(m.init);
6126
- if (!init) {
6127
- throw new Error("Unexpected enum initializer");
6128
- }
6129
- if (init != m.init) {
6130
- if (m.init.enumType) {
6131
- init.enumType = m.init.enumType;
6132
- }
6133
- m.init = init;
6134
- }
6135
- if (init.type == "Literal" &&
6136
- init.raw &&
6137
- prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
6138
- prev = init.value;
6139
- }
6140
- if (!ast_hasProperty(values, name)) {
6141
- values[name] = [];
6142
- }
6143
- (0,external_util_cjs_namespaceObject.pushUnique)(values[name], m);
6144
- if (!ast_hasProperty(state.index, name)) {
6145
- state.index[name] = [];
6146
- }
6147
- (0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
6148
- });
6149
- break;
6399
+ catch (e) {
6400
+ handleException(this, node, e);
6150
6401
  }
6151
- }
6152
- if (state.pre)
6153
- return state.pre(node, state);
6154
- }
6155
- catch (e) {
6156
- handleException(state, node, e);
6157
- }
6158
- return null;
6159
- }, (node) => {
6160
- try {
6161
- let ret;
6162
- if (state.shouldExclude && state.shouldExclude(node)) {
6163
- // delete the node.
6164
- ret = false;
6402
+ });
6403
+ },
6404
+ };
6405
+ }
6406
+ function api_collectNamespaces(ast, stateIn) {
6407
+ const state = (stateIn || {});
6408
+ if (!state.nextExposed)
6409
+ state.nextExposed = {};
6410
+ if (!state.index)
6411
+ state.index = {};
6412
+ if (!state.stack) {
6413
+ state.stack = [
6414
+ {
6415
+ type: "Program",
6416
+ name: "$",
6417
+ fullName: "$",
6418
+ node: undefined,
6419
+ attributes: 0,
6420
+ },
6421
+ ];
6422
+ }
6423
+ if (!state.lookupRules) {
6424
+ const rules = state?.config?.compilerLookupRules || "DEFAULT";
6425
+ if (rules !== "COMPILER1" && rules !== "COMPILER2") {
6426
+ const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
6427
+ if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
6428
+ state.lookupRules = "COMPILER2";
6165
6429
  }
6166
6430
  else {
6167
- const type = node.type;
6168
- if (state.post)
6169
- ret = state.post(node, state);
6170
- switch (type) {
6171
- case "TypeSpecPart":
6172
- case "TypeSpecList":
6173
- case "TypedefDeclaration":
6174
- case "EnumDeclaration":
6175
- state.inType--;
6176
- break;
6177
- case "EnumStringBody":
6178
- state.inType++;
6179
- break;
6180
- }
6181
- const [parent] = state.stack.slice(-1);
6182
- if (parent.node === node ||
6183
- // The pre function might cause node.body to be skipped,
6184
- // so we need to check here, just in case.
6185
- // (this actually happens with prettier-extenison-monkeyc's
6186
- // findItemsByRange)
6187
- (node.type === "CatchClause" && parent.node === node.body)) {
6188
- delete parent.usings;
6189
- delete parent.imports;
6190
- if (node.type != "Program") {
6191
- state.stack.pop();
6192
- }
6193
- }
6194
- }
6195
- if (ret != null) {
6196
- state.removeNodeComments(node, ast);
6431
+ state.lookupRules = "COMPILER1";
6197
6432
  }
6198
- return ret;
6199
- }
6200
- catch (e) {
6201
- handleException(state, node, e);
6202
6433
  }
6203
- });
6434
+ }
6435
+ Object.assign(state, stateFuncs());
6436
+ state.inType = 0;
6204
6437
  state.traverse(ast);
6205
6438
  if (state.inType) {
6206
6439
  throw new Error(`inType was non-zero on exit: ${state.inType}`);
@@ -6223,8 +6456,11 @@ function api_formatAst(node, monkeyCSource = null, options = null) {
6223
6456
  * should be ignored.
6224
6457
  */
6225
6458
  switch (node.type) {
6226
- case "Program":
6227
6459
  case "BlockStatement":
6460
+ if (node.body.length)
6461
+ break;
6462
+ return "{}";
6463
+ case "Program":
6228
6464
  case "ExpressionStatement":
6229
6465
  break;
6230
6466
  default: {
@@ -6353,15 +6589,16 @@ function api_getApiFunctionInfo(func) {
6353
6589
  return invokeInfo;
6354
6590
  }
6355
6591
  if (!toyboxFnInfo.calledFuncs) {
6356
- toyboxFnInfo.modifiedDecls = new Set();
6357
- toyboxFnInfo.calledFuncs = new Set();
6358
- toyboxFnInfo.resolvedDecls = new Set();
6592
+ return false;
6359
6593
  }
6360
6594
  return toyboxFnInfo;
6361
6595
  }
6362
6596
  function api_markInvokeClassMethod(func) {
6363
6597
  func.info = invokeInfo;
6364
6598
  }
6599
+ function api_isLocal(v) {
6600
+ return v.stack[v.stack.length - 1]?.type === "BlockStatement";
6601
+ }
6365
6602
 
6366
6603
  })();
6367
6604