@markw65/monkeyc-optimizer 1.0.43 → 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),
@@ -524,13 +525,73 @@ function ast_getNodeValue(node) {
524
525
  return [node, "Long"];
525
526
  }
526
527
  if (type === "string") {
527
- return [node, "String"];
528
+ return node.raw.startsWith("'")
529
+ ? [node, "Char"]
530
+ : [node, "String"];
528
531
  }
529
532
  if (type === "boolean") {
530
533
  return [node, "Boolean"];
531
534
  }
532
535
  throw new Error(`Literal has unknown type '${type}'`);
533
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
+ }
534
595
 
535
596
  ;// CONCATENATED MODULE: external "./api.cjs"
536
597
  const external_api_cjs_namespaceObject = require("./api.cjs");
@@ -585,6 +646,8 @@ function function_info_recordCalledFuncs(func, callees) {
585
646
  }
586
647
  function function_info_functionMayModify(state, func, decl) {
587
648
  const info = func.info;
649
+ if (info === false)
650
+ return false;
588
651
  if (!info || info.modifiedUnknown)
589
652
  return true;
590
653
  if (info.resolvedDecls) {
@@ -597,7 +660,7 @@ function function_info_functionMayModify(state, func, decl) {
597
660
  const visited = new Set();
598
661
  const resolved = new Set();
599
662
  const resolveDecls = (f) => {
600
- if (visited.has(f))
663
+ if (f.info === false || visited.has(f))
601
664
  return true;
602
665
  if (!f.info)
603
666
  return false;
@@ -659,6 +722,16 @@ function function_info_findCalleesForNew(lookupDefs) {
659
722
  .flatMap(initializer)
660
723
  .filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
661
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
+ }
662
735
 
663
736
  ;// CONCATENATED MODULE: ./src/optimizer-types.ts
664
737
  var optimizer_types_StateNodeAttributes;
@@ -1622,13 +1695,17 @@ function pragma_checker_pragmaChecker(state, ast, diagnostics) {
1622
1695
  if (quote == '"') {
1623
1696
  return haystack.includes(needle);
1624
1697
  }
1625
- const re = new RegExp(needle.replace(/@([\d\w]+)/g, "(pre_)?$1(_\\d+)?"));
1698
+ const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/\W/g, "_")}(?:_\\d+)?)`));
1626
1699
  return re.test(haystack);
1627
1700
  };
1628
1701
  next();
1629
1702
  traverseAst(ast, (node) => {
1630
- if (index >= comments.length)
1703
+ if (index >= comments.length ||
1704
+ node.type === "Line" ||
1705
+ node.type === "Block" ||
1706
+ node.type === "MultiLine") {
1631
1707
  return false;
1708
+ }
1632
1709
  if (node.start && node.start >= (comment.end || Infinity)) {
1633
1710
  const { kind, quote, needle } = matchers.shift();
1634
1711
  if (kind === "match") {
@@ -1776,7 +1853,7 @@ function control_flow_buildReducedGraph(state, func, notice) {
1776
1853
  try {
1777
1854
  const localState = new LocalState(func.node);
1778
1855
  const ret = localState.curBlock;
1779
- state.stack = func.stack;
1856
+ state.stack = [...func.stack];
1780
1857
  const stmtStack = [func.node];
1781
1858
  let tryActive = 0;
1782
1859
  state.pre = (node) => {
@@ -1791,6 +1868,8 @@ function control_flow_buildReducedGraph(state, func, notice) {
1791
1868
  stmtStack.push(node);
1792
1869
  }
1793
1870
  switch (node.type) {
1871
+ case "FunctionDeclaration":
1872
+ return ["body"];
1794
1873
  case "AttributeList":
1795
1874
  return [];
1796
1875
  case "SwitchStatement": {
@@ -2007,11 +2086,6 @@ function control_flow_buildReducedGraph(state, func, notice) {
2007
2086
  }
2008
2087
  case "VariableDeclarator":
2009
2088
  return ["init"];
2010
- case "MemberExpression":
2011
- if (!node.computed) {
2012
- return ["object"];
2013
- }
2014
- break;
2015
2089
  case "UnaryExpression":
2016
2090
  if (node.operator === ":") {
2017
2091
  return [];
@@ -2047,6 +2121,14 @@ function control_flow_buildReducedGraph(state, func, notice) {
2047
2121
  case "ContinueStatement":
2048
2122
  localState.terminal(node.type);
2049
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;
2050
2132
  }
2051
2133
  return null;
2052
2134
  };
@@ -2208,142 +2290,94 @@ function getPreOrder(head) {
2208
2290
 
2209
2291
  // EXTERNAL MODULE: ./node_modules/priorityqueuejs/index.js
2210
2292
  var priorityqueuejs = __webpack_require__(2789);
2211
- ;// CONCATENATED MODULE: ./src/pre.ts
2293
+ ;// CONCATENATED MODULE: ./src/data-flow.ts
2212
2294
 
2213
2295
 
2214
2296
 
2215
2297
 
2216
2298
 
2217
- /**
2218
- * This implements a pseudo Partial Redundancy Elimination
2219
- * pass. It isn't quite like traditional PRE because we're
2220
- * aiming to minimize size, not dynamic instructions. So
2221
- * for us, its worthwhile to take something like:
2222
- *
2223
- * switch (x) {
2224
- * case 1: foo(A.B); break;
2225
- * case 2: foo(C); break;
2226
- * case 3: bar(A.B); break;
2227
- * }
2228
- *
2229
- * and rewrite it as
2230
- *
2231
- * var tmp = A.B;
2232
- * switch (x) {
2233
- * case 1: foo(tmp); break;
2234
- * case 2: foo(C); break;
2235
- * case 3: bar(tmp); break;
2236
- * }
2237
- *
2238
- * because even though A.B wasn't used on all paths where we
2239
- * inserted the temporary, we still reduced the code size.
2240
- */
2241
- const logging = false;
2242
- 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;
2243
2309
  switch (decl.type) {
2244
- case "Literal":
2245
- return decl.raw || decl.value?.toString() || "null";
2246
- case "VariableDeclarator":
2247
- 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;
2248
2316
  default:
2249
2317
  throw new Error(`Unexpected EventDecl type: ${decl.type}`);
2250
2318
  }
2251
2319
  }
2252
- 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;
2253
2329
  switch (decl.type) {
2254
- case "Literal":
2255
- return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
2256
- case "VariableDeclarator":
2257
- return decl.name;
2330
+ case "BinaryExpression":
2331
+ return decl.left.name;
2332
+ case "EnumStringMember":
2333
+ return decl.id.name;
2258
2334
  default:
2259
2335
  throw new Error(`Unexpected EventDecl type: ${decl.type}`);
2260
2336
  }
2261
2337
  }
2262
- function logAntState(s, decl) {
2263
- const defs = Array.from(s.ant).reduce((defs, event) => {
2264
- if (event.type === "def" || event.type === "mod")
2265
- defs++;
2266
- return defs;
2267
- }, 0);
2268
- console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
2269
- console.log(` - members: ${Array.from(s.members)
2270
- .map(([block, live]) => block.order + (live ? "t" : "f"))
2271
- .join(", ")}`);
2272
- }
2273
- function logAntDecls(antDecls) {
2274
- antDecls.forEach(logAntState);
2275
- }
2276
- function pre_sizeBasedPRE(state, func) {
2277
- if (!func.node.body)
2278
- return;
2279
- if (!state.config ||
2280
- !state.config.sizeBasedPRE ||
2281
- (typeof state.config.sizeBasedPRE === "string" &&
2282
- state.config.sizeBasedPRE !== func.fullName)) {
2283
- return;
2284
- }
2285
- const { graph: head, identifiers } = buildPREGraph(state, func);
2286
- const candidates = computeAttributes(state, head);
2287
- if (candidates) {
2288
- if (logging) {
2289
- console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
2290
- logAntDecls(candidates);
2291
- }
2292
- const nodeMap = new Map();
2293
- const declMap = new Map();
2294
- const variableDecl = withLoc({
2295
- type: "VariableDeclaration",
2296
- declarations: [],
2297
- kind: "var",
2298
- }, func.node.body);
2299
- variableDecl.end = variableDecl.start;
2300
- variableDecl.loc.end = variableDecl.loc.start;
2301
- candidates.forEach((s, decl) => {
2302
- let name;
2303
- let i = 0;
2304
- do {
2305
- name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
2306
- if (!identifiers.has(name)) {
2307
- identifiers.add(name);
2308
- break;
2309
- }
2310
- i++;
2311
- } while (true);
2312
- declMap.set(decl, name);
2313
- variableDecl.declarations.push(withLoc({
2314
- type: "VariableDeclarator",
2315
- id: withLoc({ type: "Identifier", name }, variableDecl),
2316
- kind: "var",
2317
- }, variableDecl));
2318
- s.ant.forEach((event) => {
2319
- const events = nodeMap.get(event.node);
2320
- if (!events) {
2321
- nodeMap.set(event.node, [event]);
2322
- }
2323
- else {
2324
- events.push(event);
2325
- }
2326
- });
2327
- });
2328
- applyReplacements(func.node, nodeMap, declMap);
2329
- func.node.body.body.unshift(variableDecl);
2330
- }
2331
- }
2332
2338
  function unhandledExpression(node) {
2333
2339
  throw new Error(`Unhandled expression type: ${node.type}`);
2334
2340
  }
2335
- function buildPREGraph(state, func) {
2341
+ function data_flow_buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wantsAllRefs) {
2342
+ const uniqueDeclMap = new Map();
2336
2343
  const findDecl = (node) => {
2337
2344
  if (node.type === "Identifier" ||
2338
2345
  (node.type === "MemberExpression" && !node.computed)) {
2339
2346
  const [, results] = state.lookup(node);
2340
- if (results &&
2341
- results.length === 1 &&
2342
- results[0].parent?.type != "BlockStatement" &&
2343
- results[0].results.length === 1 &&
2344
- results[0].results[0].type === "VariableDeclarator") {
2345
- return results[0].results[0];
2346
- }
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;
2347
2381
  }
2348
2382
  return null;
2349
2383
  };
@@ -2351,18 +2385,22 @@ function buildPREGraph(state, func) {
2351
2385
  const identifiers = new Set();
2352
2386
  const liveDefs = new Map();
2353
2387
  const liveStmts = new Map();
2354
- const liveDef = (def, stmt) => {
2355
- let curNodes = liveDefs.get(def);
2356
- if (!curNodes) {
2357
- liveDefs.set(def, (curNodes = new Set()));
2358
- }
2359
- curNodes.add(stmt);
2360
- let defs = liveStmts.get(stmt);
2361
- if (!defs) {
2362
- 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);
2363
2400
  }
2364
- defs.set(def, (defs.get(def) || 0) + 1);
2365
- };
2401
+ : () => {
2402
+ /* do nothing */
2403
+ };
2366
2404
  return {
2367
2405
  identifiers,
2368
2406
  graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
@@ -2376,7 +2414,7 @@ function buildPREGraph(state, func) {
2376
2414
  }
2377
2415
  const v = liveDefs.get(def);
2378
2416
  if (!v || !v.has(node)) {
2379
- 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"}`);
2380
2418
  }
2381
2419
  v.delete(node);
2382
2420
  if (!v.size) {
@@ -2397,7 +2435,7 @@ function buildPREGraph(state, func) {
2397
2435
  case "ParenthesizedExpression":
2398
2436
  break;
2399
2437
  case "Literal":
2400
- if (refCost(node) > LocalRefCost) {
2438
+ if (wantsLiteral(node)) {
2401
2439
  const result = getNodeValue(node);
2402
2440
  const key = result[1] +
2403
2441
  (result[0].value === null
@@ -2419,34 +2457,40 @@ function buildPREGraph(state, func) {
2419
2457
  case "Identifier":
2420
2458
  identifiers.add(node.name);
2421
2459
  // fall through
2422
- case "MemberExpression":
2423
- {
2424
- const decl = findDecl(node);
2425
- if (decl && decl.type === "VariableDeclarator") {
2426
- const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
2427
- liveDefs.get(decl);
2428
- if (defStmts) {
2429
- break;
2430
- /*
2431
- // hold off on this for now. we need to communicate
2432
- // which defs need to be fixed, which involves yet-another
2433
- // table.
2434
-
2435
- if (defStmts.size !== 1) break;
2436
- const fixable = isFixableStmt([...defStmts][0]);
2437
- if (fixable === false) break;
2438
- cost += fixable;
2439
- */
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
+ }
2440
2482
  }
2441
- return {
2442
- type: "ref",
2443
- node,
2444
- decl,
2445
- mayThrow,
2446
- };
2447
- }
2483
+ return false;
2484
+ })) {
2485
+ break;
2448
2486
  }
2449
- break;
2487
+ return {
2488
+ type: "ref",
2489
+ node,
2490
+ decl: decls,
2491
+ mayThrow,
2492
+ };
2493
+ }
2450
2494
  case "VariableDeclarator": {
2451
2495
  const decl = findDecl(node.id.type === "BinaryExpression" ? node.id.left : node.id);
2452
2496
  if (decl) {
@@ -2494,8 +2538,10 @@ function buildPREGraph(state, func) {
2494
2538
  }
2495
2539
  case "CallExpression": {
2496
2540
  liveDef(null, stmt);
2497
- const [, results] = state.lookup(node.callee);
2498
- 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);
2499
2545
  return { type: "mod", node, mayThrow, callees };
2500
2546
  }
2501
2547
  default:
@@ -2510,67 +2556,193 @@ function buildPREGraph(state, func) {
2510
2556
  }),
2511
2557
  };
2512
2558
  }
2513
- function anticipatedDecls() {
2514
- return new Map();
2515
- }
2516
- function equalSet(a, b) {
2517
- if (a.size != b.size)
2518
- return false;
2519
- for (const item of a) {
2520
- if (!b.has(item))
2521
- return false;
2522
- }
2523
- return true;
2524
- }
2525
- function equalMap(a, b) {
2526
- if (a.size != b.size)
2527
- return false;
2528
- for (const [item, value] of a) {
2529
- if (b.get(item) !== value)
2530
- 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));
2531
2563
  }
2532
- return true;
2533
- }
2534
- function anticipatedState(node, events) {
2535
- return { ant: events || new Set(), live: true, node, members: new Map() };
2536
- }
2537
- function cloneAnticipatedState(as) {
2538
- return {
2539
- ant: cloneSet(as.ant),
2540
- live: as.live,
2541
- node: as.node,
2542
- members: new Map(as.members),
2543
- };
2544
- }
2545
- function mergeAnticipatedState(ae, be) {
2546
- mergeSet(ae.ant, be.ant);
2547
- be.members.forEach((live, block) => ae.members.set(block, live));
2548
- if (be.live)
2549
- ae.live = true;
2550
- }
2551
- function cloneAnticipatedDecls(ad) {
2552
- const copy = anticipatedDecls();
2553
- for (const [k, v] of ad) {
2554
- if (!v.isIsolated) {
2555
- copy.set(k, cloneAnticipatedState(v));
2564
+ enqueue(block) {
2565
+ if (!this.enqueued.has(block)) {
2566
+ this.enqueued.add(block);
2567
+ this.queue.enq(block);
2556
2568
  }
2557
2569
  }
2558
- return copy;
2559
- }
2560
- function mergeAnticipatedDecls(a, b) {
2561
- for (const [k, v] of b) {
2562
- if (v.isIsolated)
2563
- continue;
2564
- const ae = a.get(k);
2565
- if (ae) {
2566
- mergeAnticipatedState(ae, v);
2567
- }
2568
- else {
2569
- a.set(k, cloneAnticipatedState(v));
2570
- }
2570
+ dequeue() {
2571
+ const block = this.queue.deq();
2572
+ this.enqueued.delete(block);
2573
+ return block;
2574
+ }
2575
+ empty() {
2576
+ return this.queue.isEmpty();
2571
2577
  }
2572
2578
  }
2573
- 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) {
2574
2746
  if (a.size !== b.size)
2575
2747
  return false;
2576
2748
  for (const [k, ae] of a) {
@@ -2665,26 +2837,18 @@ function computeAttributes(state, head) {
2665
2837
  .join(", ")}`);
2666
2838
  if (block.events) {
2667
2839
  block.events.forEach((event) => event.type !== "exn" &&
2668
- 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
+ : "??"}`));
2669
2845
  }
2670
2846
  console.log(`Succs: ${(block.succs || [])
2671
2847
  .map((block) => block.order)
2672
2848
  .join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
2673
2849
  });
2674
2850
  }
2675
- const enqueued = new Set();
2676
- const queue = new PriorityQueue((b, a) => (a.order || 0) - (b.order || 0));
2677
- const enqueue = (block) => {
2678
- if (!enqueued.has(block)) {
2679
- enqueued.add(block);
2680
- queue.enq(block);
2681
- }
2682
- };
2683
- const dequeue = () => {
2684
- const block = queue.deq();
2685
- enqueued.delete(block);
2686
- return block;
2687
- };
2851
+ const queue = new DataflowQueue();
2688
2852
  const blockStates = [];
2689
2853
  /*
2690
2854
  Algorithm
@@ -2718,9 +2882,9 @@ function computeAttributes(state, head) {
2718
2882
  }
2719
2883
  return result;
2720
2884
  };
2721
- order.forEach((block) => enqueue(block));
2722
- while (queue.size()) {
2723
- const top = dequeue();
2885
+ order.forEach((block) => queue.enqueue(block));
2886
+ while (!queue.empty()) {
2887
+ const top = queue.dequeue();
2724
2888
  if (top.order === undefined) {
2725
2889
  throw new Error(`Unreachable block was visited!`);
2726
2890
  }
@@ -2759,13 +2923,13 @@ function computeAttributes(state, head) {
2759
2923
  break;
2760
2924
  }
2761
2925
  case "mod": {
2762
- curState.forEach((candidates, decl) => {
2763
- if (decl.type === "VariableDeclarator" &&
2926
+ curState.forEach((candidates, decls) => {
2927
+ if (some(decls, (decl) => decl.type === "VariableDeclarator" &&
2764
2928
  decl.node.kind === "var" &&
2765
2929
  candidates.live &&
2766
2930
  (!event.callees ||
2767
- event.callees.some((callee) => functionMayModify(state, callee, decl)))) {
2768
- 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));
2769
2933
  candidates.live = false;
2770
2934
  }
2771
2935
  });
@@ -2817,7 +2981,7 @@ function computeAttributes(state, head) {
2817
2981
  logAntDecls(curState);
2818
2982
  }
2819
2983
  if (top.preds) {
2820
- top.preds.forEach((pred) => enqueue(pred));
2984
+ top.preds.forEach((pred) => queue.enqueue(pred));
2821
2985
  }
2822
2986
  }
2823
2987
  const candidateDecls = anticipatedDecls();
@@ -3572,7 +3736,7 @@ function getLiteralNode(node) {
3572
3736
  case "-": {
3573
3737
  const [arg, type] = ast_getNodeValue(node.argument);
3574
3738
  if (type === "Number" || type === "Long") {
3575
- return replacementLiteral(arg, -arg.value, type);
3739
+ return replacementLiteral(node, -arg.value, type);
3576
3740
  }
3577
3741
  }
3578
3742
  }
@@ -3622,8 +3786,14 @@ function isBooleanExpression(state, node) {
3622
3786
  }
3623
3787
  return false;
3624
3788
  }
3789
+ function roundToFloat(value) {
3790
+ return new Float32Array([value])[0];
3791
+ }
3625
3792
  function replacementLiteral(arg, value, type) {
3626
- if (typeof value === "boolean") {
3793
+ if (value === null) {
3794
+ type = "Null";
3795
+ }
3796
+ else if (typeof value === "boolean") {
3627
3797
  type = "Boolean";
3628
3798
  }
3629
3799
  else if (type === "Number") {
@@ -3632,32 +3802,213 @@ function replacementLiteral(arg, value, type) {
3632
3802
  else if (type === "Long") {
3633
3803
  value = BigInt.asIntN(64, BigInt(value));
3634
3804
  }
3805
+ else if (type === "Float") {
3806
+ value = roundToFloat(Number(value));
3807
+ }
3808
+ let raw = type === "String"
3809
+ ? JSON.stringify(value)
3810
+ : type === "Char"
3811
+ ? value === "'"
3812
+ ? "'\\''"
3813
+ : "'" + JSON.stringify(value).slice(1, -1) + "'"
3814
+ : value == null
3815
+ ? "null"
3816
+ : value.toString();
3817
+ if (type === "Long") {
3818
+ raw += "l";
3819
+ }
3820
+ else if (type === "Double") {
3821
+ raw += "d";
3822
+ }
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
+ }
3838
+ }
3839
+ const { start, end, loc } = arg;
3635
3840
  return {
3636
- ...arg,
3841
+ type: "Literal",
3637
3842
  value,
3638
- raw: value.toString() + (type === "Long" ? "l" : ""),
3843
+ raw,
3844
+ start,
3845
+ end,
3846
+ loc,
3639
3847
  };
3640
3848
  }
3849
+ function classify(arg) {
3850
+ switch (arg) {
3851
+ case "Number":
3852
+ return { big: false, int: true };
3853
+ case "Long":
3854
+ return { big: true, int: true };
3855
+ case "Float":
3856
+ return { big: false, int: false };
3857
+ case "Double":
3858
+ return { big: true, int: false };
3859
+ }
3860
+ return null;
3861
+ }
3862
+ function common_arith_types(left, right) {
3863
+ const l = classify(left);
3864
+ if (!l)
3865
+ return null;
3866
+ const r = classify(right);
3867
+ if (!r)
3868
+ return null;
3869
+ if (l.big || r.big) {
3870
+ return l.int && r.int
3871
+ ? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
3872
+ : ["Double", (v) => Number(v)];
3873
+ }
3874
+ else {
3875
+ return l.int && r.int
3876
+ ? ["Number", (v) => BigInt.asIntN(32, BigInt(v))]
3877
+ : ["Float", (v) => roundToFloat(Number(v))];
3878
+ }
3879
+ }
3880
+ function common_bitwise_types(left, right) {
3881
+ if (left === "Boolean" && right === "Boolean") {
3882
+ return ["Boolean", (v) => (v ? true : false)];
3883
+ }
3884
+ const l = classify(left);
3885
+ if (!l)
3886
+ return null;
3887
+ const r = classify(right);
3888
+ if (!r)
3889
+ return null;
3890
+ if (!l.int || !r.int)
3891
+ return null;
3892
+ return l.big || r.big
3893
+ ? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
3894
+ : ["Number", (v) => Number(BigInt.asIntN(32, BigInt(v)))];
3895
+ }
3896
+ function plus_types(left, right) {
3897
+ if (left === "String" || right === "String") {
3898
+ // Boolean + String is an error, and
3899
+ // Float/Double + String is legal, but its hard to predict
3900
+ // the way the float will be formatted (and it won't match
3901
+ // what javascript would do by default)
3902
+ if (/Float|Double|Boolean/.test(left + right)) {
3903
+ return null;
3904
+ }
3905
+ return ["String", String];
3906
+ }
3907
+ if (left === "Char" || right === "Char") {
3908
+ if (left === right) {
3909
+ // adding two chars produces a string
3910
+ return ["String", String];
3911
+ }
3912
+ if (/Number|Long/.test(left + right)) {
3913
+ return ["Char", (v) => v];
3914
+ }
3915
+ }
3916
+ return common_arith_types(left, right);
3917
+ }
3918
+ function shift_mod_types(left, right) {
3919
+ const result = common_bitwise_types(left, right);
3920
+ if (result && result[0] === "Boolean") {
3921
+ return null;
3922
+ }
3923
+ return result;
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
+ }
3641
3939
  const operators = {
3642
- "+": (left, right) => left + right,
3643
- "-": (left, right) => left - right,
3644
- "*": (left, right) => left * right,
3645
- "/": (left, right) => left / right,
3646
- "%": (left, right) => left % right,
3647
- "&": (left, right) => left & right,
3648
- "|": (left, right) => left | right,
3649
- "^": (left, right) => left ^ right,
3650
- "<<": (left, right) => left << (right & 127n),
3651
- ">>": (left, right) => left >> (right & 127n),
3652
- "==": (left, right) =>
3653
- // two string literals will compare unequal, becuase string
3654
- // equality is object equality.
3655
- typeof left === "string" ? false : left === right,
3656
- "!=": (left, right) => typeof left === "string" ? true : left !== right,
3657
- "<=": (left, right) => left <= right,
3658
- ">=": (left, right) => left >= right,
3659
- "<": (left, right) => left < right,
3660
- ">": (left, right) => left > right,
3940
+ "+": {
3941
+ typeFn: plus_types,
3942
+ valueFn: (left, right) => typeof left === "string" && typeof right !== "string"
3943
+ ? String.fromCharCode(left.charCodeAt(0) + Number(right))
3944
+ : typeof left !== "string" && typeof right === "string"
3945
+ ? String.fromCharCode(right.charCodeAt(0) + Number(left))
3946
+ : left + right,
3947
+ },
3948
+ "-": {
3949
+ typeFn: common_arith_types,
3950
+ valueFn: (left, right) => left - right,
3951
+ },
3952
+ "*": {
3953
+ typeFn: common_arith_types,
3954
+ valueFn: (left, right) => left * right,
3955
+ },
3956
+ "/": {
3957
+ typeFn: common_arith_types,
3958
+ valueFn: (left, right) => left / right,
3959
+ },
3960
+ "%": {
3961
+ typeFn: shift_mod_types,
3962
+ valueFn: (left, right) => left % right,
3963
+ },
3964
+ "&": {
3965
+ typeFn: common_bitwise_types,
3966
+ valueFn: (left, right) => left & right,
3967
+ },
3968
+ "|": {
3969
+ typeFn: common_bitwise_types,
3970
+ valueFn: (left, right) => left | right,
3971
+ },
3972
+ "^": {
3973
+ typeFn: common_bitwise_types,
3974
+ valueFn: (left, right) => left ^ right,
3975
+ },
3976
+ "<<": {
3977
+ typeFn: shift_mod_types,
3978
+ valueFn: (left, right) => typeof right === "bigint"
3979
+ ? left << right
3980
+ : left << right,
3981
+ },
3982
+ ">>": {
3983
+ typeFn: shift_mod_types,
3984
+ valueFn: (left, right) => typeof right === "bigint"
3985
+ ? left >> right
3986
+ : left >> right,
3987
+ },
3988
+ "==": {
3989
+ typeFn: () => ["Boolean", (v) => v],
3990
+ valueFn: equalsFn,
3991
+ },
3992
+ "!=": {
3993
+ typeFn: () => ["Boolean", (v) => v],
3994
+ valueFn: (left, right) => !equalsFn(left, right),
3995
+ },
3996
+ "<=": {
3997
+ typeFn: common_arith_types,
3998
+ valueFn: (left, right) => left <= right,
3999
+ },
4000
+ ">=": {
4001
+ typeFn: common_arith_types,
4002
+ valueFn: (left, right) => left >= right,
4003
+ },
4004
+ "<": {
4005
+ typeFn: common_arith_types,
4006
+ valueFn: (left, right) => left < right,
4007
+ },
4008
+ ">": {
4009
+ typeFn: common_arith_types,
4010
+ valueFn: (left, right) => left > right,
4011
+ },
3661
4012
  as: null,
3662
4013
  instanceof: null,
3663
4014
  has: null,
@@ -3670,23 +4021,31 @@ function optimizeNode(state, node) {
3670
4021
  break;
3671
4022
  switch (node.operator) {
3672
4023
  case "+":
3673
- if (type === "Number" || type === "Long") {
4024
+ if (type === "Number" ||
4025
+ type === "Long" ||
4026
+ type === "Float" ||
4027
+ type === "Double" ||
4028
+ type === "Char" ||
4029
+ type === "String") {
3674
4030
  return arg;
3675
4031
  }
3676
4032
  break;
3677
4033
  case "-":
3678
- if (type === "Number" || type === "Long") {
3679
- return replacementLiteral(arg, -arg.value, type);
4034
+ if (type === "Number" ||
4035
+ type === "Long" ||
4036
+ type === "Float" ||
4037
+ type === "Double") {
4038
+ return replacementLiteral(node, -arg.value, type);
3680
4039
  }
3681
4040
  break;
3682
4041
  case "!":
3683
4042
  case "~":
3684
4043
  {
3685
4044
  if (type === "Number" || type === "Long") {
3686
- return replacementLiteral(arg, ~BigInt(arg.value), type);
4045
+ return replacementLiteral(node, ~BigInt(arg.value), type);
3687
4046
  }
3688
4047
  if (type === "Boolean" && node.operator == "!") {
3689
- return replacementLiteral(arg, !arg.value, type);
4048
+ return replacementLiteral(node, !arg.value, type);
3690
4049
  }
3691
4050
  }
3692
4051
  break;
@@ -3700,23 +4059,13 @@ function optimizeNode(state, node) {
3700
4059
  const [right, right_type] = getNodeValue(node.right);
3701
4060
  if (!left || !right)
3702
4061
  break;
3703
- let value = null;
3704
- let type;
3705
- if ((left_type != "Number" && left_type != "Long") ||
3706
- left_type != right_type) {
3707
- if (node.operator !== "==" && node.operator !== "!=") {
3708
- break;
3709
- }
3710
- value = operators[node.operator](left.value, right.value);
3711
- type = "Boolean";
3712
- }
3713
- else {
3714
- type = left_type;
3715
- value = op(BigInt(left.value), BigInt(right.value));
3716
- }
4062
+ const type = op.typeFn(left_type, right_type);
4063
+ if (!type)
4064
+ break;
4065
+ const value = op.valueFn(type[1](left.value), type[1](right.value));
3717
4066
  if (value === null)
3718
4067
  break;
3719
- return replacementLiteral(left, value, type);
4068
+ return replacementLiteral(node, value, type[0]);
3720
4069
  }
3721
4070
  break;
3722
4071
  }
@@ -4169,7 +4518,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
4169
4518
  if (!state.currentFunction) {
4170
4519
  throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
4171
4520
  }
4172
- state.currentFunction.info = state.currentFunction.next_info;
4521
+ state.currentFunction.info = state.currentFunction.next_info || false;
4173
4522
  delete state.currentFunction.next_info;
4174
4523
  delete state.currentFunction;
4175
4524
  break;
@@ -4607,6 +4956,8 @@ const external_sdk_util_cjs_namespaceObject = require("./sdk-util.cjs");
4607
4956
  ;// CONCATENATED MODULE: ./src/resources.ts
4608
4957
 
4609
4958
 
4959
+
4960
+
4610
4961
  /*
4611
4962
  * This is unavoidably ad-hoc. Garmin has arbitrary rules for how
4612
4963
  * resources can be nested, which we need to mimic here.
@@ -4759,7 +5110,7 @@ function visit_resources(elements, parent, v) {
4759
5110
  visitor.post(e);
4760
5111
  });
4761
5112
  }
4762
- function add_resources_to_ast(ast, resources, manifestXML) {
5113
+ function add_resources_to_ast(state, ast, resources, manifestXML) {
4763
5114
  const modules = {
4764
5115
  Drawables: true,
4765
5116
  Fonts: true,
@@ -4801,7 +5152,7 @@ function add_resources_to_ast(ast, resources, manifestXML) {
4801
5152
  manifestXML.body instanceof external_sdk_util_cjs_namespaceObject.xmlUtil.Nodes) {
4802
5153
  manifestXML.body
4803
5154
  .children("iq:application")
4804
- .elements.forEach((e) => add_one_resource(rez, e));
5155
+ .elements.forEach((e) => add_one_resource(state, manifestXML, rez, e));
4805
5156
  }
4806
5157
  const rezModules = Object.fromEntries(Object.entries(modules).map(([moduleName, isPublic]) => {
4807
5158
  const module = makeModule(moduleName);
@@ -4817,110 +5168,152 @@ function add_resources_to_ast(ast, resources, manifestXML) {
4817
5168
  if (!ast_hasProperty(rezModules, s))
4818
5169
  return;
4819
5170
  const module = rezModules[s];
4820
- add_one_resource(module, e);
5171
+ add_one_resource(state, rez, module, e);
4821
5172
  });
4822
5173
  });
4823
5174
  });
4824
5175
  }
4825
- function makeIdentifier(name, loc) {
4826
- return wrap({ type: "Identifier", name }, loc);
4827
- }
4828
- function makeMemberExpression(object, property) {
4829
- return wrap({
4830
- type: "MemberExpression",
4831
- object,
4832
- property,
4833
- computed: false,
4834
- }, object.loc && locRange(object.loc, property.loc));
5176
+ const drawableSkips = {
5177
+ x: { center: true, left: true, right: true, start: true },
5178
+ y: { center: true, top: true, bottom: true, start: true },
5179
+ width: { fill: true },
5180
+ height: { fill: true },
5181
+ a: { fill: true },
5182
+ b: { fill: true },
5183
+ color: {},
5184
+ corner_radius: {},
5185
+ radius: {},
5186
+ border_width: {},
5187
+ border_color: {},
5188
+ foreground: {},
5189
+ background: {},
5190
+ font: {},
5191
+ justification: {},
5192
+ };
5193
+ function addPositions(base, pos) {
5194
+ const result = { ...base };
5195
+ if (pos.line > 1) {
5196
+ result.line += pos.line - 1;
5197
+ result.column = pos.column;
5198
+ }
5199
+ else {
5200
+ result.column += pos.column - 1;
5201
+ }
5202
+ result.offset += pos.offset;
5203
+ return result;
4835
5204
  }
4836
- function makeScopedName(dotted, l) {
4837
- const loc = l && adjustLoc(l, 0, l.start.offset - l.end.offset);
4838
- return dotted.split(".").reduce(({ cur, offset }, next) => {
4839
- const id = makeIdentifier(next, loc && adjustLoc(loc, offset, offset + next.length));
4840
- if (!cur) {
4841
- cur = id;
5205
+ function visit_resource_refs(state, doc, e) {
5206
+ const result = [];
5207
+ const parseArg = (name, loc, skip) => {
5208
+ if (name.startsWith("@")) {
5209
+ name = name.substring(1);
5210
+ loc = adjustLoc(loc, 1, 0);
4842
5211
  }
4843
- else {
4844
- cur = makeMemberExpression(cur, id);
5212
+ if (ast_hasProperty(skip, name)) {
5213
+ return;
4845
5214
  }
4846
- offset += next.length + 1;
4847
- return { cur, offset };
4848
- }, { cur: null, offset: 0 }).cur;
4849
- }
4850
- function visit_resource_refs(e) {
4851
- const result = [];
4852
- const stringToScopedName = (element, id, dotted, l) => {
4853
- const match = dotted.match(/^(@)?([\w_$]+\s*\.\s*)*[\w_$]+$/);
4854
- if (!match)
5215
+ if (/^([-\w_$]+\s*\.\s*)*[-\w_$]+$/.test(name)) {
5216
+ result.push(makeScopedName(name, loc));
4855
5217
  return;
4856
- let offset = 0;
4857
- if (match[1]) {
4858
- offset = 1;
4859
5218
  }
4860
- else if ((element === "drawable" && id === "class") ||
4861
- (element === "iq:application" && id === "entry")) {
4862
- // nothing to do
5219
+ // We wrap the expression in parentheses, so adjust
5220
+ // the start position by 1 character to compensate
5221
+ // for the opening '('
5222
+ const startPos = adjustLoc(loc, -1, 0).start;
5223
+ try {
5224
+ const expr = prettier_plugin_monkeyc_default().parsers.monkeyc.parse(`(${name})`, null, {
5225
+ filepath: loc.source || undefined,
5226
+ singleExpression: true,
5227
+ });
5228
+ ast_traverseAst(expr, (node) => {
5229
+ if (node.loc) {
5230
+ node.loc = {
5231
+ source: node.loc.source,
5232
+ start: addPositions(startPos, node.loc.start),
5233
+ end: addPositions(startPos, node.loc.end),
5234
+ };
5235
+ node.start = (node.start || 0) + startPos.offset;
5236
+ node.end = (node.end || 0) + startPos.offset;
5237
+ }
5238
+ });
5239
+ result.push(expr);
4863
5240
  }
4864
- else {
4865
- return;
5241
+ catch (ex) {
5242
+ if (state) {
5243
+ const check = state.config?.checkInvalidSymbols;
5244
+ if (check !== "OFF" && ex instanceof Error) {
5245
+ const error = ex;
5246
+ if (error.location) {
5247
+ const location = {
5248
+ source: error.location.source,
5249
+ start: addPositions(startPos, error.location.start),
5250
+ end: addPositions(startPos, error.location.end),
5251
+ };
5252
+ inliner_diagnostic(state, location, ex.message, check || "WARNING");
5253
+ }
5254
+ }
5255
+ }
4866
5256
  }
4867
- const dn = makeScopedName(dotted.substring(offset), adjustLoc(l, offset, 0));
4868
- if (dn)
4869
- result.push(dn);
4870
5257
  };
4871
- visit_resources([e], null, {
4872
- pre(node) {
4873
- if (node.type === "element") {
4874
- Object.values(node.attr).forEach((attr) => {
4875
- if (!attr || !attr.value.loc)
4876
- return;
4877
- const loc = adjustLoc(attr.value.loc);
4878
- attr &&
4879
- stringToScopedName(node.name, attr.name.value, attr.value.value, loc);
4880
- });
4881
- if (node.children &&
4882
- node.children.length === 1 &&
4883
- node.children[0].type === "chardata") {
4884
- stringToScopedName(node.name, null, node.children[0].value, node.children[0].loc);
5258
+ const stringToScopedName = (element, id, dotted, l) => {
5259
+ dotted = doc.processRefs(dotted);
5260
+ if (dotted.startsWith("@")) {
5261
+ return parseArg(dotted, l);
5262
+ }
5263
+ if (/^\s*(true|false|null|NaN|(0x|#)[0-9a-f]+|[-+]?\d+%?)\s*$/i.test(dotted)) {
5264
+ return;
5265
+ }
5266
+ switch (element.name) {
5267
+ case "param":
5268
+ if (id === null) {
5269
+ parseArg(dotted, l);
5270
+ }
5271
+ return;
5272
+ case "drawable":
5273
+ if (id === "class") {
5274
+ parseArg(dotted, l);
5275
+ }
5276
+ return;
5277
+ case "shape":
5278
+ case "bitmap":
5279
+ case "drawable-list":
5280
+ case "text-area":
5281
+ case "label":
5282
+ if (id && ast_hasProperty(drawableSkips, id)) {
5283
+ parseArg(dotted, l, drawableSkips[id]);
5284
+ }
5285
+ return;
5286
+ case "iq:application":
5287
+ if (id === "entry") {
5288
+ parseArg(dotted, l);
4885
5289
  }
4886
5290
  return;
5291
+ default:
5292
+ return;
5293
+ }
5294
+ };
5295
+ external_sdk_util_cjs_namespaceObject.xmlUtil.visit_xml([e], {
5296
+ pre(node) {
5297
+ if (node.type !== "element")
5298
+ return false;
5299
+ Object.values(node.attr).forEach((attr) => {
5300
+ if (!attr || !attr.value.loc)
5301
+ return;
5302
+ const loc = adjustLoc(attr.value.loc);
5303
+ attr &&
5304
+ stringToScopedName(node, attr.name.value, attr.value.value, loc);
5305
+ });
5306
+ const content = doc.textContent(node);
5307
+ if (content) {
5308
+ stringToScopedName(node, null, content, locRange(node.children[0].loc, node.children[node.children.length - 1].loc));
5309
+ return false;
4887
5310
  }
5311
+ return;
4888
5312
  },
4889
5313
  });
4890
5314
  return result;
4891
5315
  }
4892
- function wrap(node, loc) {
4893
- if (loc) {
4894
- node.loc = loc;
4895
- node.start = loc.start.offset;
4896
- node.end = loc.end.offset;
4897
- }
4898
- return node;
4899
- }
4900
- function locRange(start, end) {
4901
- return {
4902
- source: start.source || end.source,
4903
- start: start.start,
4904
- end: end.end,
4905
- };
4906
- }
4907
- function adjustLoc(loc, start = 1, end = -1) {
4908
- /* Attributes are quoted, so skip the quotes */
4909
- return {
4910
- source: loc.source,
4911
- start: {
4912
- offset: loc.start.offset + start,
4913
- line: loc.start.line,
4914
- column: loc.start.column + start,
4915
- },
4916
- end: {
4917
- offset: loc.end.offset + end,
4918
- line: loc.end.line,
4919
- column: loc.end.column + end,
4920
- },
4921
- };
4922
- }
4923
- function add_one_resource(module, e) {
5316
+ function add_one_resource(state, doc, module, e) {
4924
5317
  let id;
4925
5318
  let func;
4926
5319
  const varDecl = () => {
@@ -4931,26 +5324,92 @@ function add_one_resource(module, e) {
4931
5324
  wrap({
4932
5325
  type: "VariableDeclarator",
4933
5326
  kind: "var",
4934
- 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
+ },
4935
5341
  init,
4936
- }, loc),
5342
+ }, e.loc),
4937
5343
  ],
4938
5344
  kind: "var",
4939
- }, loc);
5345
+ }, e.loc);
4940
5346
  };
4941
5347
  const classDecl = (parent) => {
4942
5348
  if (!id)
4943
5349
  return null;
4944
5350
  const loc = id.value.loc;
4945
5351
  const items = init
4946
- ? [{ type: "ClassElement", item: varDecl(), loc }]
5352
+ ? [{ type: "ClassElement", item: varDecl(), loc: e.loc }]
4947
5353
  : [];
4948
5354
  return {
4949
5355
  type: "ClassDeclaration",
4950
- body: { type: "ClassBody", body: items, loc },
5356
+ body: { type: "ClassBody", body: items, loc: e.loc },
4951
5357
  id: makeIdentifier(id.value.value, loc),
4952
5358
  superClass: makeScopedName(parent),
4953
- loc,
5359
+ loc: e.loc,
5360
+ };
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,
4954
5413
  };
4955
5414
  };
4956
5415
  switch (e.name) {
@@ -4959,13 +5418,16 @@ function add_one_resource(module, e) {
4959
5418
  case "jsonData":
4960
5419
  case "animation":
4961
5420
  case "bitmap":
4962
- case "layout":
4963
5421
  case "drawable-list":
4964
5422
  case "property":
4965
5423
  case "fitField":
4966
5424
  id = e.attr.id;
4967
5425
  func = varDecl;
4968
5426
  break;
5427
+ case "layout":
5428
+ id = e.attr.id;
5429
+ func = layoutDecl;
5430
+ break;
4969
5431
  case "menu":
4970
5432
  id = e.attr.id;
4971
5433
  func = () => classDecl("Ui.Menu");
@@ -4992,7 +5454,7 @@ function add_one_resource(module, e) {
4992
5454
  }
4993
5455
  if (!func)
4994
5456
  return;
4995
- const elements = visit_resource_refs(e);
5457
+ const elements = visit_resource_refs(state, doc, e);
4996
5458
  const init = elements.length
4997
5459
  ? { type: "ArrayExpression", elements }
4998
5460
  : undefined;
@@ -5228,7 +5690,7 @@ async function api_getApiMapping(state, resourcesMap, manifestXML) {
5228
5690
  const rezAst = state
5229
5691
  ? state.rezAst || { type: "Program", body: [] }
5230
5692
  : ast;
5231
- add_resources_to_ast(rezAst, resourcesMap, manifestXML);
5693
+ add_resources_to_ast(state, rezAst, resourcesMap, manifestXML);
5232
5694
  if (state) {
5233
5695
  state.rezAst = rezAst;
5234
5696
  state.manifestXML = manifestXML;
@@ -5555,387 +6017,423 @@ function lookup(state, decls, node, name, maybeStack, nonlocal, ignoreImports) {
5555
6017
  }
5556
6018
  return [false, false];
5557
6019
  }
5558
- function api_collectNamespaces(ast, stateIn) {
5559
- const state = (stateIn || {});
5560
- if (!state.nextExposed)
5561
- state.nextExposed = {};
5562
- if (!state.index)
5563
- state.index = {};
5564
- if (!state.stack) {
5565
- state.stack = [
5566
- {
5567
- type: "Program",
5568
- name: "$",
5569
- fullName: "$",
5570
- node: undefined,
5571
- attributes: 0,
5572
- },
5573
- ];
5574
- }
5575
- if (!state.lookupRules) {
5576
- const rules = state?.config?.compilerLookupRules || "DEFAULT";
5577
- if (rules !== "COMPILER1" && rules !== "COMPILER2") {
5578
- const match = state.sdk?.match(/-(\d+\.\d+\.\d+).(compiler2beta)?/i);
5579
- if (match && (match[2] || parseSdkVersion(match[1]) >= 4001006)) {
5580
- state.lookupRules = "COMPILER2";
5581
- }
5582
- else {
5583
- state.lookupRules = "COMPILER1";
5584
- }
5585
- }
5586
- }
5587
- state.removeNodeComments = (node, ast) => {
5588
- if (node.start && node.end && ast.comments && ast.comments.length) {
5589
- let low = 0, high = ast.comments.length;
5590
- while (high > low) {
5591
- const mid = (low + high) >> 1;
5592
- if ((ast.comments[mid].start || 0) < node.start) {
5593
- 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
+ }
5594
6034
  }
5595
- else {
5596
- 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);
5597
6041
  }
5598
6042
  }
5599
- while (high < ast.comments.length &&
5600
- (ast.comments[high].end || 0) < node.end) {
5601
- high++;
5602
- }
5603
- if (high > low) {
5604
- ast.comments.splice(low, high - low);
5605
- }
5606
- }
5607
- };
5608
- state.lookup = (node, name, stack) => lookup(state, state.inType ? "type_decls" : "decls", node, name, stack);
5609
- state.lookupNonlocal = (node, name, stack) => lookup(state, "decls", node, name, stack, true);
5610
- state.lookupValue = (node, name, stack) => lookup(state, "decls", node, name, stack);
5611
- state.lookupType = (node, name, stack) => lookup(state, "type_decls", node, name, stack);
5612
- state.stackClone = () => state.stack.map((elm) => elm.type === "ModuleDeclaration" || elm.type === "Program"
5613
- ? { ...elm }
5614
- : elm);
5615
- state.inType = 0;
5616
- state.traverse = (root) => ast_traverseAst(root, (node) => {
5617
- try {
5618
- if (state.shouldExclude && state.shouldExclude(node)) {
5619
- // don't visit any children, but do call post
5620
- return [];
5621
- }
5622
- switch (node.type) {
5623
- case "UnaryExpression":
5624
- if (node.operator === ":" && !state.inType) {
5625
- state.nextExposed[node.argument.name] = true;
5626
- }
5627
- break;
5628
- case "AttributeList":
5629
- return [];
5630
- case "Program":
5631
- if (state.stack.length != 1) {
5632
- 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 [];
5633
6067
  }
5634
- state.stack[0].node = node;
5635
- break;
5636
- case "TypeSpecList":
5637
- case "TypeSpecPart":
5638
- state.inType++;
5639
- break;
5640
- case "ImportModule":
5641
- case "Using": {
5642
- const [parent] = state.stack.slice(-1);
5643
- if (!parent.usings) {
5644
- parent.usings = {};
5645
- }
5646
- const name = (node.type === "Using" && node.as && node.as.name) ||
5647
- (node.id.type === "Identifier"
5648
- ? node.id.name
5649
- : node.id.property.name);
5650
- const using = { node };
5651
- parent.usings[name] = using;
5652
- if (node.type == "ImportModule") {
5653
- if (!parent.imports) {
5654
- 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;
5655
6074
  }
5656
- else {
5657
- const index = parent.imports.findIndex((using) => (using.node.id.type === "Identifier"
5658
- ? using.node.id.name
5659
- : using.node.id.property.name) === name);
5660
- if (index >= 0)
5661
- parent.imports.splice(index, 1);
5662
- 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;
5663
6118
  }
5664
- }
5665
- break;
5666
- }
5667
- case "CatchClause":
5668
- if (node.param) {
5669
- const [parent] = state.stack.slice(-1);
5670
- if (!parent.decls)
5671
- parent.decls = {};
5672
- const id = node.param.type === "Identifier"
5673
- ? node.param
5674
- : node.param.left;
5675
- state.stack.push({
5676
- type: "BlockStatement",
5677
- fullName: undefined,
5678
- name: undefined,
5679
- node: node.body,
5680
- decls: { [id.name]: [id] },
5681
- attributes: 0,
5682
- });
5683
- }
5684
- break;
5685
- case "ForStatement":
5686
- if (node.init && node.init.type === "VariableDeclaration") {
5687
- state.stack.push({
5688
- type: "BlockStatement",
5689
- fullName: undefined,
5690
- name: undefined,
5691
- node: node,
5692
- attributes: 0,
5693
- });
5694
- }
5695
- break;
5696
- case "BlockStatement": {
5697
- const [parent] = state.stack.slice(-1);
5698
- if (parent.node === node ||
5699
- (parent.type != "FunctionDeclaration" &&
5700
- parent.type != "BlockStatement")) {
5701
- break;
5702
- }
5703
- // fall through
5704
- }
5705
- case "ClassDeclaration":
5706
- case "FunctionDeclaration":
5707
- case "ModuleDeclaration": {
5708
- const [parent] = state.stack.slice(-1);
5709
- const name = "id" in node ? node.id && node.id.name : undefined;
5710
- const fullName = state.stack
5711
- .map((e) => e.name)
5712
- .concat(name)
5713
- .filter((e) => e != null)
5714
- .join(".");
5715
- const elm = {
5716
- type: node.type,
5717
- name,
5718
- fullName,
5719
- node,
5720
- attributes: node.type === "BlockStatement"
5721
- ? 0
5722
- : stateNodeAttrs(node.attrs),
5723
- };
5724
- state.stack.push(elm);
5725
- if (name) {
5726
- if (!parent.decls)
5727
- parent.decls = {};
5728
- if (ast_hasProperty(parent.decls, name)) {
5729
- const what = node.type == "ModuleDeclaration" ? "type" : "node";
5730
- const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
5731
- if (e != null) {
5732
- e.node = node;
5733
- 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")) {
5734
6153
  break;
5735
6154
  }
6155
+ // fall through
5736
6156
  }
5737
- else {
5738
- 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;
5739
6211
  }
5740
- if (node.type === "FunctionDeclaration" &&
5741
- node.params &&
5742
- node.params.length) {
5743
- const decls = (elm.decls = {});
5744
- 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));
5745
6222
  }
5746
- parent.decls[name].push(elm);
5747
- if (node.type == "ModuleDeclaration" ||
5748
- 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);
5749
6228
  if (!parent.type_decls)
5750
6229
  parent.type_decls = {};
5751
6230
  if (!ast_hasProperty(parent.type_decls, name)) {
5752
6231
  parent.type_decls[name] = [];
5753
6232
  }
5754
- 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;
5755
6346
  }
5756
6347
  }
5757
- break;
6348
+ if (this.pre)
6349
+ return this.pre(node, this);
5758
6350
  }
5759
- // an EnumDeclaration doesn't create a scope, but
5760
- // it does create a type (if it has a name)
5761
- case "EnumDeclaration": {
5762
- if (!node.id) {
5763
- state.inType++;
5764
- break;
5765
- }
5766
- const [parent] = state.stack.slice(-1);
5767
- const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
5768
- node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
6351
+ catch (e) {
6352
+ handleException(this, node, e);
5769
6353
  }
5770
- // fall through
5771
- case "TypedefDeclaration": {
5772
- state.inType++;
5773
- const name = node.id.name;
5774
- const [parent] = state.stack.slice(-1);
5775
- if (!parent.type_decls)
5776
- parent.type_decls = {};
5777
- if (!ast_hasProperty(parent.type_decls, name)) {
5778
- parent.type_decls[name] = [];
5779
- }
5780
- else if (parent.type_decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == node)) {
5781
- 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;
5782
6361
  }
5783
- parent.type_decls[name].push(node.type === "EnumDeclaration"
5784
- ? node
5785
- : {
5786
- type: "TypedefDeclaration",
5787
- node,
5788
- name,
5789
- fullName: parent.fullName + "." + name,
5790
- attributes: stateNodeAttrs(node.attrs),
5791
- });
5792
- break;
5793
- }
5794
- case "VariableDeclaration": {
5795
- const [parent] = state.stack.slice(-1);
5796
- if (!parent.decls)
5797
- parent.decls = {};
5798
- const decls = parent.decls;
5799
- const stack = state.stackClone();
5800
- node.declarations.forEach((decl) => {
5801
- const name = api_variableDeclarationName(decl.id);
5802
- if (!ast_hasProperty(decls, name)) {
5803
- decls[name] = [];
5804
- }
5805
- else if (decls[name].find((n) => (api_isStateNode(n) ? n.node : n) == decl)) {
5806
- 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;
5807
6378
  }
5808
- decl.kind = node.kind;
5809
- decls[name].push({
5810
- type: "VariableDeclarator",
5811
- node: decl,
5812
- name,
5813
- fullName: parent.fullName + "." + name,
5814
- stack,
5815
- attributes: stateNodeAttrs(node.attrs),
5816
- });
5817
- if (node.kind == "const") {
5818
- if (!ast_hasProperty(state.index, name)) {
5819
- 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();
5820
6390
  }
5821
- (0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
5822
6391
  }
5823
- });
5824
- 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;
5825
6398
  }
5826
- case "EnumStringBody": {
5827
- if (state.inType !== 1) {
5828
- throw new Error(`Expected inType to be 1 at EnumStringBody. Got ${state.inType}.`);
5829
- }
5830
- state.inType--;
5831
- const [parent] = state.stack.slice(-1);
5832
- const values = parent.decls || (parent.decls = {});
5833
- let prev = -1;
5834
- node.members.forEach((m, i) => {
5835
- if (m.type == "Identifier") {
5836
- if (typeof prev === "bigint") {
5837
- prev += 1n;
5838
- }
5839
- else {
5840
- prev += 1;
5841
- }
5842
- m = node.members[i] = {
5843
- type: "EnumStringMember",
5844
- loc: m.loc,
5845
- start: m.start,
5846
- end: m.end,
5847
- id: m,
5848
- init: {
5849
- type: "Literal",
5850
- value: prev,
5851
- raw: prev.toString() + (typeof prev === "bigint" ? "l" : ""),
5852
- enumType: m.enumType,
5853
- loc: m.loc,
5854
- start: m.start,
5855
- end: m.end,
5856
- },
5857
- };
5858
- }
5859
- const name = m.id.name;
5860
- const init = getLiteralNode(m.init);
5861
- if (!init) {
5862
- throw new Error("Unexpected enum initializer");
5863
- }
5864
- if (init != m.init) {
5865
- if (m.init.enumType) {
5866
- init.enumType = m.init.enumType;
5867
- }
5868
- m.init = init;
5869
- }
5870
- if (init.type == "Literal" &&
5871
- init.raw &&
5872
- prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
5873
- prev = init.value;
5874
- }
5875
- if (!ast_hasProperty(values, name)) {
5876
- values[name] = [];
5877
- }
5878
- (0,external_util_cjs_namespaceObject.pushUnique)(values[name], m);
5879
- if (!ast_hasProperty(state.index, name)) {
5880
- state.index[name] = [];
5881
- }
5882
- (0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
5883
- });
5884
- break;
6399
+ catch (e) {
6400
+ handleException(this, node, e);
5885
6401
  }
5886
- }
5887
- if (state.pre)
5888
- return state.pre(node, state);
5889
- }
5890
- catch (e) {
5891
- handleException(state, node, e);
5892
- }
5893
- return null;
5894
- }, (node) => {
5895
- try {
5896
- let ret;
5897
- if (state.shouldExclude && state.shouldExclude(node)) {
5898
- // delete the node.
5899
- 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";
5900
6429
  }
5901
6430
  else {
5902
- const type = node.type;
5903
- if (state.post)
5904
- ret = state.post(node, state);
5905
- switch (type) {
5906
- case "TypeSpecPart":
5907
- case "TypeSpecList":
5908
- case "TypedefDeclaration":
5909
- case "EnumDeclaration":
5910
- state.inType--;
5911
- break;
5912
- case "EnumStringBody":
5913
- state.inType++;
5914
- break;
5915
- }
5916
- const [parent] = state.stack.slice(-1);
5917
- if (parent.node === node ||
5918
- // The pre function might cause node.body to be skipped,
5919
- // so we need to check here, just in case.
5920
- // (this actually happens with prettier-extenison-monkeyc's
5921
- // findItemsByRange)
5922
- (node.type === "CatchClause" && parent.node === node.body)) {
5923
- delete parent.usings;
5924
- delete parent.imports;
5925
- if (node.type != "Program") {
5926
- state.stack.pop();
5927
- }
5928
- }
5929
- }
5930
- if (ret != null) {
5931
- state.removeNodeComments(node, ast);
6431
+ state.lookupRules = "COMPILER1";
5932
6432
  }
5933
- return ret;
5934
6433
  }
5935
- catch (e) {
5936
- handleException(state, node, e);
5937
- }
5938
- });
6434
+ }
6435
+ Object.assign(state, stateFuncs());
6436
+ state.inType = 0;
5939
6437
  state.traverse(ast);
5940
6438
  if (state.inType) {
5941
6439
  throw new Error(`inType was non-zero on exit: ${state.inType}`);
@@ -5958,8 +6456,11 @@ function api_formatAst(node, monkeyCSource = null, options = null) {
5958
6456
  * should be ignored.
5959
6457
  */
5960
6458
  switch (node.type) {
5961
- case "Program":
5962
6459
  case "BlockStatement":
6460
+ if (node.body.length)
6461
+ break;
6462
+ return "{}";
6463
+ case "Program":
5963
6464
  case "ExpressionStatement":
5964
6465
  break;
5965
6466
  default: {
@@ -6088,15 +6589,16 @@ function api_getApiFunctionInfo(func) {
6088
6589
  return invokeInfo;
6089
6590
  }
6090
6591
  if (!toyboxFnInfo.calledFuncs) {
6091
- toyboxFnInfo.modifiedDecls = new Set();
6092
- toyboxFnInfo.calledFuncs = new Set();
6093
- toyboxFnInfo.resolvedDecls = new Set();
6592
+ return false;
6094
6593
  }
6095
6594
  return toyboxFnInfo;
6096
6595
  }
6097
6596
  function api_markInvokeClassMethod(func) {
6098
6597
  func.info = invokeInfo;
6099
6598
  }
6599
+ function api_isLocal(v) {
6600
+ return v.stack[v.stack.length - 1]?.type === "BlockStatement";
6601
+ }
6100
6602
 
6101
6603
  })();
6102
6604