@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.
@@ -3585,6 +3585,17 @@ function manifestAnnotations(manifest) {
3585
3585
  .children("iq:annotation")
3586
3586
  .text();
3587
3587
  }
3588
+ function manifestLanguages(manifest) {
3589
+ if (manifest.body instanceof Error) {
3590
+ throw manifest.body;
3591
+ }
3592
+ return manifest.body
3593
+ .children()
3594
+ .filter((c) => c.name === "iq:application" || c.name === "iq:barrel")
3595
+ .children("iq:languages")
3596
+ .children("iq:language")
3597
+ .text();
3598
+ }
3588
3599
  async function checkManifest(manifest, products) {
3589
3600
  if (manifest.body instanceof Error) {
3590
3601
  throw manifest.body;
@@ -3973,10 +3984,6 @@ async function resolve_literals(qualifier, default_source, deviceInfo, cache) {
3973
3984
  const lang = qualifier["lang"];
3974
3985
  if (lang) {
3975
3986
  await Promise.all(Object.keys(lang).map((key) => {
3976
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(deviceInfo.languages, key)) {
3977
- delete lang[key];
3978
- return null;
3979
- }
3980
3987
  return resolve_one_file_list(lang, key);
3981
3988
  }));
3982
3989
  if (Object.keys(lang).length === 0)
@@ -4479,6 +4486,7 @@ async function get_jungle_and_barrels(jungleFiles, defaultProducts, options, cac
4479
4486
  jungles,
4480
4487
  resources,
4481
4488
  buildDependencies,
4489
+ devices,
4482
4490
  };
4483
4491
  }
4484
4492
  catch (e) {
@@ -4509,17 +4517,22 @@ const external_child_process_namespaceObject = require("child_process");
4509
4517
 
4510
4518
 
4511
4519
  async function launchSimulator(force = true) {
4512
- if (!force && (await checkIfSimulatorRunning()))
4513
- return;
4514
- const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
4515
- const child = (0,external_child_process_namespaceObject.execFile)(external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "simulator" : "connectiq"));
4516
- child.unref();
4517
- for (let i = 0;; i++) {
4518
- if (await checkIfSimulatorRunning())
4519
- return;
4520
- if (i === 5)
4520
+ try {
4521
+ if (!force && (await checkIfSimulatorRunning()))
4521
4522
  return;
4522
- await new Promise((r) => setTimeout(r, 200));
4523
+ const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
4524
+ const child = (0,external_child_process_namespaceObject.execFile)(external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "simulator" : "connectiq"));
4525
+ child.unref();
4526
+ for (let i = 0;; i++) {
4527
+ if (await checkIfSimulatorRunning())
4528
+ return;
4529
+ if (i === 5)
4530
+ return;
4531
+ await new Promise((r) => setTimeout(r, 200));
4532
+ }
4533
+ }
4534
+ catch (e) {
4535
+ console.log(e);
4523
4536
  }
4524
4537
  }
4525
4538
  function checkIfSimulatorRunning() {
@@ -4534,7 +4547,7 @@ function checkIfSimulatorRunningOn(port) {
4534
4547
  socket.on("end", () => resolve(listening));
4535
4548
  socket.connect(port, "localhost");
4536
4549
  socket.end();
4537
- });
4550
+ }).catch(() => false);
4538
4551
  }
4539
4552
  function simulateProgram(prg, device, test = false, logger) {
4540
4553
  const args = [prg, device];
@@ -4798,6 +4811,64 @@ function getNodeValue(node) {
4798
4811
  }
4799
4812
  throw new Error(`Literal has unknown type '${type}'`);
4800
4813
  }
4814
+ function wrap(node, loc) {
4815
+ if (loc) {
4816
+ node.loc = loc;
4817
+ node.start = loc.start.offset;
4818
+ node.end = loc.end.offset;
4819
+ }
4820
+ return node;
4821
+ }
4822
+ function locRange(start, end) {
4823
+ return {
4824
+ source: start.source || end.source,
4825
+ start: start.start,
4826
+ end: end.end,
4827
+ };
4828
+ }
4829
+ function adjustLoc(loc, start = 1, end = -1) {
4830
+ return {
4831
+ source: loc.source,
4832
+ start: {
4833
+ offset: loc.start.offset + start,
4834
+ line: loc.start.line,
4835
+ column: loc.start.column + start,
4836
+ },
4837
+ end: {
4838
+ offset: loc.end.offset + end,
4839
+ line: loc.end.line,
4840
+ column: loc.end.column + end,
4841
+ },
4842
+ };
4843
+ }
4844
+ function makeIdentifier(name, loc) {
4845
+ return wrap({ type: "Identifier", name }, loc);
4846
+ }
4847
+ function makeMemberExpression(object, property) {
4848
+ return wrap({
4849
+ type: "MemberExpression",
4850
+ object,
4851
+ property,
4852
+ computed: false,
4853
+ }, object.loc && locRange(object.loc, property.loc));
4854
+ }
4855
+ function makeScopedName(dotted, l) {
4856
+ const loc = l && adjustLoc(l, 0, l.start.offset - l.end.offset);
4857
+ const result = dotted.split(/\s*\.\s*/).reduce(({ cur, offset }, next) => {
4858
+ const id = makeIdentifier(next, loc && adjustLoc(loc, offset, offset + next.length));
4859
+ if (!cur) {
4860
+ cur = id;
4861
+ }
4862
+ else {
4863
+ cur = makeMemberExpression(cur, id);
4864
+ }
4865
+ offset += next.length + 1;
4866
+ return { cur, offset };
4867
+ }, { cur: null, offset: 0 }).cur;
4868
+ if (!result)
4869
+ throw new Error("Failed to make a ScopedName");
4870
+ return result;
4871
+ }
4801
4872
 
4802
4873
  ;// CONCATENATED MODULE: ./src/function-info.ts
4803
4874
 
@@ -4850,6 +4921,8 @@ function recordCalledFuncs(func, callees) {
4850
4921
  }
4851
4922
  function functionMayModify(state, func, decl) {
4852
4923
  const info = func.info;
4924
+ if (info === false)
4925
+ return false;
4853
4926
  if (!info || info.modifiedUnknown)
4854
4927
  return true;
4855
4928
  if (info.resolvedDecls) {
@@ -4862,7 +4935,7 @@ function functionMayModify(state, func, decl) {
4862
4935
  const visited = new Set();
4863
4936
  const resolved = new Set();
4864
4937
  const resolveDecls = (f) => {
4865
- if (visited.has(f))
4938
+ if (f.info === false || visited.has(f))
4866
4939
  return true;
4867
4940
  if (!f.info)
4868
4941
  return false;
@@ -4924,6 +4997,16 @@ function findCalleesForNew(lookupDefs) {
4924
4997
  .flatMap(initializer)
4925
4998
  .filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
4926
4999
  }
5000
+ function findCalleesByNode(state, callee) {
5001
+ const name = callee.type === "Identifier"
5002
+ ? callee.name
5003
+ : callee.type === "MemberExpression" && !callee.computed
5004
+ ? callee.property.name
5005
+ : null;
5006
+ if (!name)
5007
+ return null;
5008
+ return ((hasProperty(state.allFunctions, name) && state.allFunctions[name]) || null);
5009
+ }
4927
5010
 
4928
5011
  ;// CONCATENATED MODULE: ./src/optimizer-types.ts
4929
5012
  var StateNodeAttributes;
@@ -5887,13 +5970,17 @@ function pragmaChecker(state, ast, diagnostics) {
5887
5970
  if (quote == '"') {
5888
5971
  return haystack.includes(needle);
5889
5972
  }
5890
- const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/[".]/g, "_")}(?:_\\d+)?)`));
5973
+ const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/\W/g, "_")}(?:_\\d+)?)`));
5891
5974
  return re.test(haystack);
5892
5975
  };
5893
5976
  next();
5894
5977
  traverseAst(ast, (node) => {
5895
- if (index >= comments.length)
5978
+ if (index >= comments.length ||
5979
+ node.type === "Line" ||
5980
+ node.type === "Block" ||
5981
+ node.type === "MultiLine") {
5896
5982
  return false;
5983
+ }
5897
5984
  if (node.start && node.start >= (comment.end || Infinity)) {
5898
5985
  const { kind, quote, needle } = matchers.shift();
5899
5986
  if (kind === "match") {
@@ -6039,7 +6126,7 @@ function buildReducedGraph(state, func, notice) {
6039
6126
  try {
6040
6127
  const localState = new LocalState(func.node);
6041
6128
  const ret = localState.curBlock;
6042
- state.stack = func.stack;
6129
+ state.stack = [...func.stack];
6043
6130
  const stmtStack = [func.node];
6044
6131
  let tryActive = 0;
6045
6132
  state.pre = (node) => {
@@ -6054,6 +6141,8 @@ function buildReducedGraph(state, func, notice) {
6054
6141
  stmtStack.push(node);
6055
6142
  }
6056
6143
  switch (node.type) {
6144
+ case "FunctionDeclaration":
6145
+ return ["body"];
6057
6146
  case "AttributeList":
6058
6147
  return [];
6059
6148
  case "SwitchStatement": {
@@ -6270,11 +6359,6 @@ function buildReducedGraph(state, func, notice) {
6270
6359
  }
6271
6360
  case "VariableDeclarator":
6272
6361
  return ["init"];
6273
- case "MemberExpression":
6274
- if (!node.computed) {
6275
- return ["object"];
6276
- }
6277
- break;
6278
6362
  case "UnaryExpression":
6279
6363
  if (node.operator === ":") {
6280
6364
  return [];
@@ -6310,6 +6394,14 @@ function buildReducedGraph(state, func, notice) {
6310
6394
  case "ContinueStatement":
6311
6395
  localState.terminal(node.type);
6312
6396
  return [];
6397
+ case "CallExpression":
6398
+ if (node.callee.type === "Identifier") {
6399
+ const extra = state.stack.splice(func.stack.length);
6400
+ state.traverse(node.callee);
6401
+ state.stack.push(...extra);
6402
+ return ["arguments"];
6403
+ }
6404
+ break;
6313
6405
  }
6314
6406
  return null;
6315
6407
  };
@@ -6471,142 +6563,94 @@ function getPreOrder(head) {
6471
6563
 
6472
6564
  // EXTERNAL MODULE: ./node_modules/priorityqueuejs/index.js
6473
6565
  var priorityqueuejs = __webpack_require__(2789);
6474
- ;// CONCATENATED MODULE: ./src/pre.ts
6566
+ ;// CONCATENATED MODULE: ./src/data-flow.ts
6567
+
6475
6568
 
6476
6569
 
6477
6570
 
6478
6571
 
6479
6572
 
6480
- /**
6481
- * This implements a pseudo Partial Redundancy Elimination
6482
- * pass. It isn't quite like traditional PRE because we're
6483
- * aiming to minimize size, not dynamic instructions. So
6484
- * for us, its worthwhile to take something like:
6485
- *
6486
- * switch (x) {
6487
- * case 1: foo(A.B); break;
6488
- * case 2: foo(C); break;
6489
- * case 3: bar(A.B); break;
6490
- * }
6491
- *
6492
- * and rewrite it as
6493
- *
6494
- * var tmp = A.B;
6495
- * switch (x) {
6496
- * case 1: foo(tmp); break;
6497
- * case 2: foo(C); break;
6498
- * case 3: bar(tmp); break;
6499
- * }
6500
- *
6501
- * because even though A.B wasn't used on all paths where we
6502
- * inserted the temporary, we still reduced the code size.
6503
- */
6504
- const logging = false;
6505
6573
  function declFullName(decl) {
6574
+ if (Array.isArray(decl)) {
6575
+ decl = decl[0];
6576
+ }
6577
+ if (decl.type === "Literal") {
6578
+ return decl.raw || decl.value?.toString() || "null";
6579
+ }
6580
+ if ((0,external_api_cjs_namespaceObject.isStateNode)(decl))
6581
+ return decl.fullName;
6506
6582
  switch (decl.type) {
6507
- case "Literal":
6508
- return decl.raw || decl.value?.toString() || "null";
6509
- case "VariableDeclarator":
6510
- return decl.fullName;
6583
+ case "BinaryExpression":
6584
+ return decl.left.name;
6585
+ case "EnumStringMember":
6586
+ return decl.init
6587
+ ? `${decl.id.name}:${(0,external_api_cjs_namespaceObject.formatAst)(decl.init)}`
6588
+ : decl.id.name;
6511
6589
  default:
6512
6590
  throw new Error(`Unexpected EventDecl type: ${decl.type}`);
6513
6591
  }
6514
6592
  }
6515
6593
  function declName(decl) {
6594
+ if (Array.isArray(decl)) {
6595
+ decl = decl[0];
6596
+ }
6597
+ if (decl.type === "Literal") {
6598
+ return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
6599
+ }
6600
+ if ((0,external_api_cjs_namespaceObject.isStateNode)(decl))
6601
+ return decl.name;
6516
6602
  switch (decl.type) {
6517
- case "Literal":
6518
- return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
6519
- case "VariableDeclarator":
6520
- return decl.name;
6603
+ case "BinaryExpression":
6604
+ return decl.left.name;
6605
+ case "EnumStringMember":
6606
+ return decl.id.name;
6521
6607
  default:
6522
6608
  throw new Error(`Unexpected EventDecl type: ${decl.type}`);
6523
6609
  }
6524
6610
  }
6525
- function logAntState(s, decl) {
6526
- const defs = Array.from(s.ant).reduce((defs, event) => {
6527
- if (event.type === "def" || event.type === "mod")
6528
- defs++;
6529
- return defs;
6530
- }, 0);
6531
- console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
6532
- console.log(` - members: ${Array.from(s.members)
6533
- .map(([block, live]) => block.order + (live ? "t" : "f"))
6534
- .join(", ")}`);
6535
- }
6536
- function logAntDecls(antDecls) {
6537
- antDecls.forEach(logAntState);
6538
- }
6539
- function sizeBasedPRE(state, func) {
6540
- if (!func.node.body)
6541
- return;
6542
- if (!state.config ||
6543
- !state.config.sizeBasedPRE ||
6544
- (typeof state.config.sizeBasedPRE === "string" &&
6545
- state.config.sizeBasedPRE !== func.fullName)) {
6546
- return;
6547
- }
6548
- const { graph: head, identifiers } = buildPREGraph(state, func);
6549
- const candidates = computeAttributes(state, head);
6550
- if (candidates) {
6551
- if (logging) {
6552
- console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
6553
- logAntDecls(candidates);
6554
- }
6555
- const nodeMap = new Map();
6556
- const declMap = new Map();
6557
- const variableDecl = withLoc({
6558
- type: "VariableDeclaration",
6559
- declarations: [],
6560
- kind: "var",
6561
- }, func.node.body);
6562
- variableDecl.end = variableDecl.start;
6563
- variableDecl.loc.end = variableDecl.loc.start;
6564
- candidates.forEach((s, decl) => {
6565
- let name;
6566
- let i = 0;
6567
- do {
6568
- name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
6569
- if (!identifiers.has(name)) {
6570
- identifiers.add(name);
6571
- break;
6572
- }
6573
- i++;
6574
- } while (true);
6575
- declMap.set(decl, name);
6576
- variableDecl.declarations.push(withLoc({
6577
- type: "VariableDeclarator",
6578
- id: withLoc({ type: "Identifier", name }, variableDecl),
6579
- kind: "var",
6580
- }, variableDecl));
6581
- s.ant.forEach((event) => {
6582
- const events = nodeMap.get(event.node);
6583
- if (!events) {
6584
- nodeMap.set(event.node, [event]);
6585
- }
6586
- else {
6587
- events.push(event);
6588
- }
6589
- });
6590
- });
6591
- applyReplacements(func.node, nodeMap, declMap);
6592
- func.node.body.body.unshift(variableDecl);
6593
- }
6594
- }
6595
6611
  function unhandledExpression(node) {
6596
6612
  throw new Error(`Unhandled expression type: ${node.type}`);
6597
6613
  }
6598
- function buildPREGraph(state, func) {
6614
+ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wantsAllRefs) {
6615
+ const uniqueDeclMap = new Map();
6599
6616
  const findDecl = (node) => {
6600
6617
  if (node.type === "Identifier" ||
6601
6618
  (node.type === "MemberExpression" && !node.computed)) {
6602
6619
  const [, results] = state.lookup(node);
6603
- if (results &&
6604
- results.length === 1 &&
6605
- results[0].parent?.type != "BlockStatement" &&
6606
- results[0].results.length === 1 &&
6607
- results[0].results[0].type === "VariableDeclarator") {
6608
- return results[0].results[0];
6609
- }
6620
+ const decls = (results &&
6621
+ results.reduce((decls, result) => result.results.reduce((decls, result) => {
6622
+ if (!wantsAllRefs &&
6623
+ (result.type !== "VariableDeclarator" || (0,external_api_cjs_namespaceObject.isLocal)(result))) {
6624
+ return decls;
6625
+ }
6626
+ if (!decls)
6627
+ return result;
6628
+ if (Array.isArray(decls)) {
6629
+ decls.push(result);
6630
+ return decls;
6631
+ }
6632
+ else {
6633
+ return [decls, result];
6634
+ }
6635
+ }, decls), null)) ||
6636
+ null;
6637
+ if (!Array.isArray(decls))
6638
+ return decls;
6639
+ // We use EventDecl as a Map key, so we need to
6640
+ // uniquify it. Note that from any given function,
6641
+ // if state.lookup finds a set of non locals, it will
6642
+ // always find the same set, so we can use the first
6643
+ // such as the unique identifier.
6644
+ const canon = uniqueDeclMap.get(decls[0]);
6645
+ if (!canon) {
6646
+ uniqueDeclMap.set(decls[0], decls);
6647
+ return decls;
6648
+ }
6649
+ if (canon.length != decls.length ||
6650
+ !canon.every((v, i) => v === decls[i])) {
6651
+ throw new Error(`Canonical representation of ${declFullName(canon)} did not match`);
6652
+ }
6653
+ return canon;
6610
6654
  }
6611
6655
  return null;
6612
6656
  };
@@ -6614,18 +6658,22 @@ function buildPREGraph(state, func) {
6614
6658
  const identifiers = new Set();
6615
6659
  const liveDefs = new Map();
6616
6660
  const liveStmts = new Map();
6617
- const liveDef = (def, stmt) => {
6618
- let curNodes = liveDefs.get(def);
6619
- if (!curNodes) {
6620
- liveDefs.set(def, (curNodes = new Set()));
6621
- }
6622
- curNodes.add(stmt);
6623
- let defs = liveStmts.get(stmt);
6624
- if (!defs) {
6625
- liveStmts.set(stmt, (defs = new Map()));
6661
+ const liveDef = trackInsertionPoints
6662
+ ? (def, stmt) => {
6663
+ let curNodes = liveDefs.get(def);
6664
+ if (!curNodes) {
6665
+ liveDefs.set(def, (curNodes = new Set()));
6666
+ }
6667
+ curNodes.add(stmt);
6668
+ let defs = liveStmts.get(stmt);
6669
+ if (!defs) {
6670
+ liveStmts.set(stmt, (defs = new Map()));
6671
+ }
6672
+ defs.set(def, (defs.get(def) || 0) + 1);
6626
6673
  }
6627
- defs.set(def, (defs.get(def) || 0) + 1);
6628
- };
6674
+ : () => {
6675
+ /* do nothing */
6676
+ };
6629
6677
  return {
6630
6678
  identifiers,
6631
6679
  graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
@@ -6660,7 +6708,7 @@ function buildPREGraph(state, func) {
6660
6708
  case "ParenthesizedExpression":
6661
6709
  break;
6662
6710
  case "Literal":
6663
- if (refCost(node) > LocalRefCost) {
6711
+ if (wantsLiteral(node)) {
6664
6712
  const result = getNodeValue(node);
6665
6713
  const key = result[1] +
6666
6714
  (result[0].value === null
@@ -6682,34 +6730,40 @@ function buildPREGraph(state, func) {
6682
6730
  case "Identifier":
6683
6731
  identifiers.add(node.name);
6684
6732
  // fall through
6685
- case "MemberExpression":
6686
- {
6687
- const decl = findDecl(node);
6688
- if (decl && decl.type === "VariableDeclarator") {
6689
- const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
6690
- liveDefs.get(decl);
6691
- if (defStmts) {
6692
- break;
6693
- /*
6694
- // hold off on this for now. we need to communicate
6695
- // which defs need to be fixed, which involves yet-another
6696
- // table.
6697
-
6698
- if (defStmts.size !== 1) break;
6699
- const fixable = isFixableStmt([...defStmts][0]);
6700
- if (fixable === false) break;
6701
- cost += fixable;
6702
- */
6733
+ case "MemberExpression": {
6734
+ const decls = findDecl(node);
6735
+ if (!decls)
6736
+ break;
6737
+ if (trackInsertionPoints &&
6738
+ (0,external_util_cjs_namespaceObject.some)(decls, (decl) => {
6739
+ if (decl.type === "VariableDeclarator") {
6740
+ const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
6741
+ liveDefs.get(decl);
6742
+ if (defStmts) {
6743
+ return true;
6744
+ /*
6745
+ // hold off on this for now. we need to communicate
6746
+ // which defs need to be fixed, which involves yet-another
6747
+ // table.
6748
+
6749
+ if (defStmts.size !== 1) break;
6750
+ const fixable = isFixableStmt([...defStmts][0]);
6751
+ if (fixable === false) break;
6752
+ cost += fixable;
6753
+ */
6754
+ }
6703
6755
  }
6704
- return {
6705
- type: "ref",
6706
- node,
6707
- decl,
6708
- mayThrow,
6709
- };
6710
- }
6756
+ return false;
6757
+ })) {
6758
+ break;
6711
6759
  }
6712
- break;
6760
+ return {
6761
+ type: "ref",
6762
+ node,
6763
+ decl: decls,
6764
+ mayThrow,
6765
+ };
6766
+ }
6713
6767
  case "VariableDeclarator": {
6714
6768
  const decl = findDecl(node.id.type === "BinaryExpression" ? node.id.left : node.id);
6715
6769
  if (decl) {
@@ -6757,8 +6811,10 @@ function buildPREGraph(state, func) {
6757
6811
  }
6758
6812
  case "CallExpression": {
6759
6813
  liveDef(null, stmt);
6760
- const [, results] = state.lookup(node.callee);
6761
- const callees = results ? findCallees(results) : null;
6814
+ const [, results] = state.lookupNonlocal(node.callee);
6815
+ const callees = results
6816
+ ? findCallees(results)
6817
+ : findCalleesByNode(state, node.callee);
6762
6818
  return { type: "mod", node, mayThrow, callees };
6763
6819
  }
6764
6820
  default:
@@ -6773,6 +6829,132 @@ function buildPREGraph(state, func) {
6773
6829
  }),
6774
6830
  };
6775
6831
  }
6832
+ class DataflowQueue {
6833
+ constructor() {
6834
+ this.enqueued = new Set();
6835
+ this.queue = new priorityqueuejs((b, a) => (a.order || 0) - (b.order || 0));
6836
+ }
6837
+ enqueue(block) {
6838
+ if (!this.enqueued.has(block)) {
6839
+ this.enqueued.add(block);
6840
+ this.queue.enq(block);
6841
+ }
6842
+ }
6843
+ dequeue() {
6844
+ const block = this.queue.deq();
6845
+ this.enqueued.delete(block);
6846
+ return block;
6847
+ }
6848
+ empty() {
6849
+ return this.queue.isEmpty();
6850
+ }
6851
+ }
6852
+
6853
+ ;// CONCATENATED MODULE: ./src/pre.ts
6854
+
6855
+
6856
+
6857
+
6858
+
6859
+
6860
+ /**
6861
+ * This implements a pseudo Partial Redundancy Elimination
6862
+ * pass. It isn't quite like traditional PRE because we're
6863
+ * aiming to minimize size, not dynamic instructions. So
6864
+ * for us, its worthwhile to take something like:
6865
+ *
6866
+ * switch (x) {
6867
+ * case 1: foo(A.B); break;
6868
+ * case 2: foo(C); break;
6869
+ * case 3: bar(A.B); break;
6870
+ * }
6871
+ *
6872
+ * and rewrite it as
6873
+ *
6874
+ * var tmp = A.B;
6875
+ * switch (x) {
6876
+ * case 1: foo(tmp); break;
6877
+ * case 2: foo(C); break;
6878
+ * case 3: bar(tmp); break;
6879
+ * }
6880
+ *
6881
+ * because even though A.B wasn't used on all paths where we
6882
+ * inserted the temporary, we still reduced the code size.
6883
+ */
6884
+ const logging = false;
6885
+ function logAntState(s, decl) {
6886
+ const defs = Array.from(s.ant).reduce((defs, event) => {
6887
+ if (event.type === "def" || event.type === "mod")
6888
+ defs++;
6889
+ return defs;
6890
+ }, 0);
6891
+ console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
6892
+ console.log(` - members: ${Array.from(s.members)
6893
+ .map(([block, live]) => block.order + (live ? "t" : "f"))
6894
+ .join(", ")}`);
6895
+ }
6896
+ function logAntDecls(antDecls) {
6897
+ antDecls.forEach(logAntState);
6898
+ }
6899
+ function sizeBasedPRE(state, func) {
6900
+ if (!func.node.body)
6901
+ return;
6902
+ if (!state.config ||
6903
+ !state.config.sizeBasedPRE ||
6904
+ (typeof state.config.sizeBasedPRE === "string" &&
6905
+ state.config.sizeBasedPRE !== func.fullName)) {
6906
+ return;
6907
+ }
6908
+ const { graph: head, identifiers } = buildPREGraph(state, func);
6909
+ const candidates = computeAttributes(state, head);
6910
+ if (candidates) {
6911
+ if (logging) {
6912
+ console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
6913
+ logAntDecls(candidates);
6914
+ }
6915
+ const nodeMap = new Map();
6916
+ const declMap = new Map();
6917
+ const variableDecl = withLoc({
6918
+ type: "VariableDeclaration",
6919
+ declarations: [],
6920
+ kind: "var",
6921
+ }, func.node.body);
6922
+ variableDecl.end = variableDecl.start;
6923
+ variableDecl.loc.end = variableDecl.loc.start;
6924
+ candidates.forEach((s, decl) => {
6925
+ let name;
6926
+ let i = 0;
6927
+ do {
6928
+ name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
6929
+ if (!identifiers.has(name)) {
6930
+ identifiers.add(name);
6931
+ break;
6932
+ }
6933
+ i++;
6934
+ } while (true);
6935
+ declMap.set(decl, name);
6936
+ variableDecl.declarations.push(withLoc({
6937
+ type: "VariableDeclarator",
6938
+ id: withLoc({ type: "Identifier", name }, variableDecl),
6939
+ kind: "var",
6940
+ }, variableDecl));
6941
+ s.ant.forEach((event) => {
6942
+ const events = nodeMap.get(event.node);
6943
+ if (!events) {
6944
+ nodeMap.set(event.node, [event]);
6945
+ }
6946
+ else {
6947
+ events.push(event);
6948
+ }
6949
+ });
6950
+ });
6951
+ applyReplacements(func.node, nodeMap, declMap);
6952
+ func.node.body.body.unshift(variableDecl);
6953
+ }
6954
+ }
6955
+ function buildPREGraph(state, func) {
6956
+ return buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
6957
+ }
6776
6958
  function anticipatedDecls() {
6777
6959
  return new Map();
6778
6960
  }
@@ -6928,26 +7110,18 @@ function computeAttributes(state, head) {
6928
7110
  .join(", ")}`);
6929
7111
  if (block.events) {
6930
7112
  block.events.forEach((event) => event.type !== "exn" &&
6931
- console.log(` ${event.type}: ${event.decl ? declFullName(event.decl) : "??"}`));
7113
+ console.log(` ${event.type}: ${event.decl
7114
+ ? declFullName(event.decl)
7115
+ : event.node
7116
+ ? (0,external_api_cjs_namespaceObject.formatAst)(event.node)
7117
+ : "??"}`));
6932
7118
  }
6933
7119
  console.log(`Succs: ${(block.succs || [])
6934
7120
  .map((block) => block.order)
6935
7121
  .join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
6936
7122
  });
6937
7123
  }
6938
- const enqueued = new Set();
6939
- const queue = new priorityqueuejs((b, a) => (a.order || 0) - (b.order || 0));
6940
- const enqueue = (block) => {
6941
- if (!enqueued.has(block)) {
6942
- enqueued.add(block);
6943
- queue.enq(block);
6944
- }
6945
- };
6946
- const dequeue = () => {
6947
- const block = queue.deq();
6948
- enqueued.delete(block);
6949
- return block;
6950
- };
7124
+ const queue = new DataflowQueue();
6951
7125
  const blockStates = [];
6952
7126
  /*
6953
7127
  Algorithm
@@ -6981,9 +7155,9 @@ function computeAttributes(state, head) {
6981
7155
  }
6982
7156
  return result;
6983
7157
  };
6984
- order.forEach((block) => enqueue(block));
6985
- while (queue.size()) {
6986
- const top = dequeue();
7158
+ order.forEach((block) => queue.enqueue(block));
7159
+ while (!queue.empty()) {
7160
+ const top = queue.dequeue();
6987
7161
  if (top.order === undefined) {
6988
7162
  throw new Error(`Unreachable block was visited!`);
6989
7163
  }
@@ -7022,13 +7196,13 @@ function computeAttributes(state, head) {
7022
7196
  break;
7023
7197
  }
7024
7198
  case "mod": {
7025
- curState.forEach((candidates, decl) => {
7026
- if (decl.type === "VariableDeclarator" &&
7199
+ curState.forEach((candidates, decls) => {
7200
+ if ((0,external_util_cjs_namespaceObject.some)(decls, (decl) => decl.type === "VariableDeclarator" &&
7027
7201
  decl.node.kind === "var" &&
7028
7202
  candidates.live &&
7029
7203
  (!event.callees ||
7030
- event.callees.some((callee) => functionMayModify(state, callee, decl)))) {
7031
- candidates.ant.add(getMod(event, decl, candidates.node));
7204
+ event.callees.some((callee) => functionMayModify(state, callee, decl))))) {
7205
+ candidates.ant.add(getMod(event, decls, candidates.node));
7032
7206
  candidates.live = false;
7033
7207
  }
7034
7208
  });
@@ -7080,7 +7254,7 @@ function computeAttributes(state, head) {
7080
7254
  logAntDecls(curState);
7081
7255
  }
7082
7256
  if (top.preds) {
7083
- top.preds.forEach((pred) => enqueue(pred));
7257
+ top.preds.forEach((pred) => queue.enqueue(pred));
7084
7258
  }
7085
7259
  }
7086
7260
  const candidateDecls = anticipatedDecls();
@@ -7918,8 +8092,21 @@ function replacementLiteral(arg, value, type) {
7918
8092
  else if (type === "Double") {
7919
8093
  raw += "d";
7920
8094
  }
7921
- else if (type === "Float" && prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
7922
- raw += "f";
8095
+ else if (type === "Float") {
8096
+ if (prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
8097
+ raw += "f";
8098
+ }
8099
+ else {
8100
+ const match = raw.match(/^(-)?(\d*)\.(\d+)(e\d+)?/);
8101
+ if (match && match[2].length + match[3].length > 9) {
8102
+ for (let l = 9 - match[2].length; l > 0; l--) {
8103
+ const s = `${match[1] || ""}${match[2]}.${match[3].substring(0, l)}${match[4] || ""}`;
8104
+ if (value !== roundToFloat(parseFloat(s)))
8105
+ break;
8106
+ raw = s;
8107
+ }
8108
+ }
8109
+ }
7923
8110
  }
7924
8111
  const { start, end, loc } = arg;
7925
8112
  return {
@@ -8007,6 +8194,20 @@ function shift_mod_types(left, right) {
8007
8194
  }
8008
8195
  return result;
8009
8196
  }
8197
+ function equalsFn(left, right) {
8198
+ const lt = typeof left;
8199
+ const rt = typeof right;
8200
+ return lt === "string" || rt === "string"
8201
+ ? // two string literals will compare unequal, becuase string
8202
+ // equality is object equality.
8203
+ false
8204
+ : (lt === "number" || lt === "bigint") &&
8205
+ (rt === "number" || rt === "bigint")
8206
+ ? // numeric types are compared for value equality
8207
+ left == right
8208
+ : // otherwise types and values must match
8209
+ left === right;
8210
+ }
8010
8211
  const operators = {
8011
8212
  "+": {
8012
8213
  typeFn: plus_types,
@@ -8058,14 +8259,11 @@ const operators = {
8058
8259
  },
8059
8260
  "==": {
8060
8261
  typeFn: () => ["Boolean", (v) => v],
8061
- valueFn: (left, right) =>
8062
- // two string literals will compare unequal, becuase string
8063
- // equality is object equality.
8064
- typeof left === "string" ? false : left === right,
8262
+ valueFn: equalsFn,
8065
8263
  },
8066
8264
  "!=": {
8067
8265
  typeFn: () => ["Boolean", (v) => v],
8068
- valueFn: (left, right) => typeof left === "string" ? true : left !== right,
8266
+ valueFn: (left, right) => !equalsFn(left, right),
8069
8267
  },
8070
8268
  "<=": {
8071
8269
  typeFn: common_arith_types,
@@ -8592,7 +8790,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8592
8790
  if (!state.currentFunction) {
8593
8791
  throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
8594
8792
  }
8595
- state.currentFunction.info = state.currentFunction.next_info;
8793
+ state.currentFunction.info = state.currentFunction.next_info || false;
8596
8794
  delete state.currentFunction.next_info;
8597
8795
  delete state.currentFunction;
8598
8796
  break;
@@ -9155,7 +9353,7 @@ async function createLocalBarrels(targets, options) {
9155
9353
  async function generateOptimizedProject(options) {
9156
9354
  const config = await getConfig(options);
9157
9355
  const workspace = config.workspace;
9158
- const { manifest, targets, xml, jungles } = await get_jungle(config.jungleFiles, config);
9356
+ const { manifest, targets, xml, devices, resources, buildDependencies } = await get_jungle(config.jungleFiles, config);
9159
9357
  if (xml.body instanceof Error) {
9160
9358
  throw xml.body;
9161
9359
  }
@@ -9167,7 +9365,7 @@ async function generateOptimizedProject(options) {
9167
9365
  xml.body.elements[0].loc || undefined;
9168
9366
  throw error;
9169
9367
  }
9170
- const dependencyFiles = [manifest, ...jungles];
9368
+ const dependencyFiles = Object.keys(resources).concat(Object.keys(buildDependencies));
9171
9369
  await createLocalBarrels(targets, config);
9172
9370
  const buildConfigs = {};
9173
9371
  const products = {};
@@ -9265,13 +9463,35 @@ async function generateOptimizedProject(options) {
9265
9463
  relative_manifest = "manifest.xml";
9266
9464
  }
9267
9465
  const parts = [`project.manifest=${relative_manifest}`];
9268
- const process_field = (prefix, base, name, mapper = null) => {
9466
+ const map_field = (base, name, mapper = null) => {
9269
9467
  const obj = base[name];
9270
9468
  if (!obj)
9271
- return;
9469
+ return null;
9272
9470
  const map_one = (s) => (mapper ? mapper(s) : s);
9273
9471
  const map = (s) => Array.isArray(s) ? `[${s.map(map_one).join(";")}]` : map_one(s);
9274
- parts.push(`${prefix}${name} = ${obj.map(map).join(";")}`);
9472
+ return `${obj.map(map).join(";")}`;
9473
+ };
9474
+ const process_field = (prefix, base, name, mapper = null) => {
9475
+ const mapped = map_field(base, name, mapper);
9476
+ if (!mapped)
9477
+ return;
9478
+ parts.push(`${prefix}${name} = ${mapped}`);
9479
+ };
9480
+ const languagesToInclude = Object.fromEntries((manifestLanguages(xml) || []).map((lang) => [lang, true]));
9481
+ const unsupportedLangsCache = {};
9482
+ let availableDefaults = null;
9483
+ const nextAvailableDefault = () => {
9484
+ if (!availableDefaults) {
9485
+ availableDefaults = Object.keys(Object.values(devices).reduce((m, d) => {
9486
+ m[d.deviceFamily] = true;
9487
+ const match = d.deviceFamily.match(/^(\w+)-\d+x\d+/);
9488
+ if (match)
9489
+ m[match[1]] = true;
9490
+ return m;
9491
+ }, {})).sort();
9492
+ availableDefaults.unshift("base");
9493
+ }
9494
+ return availableDefaults.shift();
9275
9495
  };
9276
9496
  targets.forEach((target) => {
9277
9497
  if (!buildConfigs[configKey(target)])
@@ -9308,8 +9528,39 @@ async function generateOptimizedProject(options) {
9308
9528
  process_field(prefix, qualifier, "excludeAnnotations");
9309
9529
  const qlang = qualifier.lang;
9310
9530
  if (qlang) {
9531
+ const devLang = devices[product].languages;
9532
+ const unsupportedLangs = Object.keys(qlang)
9533
+ .sort()
9534
+ .map((key) => {
9535
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(devLang, key) ||
9536
+ !(0,external_api_cjs_namespaceObject.hasProperty)(languagesToInclude, key)) {
9537
+ return null;
9538
+ }
9539
+ const mapped = map_field(qlang, key, relative_path);
9540
+ if (!mapped)
9541
+ return null;
9542
+ return [key, mapped];
9543
+ })
9544
+ .filter((a) => a != null);
9545
+ let keysToSkip = null;
9546
+ if (unsupportedLangs.length) {
9547
+ const key = JSON.stringify(unsupportedLangs);
9548
+ if (!(0,external_api_cjs_namespaceObject.hasProperty)(unsupportedLangsCache, key)) {
9549
+ const base = nextAvailableDefault();
9550
+ if (base) {
9551
+ unsupportedLangs.forEach(([key, value]) => parts.push(`${base}.lang.${key} = ${value}`));
9552
+ unsupportedLangsCache[key] = `${base}.lang`;
9553
+ }
9554
+ }
9555
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(unsupportedLangsCache, key)) {
9556
+ keysToSkip = Object.fromEntries(unsupportedLangs);
9557
+ parts.push(`${prefix}lang = $(${unsupportedLangsCache[key]})`);
9558
+ }
9559
+ }
9311
9560
  Object.keys(qlang).forEach((key) => {
9312
- process_field(`${prefix}lang.`, qlang, key, relative_path);
9561
+ (0,external_api_cjs_namespaceObject.hasProperty)(keysToSkip, key) ||
9562
+ !(0,external_api_cjs_namespaceObject.hasProperty)(languagesToInclude, key) ||
9563
+ process_field(`${prefix}lang.`, qlang, key, relative_path);
9313
9564
  });
9314
9565
  }
9315
9566
  });
@@ -9429,7 +9680,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
9429
9680
  // the oldest optimized file, we don't need to regenerate
9430
9681
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
9431
9682
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
9432
- if (source_time < opt_time && 1670782882733 < opt_time) {
9683
+ if (source_time < opt_time && 1672601827382 < opt_time) {
9433
9684
  return { hasTests, diagnostics: prevDiagnostics };
9434
9685
  }
9435
9686
  }
@@ -9456,7 +9707,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
9456
9707
  return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
9457
9708
  hasTests,
9458
9709
  diagnostics,
9459
- optimizerVersion: "1.0.44",
9710
+ optimizerVersion: "1.0.45",
9460
9711
  ...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
9461
9712
  }))
9462
9713
  .then(() => ({ hasTests, diagnostics }));