pxt-core 8.2.4 → 8.2.7

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.
Files changed (64) hide show
  1. package/built/backendutils.js +19 -1
  2. package/built/cli.js +1 -0
  3. package/built/pxt-common.json +1 -1
  4. package/built/pxt.js +191 -33
  5. package/built/pxtblockly.js +17 -4
  6. package/built/pxtblocks.d.ts +1 -0
  7. package/built/pxtblocks.js +17 -4
  8. package/built/pxtcompiler.d.ts +1 -0
  9. package/built/pxtcompiler.js +34 -8
  10. package/built/pxteditor.d.ts +1 -0
  11. package/built/pxteditor.js +5 -0
  12. package/built/pxtlib.d.ts +14 -0
  13. package/built/pxtlib.js +117 -9
  14. package/built/pxtpy.d.ts +1 -0
  15. package/built/pxtpy.js +39 -16
  16. package/built/target.js +1 -1
  17. package/built/web/blockly.css +1 -1
  18. package/built/web/main.js +1 -1
  19. package/built/web/pxtapp.js +1 -1
  20. package/built/web/pxtasseteditor.js +1 -1
  21. package/built/web/pxtblockly.js +1 -1
  22. package/built/web/pxtblocks.js +1 -1
  23. package/built/web/pxtcompiler.js +1 -1
  24. package/built/web/pxteditor.js +1 -1
  25. package/built/web/pxtembed.js +2 -2
  26. package/built/web/pxtlib.js +1 -1
  27. package/built/web/pxtpy.js +1 -1
  28. package/built/web/pxtworker.js +1 -1
  29. package/built/web/react-common-authcode.css +98 -0
  30. package/built/web/react-common-skillmap.css +1 -1
  31. package/built/web/rtlblockly.css +1 -1
  32. package/built/web/rtlreact-common-skillmap.css +1 -1
  33. package/built/web/rtlsemantic.css +1 -1
  34. package/built/web/semantic.css +1 -1
  35. package/built/web/skillmap/css/main.3684f34d.chunk.css +1 -0
  36. package/built/web/skillmap/js/2.26325281.chunk.js +2 -0
  37. package/built/web/skillmap/js/main.b87a119c.chunk.js +1 -0
  38. package/localtypings/react.d.ts +5 -0
  39. package/package.json +1 -1
  40. package/react-common/components/controls/Checkbox.tsx +1 -1
  41. package/react-common/components/palette/ColorPickerField.tsx +65 -0
  42. package/react-common/components/palette/PaletteEditor.tsx +66 -0
  43. package/react-common/components/palette/PalettePicker.tsx +52 -0
  44. package/react-common/components/palette/PaletteSwatch.tsx +27 -0
  45. package/react-common/components/palette/Palettes.ts +289 -0
  46. package/react-common/components/profile/SignInModal.tsx +100 -0
  47. package/react-common/components/profile/UserPane.tsx +17 -9
  48. package/react-common/styles/palette/ColorPickerField.less +21 -0
  49. package/react-common/styles/palette/PalettePicker.less +10 -0
  50. package/react-common/styles/palette/PaletteSwatch.less +27 -0
  51. package/react-common/styles/palette/palette.less +3 -0
  52. package/react-common/styles/profile/profile.less +64 -1
  53. package/react-common/styles/react-common.less +1 -0
  54. package/theme/asset-editor.less +5 -0
  55. package/theme/blockly-core.less +1 -1
  56. package/theme/common.less +13 -2
  57. package/theme/greenscreen.less +4 -1
  58. package/theme/home.less +0 -5
  59. package/theme/image-editor/bottomBar.less +1 -1
  60. package/theme/tutorial-sidebar.less +43 -2
  61. package/webapp/public/skillmap.html +2 -2
  62. package/built/web/skillmap/css/main.c5811548.chunk.css +0 -1
  63. package/built/web/skillmap/js/2.26b9a6f6.chunk.js +0 -2
  64. package/built/web/skillmap/js/main.98eed582.chunk.js +0 -1
@@ -665,6 +665,7 @@ var ts;
665
665
  const info = utf8AsmStringLiteral(strLit);
666
666
  return `
667
667
  .balign 4
668
+ .object ${lbl}
668
669
  ${lbl}: ${this.obj_header(info.vt)}
669
670
  ${info.asm}
670
671
  `;
@@ -675,6 +676,7 @@ var ts;
675
676
  const align = /f{16}/i.test(data) ? 8 : 4;
676
677
  return `
677
678
  .balign ${align}
679
+ .object ${lbl}
678
680
  ${lbl}: ${this.obj_header("pxt::buffer_vt")}
679
681
  ${hexLiteralAsm(data)}
680
682
  `;
@@ -784,6 +786,7 @@ ${hexLiteralAsm(data)}
784
786
  ;
785
787
  `);
786
788
  let baseLabel = this.proc.label();
789
+ this.write(`.object ${baseLabel} ${JSON.stringify(this.proc.getFullName())}`);
787
790
  let preLabel = baseLabel + "_pre";
788
791
  let bkptLabel = baseLabel + "_bkpt";
789
792
  let locLabel = baseLabel + "_locals";
@@ -1148,9 +1151,13 @@ ${baseLabel}_nochk:
1148
1151
  this.writeFailBranch();
1149
1152
  });
1150
1153
  }
1154
+ helperObject(desc) {
1155
+ return `.object _pxt_helper_${desc.replace(/[^\w]+/g, "_")} "helper: ${desc}"`;
1156
+ }
1151
1157
  emitBindHelper() {
1152
1158
  const maxArgs = 12;
1153
1159
  this.write(`
1160
+ ${this.helperObject("bind")}
1154
1161
  .section code
1155
1162
  _pxt_bind_helper:
1156
1163
  push {r0, r2}
@@ -1625,6 +1632,7 @@ ${baseLabel}_nochk:
1625
1632
  emitFieldMethods() {
1626
1633
  for (let op of ["get", "set"]) {
1627
1634
  this.write(`
1635
+ ${this.helperObject(op)}
1628
1636
  .section code
1629
1637
  _pxt_map_${op}:
1630
1638
  `);
@@ -1666,6 +1674,7 @@ ${baseLabel}_nochk:
1666
1674
  }
1667
1675
  emitArrayMethod(op, isBuffer) {
1668
1676
  this.write(`
1677
+ ${this.helperObject(op + " " + (isBuffer ? "buffer" : "array"))}
1669
1678
  .section code
1670
1679
  _pxt_${isBuffer ? "buffer" : "array"}_${op}:
1671
1680
  `);
@@ -1750,6 +1759,7 @@ ${baseLabel}_nochk:
1750
1759
  emitLambdaTrampoline() {
1751
1760
  let r3 = pxtc.target.stackAlign ? "r3," : "";
1752
1761
  this.write(`
1762
+ ${this.helperObject("trampoline")}
1753
1763
  .section code
1754
1764
  _pxt_lambda_trampoline:
1755
1765
  push {${r3} r4, r5, r6, r7, lr}
@@ -1789,6 +1799,7 @@ ${baseLabel}_nochk:
1789
1799
  mov r11, r7
1790
1800
  pop {${r3} r4, r5, r6, r7, pc}`);
1791
1801
  this.write(`
1802
+ ${this.helperObject("exn")}
1792
1803
  .section code
1793
1804
  ; r0 - try frame
1794
1805
  ; r1 - handler PC
@@ -1817,6 +1828,7 @@ ${baseLabel}_nochk:
1817
1828
  bx r1
1818
1829
  `);
1819
1830
  this.write(`
1831
+ ${this.helperObject("stringconv")}
1820
1832
  .section code
1821
1833
  _pxt_stringConv:
1822
1834
  `);
@@ -3131,6 +3143,7 @@ _numops_fromInt:
3131
3143
  // this make sure to set the Z flag correctly
3132
3144
  r += `
3133
3145
  .section code
3146
+ .object _pxt_helper_cmp_${op}
3134
3147
  _cmp_${op}:
3135
3148
  lsls r2, r0, #31
3136
3149
  beq .boxed
@@ -7716,7 +7729,8 @@ var ts;
7716
7729
  lbl = "_ldlit_" + ++seq;
7717
7730
  values[v] = lbl;
7718
7731
  }
7719
- line.update(`ldr ${reg}, ${lbl}`);
7732
+ line.ldlitLabel = line.words[3];
7733
+ line.update(`ldr ${reg}, ${lbl} ; ${line.ldlitLabel}`);
7720
7734
  }
7721
7735
  if (line === nextGoodSpot) {
7722
7736
  nextGoodSpot = null;
@@ -7724,6 +7738,7 @@ var ts;
7724
7738
  let jmplbl = "_jmpwords_" + ++seq;
7725
7739
  if (needsJumpOver)
7726
7740
  txtLines.push("bb " + jmplbl);
7741
+ txtLines.push(`.object PUSH`);
7727
7742
  txtLines.push(".balign 4");
7728
7743
  for (let v of Object.keys(values)) {
7729
7744
  let lbl = values[v];
@@ -7731,6 +7746,7 @@ var ts;
7731
7746
  }
7732
7747
  if (needsJumpOver)
7733
7748
  txtLines.push(jmplbl + ":");
7749
+ txtLines.push(`.object POP`);
7734
7750
  for (let t of txtLines) {
7735
7751
  f.buildLine(t, outlines);
7736
7752
  let ll = outlines[outlines.length - 1];
@@ -9025,7 +9041,7 @@ var ts;
9025
9041
  function inspect(n) {
9026
9042
  console.log(stringKind(n));
9027
9043
  }
9028
- // next free error 9283
9044
+ // next free error 9284
9029
9045
  function userError(code, msg, secondary = false) {
9030
9046
  let e = new Error(msg);
9031
9047
  e.ksEmitterUserError = true;
@@ -15195,7 +15211,8 @@ var ts;
15195
15211
  asmLabels[lbl] = true;
15196
15212
  return "";
15197
15213
  });
15198
- let code = ".section code\n" +
15214
+ let code = ".object inlineasm\n" +
15215
+ ".section code\n" +
15199
15216
  "@stackmark func\n" +
15200
15217
  "@scope user" + asmIdx++ + "\n" +
15201
15218
  src + "\n" +
@@ -15728,6 +15745,7 @@ var ts;
15728
15745
  for (let data of Object.keys(bin.doubles)) {
15729
15746
  let lbl = bin.doubles[data];
15730
15747
  bin.otherLiterals.push(`
15748
+ .object ${lbl}
15731
15749
  .balign 4
15732
15750
  ${lbl}: ${snippets.obj_header("pxt::number_vt")}
15733
15751
  .hex ${data}
@@ -15820,6 +15838,7 @@ ${lbl}: ${snippets.obj_header("pxt::number_vt")}
15820
15838
  // ifaceInfo.mult = 0
15821
15839
  let ptrSz = pxtc.target.shortPointers ? ".short" : ".word";
15822
15840
  let s = `
15841
+ .object ${info.id}_VT
15823
15842
  .balign 4
15824
15843
  ${info.id}_VT:
15825
15844
  .short ${info.allfields.length * 4 + 4} ; size in bytes
@@ -15917,14 +15936,18 @@ ${hexfile.hexPrelude()}
15917
15936
  asmsource += hexfile.asmTotalSource; // user-supplied asm
15918
15937
  asmsource += "_code_end:\n\n";
15919
15938
  pxtc.U.iterMap(bin.codeHelpers, (code, lbl) => {
15920
- asmsource += ` .section code\n${lbl}:\n${code}\n`;
15939
+ asmsource +=
15940
+ ` .section code\n` +
15941
+ ` .object _code_helper_${lbl}\n` +
15942
+ `${lbl}:\n` +
15943
+ `${code}\n`;
15921
15944
  });
15922
15945
  asmsource += snippets.arithmetic();
15923
15946
  asmsource += "_helpers_end:\n\n";
15924
15947
  bin.usedClassInfos.forEach(info => {
15925
15948
  asmsource += vtableToAsm(info, opts, bin);
15926
15949
  });
15927
- asmsource += `\n.balign 4\n_pxt_iface_member_names:\n`;
15950
+ asmsource += `\n.balign 4\n.object _pxt_iface_member_names\n_pxt_iface_member_names:\n`;
15928
15951
  asmsource += ` .word ${bin.ifaceMembers.length}\n`;
15929
15952
  let idx = 0;
15930
15953
  for (let d of bin.ifaceMembers) {
@@ -15933,7 +15956,7 @@ ${hexfile.hexPrelude()}
15933
15956
  }
15934
15957
  asmsource += ` .word 0\n`;
15935
15958
  asmsource += "_vtables_end:\n\n";
15936
- asmsource += `\n.balign 4\n_pxt_config_data:\n`;
15959
+ asmsource += `\n.balign 4\n.object _pxt_config_data\n_pxt_config_data:\n`;
15937
15960
  const cfg = bin.res.configData || [];
15938
15961
  // asmsource += ` .word ${cfg.length}, 0 ; num. entries`
15939
15962
  for (let d of cfg) {
@@ -15942,7 +15965,7 @@ ${hexfile.hexPrelude()}
15942
15965
  asmsource += ` .word 0\n\n`;
15943
15966
  emitStrings(snippets, bin);
15944
15967
  asmsource += bin.otherLiterals.join("");
15945
- asmsource += `\n.balign 4\n.section code\n_pxt_perf_counters:\n`;
15968
+ asmsource += `\n.balign 4\n.section code\n.object _perf_counters\n_pxt_perf_counters:\n`;
15946
15969
  asmsource += ` .word ${perfCounters.length}\n`;
15947
15970
  let strs = "";
15948
15971
  for (let i = 0; i < perfCounters.length; ++i) {
@@ -15975,6 +15998,8 @@ ${hexfile.hexPrelude()}
15975
15998
  b.ei.testAssembler(); // just in case
15976
15999
  if (target.switches.noPeepHole)
15977
16000
  b.disablePeepHole = true;
16001
+ if (target.switches.size)
16002
+ b.codeSizeStats = true;
15978
16003
  b.lookupExternalLabel = hexfile.lookupFunctionAddr;
15979
16004
  b.normalizeExternalLabel = s => {
15980
16005
  let inf = hexfile.lookupFunc(s);
@@ -16035,6 +16060,7 @@ ${hexfile.hexPrelude()}
16035
16060
  }
16036
16061
  return `
16037
16062
  .balign 16
16063
+ .object _stored_program
16038
16064
  _stored_program: .hex ${res}
16039
16065
  `;
16040
16066
  }
@@ -18582,7 +18608,7 @@ var ts;
18582
18608
  }
18583
18609
  const type = checker === null || checker === void 0 ? void 0 : checker.getTypeAtLocation(param);
18584
18610
  const typeSymbol = service.getPxtSymbolFromTsSymbol(type === null || type === void 0 ? void 0 : type.symbol, apis, checker);
18585
- if ((typeSymbol === null || typeSymbol === void 0 ? void 0 : typeSymbol.attributes.fixedInstances) && python) {
18611
+ if (((typeSymbol === null || typeSymbol === void 0 ? void 0 : typeSymbol.attributes.fixedInstances) || (typeSymbol === null || typeSymbol === void 0 ? void 0 : typeSymbol.attributes.emitAsConstant)) && python) {
18586
18612
  return pxt.Util.snakify(paramDefl);
18587
18613
  }
18588
18614
  if (python) {
@@ -377,6 +377,7 @@ declare namespace pxt.editor {
377
377
  renderUsbPairDialog?: (firmwareUrl?: string, failedOnce?: boolean) => any;
378
378
  renderIncompatibleHardwareDialog?: (unsupportedParts: string[]) => any;
379
379
  showUploadInstructionsAsync?: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => Promise<void>;
380
+ showProgramTooLargeErrorAsync?: (variants: string[], confirmAsync: (options: any) => Promise<number>) => Promise<pxt.commands.RecompileOptions>;
380
381
  toolboxOptions?: IToolboxOptions;
381
382
  blocklyPatch?: (pkgTargetVersion: string, dom: Element) => void;
382
383
  webUsbPairDialogAsync?: (pairAsync: () => Promise<boolean>, confirmAsync: (options: any) => Promise<number>) => Promise<number>;
@@ -558,6 +558,11 @@ var pxt;
558
558
  name: lf("Blocks Error List"),
559
559
  description: lf("Show an error list panel for Blocks")
560
560
  },
561
+ {
562
+ id: "palettePicker",
563
+ name: lf("Change Color Palette"),
564
+ description: lf("Change the game palette in project settings")
565
+ },
561
566
  ].filter(experiment => ids.indexOf(experiment.id) > -1 && !(pxt.BrowserUtils.isPxtElectron() && experiment.enableOnline));
562
567
  }
563
568
  experiments_1.all = all;
package/built/pxtlib.d.ts CHANGED
@@ -878,6 +878,10 @@ declare namespace pxt.cloud {
878
878
  };
879
879
  }
880
880
  declare namespace pxt.commands {
881
+ interface RecompileOptions {
882
+ recompile: boolean;
883
+ useVariants: string[];
884
+ }
881
885
  interface DeployOptions {
882
886
  reportError: (e: string) => void;
883
887
  showNotification: (msg: string) => void;
@@ -899,6 +903,7 @@ declare namespace pxt.commands {
899
903
  helpUrl: string;
900
904
  };
901
905
  let showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>, saveonly?: boolean) => Promise<void>;
906
+ let showProgramTooLargeErrorAsync: (variants: string[], confirmAsync: (options: any) => Promise<number>) => Promise<RecompileOptions>;
902
907
  let saveProjectAsync: (project: pxt.cpp.HexFile) => Promise<void>;
903
908
  let electronDeployAsync: (r: ts.pxtc.CompileResult) => Promise<void>;
904
909
  let webUsbPairDialogAsync: (pairAsync: () => Promise<boolean>, confirmAsync: (options: any) => Promise<number>) => Promise<number>;
@@ -3400,6 +3405,7 @@ declare namespace ts.pxtc.assembler {
3400
3405
  opcode: number;
3401
3406
  stack: number;
3402
3407
  isLong: boolean;
3408
+ ldlitLabel: string;
3403
3409
  constructor(bin: File, text: string);
3404
3410
  getOpExt(): string;
3405
3411
  getOp(): string;
@@ -3437,10 +3443,17 @@ declare namespace ts.pxtc.assembler {
3437
3443
  disablePeepHole: boolean;
3438
3444
  stackAtLabel: pxt.Map<number>;
3439
3445
  private prevLabel;
3446
+ codeSizeStats: boolean;
3447
+ private labelToObject;
3448
+ private idToObject;
3449
+ private objSuspendStart;
3450
+ private currObject;
3451
+ private labelsToObjectDone;
3440
3452
  protected emitShort(op: number): void;
3441
3453
  protected emitOpCode(op: number): void;
3442
3454
  location(): number;
3443
3455
  pc(): number;
3456
+ useLabel(name: string): void;
3444
3457
  parseOneInt(s: string): number;
3445
3458
  private looksLikeLabel;
3446
3459
  private scopedName;
@@ -3461,6 +3474,7 @@ declare namespace ts.pxtc.assembler {
3461
3474
  private prepLines;
3462
3475
  private iterLines;
3463
3476
  getSourceMap(): pxt.Map<number[]>;
3477
+ getCodeSizeStats(): string;
3464
3478
  getSource(clean: boolean, numStmts?: number, flashSize?: number): string;
3465
3479
  private peepHole;
3466
3480
  private clearLabels;
package/built/pxtlib.js CHANGED
@@ -4110,7 +4110,7 @@ var pxt;
4110
4110
  MATH_ADDITION_SYMBOL: pxt.Util.lf("{id:op}+"),
4111
4111
  MATH_SUBTRACTION_SYMBOL: pxt.Util.lf("{id:op}-"),
4112
4112
  MATH_MULTIPLICATION_SYMBOL: pxt.Util.lf("{id:op}×"),
4113
- MATH_DIVISION_SYMBOL: pxt.Util.lf("{id:op}÷"),
4113
+ MATH_DIVISION_SYMBOL: pxt.Util.lf("{id:op}/"),
4114
4114
  MATH_POWER_SYMBOL: pxt.Util.lf("{id:op}**")
4115
4115
  }
4116
4116
  },
@@ -4120,7 +4120,7 @@ var pxt;
4120
4120
  url: '/blocks/math',
4121
4121
  category: 'math',
4122
4122
  block: {
4123
- MATH_MODULO_TITLE: pxt.Util.lf("remainder of %1 ÷ %2")
4123
+ MATH_MODULO_TITLE: pxt.Util.lf("remainder of %1 / %2")
4124
4124
  }
4125
4125
  },
4126
4126
  'math_js_op': {
@@ -4149,7 +4149,7 @@ var pxt;
4149
4149
  "acos": pxt.Util.lf("{id:op}acos"),
4150
4150
  "tan": pxt.Util.lf("{id:op}tan"),
4151
4151
  "atan2": pxt.Util.lf("{id:op}atan2"),
4152
- "idiv": pxt.Util.lf("{id:op}integer ÷"),
4152
+ "idiv": pxt.Util.lf("{id:op}integer /"),
4153
4153
  "imul": pxt.Util.lf("{id:op}integer ×"),
4154
4154
  }
4155
4155
  },
@@ -8713,6 +8713,7 @@ var pxt;
8713
8713
  docs.prepTemplate = prepTemplate;
8714
8714
  function setupRenderer(renderer) {
8715
8715
  renderer.image = function (href, title, text) {
8716
+ var _a, _b;
8716
8717
  const endpointName = "makecodeprodmediaeastus-usea";
8717
8718
  if (href.startsWith("youtube:")) {
8718
8719
  let out = '<div class="tutorial-video-embed"><iframe class="yt-embed" src="https://www.youtube.com/embed/' + href.split(":").pop()
@@ -8720,7 +8721,24 @@ var pxt;
8720
8721
  return out;
8721
8722
  }
8722
8723
  else if (href.startsWith("azuremedia:")) {
8723
- let out = `<div class="tutorial-video-embed"><video class="ams-embed" controls src="https://${endpointName}.streaming.media.azure.net/` + href.split(":").pop() + '/manifest(format=mpd-time-cmaf)" /></div>';
8724
+ let videoID = href.split(":")[1];
8725
+ const flagsSplit = videoID.split("?");
8726
+ let startTime;
8727
+ let endTime;
8728
+ if (flagsSplit[1]) {
8729
+ videoID = flagsSplit[0];
8730
+ const passedParameters = flagsSplit[1];
8731
+ startTime = (_a = /start(?:time)?=(\d+)/i.exec(passedParameters)) === null || _a === void 0 ? void 0 : _a[1];
8732
+ endTime = (_b = /end(?:time)?=(\d+)/i.exec(passedParameters)) === null || _b === void 0 ? void 0 : _b[1];
8733
+ }
8734
+ const url = new URL(`https://${endpointName}.streaming.media.azure.net/${videoID}/manifest(format=mpd-time-csf).mpd`);
8735
+ if (startTime) {
8736
+ url.hash = `t=${startTime}`;
8737
+ }
8738
+ if (endTime) {
8739
+ url.searchParams.append("endTime", endTime);
8740
+ }
8741
+ let out = `<div class="tutorial-video-embed"><video class="ams-embed" controls src="${url.toString()}" /></div>`;
8724
8742
  return out;
8725
8743
  }
8726
8744
  else {
@@ -14275,7 +14293,7 @@ var pxt;
14275
14293
  // and pulls from master
14276
14294
  const modtag = (modid === null || modid === void 0 ? void 0 : modid.tag) || ((_a = mod.config) === null || _a === void 0 ? void 0 : _a.version);
14277
14295
  const vertag = verid.tag;
14278
- // if there is no tag on the current dependency,
14296
+ // if there is no tag on the current dependency,
14279
14297
  // assume same as existing module version if any
14280
14298
  if (modtag && !vertag) {
14281
14299
  pxt.debug(`unversioned ${ver}, using ${modtag}`);
@@ -14734,6 +14752,8 @@ var pxt;
14734
14752
  opts.otherMultiVariants.push(etarget);
14735
14753
  }
14736
14754
  else {
14755
+ etarget.target.isNative = opts.target.isNative;
14756
+ opts.target = etarget.target;
14737
14757
  ext = einfo;
14738
14758
  opts.otherMultiVariants = [];
14739
14759
  }
@@ -15689,7 +15709,12 @@ var ts;
15689
15709
  const left = param.substr(0, dotIdx);
15690
15710
  let right = param.substr(dotIdx + 1);
15691
15711
  right = pxtc.U.snakify(right).toUpperCase();
15692
- return `${left}.${right}`;
15712
+ if (left) {
15713
+ return `${left}.${right}`;
15714
+ }
15715
+ else {
15716
+ return right;
15717
+ }
15693
15718
  }
15694
15719
  return param;
15695
15720
  }
@@ -21603,6 +21628,18 @@ var ts;
21603
21628
  }
21604
21629
  }
21605
21630
  assembler.Line = Line;
21631
+ const MAX_OBJ_USERS = 5;
21632
+ class AsmObject {
21633
+ constructor(id, description) {
21634
+ this.id = id;
21635
+ this.description = description;
21636
+ this.sizeAdj = 0;
21637
+ this.users = [];
21638
+ }
21639
+ get size() {
21640
+ return (this.endLocation - this.startLocation) - this.sizeAdj;
21641
+ }
21642
+ }
21606
21643
  // File is the center of the action: parsing a file into a sequence of Lines
21607
21644
  // and also emitting the binary (buf)
21608
21645
  class File {
@@ -21627,6 +21664,11 @@ var ts;
21627
21664
  this.throwOnError = false;
21628
21665
  this.disablePeepHole = false;
21629
21666
  this.stackAtLabel = {};
21667
+ this.codeSizeStats = false;
21668
+ this.labelToObject = {};
21669
+ this.idToObject = {};
21670
+ this.objSuspendStart = 0;
21671
+ this.labelsToObjectDone = false;
21630
21672
  this.currLine = new Line(this, "<start>");
21631
21673
  this.currLine.lineNo = 0;
21632
21674
  this.ei = ei;
@@ -21646,6 +21688,15 @@ var ts;
21646
21688
  pc() {
21647
21689
  return this.location() + this.baseOffset;
21648
21690
  }
21691
+ useLabel(name) {
21692
+ if (!this.currObject || name[0] == '.' || this.objSuspendStart)
21693
+ return;
21694
+ const obj = pxtc.U.lookup(this.labelToObject, name);
21695
+ if (!obj || obj == this.currObject)
21696
+ return;
21697
+ if (obj.users.length < MAX_OBJ_USERS && obj.users.indexOf(this.currObject) < 0)
21698
+ obj.users.push(this.currObject);
21699
+ }
21649
21700
  // parsing of an "integer", well actually much more than
21650
21701
  // just that
21651
21702
  parseOneInt(s) {
@@ -21775,6 +21826,7 @@ var ts;
21775
21826
  return name;
21776
21827
  }
21777
21828
  lookupLabel(name, direct = false) {
21829
+ this.useLabel(name);
21778
21830
  let v = null;
21779
21831
  let scoped = this.scopedName(name);
21780
21832
  if (this.labels.hasOwnProperty(scoped)) {
@@ -21933,6 +21985,37 @@ var ts;
21933
21985
  };
21934
21986
  let num0;
21935
21987
  switch (words[0]) {
21988
+ case ".object":
21989
+ if (!this.codeSizeStats) {
21990
+ // do nothing
21991
+ }
21992
+ else if (words[1] == "PUSH") {
21993
+ this.objSuspendStart = this.location();
21994
+ }
21995
+ else if (words[1] == "POP") {
21996
+ if (this.objSuspendStart)
21997
+ this.currObject.sizeAdj += this.location() - this.objSuspendStart;
21998
+ this.objSuspendStart = 0;
21999
+ }
22000
+ else {
22001
+ if (this.currObject)
22002
+ this.currObject.endLocation = this.location();
22003
+ this.currObject = pxtc.U.lookup(this.idToObject, words[1]);
22004
+ if (!this.currObject) {
22005
+ const str = l.text.replace(/^[^"]*/, "");
22006
+ let parsed = words[1];
22007
+ if (words.length > 2) {
22008
+ parsed = parseString(str.trim());
22009
+ if (parsed == null)
22010
+ this.directiveError(lf("expecting string in .object"));
22011
+ }
22012
+ this.currObject = new AsmObject(words[1], parsed);
22013
+ this.idToObject[words[1]] = this.currObject;
22014
+ }
22015
+ this.currObject.sizeAdj = 0;
22016
+ this.currObject.startLocation = this.location();
22017
+ }
22018
+ break;
21936
22019
  case ".ascii":
21937
22020
  case ".asciz":
21938
22021
  case ".string":
@@ -22127,6 +22210,8 @@ var ts;
22127
22210
  }
22128
22211
  }
22129
22212
  handleOneInstruction(ln, instr) {
22213
+ if (this.codeSizeStats && ln.ldlitLabel)
22214
+ this.useLabel(ln.ldlitLabel);
22130
22215
  let op = instr.emit(ln);
22131
22216
  if (!op.error) {
22132
22217
  this.stack += op.stack;
@@ -22235,6 +22320,8 @@ var ts;
22235
22320
  if (l.words.length == 0)
22236
22321
  return;
22237
22322
  if (l.type == "label") {
22323
+ if (this.currObject && !this.labelsToObjectDone && l.words[0][0] != '.')
22324
+ this.labelToObject[l.words[0]] = this.currObject;
22238
22325
  let lblname = this.scopedName(l.words[0]);
22239
22326
  this.prevLabel = lblname;
22240
22327
  if (this.finalEmit) {
@@ -22275,6 +22362,8 @@ var ts;
22275
22362
  pxtc.oops();
22276
22363
  }
22277
22364
  });
22365
+ this.labelsToObjectDone = true;
22366
+ this.currObject = null;
22278
22367
  }
22279
22368
  getSourceMap() {
22280
22369
  const sourceMap = {};
@@ -22307,6 +22396,22 @@ var ts;
22307
22396
  }
22308
22397
  return sourceMap;
22309
22398
  }
22399
+ getCodeSizeStats() {
22400
+ if (!this.codeSizeStats)
22401
+ return "";
22402
+ const objs = pxtc.U.values(this.idToObject);
22403
+ objs.sort((a, b) => b.size - a.size);
22404
+ let r = ";\n; Code size:\n;\n";
22405
+ for (const obj of objs) {
22406
+ r += `; ${(" " + obj.size).slice(-6)} ${obj.description} [${obj.id}]\n`;
22407
+ if (obj.users.length >= MAX_OBJ_USERS)
22408
+ r += `; by many, including ${obj.users[0].description}\n`;
22409
+ else
22410
+ for (const x of obj.users)
22411
+ r += `; by ${x.description} [${x.id}]\n`;
22412
+ }
22413
+ return r;
22414
+ }
22310
22415
  getSource(clean, numStmts = 1, flashSize = 0) {
22311
22416
  let lenPrev = 0;
22312
22417
  let size = (lbl) => {
@@ -22322,8 +22427,11 @@ var ts;
22322
22427
  let lenLiterals = size("_literals_end");
22323
22428
  let lenAllCode = lenPrev;
22324
22429
  let totalSize = (lenTotal + this.baseOffset) & 0xffffff;
22325
- if (flashSize && totalSize > flashSize)
22326
- pxtc.U.userError(lf("program too big by {0} bytes!", totalSize - flashSize));
22430
+ if (flashSize && totalSize > flashSize) {
22431
+ const e = new Error(lf("program too big by {0} bytes!", totalSize - flashSize));
22432
+ e.ksErrorCode = 9283;
22433
+ throw e;
22434
+ }
22327
22435
  flashSize = flashSize || 128 * 1024;
22328
22436
  let totalInfo = lf("; total bytes: {0} ({1}% of {2}k flash with {3} free)", totalSize, (100 * totalSize / flashSize).toFixed(1), (flashSize / 1024).toFixed(1), flashSize - totalSize);
22329
22437
  let res =
@@ -22331,7 +22439,7 @@ var ts;
22331
22439
  lf("; generated code sizes (bytes): {0} (incl. {1} user, {2} helpers, {3} vtables, {4} lits); src size {5}\n", lenAllCode, lenCode, lenHelpers, lenVtables, lenLiterals, lenTotal - lenAllCode) +
22332
22440
  lf("; assembly: {0} lines; density: {1} bytes/stmt; ({2} stmts)\n", this.lines.length, Math.round(100 * lenCode / numStmts) / 100, numStmts) +
22333
22441
  totalInfo + "\n" +
22334
- this.stats + "\n\n";
22442
+ this.stats + this.getCodeSizeStats() + "\n\n";
22335
22443
  let skipOne = false;
22336
22444
  this.lines.forEach((ln, i) => {
22337
22445
  if (ln.words[0] == "_stored_program") {
package/built/pxtpy.d.ts CHANGED
@@ -145,6 +145,7 @@ declare namespace pxt.py {
145
145
  vars: Map<ScopeSymbolInfo>;
146
146
  parent?: ScopeDef;
147
147
  blockDepth?: number;
148
+ nextHelperVariableId?: number;
148
149
  }
149
150
  interface FunctionDef extends Symbol, ScopeDef {
150
151
  kind: "FunctionDef";
package/built/pxtpy.js CHANGED
@@ -342,6 +342,13 @@ var pxt;
342
342
  error(a, 9503, pxt.U.lf("No module named '{0}'", name));
343
343
  return sym;
344
344
  }
345
+ function getHelperVariableName() {
346
+ const scope = currentScope();
347
+ if (scope.nextHelperVariableId === undefined) {
348
+ scope.nextHelperVariableId = 0;
349
+ }
350
+ return "___tempvar" + scope.nextHelperVariableId++;
351
+ }
345
352
  function defvar(name, opts, modifier, scope) {
346
353
  if (!scope)
347
354
  scope = currentScope();
@@ -1648,20 +1655,7 @@ var pxt;
1648
1655
  return B.mkStmt(B.mkText(pref), B.mkInfix(expr(target), "=", expr(value)));
1649
1656
  }
1650
1657
  if (!pref && target.kind == "Tuple") {
1651
- let tup = target;
1652
- let targs = [B.mkText("let "), B.mkText("[")];
1653
- let nonNames = tup.elts.filter(e => e.kind !== "Name");
1654
- if (nonNames.length) {
1655
- error(n, 9556, pxt.U.lf("non-trivial tuple assignment unsupported"));
1656
- return stmtTODO(n);
1657
- }
1658
- let tupNames = tup.elts
1659
- .map(e => e)
1660
- .map(convertName);
1661
- targs.push(B.mkCommaSep(tupNames));
1662
- targs.push(B.mkText("]"));
1663
- let res = B.mkStmt(B.mkInfix(B.mkGroup(targs), "=", expr(value)));
1664
- return res;
1658
+ return convertDestructuring(n, target, value);
1665
1659
  }
1666
1660
  if (target.kind === "Name") {
1667
1661
  const scopeSym = currentScope().vars[nm];
@@ -1689,12 +1683,41 @@ var pxt;
1689
1683
  if (!lExp)
1690
1684
  lExp = expr(target);
1691
1685
  return B.mkStmt(B.mkText(pref), B.mkInfix(lExp, "=", expr(value)));
1692
- function convertName(n) {
1686
+ }
1687
+ function convertDestructuring(parent, targets, value) {
1688
+ let nonNames = targets.elts.filter(e => e.kind !== "Name");
1689
+ if (nonNames.length) {
1690
+ error(parent, 9556, pxt.U.lf("non-trivial tuple assignment unsupported"));
1691
+ return stmtTODO(parent);
1692
+ }
1693
+ const names = targets.elts.map(tryGetName);
1694
+ const symbols = names
1695
+ .map(nm => nm ? currentScope().vars[nm] : undefined);
1696
+ if (symbols.some(s => (s === null || s === void 0 ? void 0 : s.modifier) !== undefined)) {
1697
+ const helperVar = getHelperVariableName();
1698
+ const valueAssign = B.mkStmt(B.mkInfix(B.mkGroup([B.mkText("let "), B.mkText(helperVar)]), "=", expr(value)));
1699
+ const assignStatements = [valueAssign];
1700
+ for (let i = 0; i < symbols.length; i++) {
1701
+ const name = convertName(targets.elts[i]);
1702
+ assignStatements.push(B.mkStmt(B.mkInfix(name, "=", B.mkGroup([B.mkText(helperVar), B.mkText(`[${i}]`)]))));
1703
+ }
1704
+ return B.mkGroup(assignStatements);
1705
+ }
1706
+ else {
1707
+ let targs = [B.mkText("let "), B.mkText("[")];
1708
+ let tupNames = targets.elts
1709
+ .map(e => e)
1710
+ .map(e => convertName(e, true));
1711
+ targs.push(B.mkCommaSep(tupNames));
1712
+ targs.push(B.mkText("]"));
1713
+ return B.mkStmt(B.mkInfix(B.mkGroup(targs), "=", expr(value)));
1714
+ }
1715
+ function convertName(n, excludeLet = false) {
1693
1716
  // TODO resuse with Name expr
1694
1717
  markInfoNode(n, "identifierCompletion");
1695
1718
  typeOf(n);
1696
1719
  let v = lookupName(n);
1697
- return possibleDef(n, /*excludeLet*/ true);
1720
+ return possibleDef(n, excludeLet);
1698
1721
  }
1699
1722
  }
1700
1723
  function possibleDef(n, excludeLet = false) {