basedpl 0.1.78__tar.gz → 0.1.80__tar.gz

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 (503) hide show
  1. {basedpl-0.1.78 → basedpl-0.1.80}/.github/workflows/test.yml +2 -1
  2. {basedpl-0.1.78 → basedpl-0.1.80}/Cargo.lock +40 -26
  3. {basedpl-0.1.78 → basedpl-0.1.80}/Cargo.toml +7 -4
  4. {basedpl-0.1.78 → basedpl-0.1.80}/DEV.md +9 -9
  5. {basedpl-0.1.78 → basedpl-0.1.80}/PKG-INFO +1 -1
  6. basedpl-0.1.80/build.rs +58 -0
  7. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/cli.qmd +1 -1
  8. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/composition.qmd +1 -1
  9. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/getting-started.ipynb +11 -11
  10. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/left-tail-arrow.qmd +1 -1
  11. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/right-tail-arrow.qmd +1 -1
  12. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/llms.txt +1 -1
  13. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/regex.ipynb +3 -5
  14. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/repl.qmd +16 -4
  15. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/prefs.qmd +6 -2
  16. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/r.qmd +1 -1
  17. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/web.ipynb +1 -1
  18. {basedpl-0.1.78 → basedpl-0.1.80}/py/src/lib.rs +59 -31
  19. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/bpltests.py +57 -18
  20. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/ipython.py +3 -1
  21. {basedpl-0.1.78 → basedpl-0.1.80}/src/agreement.rs +5 -6
  22. {basedpl-0.1.78 → basedpl-0.1.80}/src/array/storage.rs +88 -64
  23. {basedpl-0.1.78 → basedpl-0.1.80}/src/array/text.rs +44 -32
  24. {basedpl-0.1.78 → basedpl-0.1.80}/src/array.rs +145 -95
  25. {basedpl-0.1.78 → basedpl-0.1.80}/src/batch.rs +66 -75
  26. {basedpl-0.1.78 → basedpl-0.1.80}/src/canvas.rs +5 -3
  27. {basedpl-0.1.78 → basedpl-0.1.80}/src/csv.rs +20 -19
  28. {basedpl-0.1.78 → basedpl-0.1.80}/src/data.rs +52 -54
  29. {basedpl-0.1.78 → basedpl-0.1.80}/src/date.rs +2 -2
  30. {basedpl-0.1.78 → basedpl-0.1.80}/src/derivative.rs +89 -108
  31. {basedpl-0.1.78 → basedpl-0.1.80}/src/display.rs +41 -38
  32. {basedpl-0.1.78 → basedpl-0.1.80}/src/distribution.rs +16 -17
  33. {basedpl-0.1.78 → basedpl-0.1.80}/src/element.rs +10 -10
  34. {basedpl-0.1.78 → basedpl-0.1.80}/src/error.rs +32 -23
  35. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/assign.rs +42 -28
  36. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/binder.rs +131 -60
  37. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/bindings.rs +36 -11
  38. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/idioms.rs +10 -18
  39. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/operators.rs +192 -139
  40. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/session.rs +102 -67
  41. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/tree.rs +152 -73
  42. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval.rs +132 -108
  43. {basedpl-0.1.78 → basedpl-0.1.80}/src/execution.rs +29 -16
  44. {basedpl-0.1.78 → basedpl-0.1.80}/src/explain.rs +58 -40
  45. {basedpl-0.1.78 → basedpl-0.1.80}/src/files.rs +5 -10
  46. {basedpl-0.1.78 → basedpl-0.1.80}/src/fusion.rs +92 -56
  47. {basedpl-0.1.78 → basedpl-0.1.80}/src/host.rs +12 -6
  48. {basedpl-0.1.78 → basedpl-0.1.80}/src/host_web.rs +17 -11
  49. {basedpl-0.1.78 → basedpl-0.1.80}/src/image/codecs.rs +1 -1
  50. {basedpl-0.1.78 → basedpl-0.1.80}/src/image/imageio.rs +5 -6
  51. {basedpl-0.1.78 → basedpl-0.1.80}/src/image.rs +5 -7
  52. {basedpl-0.1.78 → basedpl-0.1.80}/src/inspection.rs +52 -7
  53. {basedpl-0.1.78 → basedpl-0.1.80}/src/jit.rs +181 -127
  54. {basedpl-0.1.78 → basedpl-0.1.80}/src/js.rs +8 -8
  55. {basedpl-0.1.78 → basedpl-0.1.80}/src/json.rs +10 -5
  56. {basedpl-0.1.78 → basedpl-0.1.80}/src/keyed.rs +5 -3
  57. {basedpl-0.1.78 → basedpl-0.1.80}/src/lib.rs +4 -4
  58. {basedpl-0.1.78 → basedpl-0.1.80}/src/linear.rs +88 -75
  59. {basedpl-0.1.78 → basedpl-0.1.80}/src/name.rs +5 -1
  60. {basedpl-0.1.78 → basedpl-0.1.80}/src/number.rs +120 -98
  61. {basedpl-0.1.78 → basedpl-0.1.80}/src/number_theory.rs +7 -8
  62. {basedpl-0.1.78 → basedpl-0.1.80}/src/optimize.rs +11 -14
  63. {basedpl-0.1.78 → basedpl-0.1.80}/src/pervasive.rs +289 -230
  64. {basedpl-0.1.78 → basedpl-0.1.80}/src/plan.rs +58 -34
  65. {basedpl-0.1.78 → basedpl-0.1.80}/src/plot.rs +6 -10
  66. {basedpl-0.1.78 → basedpl-0.1.80}/src/polynomial.rs +9 -11
  67. {basedpl-0.1.78 → basedpl-0.1.80}/src/primitive/indexing.rs +135 -100
  68. {basedpl-0.1.78 → basedpl-0.1.80}/src/primitive/numeric.rs +74 -61
  69. {basedpl-0.1.78 → basedpl-0.1.80}/src/primitive/search.rs +33 -28
  70. {basedpl-0.1.78 → basedpl-0.1.80}/src/primitive/structural.rs +26 -15
  71. {basedpl-0.1.78 → basedpl-0.1.80}/src/primitive.rs +405 -152
  72. {basedpl-0.1.78 → basedpl-0.1.80}/src/program/blocks.rs +267 -142
  73. {basedpl-0.1.78 → basedpl-0.1.80}/src/program/contraction.rs +18 -16
  74. {basedpl-0.1.78 → basedpl-0.1.80}/src/program/layout.rs +28 -22
  75. {basedpl-0.1.78 → basedpl-0.1.80}/src/program/run.rs +28 -15
  76. {basedpl-0.1.78 → basedpl-0.1.80}/src/program/trace.rs +72 -41
  77. {basedpl-0.1.78 → basedpl-0.1.80}/src/program/verify.rs +4 -4
  78. {basedpl-0.1.78 → basedpl-0.1.80}/src/program.rs +111 -72
  79. {basedpl-0.1.78 → basedpl-0.1.80}/src/protocol.rs +7 -6
  80. {basedpl-0.1.78 → basedpl-0.1.80}/src/reference.rs +74 -51
  81. {basedpl-0.1.78 → basedpl-0.1.80}/src/regex.rs +3 -5
  82. {basedpl-0.1.78 → basedpl-0.1.80}/src/search.rs +23 -23
  83. {basedpl-0.1.78 → basedpl-0.1.80}/src/selection.rs +50 -31
  84. {basedpl-0.1.78 → basedpl-0.1.80}/src/settings.rs +23 -10
  85. {basedpl-0.1.78 → basedpl-0.1.80}/src/symbols.rs +9 -8
  86. {basedpl-0.1.78 → basedpl-0.1.80}/src/syntax.rs +121 -100
  87. {basedpl-0.1.78 → basedpl-0.1.80}/src/system.rs +45 -39
  88. {basedpl-0.1.78 → basedpl-0.1.80}/src/timing.rs +61 -27
  89. {basedpl-0.1.78 → basedpl-0.1.80}/src/transform.rs +148 -83
  90. {basedpl-0.1.78 → basedpl-0.1.80}/src/xml.rs +1 -1
  91. {basedpl-0.1.78 → basedpl-0.1.80}/tests/core.rs +7 -3
  92. {basedpl-0.1.78 → basedpl-0.1.80}/tests/derivatives.rs +10 -3
  93. {basedpl-0.1.78 → basedpl-0.1.80}/tests/explain.rs +30 -23
  94. {basedpl-0.1.78 → basedpl-0.1.80}/tests/jit.rs +146 -61
  95. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/README.md +8 -2
  96. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/aplcart.bpl +1 -1
  97. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/april.bpl +1 -1
  98. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/core.bpl +49 -46
  99. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/lib.bpl +2 -2
  100. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/regex.bpl +4 -4
  101. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference.rs +36 -20
  102. {basedpl-0.1.78 → basedpl-0.1.80}/tests/scaling.rs +3 -2
  103. {basedpl-0.1.78 → basedpl-0.1.80}/tests/settings.rs +29 -13
  104. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/README.md +1 -1
  105. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/arrays.bpl +14 -11
  106. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/maps.bpl +1 -1
  107. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/models.bpl +7 -7
  108. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/structure.bpl +5 -5
  109. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed.rs +5 -5
  110. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_api.py +16 -3
  111. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_ipython.py +1 -0
  112. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_kernel.py +18 -3
  113. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_repl.py +10 -10
  114. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_worker.py +2 -2
  115. {basedpl-0.1.78 → basedpl-0.1.80}/tests/units.rs +20 -11
  116. {basedpl-0.1.78 → basedpl-0.1.80}/tests/wasm-pkg.mjs +2 -2
  117. {basedpl-0.1.78 → basedpl-0.1.80}/tests/wasm-speed.mjs +6 -6
  118. {basedpl-0.1.78 → basedpl-0.1.80}/tests/wasm.mjs +24 -19
  119. basedpl-0.1.78/build.rs +0 -35
  120. {basedpl-0.1.78 → basedpl-0.1.80}/.cargo/config.toml +0 -0
  121. {basedpl-0.1.78 → basedpl-0.1.80}/.gitattributes +0 -0
  122. {basedpl-0.1.78 → basedpl-0.1.80}/.github/workflows/ci.yml +0 -0
  123. {basedpl-0.1.78 → basedpl-0.1.80}/.github/workflows/docs.yml +0 -0
  124. {basedpl-0.1.78 → basedpl-0.1.80}/.github/workflows/speed.yml +0 -0
  125. {basedpl-0.1.78 → basedpl-0.1.80}/.gitignore +0 -0
  126. {basedpl-0.1.78 → basedpl-0.1.80}/.node-version +0 -0
  127. {basedpl-0.1.78 → basedpl-0.1.80}/CONTRIBUTING.md +0 -0
  128. {basedpl-0.1.78 → basedpl-0.1.80}/LICENSE +0 -0
  129. {basedpl-0.1.78 → basedpl-0.1.80}/README.md +0 -0
  130. {basedpl-0.1.78 → basedpl-0.1.80}/_config.yml +0 -0
  131. {basedpl-0.1.78 → basedpl-0.1.80}/_layouts/default.html +0 -0
  132. {basedpl-0.1.78 → basedpl-0.1.80}/editors/jetbrains/BPL.tmbundle/Syntaxes/bpl.tmLanguage.json +0 -0
  133. {basedpl-0.1.78 → basedpl-0.1.80}/editors/jetbrains/BPL.tmbundle/Syntaxes/hpl.tmLanguage.json +0 -0
  134. {basedpl-0.1.78 → basedpl-0.1.80}/editors/jetbrains/BPL.tmbundle/info.plist +0 -0
  135. {basedpl-0.1.78 → basedpl-0.1.80}/editors/jetbrains/BPL.xml +0 -0
  136. {basedpl-0.1.78 → basedpl-0.1.80}/editors/jetbrains/README.md +0 -0
  137. {basedpl-0.1.78 → basedpl-0.1.80}/editors/macos/BasedPL-de.txt +0 -0
  138. {basedpl-0.1.78 → basedpl-0.1.80}/editors/macos/BasedPL-es.txt +0 -0
  139. {basedpl-0.1.78 → basedpl-0.1.80}/editors/macos/BasedPL-fr.txt +0 -0
  140. {basedpl-0.1.78 → basedpl-0.1.80}/editors/macos/BasedPL-uk.txt +0 -0
  141. {basedpl-0.1.78 → basedpl-0.1.80}/editors/macos/BasedPL-us.txt +0 -0
  142. {basedpl-0.1.78 → basedpl-0.1.80}/editors/vim/ftdetect/bpl.vim +0 -0
  143. {basedpl-0.1.78 → basedpl-0.1.80}/editors/vim/syntax/bpl.vim +0 -0
  144. {basedpl-0.1.78 → basedpl-0.1.80}/editors/windows/README.md +0 -0
  145. {basedpl-0.1.78 → basedpl-0.1.80}/editors/windows/build.ps1 +0 -0
  146. {basedpl-0.1.78 → basedpl-0.1.80}/editors/windows/install.ps1 +0 -0
  147. {basedpl-0.1.78 → basedpl-0.1.80}/editors/windows/keyboard.c +0 -0
  148. {basedpl-0.1.78 → basedpl-0.1.80}/editors/windows/keyboard.def +0 -0
  149. {basedpl-0.1.78 → basedpl-0.1.80}/editors/windows/keyboard.rc +0 -0
  150. {basedpl-0.1.78 → basedpl-0.1.80}/editors/windows/layout.h +0 -0
  151. {basedpl-0.1.78 → basedpl-0.1.80}/index_files/figure-commonmark/cell-17-output-1.svg +0 -0
  152. {basedpl-0.1.78 → basedpl-0.1.80}/index_files/figure-commonmark/cell-18-output-1.svg +0 -0
  153. {basedpl-0.1.78 → basedpl-0.1.80}/index_files/figure-html/cell-17-output-1.svg +0 -0
  154. {basedpl-0.1.78 → basedpl-0.1.80}/index_files/figure-html/cell-18-output-1.svg +0 -0
  155. {basedpl-0.1.78 → basedpl-0.1.80}/lib/LICENSE-april +0 -0
  156. {basedpl-0.1.78 → basedpl-0.1.80}/lib/README.md +0 -0
  157. {basedpl-0.1.78 → basedpl-0.1.80}/lib/array.bpl +0 -0
  158. {basedpl-0.1.78 → basedpl-0.1.80}/lib/dyalog.bpl +0 -0
  159. {basedpl-0.1.78 → basedpl-0.1.80}/lib/graph.bpl +0 -0
  160. {basedpl-0.1.78 → basedpl-0.1.80}/lib/numeric.bpl +0 -0
  161. {basedpl-0.1.78 → basedpl-0.1.80}/lib/power.bpl +0 -0
  162. {basedpl-0.1.78 → basedpl-0.1.80}/lib/regex.bpl +0 -0
  163. {basedpl-0.1.78 → basedpl-0.1.80}/lib/string.bpl +0 -0
  164. {basedpl-0.1.78 → basedpl-0.1.80}/lib/tree.bpl +0 -0
  165. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/.gitignore +0 -0
  166. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/_quarto.yml +0 -0
  167. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/arrays.ipynb +0 -0
  168. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/assignment.ipynb +0 -0
  169. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/autodiff.qmd +0 -0
  170. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/bpl.xml +0 -0
  171. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/bqn.xml +0 -0
  172. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/bracket-types.ipynb +0 -0
  173. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/comparison.qmd +0 -0
  174. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/data.ipynb +0 -0
  175. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/dfns.ipynb +0 -0
  176. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/distributions.ipynb +0 -0
  177. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/driver.js +0 -0
  178. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/dyalog.ipynb +0 -0
  179. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/dyalog.xml +0 -0
  180. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/evaluation.qmd +0 -0
  181. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/fonts/BQN386B.woff2 +0 -0
  182. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/fonts/README.md +0 -0
  183. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/fonts/SAX2B.woff2 +0 -0
  184. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/fonts.css +0 -0
  185. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/attractor.bpl +0 -0
  186. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/boids.bpl +0 -0
  187. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/dragon.bpl +0 -0
  188. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/flow.bpl +0 -0
  189. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/mandelbrot.bpl +0 -0
  190. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/mandelbrot32.bpl +0 -0
  191. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/orbits.bpl +0 -0
  192. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/phyllotaxis.bpl +0 -0
  193. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/prefs.bpl +0 -0
  194. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery/reaction.bpl +0 -0
  195. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/gallery.qmd +0 -0
  196. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/_metadata.yml +0 -0
  197. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/alpha-underbar.qmd +0 -0
  198. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/alpha.qmd +0 -0
  199. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/at.qmd +0 -0
  200. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/backslash-bar.qmd +0 -0
  201. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/backslash.qmd +0 -0
  202. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/braces.qmd +0 -0
  203. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/brackets.qmd +0 -0
  204. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/bullet.qmd +0 -0
  205. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-backslash.qmd +0 -0
  206. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-bar.qmd +0 -0
  207. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-diaeresis.qmd +0 -0
  208. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-divide.qmd +0 -0
  209. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-slash.qmd +0 -0
  210. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-star.qmd +0 -0
  211. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-stile.qmd +0 -0
  212. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle-times.qmd +0 -0
  213. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/circle.qmd +0 -0
  214. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/colon.qmd +0 -0
  215. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/comma-bar.qmd +0 -0
  216. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/comma.qmd +0 -0
  217. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/del-diaeresis.qmd +0 -0
  218. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/del-stile.qmd +0 -0
  219. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/del.qmd +0 -0
  220. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/delta-stile.qmd +0 -0
  221. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/diaeresis.qmd +0 -0
  222. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/diamond-underbar.qmd +0 -0
  223. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/diamond.qmd +0 -0
  224. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/domino.qmd +0 -0
  225. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/dot.qmd +0 -0
  226. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/down-arrow.qmd +0 -0
  227. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/down-shoe.qmd +0 -0
  228. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/down-tack.qmd +0 -0
  229. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/downstile.qmd +0 -0
  230. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/epsilon-underbar.qmd +0 -0
  231. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/epsilon.qmd +0 -0
  232. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/equal-underbar-slash.qmd +0 -0
  233. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/equal-underbar.qmd +0 -0
  234. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/equals.qmd +0 -0
  235. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/error-guard.qmd +0 -0
  236. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/exclamation.qmd +0 -0
  237. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/greater-than-or-equal.qmd +0 -0
  238. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/greater-than.qmd +0 -0
  239. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/hash.qmd +0 -0
  240. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/hydrant.qmd +0 -0
  241. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/infinity.qmd +0 -0
  242. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/inverted-question.qmd +0 -0
  243. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/iota-underbar.qmd +0 -0
  244. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/iota.qmd +0 -0
  245. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/jot-diaeresis.qmd +0 -0
  246. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/jot.qmd +0 -0
  247. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/lamp.qmd +0 -0
  248. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/left-arrow.qmd +0 -0
  249. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/left-shoe-underbar.qmd +0 -0
  250. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/left-shoe.qmd +0 -0
  251. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/left-tack.qmd +0 -0
  252. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/less-than-or-equal.qmd +0 -0
  253. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/less-than.qmd +0 -0
  254. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/minus.qmd +0 -0
  255. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/not-equals.qmd +0 -0
  256. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/obelus.qmd +0 -0
  257. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/omega-underbar.qmd +0 -0
  258. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/omega.qmd +0 -0
  259. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/overbar.qmd +0 -0
  260. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/parentheses.qmd +0 -0
  261. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/partial.qmd +0 -0
  262. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/pi.qmd +0 -0
  263. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/plus.qmd +0 -0
  264. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/quad-colon.qmd +0 -0
  265. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/quad-diamond.qmd +0 -0
  266. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/quad-equal.qmd +0 -0
  267. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/quad-jot.qmd +0 -0
  268. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/quad.qmd +0 -0
  269. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/question.qmd +0 -0
  270. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/quote.qmd +0 -0
  271. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/radical.qmd +0 -0
  272. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/rho.qmd +0 -0
  273. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/right-arrow-from-bar.qmd +0 -0
  274. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/right-left-arrows.qmd +0 -0
  275. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/right-shoe.qmd +0 -0
  276. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/right-tack.qmd +0 -0
  277. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/slash-bar.qmd +0 -0
  278. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/slash.qmd +0 -0
  279. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/squad.qmd +0 -0
  280. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/star-diaeresis.qmd +0 -0
  281. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/star.qmd +0 -0
  282. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/stile-tilde.qmd +0 -0
  283. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/stile.qmd +0 -0
  284. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/superscript-b.qmd +0 -0
  285. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/thorn.qmd +0 -0
  286. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/tilde-diaeresis.qmd +0 -0
  287. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/tilde.qmd +0 -0
  288. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/times.qmd +0 -0
  289. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/tricolon.qmd +0 -0
  290. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/up-arrow.qmd +0 -0
  291. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/up-down-arrow.qmd +0 -0
  292. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/up-shoe.qmd +0 -0
  293. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/up-tack.qmd +0 -0
  294. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/upstile.qmd +0 -0
  295. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/vee-bar.qmd +0 -0
  296. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/vee.qmd +0 -0
  297. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/wedge-bar.qmd +0 -0
  298. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/wedge.qmd +0 -0
  299. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs/zilde.qmd +0 -0
  300. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs-study.qmd +0 -0
  301. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/glyphs.qmd +0 -0
  302. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/hanzi-notation-zh.ipynb +0 -0
  303. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/hanzi-notation.ipynb +0 -0
  304. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/hpl.xml +0 -0
  305. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/index-notation.qmd +0 -0
  306. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/index.ipynb +0 -0
  307. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/indexing.ipynb +0 -0
  308. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/introspection.ipynb +0 -0
  309. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/keyboard.qmd +0 -0
  310. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/keyed.ipynb +0 -0
  311. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/magics.ipynb +0 -0
  312. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/mathish.qmd +0 -0
  313. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/modules.qmd +0 -0
  314. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/nbdev.yml +0 -0
  315. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/notebooks.ipynb +0 -0
  316. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/numbers.qmd +0 -0
  317. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/overview.ipynb +0 -0
  318. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/papers/aplwiki-arrays.md +0 -0
  319. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/papers/brickman-depth-1-scalars.md +0 -0
  320. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/papers/mercer-based-system.md +0 -0
  321. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/performance.qmd +0 -0
  322. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/playground/bpl.js +0 -0
  323. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/playground/gallery.js +0 -0
  324. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/playground/monaco-worker.js +0 -0
  325. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/playground/page.js +0 -0
  326. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/playground/worker.js +0 -0
  327. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/playground.qmd +0 -0
  328. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/plot.ipynb +0 -0
  329. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/principles.ipynb +0 -0
  330. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/processes.qmd +0 -0
  331. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/puppy.jpg +0 -0
  332. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/python.ipynb +0 -0
  333. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/scripts.ipynb +0 -0
  334. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/sidebar.yml +0 -0
  335. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/strings.ipynb +0 -0
  336. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/study/01_basics.ipynb +0 -0
  337. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/study/02_functions.ipynb +0 -0
  338. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/study/03_operators.ipynb +0 -0
  339. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/study/04_nested-arrays.ipynb +0 -0
  340. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/study/05_searching-indexing.ipynb +0 -0
  341. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/study/06_rearranging-arrays.ipynb +0 -0
  342. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/study/07_numerical-tools.ipynb +0 -0
  343. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/style.qmd +0 -0
  344. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/styles.css +0 -0
  345. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/syntax.qmd +0 -0
  346. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/_metadata.yml +0 -0
  347. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/c.qmd +0 -0
  348. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/canvas.qmd +0 -0
  349. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/constants.qmd +0 -0
  350. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/copy.qmd +0 -0
  351. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/csv.qmd +0 -0
  352. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/date.qmd +0 -0
  353. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/decompose.qmd +0 -0
  354. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/deflate.qmd +0 -0
  355. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/delay.qmd +0 -0
  356. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/detach.qmd +0 -0
  357. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/distribution.qmd +0 -0
  358. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/edge.qmd +0 -0
  359. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/element.qmd +0 -0
  360. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/ex.qmd +0 -0
  361. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/explain.qmd +0 -0
  362. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/fetch.qmd +0 -0
  363. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/float.qmd +0 -0
  364. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/hash.qmd +0 -0
  365. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/host.qmd +0 -0
  366. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/image.qmd +0 -0
  367. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/index.qmd +0 -0
  368. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/js.qmd +0 -0
  369. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/json.qmd +0 -0
  370. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/literal.qmd +0 -0
  371. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/load.qmd +0 -0
  372. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/memory.qmd +0 -0
  373. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/metadata.qmd +0 -0
  374. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/mime.qmd +0 -0
  375. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/mkdir.qmd +0 -0
  376. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/nc.qmd +0 -0
  377. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/nget.qmd +0 -0
  378. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/nl.qmd +0 -0
  379. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/normalize.qmd +0 -0
  380. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/nput.qmd +0 -0
  381. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/path.qmd +0 -0
  382. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/plot.qmd +0 -0
  383. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/rand.qmd +0 -0
  384. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/readdir.qmd +0 -0
  385. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/remove.qmd +0 -0
  386. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/rename.qmd +0 -0
  387. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/signal.qmd +0 -0
  388. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/src.qmd +0 -0
  389. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/storage.qmd +0 -0
  390. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/svg.qmd +0 -0
  391. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/time.qmd +0 -0
  392. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/ucs.qmd +0 -0
  393. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/uuid.qmd +0 -0
  394. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/vfi.qmd +0 -0
  395. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system/xml.qmd +0 -0
  396. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/system-functions.qmd +0 -0
  397. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/terms.qmd +0 -0
  398. {basedpl-0.1.78 → basedpl-0.1.80}/nbs/xml.ipynb +0 -0
  399. {basedpl-0.1.78 → basedpl-0.1.80}/package-lock.json +0 -0
  400. {basedpl-0.1.78 → basedpl-0.1.80}/package.json +0 -0
  401. {basedpl-0.1.78 → basedpl-0.1.80}/provenance/README.md +0 -0
  402. {basedpl-0.1.78 → basedpl-0.1.80}/provenance/aplcart.jsonl +0 -0
  403. {basedpl-0.1.78 → basedpl-0.1.80}/provenance/april.jsonl +0 -0
  404. {basedpl-0.1.78 → basedpl-0.1.80}/provenance/bqn.jsonl +0 -0
  405. {basedpl-0.1.78 → basedpl-0.1.80}/provenance/core.jsonl +0 -0
  406. {basedpl-0.1.78 → basedpl-0.1.80}/provenance/dyalog.jsonl +0 -0
  407. {basedpl-0.1.78 → basedpl-0.1.80}/provenance/ngn.jsonl +0 -0
  408. {basedpl-0.1.78 → basedpl-0.1.80}/py/Cargo.toml +0 -0
  409. {basedpl-0.1.78 → basedpl-0.1.80}/py/build.rs +0 -0
  410. {basedpl-0.1.78 → basedpl-0.1.80}/pyproject.toml +0 -0
  411. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/__init__.py +0 -0
  412. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/_modidx.py +0 -0
  413. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/__init__.py +0 -0
  414. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/fonts/BQN386B.ttf +0 -0
  415. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/fonts/LICENSE-BQN386 +0 -0
  416. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/fonts/LICENSE-SAX2 +0 -0
  417. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/fonts/SAX2B.ttf +0 -0
  418. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-de.bundle/Contents/Info.plist +0 -0
  419. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-de.bundle/Contents/Resources/BasedPL-de.icns +0 -0
  420. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-de.bundle/Contents/Resources/BasedPL-de.keylayout +0 -0
  421. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-de.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  422. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-de.bundle/Contents/version.plist +0 -0
  423. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-es.bundle/Contents/Info.plist +0 -0
  424. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-es.bundle/Contents/Resources/BasedPL-es.icns +0 -0
  425. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-es.bundle/Contents/Resources/BasedPL-es.keylayout +0 -0
  426. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-es.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  427. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-es.bundle/Contents/version.plist +0 -0
  428. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-fr.bundle/Contents/Info.plist +0 -0
  429. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-fr.bundle/Contents/Resources/BasedPL-fr.icns +0 -0
  430. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-fr.bundle/Contents/Resources/BasedPL-fr.keylayout +0 -0
  431. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-fr.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  432. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-fr.bundle/Contents/version.plist +0 -0
  433. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-uk.bundle/Contents/Info.plist +0 -0
  434. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-uk.bundle/Contents/Resources/BasedPL-uk.icns +0 -0
  435. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-uk.bundle/Contents/Resources/BasedPL-uk.keylayout +0 -0
  436. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-uk.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  437. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-uk.bundle/Contents/version.plist +0 -0
  438. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-us.bundle/Contents/Info.plist +0 -0
  439. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-us.bundle/Contents/Resources/BasedPL-us.icns +0 -0
  440. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-us.bundle/Contents/Resources/BasedPL-us.keylayout +0 -0
  441. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-us.bundle/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  442. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/assets/macos/BasedPL-us.bundle/Contents/version.plist +0 -0
  443. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/bpl.tmLanguage.json +0 -0
  444. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/dyalog.py +0 -0
  445. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/editors.py +0 -0
  446. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/font.py +0 -0
  447. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/fonts.css +0 -0
  448. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/functions.py +0 -0
  449. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/hpl.tmLanguage.json +0 -0
  450. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/input.js +0 -0
  451. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/install.py +0 -0
  452. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/keyboards.json +0 -0
  453. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/keyboards.py +0 -0
  454. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/layout.json +0 -0
  455. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/lb.js +0 -0
  456. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/notebook_runner.py +0 -0
  457. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/notebooks.py +0 -0
  458. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/printing.py +0 -0
  459. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/reference.py +0 -0
  460. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/syntax.py +0 -0
  461. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/windows_keyboard.py +0 -0
  462. {basedpl-0.1.78 → basedpl-0.1.80}/python/basedpl/worker.py +0 -0
  463. {basedpl-0.1.78 → basedpl-0.1.80}/rustfmt.toml +0 -0
  464. {basedpl-0.1.78 → basedpl-0.1.80}/src/canvas.js +0 -0
  465. {basedpl-0.1.78 → basedpl-0.1.80}/src/eval/dissect.rs +0 -0
  466. {basedpl-0.1.78 → basedpl-0.1.80}/tests/common/mod.rs +0 -0
  467. {basedpl-0.1.78 → basedpl-0.1.80}/tests/conftest.py +0 -0
  468. {basedpl-0.1.78 → basedpl-0.1.80}/tests/highlighting.mjs +0 -0
  469. {basedpl-0.1.78 → basedpl-0.1.80}/tests/input.mjs +0 -0
  470. {basedpl-0.1.78 → basedpl-0.1.80}/tests/instructions.txt +0 -0
  471. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/LICENSE-aplcart +0 -0
  472. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/LICENSE-april +0 -0
  473. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/LICENSE-bqn +0 -0
  474. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/LICENSE-bqncrate +0 -0
  475. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/LICENSE-dyalog +0 -0
  476. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/LICENSE-ngn +0 -0
  477. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/bqn.bpl +0 -0
  478. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/distributions.bpl +0 -0
  479. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/dyalog.bpl +0 -0
  480. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/graphics.bpl +0 -0
  481. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/ngn.bpl +0 -0
  482. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/static-int32.bpl +0 -0
  483. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/static.bpl +0 -0
  484. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/support/april.bpl +0 -0
  485. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/support/avl.bpl +0 -0
  486. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/support/redblack.bpl +0 -0
  487. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/support/sbst.bpl +0 -0
  488. {basedpl-0.1.78 → basedpl-0.1.80}/tests/reference/support/splay.bpl +0 -0
  489. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/calls.bpl +0 -0
  490. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/images.bpl +0 -0
  491. {basedpl-0.1.78 → basedpl-0.1.80}/tests/speed/tables.bpl +0 -0
  492. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_basic.py +0 -0
  493. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_bpltests.py +0 -0
  494. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_glyphs.py +0 -0
  495. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_graphics.py +0 -0
  496. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_install.py +0 -0
  497. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_instructions.py +0 -0
  498. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_keylayout.py +0 -0
  499. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_notebooks.py +0 -0
  500. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_reference.py +0 -0
  501. {basedpl-0.1.78 → basedpl-0.1.80}/tests/test_windows_keyboard.py +0 -0
  502. {basedpl-0.1.78 → basedpl-0.1.80}/tests/windows_keyboard.c +0 -0
  503. {basedpl-0.1.78 → basedpl-0.1.80}/wheel/data/share/jupyter/kernels/bpl/kernel.json +0 -0
@@ -9,12 +9,13 @@ permissions:
9
9
  contents: read
10
10
 
11
11
  # In each job, every test step after the first runs even when an earlier step fails, to report every test's result in one run.
12
- # A build step that runs past 10 minutes has stalled. These builds normally take about 3.
13
12
  jobs:
14
13
  test:
15
14
  runs-on: ubicloud-standard-4-ubuntu-2604
16
15
  steps:
17
16
  - uses: actions/checkout@v7
17
+ # The speed tests' costs for large new arrays depend on whether the kernel gives them transparent huge pages.
18
+ - run: cat /sys/kernel/mm/transparent_hugepage/enabled
18
19
  # `tests/highlighting.mjs` reads the TextMate grammar through `shiki`, which `package.json` pins.
19
20
  - run: npm ci
20
21
  - uses: dtolnay/rust-toolchain@stable
@@ -99,7 +99,7 @@ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
99
99
 
100
100
  [[package]]
101
101
  name = "basedpl"
102
- version = "0.1.78"
102
+ version = "0.1.80"
103
103
  dependencies = [
104
104
  "base64 0.23.1",
105
105
  "bytemuck",
@@ -110,6 +110,7 @@ dependencies = [
110
110
  "cranelift-module",
111
111
  "cranelift-native",
112
112
  "csv",
113
+ "fancy-regex",
113
114
  "flate2",
114
115
  "getrandom",
115
116
  "globset",
@@ -127,7 +128,6 @@ dependencies = [
127
128
  "plotters",
128
129
  "png",
129
130
  "rand",
130
- "regex",
131
131
  "roxmltree",
132
132
  "rustc-demangle",
133
133
  "rustix",
@@ -148,7 +148,7 @@ dependencies = [
148
148
 
149
149
  [[package]]
150
150
  name = "basedpl-cli"
151
- version = "0.1.78"
151
+ version = "0.1.80"
152
152
  dependencies = [
153
153
  "async-trait",
154
154
  "basedpl",
@@ -162,7 +162,7 @@ dependencies = [
162
162
 
163
163
  [[package]]
164
164
  name = "basedpl-py"
165
- version = "0.1.78"
165
+ version = "0.1.80"
166
166
  dependencies = [
167
167
  "basedpl",
168
168
  "ctrlc",
@@ -180,7 +180,7 @@ dependencies = [
180
180
 
181
181
  [[package]]
182
182
  name = "basedpl-wasm"
183
- version = "0.1.78"
183
+ version = "0.1.80"
184
184
  dependencies = [
185
185
  "basedpl",
186
186
  "js-sys",
@@ -189,6 +189,21 @@ dependencies = [
189
189
  "wasm-bindgen",
190
190
  ]
191
191
 
192
+ [[package]]
193
+ name = "bit-set"
194
+ version = "0.8.0"
195
+ source = "registry+https://github.com/rust-lang/crates.io-index"
196
+ checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
197
+ dependencies = [
198
+ "bit-vec",
199
+ ]
200
+
201
+ [[package]]
202
+ name = "bit-vec"
203
+ version = "0.8.0"
204
+ source = "registry+https://github.com/rust-lang/crates.io-index"
205
+ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
206
+
192
207
  [[package]]
193
208
  name = "bitflags"
194
209
  version = "1.3.2"
@@ -712,6 +727,17 @@ version = "0.3.0"
712
727
  source = "registry+https://github.com/rust-lang/crates.io-index"
713
728
  checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
714
729
 
730
+ [[package]]
731
+ name = "fancy-regex"
732
+ version = "0.20.0"
733
+ source = "registry+https://github.com/rust-lang/crates.io-index"
734
+ checksum = "20ed7f62ce0ae0da1a8b93c3c7104ab7e0760a74491e097c701fff966e945390"
735
+ dependencies = [
736
+ "bit-set",
737
+ "regex-automata",
738
+ "regex-syntax",
739
+ ]
740
+
715
741
  [[package]]
716
742
  name = "fastrand"
717
743
  version = "2.5.0"
@@ -1071,9 +1097,9 @@ dependencies = [
1071
1097
 
1072
1098
  [[package]]
1073
1099
  name = "json5"
1074
- version = "1.3.4"
1100
+ version = "1.3.6"
1075
1101
  source = "registry+https://github.com/rust-lang/crates.io-index"
1076
- checksum = "1628f14e201e5d6683248a22736547a083c2c176652d65b1068be73dab213a28"
1102
+ checksum = "e46128c9fb848c29097da3149e627cce5496d0b2820a9be06d12ee266c09c749"
1077
1103
  dependencies = [
1078
1104
  "serde",
1079
1105
  "ucd-trie",
@@ -1124,9 +1150,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
1124
1150
 
1125
1151
  [[package]]
1126
1152
  name = "libz-sys"
1127
- version = "1.1.30"
1153
+ version = "1.1.31"
1128
1154
  source = "registry+https://github.com/rust-lang/crates.io-index"
1129
- checksum = "f710a23e6dbf193214fd46ca56a9d6864e550abe86202184532ae7275e46de19"
1155
+ checksum = "ff20308ecabd635a2dc1dd5834a86c462cca20efba1d5d3ddab1f8aea3455cb2"
1130
1156
  dependencies = [
1131
1157
  "cc",
1132
1158
  "pkg-config",
@@ -1582,18 +1608,6 @@ dependencies = [
1582
1608
  "smallvec",
1583
1609
  ]
1584
1610
 
1585
- [[package]]
1586
- name = "regex"
1587
- version = "1.13.1"
1588
- source = "registry+https://github.com/rust-lang/crates.io-index"
1589
- checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
1590
- dependencies = [
1591
- "aho-corasick",
1592
- "memchr",
1593
- "regex-automata",
1594
- "regex-syntax",
1595
- ]
1596
-
1597
1611
  [[package]]
1598
1612
  name = "regex-automata"
1599
1613
  version = "0.4.18"
@@ -1683,9 +1697,9 @@ dependencies = [
1683
1697
 
1684
1698
  [[package]]
1685
1699
  name = "rustymath"
1686
- version = "0.1.52"
1700
+ version = "0.1.53"
1687
1701
  source = "registry+https://github.com/rust-lang/crates.io-index"
1688
- checksum = "9eb8e5ce5edc62d2314664c772662b48992258f6a42ea076053f2169b229c45e"
1702
+ checksum = "f23d74fe738a2a8ed77303288e1cfb1eccf87005fb55c2876814e41374d1f54a"
1689
1703
  dependencies = [
1690
1704
  "foldhash",
1691
1705
  "half",
@@ -1704,9 +1718,9 @@ dependencies = [
1704
1718
 
1705
1719
  [[package]]
1706
1720
  name = "rustymath-buffer"
1707
- version = "0.1.52"
1721
+ version = "0.1.53"
1708
1722
  source = "registry+https://github.com/rust-lang/crates.io-index"
1709
- checksum = "45f92e085b223eb9048ad95befcff11b849d4fa728d2dd31eb6ca76fc7c4390a"
1723
+ checksum = "acf6a5013fe3dbbc1b1883fd10b26848e464fdc185837164352a1cca162bc246"
1710
1724
  dependencies = [
1711
1725
  "pyo3",
1712
1726
  "rustymath",
@@ -2450,7 +2464,7 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
2450
2464
 
2451
2465
  [[package]]
2452
2466
  name = "xtask"
2453
- version = "0.1.78"
2467
+ version = "0.1.80"
2454
2468
  dependencies = [
2455
2469
  "anyhow",
2456
2470
  "rustymath",
@@ -5,14 +5,14 @@ members = ["py"]
5
5
  join_comments = true
6
6
 
7
7
  [workspace.package]
8
- version = "0.1.78"
8
+ version = "0.1.80"
9
9
  edition = "2024"
10
10
  rust-version = "1.98"
11
11
  license = "Apache-2.0"
12
12
 
13
13
  [workspace.dependencies]
14
- rustymath = { version = ">=0.1.52, <1", default-features = false }
15
- rustymath-buffer = ">=0.1.52, <1"
14
+ rustymath = { version = ">=0.1.53, <1", default-features = false }
15
+ rustymath-buffer = ">=0.1.53, <1"
16
16
  pyo3 = ">=0.29.2, <1"
17
17
  pyo3-build-config = ">=0.29.2, <1"
18
18
  ctrlc = ">=3.5.2, <4"
@@ -103,7 +103,7 @@ png = ">=0.18.1, <1"
103
103
  [target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies]
104
104
  chrono = { version = ">=0.4.45, <0.5", features = ["unstable-locales"] }
105
105
  icu_normalizer = ">=2, <3"
106
- regex = "1"
106
+ fancy-regex = "0.20"
107
107
  walkdir = ">=2.5.0, <3"
108
108
  globset = ">=0.4.20, <1"
109
109
  # Cranelift compiles a typed program's loops while BPL runs. The browser build has no JIT.
@@ -126,3 +126,6 @@ wasm-bindgen = ">=0.2.129, <0.3"
126
126
  [dev-dependencies]
127
127
  object = { version = ">=0.39.1, <1", default-features = false, features = ["read"] }
128
128
  rustc-demangle = ">=0.1.28, <1"
129
+
130
+ [build-dependencies]
131
+ serde_json = "1"
@@ -36,7 +36,7 @@ These design notes in `meta/` guide work still ahead:
36
36
  - `linear.md`: the analysis that carries over to deferred Jacobians. Jeremy replaced its notation on 17 October 2026, as "Language changes under study" in `programs.md` describes.
37
37
  - `stage3-build.md`'s "Step 4: shared values as outputs": the plan for bringing outputs back.
38
38
  - `stage4-build.md`'s "Step 5 in outline", its choice 8 and "Not in stage 4": the stage's last step and what it leaves out.
39
- - `design-audit-summary-2026-10-26.md`: the combined view of four audits of stages 1 to 4, whose order of work the release plan in `open.md` replaced. The four `design-audit-*` notes beside it give the evidence.
39
+ - `design-audit-summary-2026-10-26.md`: the combined view of four audits of stages 1 to 4, whose order of work the indexing release's plan replaced. The four `design-audit-*` notes beside it give the evidence.
40
40
  - `learned-2026-10-26.md`: what 26 October 2026 established, where each record is, and what's planned.
41
41
  - `open.md`: every open item.
42
42
 
@@ -76,11 +76,11 @@ Costs in copies can't show a per-call change of a few percent, because code layo
76
76
 
77
77
  `call_profile(case, function)` counts every instruction that one call of `function` retires, with the calls it makes, by function, on macOS on Apple silicon. `lldb` runs the case once per step in a fresh process, lets `skip=` calls of `function` run, then single-steps the next one to its return. `function` is a regex for a demangled name, such as `binder::derived`, and needs code of its own. `base=` names a saved copy whose counts appear beside the build's. The allocator's functions, with the functions that they call, share one row, because what they retire depends on the heap's state. A second total leaves that row out. These counts are exact, where `profile`'s come from time. `profile_diff` once put about 50 instructions of a value mark's rise on a conversion loop whose machine code hadn't changed, and single-stepping found them in `derivative::converted`. Use `profile_diff` to find the function whose call changed, then `call_profile` on that function to settle the change. It counts calls of up to 100,000 instructions, at about 450 a second.
78
78
 
79
- `bpl-tests NAME ARGUMENT...` runs one of these functions from the shell and prints its result: `check_file`, `check_page`, `time_cases`, `instructions`, `instruction_budgets`, `profile`, `profile_diff`, `call_profile`, `disasm`, `jit_disasm`, `speed_costs`, `thread_scaling`, `cargo_costs`, `pytest_costs`, `compare_costs` or `wasm_test`. For example, `bpl-tests time_cases '+/v' --threads 4` times `+/v` on four threads. `time_cases`, `instructions` and `speed_costs` take cases as positional arguments. When a case starts with `-`, put the cases last, after `--`, as in `bpl-tests speed_costs -- '-.×m' '+/v'`. `bpl-tests NAME -h` lists a function's arguments. Called in a kernel, the same functions return Python objects, such as the rows that `compare_costs` reads.
79
+ `bpl-tests NAME ARGUMENT...` runs one of these functions from the shell and prints its result: `check_file`, `check_page`, `time_cases`, `instructions`, `instruction_budgets`, `profile`, `profile_diff`, `call_profile`, `disasm`, `jit_disasm`, `speed_costs`, `thread_scaling`, `cargo_costs`, `pytest_costs`, `compare_costs`, `wasm_test` or `wasm_stack`. For example, `bpl-tests time_cases '+/v' --threads 4` times `+/v` on four threads. `time_cases`, `instructions` and `speed_costs` take cases as positional arguments. When a case starts with `-`, put the cases last, after `--`, as in `bpl-tests speed_costs -- '-.×m' '+/v'`. `bpl-tests NAME -h` lists a function's arguments. Called in a kernel, the same functions return Python objects, such as the rows that `compare_costs` reads.
80
80
 
81
- On each push, the `Test` workflow logs every native cost in its `test` job and every wasm cost in its `wasm` job. The speed test that writes them times the test-profile build that the budgets limit. `bpl --costs PATH` times a `.bpl` file or a directory of them as the speed test does, and prints each cost with this machine's budget, without failing on a budget. The manual `Speed` workflow runs it on a `dist` build, the profile releases use, on CI's runner, beside its wasm timing. The `Release` workflow runs it on each binary it builds, on GitHub's runners. Their logs show what releases cost, for comparison with the `Test` workflow's. `logged_costs` reads all three workflows' logs. When you review a run, look for costs over their budgets and for costs that changed by more than 20% since the run before. `compare_costs(before, after)` lists both, from two runs' logs or from the rows that `speed_costs` and the other timing functions give. It measures each change on times per item where both runs give them, so a change to `COPIES` doesn't show as one. Every log names its CPU in its copy lines. Study a slowdown until you know its cause only when it appears in more than one CI run, or when two or more similar cases slow by similar amounts. Treat any other slowdown as normal variation.
81
+ On each push, the `Test` workflow logs every native cost in its `test` job and every wasm cost in its `wasm` job. The speed test that writes them times the test-profile build that the budgets limit. `bpl --costs PATH` times a `.bpl` file or a directory of them as the speed test does, and prints each cost with this machine's budget, then each case still over its budget after the retries, marked `over`, without failing on a budget. The manual `Speed` workflow runs it on a `dist` build, the profile releases use, on CI's runner, beside its wasm timing. The `Release` workflow runs it on each binary it builds, on GitHub's runners. Their logs show what releases cost, for comparison with the `Test` workflow's. `logged_costs` reads all three workflows' logs. When you review a run, look for costs over their budgets and for costs that changed by more than 20% since the run before. `compare_costs(before, after)` lists both, from two runs' logs or from the rows that `speed_costs` and the other timing functions give. It measures each change on times per item where both runs give them, so a change to `COPIES` doesn't show as one. Every log names its CPU in its copy lines. Study a slowdown until you know its cause only when it appears in more than one CI run, or when two or more similar cases slow by similar amounts. Treat any other slowdown as normal variation.
82
82
 
83
- A budget is a case's expected cost times a multiplier: 2 under 50 copies, 1.5 from 50 to 500, and 1.3 over 500. The multiplier is largest for cheap cases, which vary most between runs. The expected cost starts from a first-principles analysis of what the case should cost. A later expected cost comes from a fuller understanding of the case than that analysis gives, such as a platform difference or a cost the analysis missed, and the case's comment records it. For a case with a known gap, the multiplier applies to today's measured cost, held until the gap is fixed, and the case's comment names the gap. A platform's cost that no run has measured there, such as an estimate for Linux or wasm, keeps twice the estimate until CI measures it. Budgets set before 27 October 2026 are still twice their expected cost, until a survey of logged costs applies the steps to them. A case over its budget needs study, which finds either a speed bug to fix or something the analysis missed. Avoid raising a budget to match a run without understanding why the case costs what it does. Each `⍝⍝:` footer in a BPL speed file holds a native budget for macOS on Apple silicon, then one for Linux on CI's x86 runner, then, in basedpl's file, a wasm budget for Node on CI's x86 runner. One expected cost serves every platform at first, until a specific difference on one platform is found. macOS running matrix products and decompositions on Accelerate, where CI runs rustymath's own kernels, is such a difference. A comment above each case, or above its group, gives the expected cost with its reason, and any platform's own cost with the reason for it. `set_budgets(expected)` applies the multiplier and writes the budgets for the cases that `expected` names, a dict from each case's code to its expected cost. `builds=` limits the change to one platform's column, for a cost that differs there. `estimate=True` keeps twice the cost, for a platform's estimates. A case can appear in more than one section, such as `copies` and `widths`. `sections=` limits the change to the sections it names. `path=` selects a BPL speed file or directory, or one of Rustymath's table-format files, `tests/speed.txt` or `tests/speed_python.txt`.
83
+ A budget is a case's expected cost times a multiplier: 2 under 50 copies, 1.5 from 50 to 500, and 1.3 over 500. The multiplier is largest for cheap cases, which vary most between runs. The expected cost starts from a first-principles analysis of what the case should cost. A later expected cost comes from a fuller understanding of the case than that analysis gives, such as a platform difference or a cost the analysis missed, and the case's comment records it. For a case with a known gap, the multiplier applies to today's measured cost, held until the gap is fixed, and the case's comment names the gap. A platform's cost that no run has measured there, such as an estimate for Linux or wasm, keeps twice the estimate until CI measures it. Budgets set before 27 October 2026 are still twice their expected cost, until a survey of logged costs applies the steps to them. A case over its budget needs study, which finds either a speed bug to fix or something the analysis missed. Avoid raising a budget to match a run without understanding why the case costs what it does. Each `⍝⍝:` footer in a BPL speed file holds a native budget for macOS on Apple silicon, then one for Linux on CI's x86 runner, then, in basedpl's file, a wasm budget for Node on CI's x86 runner. A speed test fails on a budget only on the CPU that the budgets were set for, `rustymath::timing::BUDGET_CPU`: the development Mac's for macOS, and CI's runner's for Linux and wasm. On any other CPU, it prints every cost, then each case still over its budget after the retries, marked `over`, and fails on none. A cost in copies depends on a CPU's caches as well as its speed, as rustymath's DEV.md shows for the 9950X that joined CI's runner pool in October 2026. One expected cost serves every platform at first, until a specific difference on one platform is found. macOS running matrix products and decompositions on Accelerate, where CI runs rustymath's own kernels, is such a difference. A comment above each case, or above its group, gives the expected cost with its reason, and any platform's own cost with the reason for it. `set_budgets(expected)` applies the multiplier and writes the budgets for the cases that `expected` names, a dict from each case's code to its expected cost. `builds=` limits the change to one platform's column, for a cost that differs there. `estimate=True` keeps twice the cost, for a platform's estimates. A case can appear in more than one section, such as `copies` and `widths`. `sections=` limits the change to the sections it names. `path=` selects a BPL speed file or directory, or one of Rustymath's table-format files, `tests/speed.txt` or `tests/speed_python.txt`.
84
84
 
85
85
  `tests/explain.rs`'s `speed_cases_take_their_routes` captures every speed case after warm-up, with its normal setup and size, forcing the result outside timing (`timing::routes`). It also captures each reference case that has route directives, once under ordinary preferences. Within `cargo test`, only this test checks route directives. `check_file` checks a file's directives too, through `reference::check`. Put `⍝⍝⍝ route NAME` above a case to require that fast route to execute. A permitted slow event never excuses a missing required route.
86
86
 
@@ -98,7 +98,7 @@ In a Claude Code session, every exhash edit is recorded in `/tmp/exhash-journal/
98
98
 
99
99
  Cooperating tools share the machine's timing lock, `/tmp/aai-ws-timing.lock`. Timings take it exclusively. `cargo develop`, `cargo wait`, `cargo wasm`, the reference test, pytest, `check_file`, `check_page`, `bpl-nb` and `wasm_test` without `speed` take it shared. Rust code takes it through `rustymath::timing`. When a kernel calls `time_cases` or native `speed_costs`, the `bpl` worker that the call starts takes the lock, not the kernel. Python code takes it with `fastws.cargo.timing_lock`. Node can't lock a file. `wasm_test` and `speed_costs(wasm=DIR)` hold the lock in Python while Node runs. Other Rust tests and bare Cargo commands do not all take it. After five minutes a timing fails. A build or test run then goes ahead without the lock. After 30 seconds, an exclusive wait prints the processes with the lock file open. The list can include processes that are only waiting for the lock. Never take the lock yourself in a kernel process. Never coordinate timings by hand. A hold that outlasts its call blocks the timings that later calls launch. Native timings run on one thread and request user-interactive macOS QoS, which favours the performance cores. QoS is not CPU affinity.
100
100
 
101
- Run `cargo wasm` during development only for browser work. Agents use `cargo wasm --out DIR`, then run the browser tests against that build with `basedpl.bpltests.wasm_test(DIR)` for `tests/wasm.mjs` and `wasm_test(DIR, speed=True)` for `tests/wasm-speed.mjs`. That speed test fails on a wasm budget only on Linux x86-64, CI's platform. On any other host it prints every cost and marks each case still over its budget after the retries, as `bpl --costs` does. This avoids replacing a module another agent is using. For other edits under `cfg(web)` or `host_web.rs`, check compilation with `cargo cs -p basedpl-wasm --target wasm32-unknown-unknown`, which checks the browser wrapper crate together with basedpl's browser code. `cargo cs` alone compiles neither.
101
+ Run `cargo wasm` during development only for browser work. Agents use `cargo wasm --out DIR`, then run the browser tests against that build with `basedpl.bpltests.wasm_test(DIR)` for `tests/wasm.mjs` and `wasm_test(DIR, speed=True)` for `tests/wasm-speed.mjs`. On this Mac, that speed test prints every cost and marks each case still over its wasm budget without failing, because those budgets were set for CI's runner. This avoids replacing a module another agent is using. For other edits under `cfg(web)` or `host_web.rs`, check compilation with `cargo cs -p basedpl-wasm --target wasm32-unknown-unknown`, which checks the browser wrapper crate together with basedpl's browser code. `cargo cs` alone compiles neither.
102
102
 
103
103
  ### Machine code
104
104
 
@@ -128,7 +128,7 @@ Basedpl's crates pass on rustymath's default `native` feature, which rustymath's
128
128
 
129
129
  Use published dependency ranges with the lower bounds required by the APIs in use. `Cargo.toml` names a published rustymath range; the `~/aai-ws` Cargo patch selects the sibling checkout locally. CI resolves published crates. Release rustymath changes before relying on them in basedpl CI. Don't edit fastws-generated Cargo patches, `.git/fastws-cargo-key` or workspace configuration, and don't commit the workspace-generated `Cargo.lock`. `meta/` is ignored planning material, not contributor documentation. `[tool.uv] cache-keys` tracks packaging manifests, not Rust sources.
130
130
 
131
- `Test` runs native and wasm jobs on pushes to main and pull requests. Native CI runs `cargo test`, editable installation, `cargo develop`, pytest, `bpl-nb` and `nbdev-test`. Python tests use the same test-profile build. The wasm job builds with `cargo wasm --strip` and runs both Node suites. Both jobs run on `ubicloud-standard-4-ubuntu-2604`, which is Ubuntu 26.04 on the `ubicloud-standard-4` VM size that speed budgets are set for. A build step that runs past 10 minutes fails. These steps normally take about 3. They generate a lockfile before restoring `Swatinem/rust-cache`, making dependency changes part of the cache key. `Speed` is manually triggered. Its `wasm` job restores the `Test` workflow's wasm cache. Its native job builds the `dist` profile without one.
131
+ `Test` runs native and wasm jobs on pushes to main and pull requests. Native CI runs `cargo test`, editable installation, `cargo develop`, pytest, `bpl-nb` and `nbdev-test`. Python tests use the same test-profile build. The wasm job builds with `cargo wasm --strip` and runs both Node suites. Both jobs run on `ubicloud-standard-4-ubuntu-2604`, which is Ubuntu 26.04 on the `ubicloud-standard-4` VM size that speed budgets are set for. They generate a lockfile before restoring `Swatinem/rust-cache`, making dependency changes part of the cache key. `Speed` is manually triggered. Its `wasm` job restores the `Test` workflow's wasm cache. Its native job builds the `dist` profile without one.
132
132
 
133
133
  `Release` runs separately on `v*` tags on GitHub's runners. It builds dist wheels, sdist, standalone CLI artifacts and the Windows keyboard archive, then publishes Python artifacts and the GitHub release. Its npm job publishes the stripped browser package through trusted publishing and purges jsDelivr's package files to avoid stale unversioned URLs. Release neither runs tests nor waits for the Test workflow.
134
134
 
@@ -195,7 +195,7 @@ An assignment compiles to one instruction, which runs `Session::assigned`, the s
195
195
 
196
196
  Each item of a bracket literal is a level whose value goes into the literal at once, as `Session::item_result` converts it, and `Session::bracket` builds the literal for `resolve` and for the compiled `Array` instruction alike. A literal with a computed key that isn't constant stays with `resolve`. Each statement keeps the recording of its first evaluation (`Statement::recording`). A later call whose `⍺` is absent where that evaluation's held an argument, or the reverse, resumes the binder where the statement reads `⍺`.
197
197
 
198
- Tail calls reuse frames while preserving lexical dependencies. Handlers disable tail reuse. Evaluation depth is capped at 20,000 natively and at 346 in the browser, whose stack runs out first. Each call of a function other than a primitive counts toward it, and so do each statement of a dfn other than its last, each group, each run that ends in a dyadic operator and each bracket item, compiled or not. A compiled statement or level counts with `Session::descend` alone, without the interrupt check and stack growth of `Session::nested`. Calls of primitives other than `⍎` don't count, because a primitive never calls back into BPL. They skip the depth, capture and stack bookkeeping, and on numbers a form that applies a kernel to each pair of items runs that kernel at once (`Primitive::scalar_call`). A separate 20,000-frame limit bounds retained lexical frames. Late-bound name resolution stops at 128 levels. These are execution limits, not a sandbox against arbitrarily deep source, arrays or function graphs.
198
+ Tail calls reuse frames while preserving lexical dependencies. Handlers disable tail reuse. Evaluation depth is capped at 20,000 natively and at 244 in the browser, whose stack runs out first. Each call of a function other than a primitive counts toward it, and so do each statement of a dfn other than its last, each group, each run that ends in a dyadic operator and each bracket item, compiled or not. A compiled statement or level counts with `Session::descend` alone, without the interrupt check and stack growth of `Session::nested`. Calls of primitives other than `⍎` don't count, because a primitive never calls back into BPL. They skip the depth, capture and stack bookkeeping, and on numbers a form that applies a kernel to each pair of items runs that kernel at once (`Primitive::scalar_call`). A separate 20,000-frame limit bounds retained lexical frames. Late-bound name resolution stops at 128 levels. These are execution limits, not a sandbox against arbitrarily deep source, arrays or function graphs.
199
199
 
200
200
  ## Values, layouts and assignment
201
201
 
@@ -241,7 +241,7 @@ Floats use IEEE NaN, infinity and signed zero. Comparison treats NaN as unequal;
241
241
 
242
242
  Under `•prefs ["kinds":"static"]`, a result's kind follows from its arguments' kinds alone, as `meta/kinds.md` describes. `Numeric` carries `kinds` and `int`. Until the `float` pref sets a width, `Numeric::set` gives new floats the width the kinds give, 32 bits under static kinds and 64 under dynamic kinds (`Kinds::float_width`). Whether the pref has set one lives in `settings::float_set`, outside `Numeric`: every call builds and copies a `Numeric`, and a Boolean field there cost about 14 instructions on each primitive call and 34 on each dfn call. A pervasive call on arrays plans before it computes. `plan::pervasive` builds a `plan::Pervasive` from the operands' kinds (`plan::Kind`: type, fixed width and weakness) and the settings, without reading items. It holds the settings with the fixed width that the operands give (`Numeric::for_kinds`), whether 16-bit floats compute in 32 bits, the kind that the call computes in (`computes_in`, which applies rustymath's `DType::common` after `Numeric::kind`), its kernel table (`computes`) and, under static kinds, every result's kind (`Pervasive::result`). Eager dispatch, fusion's deferral (`Pervasive::fuses`) and typed programs read the same plan. Products and folds plan the same way. `plan::Product` holds `g`'s pervasive plan and the settings under which `f` folds its results (`Product::folds`). `plan::Fold` holds a fold's or scan's settings and its operands' kinds. Eager products, folds and scans read them, as typed programs do. Comparisons, `⌈ ⌊` and bitwise functions compute at their arguments' storage width instead, where their results are the same at every width (`pervasive::first_kind`). A comparison between integers and a whole float that stands for an integer computes on integers, through `Pervasive::computes`, as does a residue by such a float or a residue scan from one, whose results then convert to floats (`plan::whole_float`). Literals, values computed only from literals, and Python's scalar arguments are weak (`Number::is_weak`). Before a call, `Primitive::weakened` converts a weak number beside a strong one to the width that rustymath's `DType::common_weak` gives it, or to a fixed integer's width where it fits. The loops keep the failed results that `keeps` names: floats' NaNs, and the wrapped integers of objects that report `WRAPS`. The kernel tables choose float `⌊ ⌈ ×` and wrapping negation from `run.numeric()`. `Stored::build_at` keeps complex results complex. `Primitive::number` gives every pervasive result on numbers, as well as each step of the fold of numbers. Under static kinds, `statically` converts it to the kind that the call's plan gives. A static call on ordinary integers that an integer kernel takes runs that kernel at the `int` width instead, as a call on fixed integers runs it at theirs (`Primitive::integer_kernel`). Under dynamic kinds, a call on two numbers stays outside plans, because the type of its result depends on their values. `Number::wrapped` and `Value::wrapped` wrap an exact integer result to the integer width, the fixed width that `Numeric::for_kinds` finds among a call's operands, or the `int` width under static kinds. Under static kinds a strong ordinary integer is a fixed integer of the width it computes at, the `int` width joined with its storage width (`plan::Kind::stored`). Every static call on integer arrays then computes under a fixed width. Weak integers have no fixed width. NEP 50 decides theirs, as before. Display marks a fixed integer of the `int` width with plain `ₓ` (`Mark::integer`). A fixed kernel that fails where a result doesn't fit, as lcm and binomial coefficients can, gives the exact result wrapped (`Primitive::fixed_number`). `statically` uses them, and so do the functions that compute exactly, such as `⊥`, `⌻` and the determinant. Where integers wrap, a function whose results are approximate, such as `⌹` or polar parts, computes integers as floats of the width that their division gives (`plan::Kind::approximate`). `∂` converts the integers that wrap in its argument to those floats before it runs its function (`derivative::differentiate`). `Number::parse` keeps complex literals and checks integer literals against the `int` width.
243
243
 
244
- Settings live once for the whole process, in `settings.rs`, and are read from there, not passed through functions, except where a read is slow and on a hot path. Each setting that calls and scalar operations read is an atomic: the numeric settings, the hanzi aliases, the `batch` pref, the verifier flag, the fusion report flag, fusion's small sizes and the compile setting. The display settings sit behind one lock. `•prefs` writes them, the lexer writes a source's leading `•prefs` header as it reads it, and `settings::reset` restores the defaults, as `]clear` and the test harnesses do. A module that `•load` runs changes the settings for the whole process. Nothing restores them when it returns. Rustymath holds the thread count, the one setting that it reads itself, and `•prefs` writes it there. Each call reads the store once where it starts. Pervasive calls, folds and products read it as they plan (`Primitive::pervasive_mapped`). A dfn call reads it as it looks for its program (`program::call`). So do `Domain::of` and the lexer. Values derived from the settings within a call stay explicit arguments. A call's plan holds the settings it computes under. A pending array computes under the plans that its calls made, whatever settings are in force when it computes. A pending conversion holds the settings that give its floor's tolerance (`Step::Convert`'s `numeric`). A dfn's programs are found by the settings they were traced under (`program::Key`). Under other settings, the dfn traces a new program. The loop structs keep the settings because their closures run on rustymath's worker threads. `Number`'s tolerance methods and `Primitive::number` take them because they run once per item. The parser's leaves take a width marker's width, and `matches_within` takes `⍣∞`'s convergence tolerance. Imports build complex numbers with `Number::complex_in_session`: Python's `_Session.array` and the JSON protocol's `request`. JavaScript values hold no complex numbers.
244
+ Settings live once for the whole process, in `settings.rs`, and are read from there, not passed through functions, except where a read is slow and on a hot path. Each setting that calls and scalar operations read is an atomic: the numeric settings, the hanzi aliases, the `batch` pref, the verifier flag, the fusion report flag, fusion's sizes, which `settings::set_sizes` sets, and the compile setting. The display settings sit behind one lock. `•prefs` writes them, the lexer writes a source's leading `•prefs` header as it reads it, and `settings::reset` restores the defaults, as `]clear` and the test harnesses do. A module that `•load` runs changes the settings for the whole process. Nothing restores them when it returns. Rustymath holds the thread count, the one setting that it reads itself, and `•prefs` writes it there. Each call reads the store once where it starts. Pervasive calls, folds and products read it as they plan (`Primitive::pervasive_mapped`). A dfn call reads it as it looks for its program (`program::call`). So do `Domain::of` and the lexer. Values derived from the settings within a call stay explicit arguments. A call's plan holds the settings it computes under. A pending array computes under the plans that its calls made, whatever settings are in force when it computes. A pending conversion holds the settings that give its floor's tolerance (`Step::Convert`'s `numeric`). A dfn's programs are found by the settings they were traced under (`program::Key`). Under other settings, the dfn traces a new program. The loop structs keep the settings because their closures run on rustymath's worker threads. `Number`'s tolerance methods and `Primitive::number` take them because they run once per item. The parser's leaves take a width marker's width, and `matches_within` takes `⍣∞`'s convergence tolerance. Imports build complex numbers with `Number::complex_in_session`: Python's `_Session.array` and the JSON protocol's `request`. JavaScript values hold no complex numbers.
245
245
 
246
246
  `Numeric::mathish_at(width)` owns Mathish eligibility: the preference must be on, kinds dynamic and the calculation ordinary exact, f64 or complex128. Fixed-integer operations are excluded even when computing at f64. Kernels select their numerical objects before the loop. Mathish comparison tolerance is `1E-14`. f32/f16 compare exactly. Fixed-point convergence uses four ulps at those widths and `1E-14` at f64, independently of Mathish. Index/count/Boolean/character-offset conversion uses `near_integer` with the fixed default tolerance. The numerical objects come from rustymath. Use independent inside/outside-tolerance tests with exact/mixed controls rather than language comparison as its own oracle.
247
247
 
@@ -327,7 +327,7 @@ Browser `Session.run` streams MIME events and returns a protocol error or null.
327
327
 
328
328
  The playground and gallery load released assets from jsDelivr, or local `nbs/playground/` assets on localhost. Shared `bpl.js` owns editors, worker startup and output. Restarting a trapped/stopped worker loses its state. `worker.js`, `page.js` and `gallery.js` own their respective protocols/UI; `nbs/driver.js` documents canvas drawing data. Gallery demos are `.bpl` sources with shared preferences, checked natively by `language_examples`. Browser recursion tests cover both V8 compilers and fail with LIMIT before stack exhaustion.
329
329
 
330
- CI's two `wasm` jobs, in the `Test` and `Speed` workflows, take Node's version from `.node-version`. TurboFan's frame sizes vary between V8 versions by enough to decide whether a recursion test overflows. On 28 October 2026, one build's `each` shape needed 0.68 MB of stack to reach 171 levels under Node 24's TurboFan, against 0.62 MB under Node 26's. `tests/wasm.mjs` runs its depth checks with Node's 192 KB reserve plus 80% of the roughly 470 KB that a Chrome worker gives, 0.5575 MB in all. A build whose frames grow into the remaining 20% fails the test. In wasm, `Binder::reduce` and `Bindings::enter` stay out of line, to keep their locals out of the frames that stay on the stack at every level of recursion. To find a frame that grew, print each function's TurboFan frame size, in "stack slots", with `node --no-liftoff --print-wasm-code-function-index=N`. Measure with the test's own sequence in a fresh worker: code compiled once and shared across workers gets different frames.
330
+ CI's two `wasm` jobs, in the `Test` and `Speed` workflows, take Node's version from `.node-version`. TurboFan's frame sizes vary between V8 versions by enough to decide whether a recursion test overflows. On 28 October 2026, one build's `each` shape needed 0.68 MB of stack to reach 171 levels under Node 24's TurboFan, against 0.62 MB under Node 26's. `tests/wasm.mjs` runs its depth checks with Node's 192 KB reserve plus 80% of the roughly 470 KB that a Chrome worker gives, 0.5575 MB in all. A build whose frames grow into the remaining 20% fails the test. CI's x86-64 V8 takes more stack per level than Apple silicon's. The browser's depth limit, `MAX_CALL_DEPTH` in `src/eval.rs`, allows for levels up to 1.48 times their size on Apple silicon. `basedpl.bpltests.wasm_stack(DIR)` measures the stack that each recursion shape takes per level and below its first level. The limit is set from those figures. In wasm, `Binder::reduce` and `Bindings::enter` stay out of line, to keep their locals out of the frames that stay on the stack at every level of recursion. To find a frame that grew, print each function's TurboFan frame size, in "stack slots", with `node --no-liftoff --print-wasm-code-function-index=N`. `wasm_stack` runs each trial in a fresh `node` process whose worker compiles the module, as the test's worker does. Code compiled once and shared across workers gets different frames.
331
331
 
332
332
  ## System functions and rendering
333
333
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basedpl
3
- Version: 0.1.78
3
+ Version: 0.1.80
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Requires-Dist: fastcore
@@ -0,0 +1,58 @@
1
+ use std::{env, fs, path::Path};
2
+
3
+ fn page_text(path: &Path) -> String {
4
+ let text = fs::read_to_string(path).unwrap();
5
+ if path.extension().is_none_or(|s| s != "ipynb") { return text; }
6
+ let notebook: serde_json::Value = serde_json::from_str(&text).unwrap();
7
+ let language = notebook["metadata"]["kernelspec"]["language"].as_str().unwrap_or("bpl");
8
+ let mut text = String::new();
9
+ for cell in notebook["cells"].as_array().unwrap() {
10
+ let source = match &cell["source"] {
11
+ serde_json::Value::String(s) => s.clone(), lines => lines.as_array().unwrap().iter().map(|s| s.as_str().unwrap()).collect()
12
+ };
13
+ match cell["cell_type"].as_str().unwrap() {
14
+ "markdown" => text.push_str(&source), "code" => text.push_str(&format!("```{language}\n{source}\n```")), _ => continue
15
+ }
16
+ text.push_str("\n\n");
17
+ }
18
+ text
19
+ }
20
+
21
+ /// Embeds the reference pages and guides, including notebook source but not outputs.
22
+ fn main() {
23
+ println!("cargo::rustc-check-cfg=cfg(web)");
24
+ if env::var("CARGO_CFG_TARGET_ARCH").is_ok_and(|a| a == "wasm32") && env::var("CARGO_CFG_TARGET_OS").is_ok_and(|o| o == "unknown") {
25
+ println!("cargo::rustc-cfg=web");
26
+ }
27
+ let mut entries = Vec::new();
28
+ for dir in ["", "glyphs", "system"] {
29
+ let folder = Path::new("nbs").join(dir);
30
+ println!("cargo::rerun-if-changed={}", folder.display());
31
+ let mut paths: Vec<_> = fs::read_dir(&folder).unwrap().map(|entry| entry.unwrap().path())
32
+ .filter(|path| path.extension().is_some_and(|s| s == "qmd" || s == "ipynb")).collect();
33
+ paths.sort();
34
+ for path in &paths {
35
+ let stem = path.file_stem().unwrap().to_str().unwrap();
36
+ let name = if dir.is_empty() { stem.to_owned() } else { format!("{dir}/{stem}") };
37
+ let mut help = page_text(path);
38
+ if !dir.is_empty() {
39
+ for target in &paths {
40
+ let file = target.file_name().unwrap().to_str().unwrap();
41
+ help = help.replace(&format!("]({file}"), &format!("]({dir}/{file}"));
42
+ }
43
+ help = help.replace("](../", "](");
44
+ }
45
+ let title = help.lines().find_map(|l| l.strip_prefix("# ")).unwrap_or(stem);
46
+ let aliases: Vec<&str> = if dir == "glyphs" { vec![stem] }
47
+ else if dir == "system" {
48
+ let mut fenced = false;
49
+ help.lines().filter(|line| {
50
+ fenced ^= line.starts_with("```");
51
+ !fenced && line.starts_with('#')
52
+ }).flat_map(|line| line.split('`').skip(1).step_by(2)).filter(|name| name.starts_with(['•', '$'])).collect()
53
+ } else { Vec::new() };
54
+ entries.push(format!("Page {{ name: {name:?}, title: {title:?}, aliases: &{aliases:?}, text: {help:?} }}"));
55
+ }
56
+ }
57
+ fs::write(Path::new(&env::var("OUT_DIR").unwrap()).join("help.rs"), format!("const HELP: &[Page] = &[{}];", entries.join(",\n"))).unwrap();
58
+ }
@@ -52,6 +52,6 @@ Use actual glyphs in files, pipes and `-e`; backtick names are a [REPL input met
52
52
  | `bpl --help` | Usage |
53
53
  | `bpl --version` | Version |
54
54
  | `bpl --worker` | JSON-lines requests with deadlines and interruption |
55
- | `bpl --costs FILE` | Times the cases in a file in `tests/speed.txt`'s format, as the speed test does, and prints each cost with this machine's budget. A case over its budget leaves the exit status at 0 |
55
+ | `bpl --costs PATH` | Times the cases in a speed file in the format of basedpl's `tests/speed/*.bpl`, or in a directory of them, as the speed test does. Prints each cost with this machine's budget, then each case still over its budget after the retries, marked `over`. A case over its budget leaves the exit status at 0 |
56
56
 
57
57
  See [process interfaces](processes.qmd) for machine-readable output. The exit status is 0 on success, 1 after an evaluation or I/O error, and 2 for invalid command arguments. An error doesn't discard the output written before it.
@@ -66,7 +66,7 @@ n←⊽⁻¹+÷ ⋄ n 1.5 ⍝ 1.416666667
66
66
  -↢10⁝3 ⍝ ¯7
67
67
  ```
68
68
 
69
- Between two functions, `f↣g Y` is `(f Y)g Y` and `f↢g Y` is `Y f(g Y)`. `(3<)↣# Y` is `(3<Y)#Y`. It keeps the items of `Y` that are greater than 3:
69
+ With two function operands, `↣` and `↢` form monadic hooks. `f↣g Y` is `(f Y)g Y` and `f↢g Y` is `Y f(g Y)`. Two-function trains in BPL are atops. `(3<)↣# Y` is `(3<Y)#Y`. It keeps the items of `Y` that are greater than 3:
70
70
 
71
71
  ```bpl
72
72
  (3<)↣# 2 7 1 8 ⍝ 7 8
@@ -32,7 +32,7 @@
32
32
  "source": [
33
33
  "## First calculations\n",
34
34
  "\n",
35
- "Run `bpl` to open the [REPL](repl.qmd). Type an expression and press Enter. `⍝` starts a comment. The examples use comments to show each result.\n",
35
+ "Run `bpl` to open the [REPL](repl.qmd). Type an expression and press Enter. `⍝` starts a comment.\n",
36
36
  "\n",
37
37
  "BPL evaluates right to left. Parentheses group, and so do spaces. BPL evaluates each part between spaces first."
38
38
  ]
@@ -72,9 +72,9 @@
72
72
  }
73
73
  ],
74
74
  "source": [
75
- "2×3+4 ⍝ 14\n",
76
- "(2×3)+4 ⍝ 10\n",
77
- "2×3 + 4 ⍝ 10"
75
+ "2×3+4\n",
76
+ "(2×3)+4\n",
77
+ "2×3 + 4"
78
78
  ]
79
79
  },
80
80
  {
@@ -102,7 +102,7 @@
102
102
  }
103
103
  ],
104
104
  "source": [
105
- "10+1 2 3 ⍝ 11 12 13"
105
+ "10+1 2 3"
106
106
  ]
107
107
  },
108
108
  {
@@ -139,8 +139,8 @@
139
139
  }
140
140
  ],
141
141
  "source": [
142
- "v←⍳5 ⋄ v ⍝ 0 1 2 3 4\n",
143
- "+/⍳5 ⍝ 10"
142
+ "v←⍳5 ⋄ v\n",
143
+ "+/⍳5"
144
144
  ]
145
145
  },
146
146
  {
@@ -187,8 +187,8 @@
187
187
  }
188
188
  ],
189
189
  "source": [
190
- "1÷3 ⍝ 0.3333333333333333\n",
191
- "1ₓ÷3ₓ ⍝ 1ᵣ3"
190
+ "1÷3\n",
191
+ "1ₓ÷3ₓ"
192
192
  ]
193
193
  },
194
194
  {
@@ -216,7 +216,7 @@
216
216
  }
217
217
  ],
218
218
  "source": [
219
- "1j2×1j¯2 ⍝ 5"
219
+ "1j2×1j¯2"
220
220
  ]
221
221
  },
222
222
  {
@@ -244,7 +244,7 @@
244
244
  }
245
245
  ],
246
246
  "source": [
247
- "+/2 3⍴⍳6 ⍝ 3 12"
247
+ "+/2 3⍴⍳6"
248
248
  ]
249
249
  },
250
250
  {
@@ -2,7 +2,7 @@
2
2
 
3
3
  Dyadic operator. Keys: `Alt-,`. Hanzi: `后` (`後`)
4
4
 
5
- `f↢g Y` is `Y f(g Y)`. The left argument of `f` is `Y` itself. For `f(g Y)`, use [Atop](jot.qmd), `f∘g`.
5
+ The monadic hook `f↢g Y` is `Y f(g Y)`. The left argument of `f` is `Y` itself. For `f(g Y)`, use [Atop](jot.qmd), `f∘g`.
6
6
 
7
7
  ```bpl
8
8
  ×↢- 5 ⍝ ¯25
@@ -2,7 +2,7 @@
2
2
 
3
3
  Dyadic operator. Keys: `Alt-.`. Hanzi: `先`
4
4
 
5
- `f↣g Y` is `(f Y)g Y`, where `f` prepares the left argument of `g`. Operators bind from the left. For example, `3↣<↣#` is `(3↣<)↣#`, which keeps the items greater than 3.
5
+ The monadic hook `f↣g Y` is `(f Y)g Y`, where `f` prepares the left argument of `g`. Operators bind from the left. For example, `3↣<↣#` is `(3↣<)↣#`, which keeps the items greater than 3.
6
6
 
7
7
  ```bpl
8
8
  -↣+ 5 ⍝ 0
@@ -14,7 +14,7 @@ Entry: Dyalog diff, example, defining page. Not the reference: read the page bef
14
14
 
15
15
  ## Language
16
16
 
17
- - [Syntax](syntax.html.md): BQN stranding: mark strands with `[]` (per BQN's 5-year retrospective), except spaced literals (step 1) and subjects side by side (step 3); like BQN, a space is semantic. `⁝` (Alt-:) separates tokens and stops literal stranding without ending the run: `h⁝m`≡`h(m)`, `f⍣3⁝0`≡`(f⍣3)0`. 3 steps: 1. spaced literals join, 1 vector: `1 2`, `"ab" "cd"`; even operand+arg: `+/⍠2 3 3 3↕m` has operand `2 3 3 3`, write `+/⍠2 3⁝3 3↕m`. 2. each other run→`(run)`: `a+b × c+d`≡`(a+b)(×)(c+d)`; fn between two runs: space both sides: `a×b + c`≡`(a×b)+c`; `a×b +c`≡`[a×b ; +c]`; `a×b+ c`≡`(a×b+)c`, train `a×(b+c)`; `1+k (⌈/⊢)⌸ a`≡`(1+k)((⌈/⊢)⌸)(a)`. 3. read as APL, right to left; subjects side by side strand: `a b`≡`(a)(b)`≡`[a b]` only if neither touches; `1+a b`≡`(1+a)(b)`→`11 20`, 1 plus both: `1+[a b]`→`11 21`; `n 2⍴0`≡`(n)(2⍴0)`→`[3 [0 0]]`, names never join literal strands: write `[n 2]⍴0`. no needless spaces; join by deleting spaces, not adding parens: `1+k(⌈/⊢)⌸a`. name fn, name arg: `h⁝m` `h[m n]`. name operand, glyph arg: `+/⍠k⍵`. list: `[+/x ; +/x ÷ ≢x]`. name digits: `x_1`; `x1`≡`x(1)`.
17
+ - [Syntax](syntax.html.md): BQN stranding: mark strands with `[]` (per BQN's 5-year retrospective), except spaced literals (step 1) and subjects side by side (step 3); like BQN, a space is semantic. `⁝` separates tokens and stops literal stranding without ending the run: `h⁝m`≡`h(m)`, `f⍣3⁝0`≡`(f⍣3)0`. 3 steps: 1. spaced literals join, 1 vector: `1 2`, `"ab" "cd"`; even operand+arg: `+/⍠2 3 3 3↕m` has operand `2 3 3 3`, write `+/⍠2 3⁝3 3↕m`. 2. each other run→`(run)`: `a+b × c+d`≡`(a+b)(×)(c+d)`; fn between two runs: space both sides: `a×b + c`≡`(a×b)+c`; `a×b +c`≡`[a×b ; +c]`; `a×b+ c`≡`(a×b+)c`, train `a×(b+c)`; `1+k (⌈/⊢)⌸ a`≡`(1+k)((⌈/⊢)⌸)(a)`. 3. read as APL, right to left; subjects side by side strand: `a b`≡`(a)(b)`≡`[a b]` only if neither touches; `1+a b`≡`(1+a)(b)`→`11 20`, 1 plus both: `1+[a b]`→`11 21`; `n 2⍴0`≡`(n)(2⍴0)`→`[3 [0 0]]`, names never join literal strands: write `[n 2]⍴0`. no needless spaces; join by deleting spaces, not adding parens: `1+k(⌈/⊢)⌸a`. name fn, name arg: `h⁝m` `h[m n]`. name operand, glyph arg: `+/⍠k⍵`. list: `[+/x ; +/x ÷ ≢x]`. name digits: `x_1`; `x1`≡`x(1)`.
18
18
  - [Evaluation](evaluation.html.md): run ending in fn: train. `+/÷≢ x` mean; `+/÷≢x`≡`+/÷(≢x)`. `⁝` doesn't group a train: `+/÷≢⁝x` still means the latter. A space before an arg makes the run on its left a train: `10÷√1++/⍠i x` calls dyadic `√`, write `10÷√1++/⍠i⁝x`; `+/,m+⍤2 P` applies the train `+/,m+⍤2` to `P`, write `+/,m(+⍤2)P`.
19
19
  - [Composition](composition.html.md): read before writing tests or examples. trains: `f⁝g Y`≡`f(g Y)`, `f⁝g⁝h Y`≡`(f Y)g(h Y)`; `∘` atop, `⍥` over, `↣` `↢` bind left, right; `⍨` self, commute; `⊢` `⊣` stand for args in trains; `⁻¹` inverse; `@` under. worse→better, same results: `0.5×⊢+2÷⊢`→`⊽⁻¹+÷`; `{⍵,1}`→`,↢1`; `×⍨x`→`x²`; `≥⍣3⊢5`→`≥⍣3⁝5`; `+/⍠i⊢m`→`+/⍠i⁝m`. Prefer spaces for top-level groups/subtrains: `+/÷≢ ⊼v`, `mean_square←+/÷≢ ⊼`, `f⁝g⁝h x`. A space groups the whole left run, including any prefix. Nested `()`: try the inner pair first. With only a right arg, prefer `⁝` where a boundary is needed: `f⍣3⁝0`, `(+/÷≢)⍤1⁝2 3⍴⍳6`. With both args, group the derived fn: `10 20(+⍤1)m`. Keep compound operands grouped: `⌊@(10×)x`. Add nothing where tokens already stay distinct: `+/⍤1m`.
20
20
  - [Agreement](evaluation.html.md#agreement-and-pervasion): pervasive fns, Each, Rank align leading axes: `[1 2 3⋄4 5 6]+10 20`→`[11 12 13⋄24 25 26]`. length-1 axes expand.
@@ -22,7 +22,7 @@
22
22
  "\n",
23
23
  "`•r pattern` compiles a regular expression. It returns a keyed vector of two functions that share the pattern. `p.matches text` gives a table of the matches, as a record of columns: `text`, the matched text; `position`, its position in characters from 0; and `groups`, the text of each group, which is empty for a group that took no part. `template p.replace text` replaces each match with `template`, expanded with the match's groups.\n",
24
24
  "\n",
25
- "Natively the pattern is a Rust regex, with [the regex crate's syntax](https://docs.rs/regex/latest/regex/#syntax). Flags go in the pattern, as in `(?i)`, and templates use `$1`, `${name}` and `$$`. In the browser the pattern is a JavaScript regular expression, with [JavaScript's syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions), and templates use `$1`, `$<name>` and `$$`. [Regular expressions](regex.ipynb) covers each function.\n",
25
+ "Natively the pattern uses [fancy-regex's syntax](https://docs.rs/fancy-regex/latest/fancy_regex/#syntax), including lookaround and backreferences. Flags go in the pattern, as in `(?i)`, and templates use `$1`, `${name}` and `$$`. A search that exceeds the engine's backtracking limit raises `DOMAIN`. In the browser the pattern is a JavaScript regular expression, with [JavaScript's syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions), and templates use `$1`, `$<name>` and `$$`. [Regular expressions](regex.ipynb) covers each function.\n",
26
26
  "\n",
27
27
  "```bpl\n",
28
28
  "p←•r \"([a-z]+)([0-9]+)\"\n",
@@ -33,13 +33,11 @@
33
33
  "Errors: `DOMAIN` for invalid patterns and non-text arguments; `SYNTAX` for the wrong valence; `LIMIT` for oversized results.\n"
34
34
  ],
35
35
  "text/plain": [
36
- "function\n",
37
- "\n",
38
36
  "# `•r` — Regular expressions\n",
39
37
  "\n",
40
38
  "`•r pattern` compiles a regular expression. It returns a keyed vector of two functions that share the pattern. `p.matches text` gives a table of the matches, as a record of columns: `text`, the matched text; `position`, its position in characters from 0; and `groups`, the text of each group, which is empty for a group that took no part. `template p.replace text` replaces each match with `template`, expanded with the match's groups.\n",
41
39
  "\n",
42
- "Natively the pattern is a Rust regex, with [the regex crate's syntax](https://docs.rs/regex/latest/regex/#syntax). Flags go in the pattern, as in `(?i)`, and templates use `$1`, `${name}` and `$$`. In the browser the pattern is a JavaScript regular expression, with [JavaScript's syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions), and templates use `$1`, `$<name>` and `$$`. [Regular expressions](regex.ipynb) covers each function.\n",
40
+ "Natively the pattern uses [fancy-regex's syntax](https://docs.rs/fancy-regex/latest/fancy_regex/#syntax), including lookaround and backreferences. Flags go in the pattern, as in `(?i)`, and templates use `$1`, `${name}` and `$$`. A search that exceeds the engine's backtracking limit raises `DOMAIN`. In the browser the pattern is a JavaScript regular expression, with [JavaScript's syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions), and templates use `$1`, `$<name>` and `$$`. [Regular expressions](regex.ipynb) covers each function.\n",
43
41
  "\n",
44
42
  "```bpl\n",
45
43
  "p←•r \"([a-z]+)([0-9]+)\"\n",
@@ -63,7 +61,7 @@
63
61
  "id": "f6464060",
64
62
  "metadata": {},
65
63
  "source": [
66
- "Natively, patterns use [Rust regex syntax](https://docs.rs/regex/latest/regex/#syntax). In the browser they use [JavaScript's](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions). `p.matches` gives a table of the matches, as a record of columns. Here `p` finds runs of digits:"
64
+ "Natively, patterns use [fancy-regex syntax](https://docs.rs/fancy-regex/latest/fancy_regex/#syntax), including lookaround and backreferences. Exceeding the engine's backtracking limit raises `DOMAIN`. In the browser they use [JavaScript's](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions). `p.matches` gives a table of the matches, as a record of columns. Here `p` finds runs of digits:"
67
65
  ]
68
66
  },
69
67
  {
@@ -86,11 +86,26 @@ An unclosed delimiter gives a continuation prompt. Closing it evaluates the comp
86
86
 
87
87
  Inside brackets and parentheses, a line break means `⋄`, so each line of a bracket list is a row of the array.
88
88
 
89
+ ## Help
90
+
91
+ `]help` lists the topics available offline. Open a topic by name, as in `]help indexing`, or enter part of its name or title to find matching topics. Names and glyphs work too:
92
+
93
+ | Command | Effect |
94
+ |---|---|
95
+ | `]help indexing` | The indexing guide |
96
+ | `]help +` | Help for a name or glyph |
97
+ | `]help mean -source` | Definition source |
98
+ | `]help llms` | The concise language reference |
99
+ | `]help ?` | Help for the guard glyph |
100
+ | `]help? index(?!ing)` | Regex search over all help text |
101
+
102
+ Everything after `]help?` is the pattern, without quotes. Search ignores case by default. Results put name/title matches before headings, then body text, and show the command to open each topic. Search uses the same platform-specific regex syntax as [`•r`](system/r.qmd). For example, `]help? index|select` finds both terms. Natively, `(?-i)` makes the pattern case-sensitive.
103
+
89
104
  ## Array and function display
90
105
 
91
106
  Interactive sessions draw arrays in boxes, show functions as trees, and box output made inside functions. [`•prefs`](system/prefs.qmd) reads and changes these settings: `•prefs ["box":$f]` turns boxes off, and `•prefs ⍬` shows every setting. Batch and JSON sessions start without boxes, and so does Python until IPython loads BPL's magics.
92
107
 
93
- Matrices, nested arrays and strings have boxes, axis arrows and a type marker on the bottom edge. Other vectors stay plain. Their plain form shows their kind, keys and axis name, as in `[2 3 5]ₓ`, `[1.5 2.5]ₛ` and `$t $f`. The marker names the storage: `ₓ` for exact integers, `~` for floats, `j` for complex numbers, `─` for characters, `∊` for nested arrays and `+` for mixed storage, whose items keep their own kinds. Numbers inside an `ₓ` box carry no mark of their own. Without boxes, a matrix whose numbers share a marked kind shows as its literal laid out in rows, with one mark after the brackets. A keyed matrix shows that mark in its corner. Enter a function name to see its tree.
108
+ Matrices and nested arrays have boxes, axis arrows and a type marker on the bottom edge. Other vectors stay plain. Character vectors display as quoted strings, including inside arrays. Their plain form shows their kind, keys and axis name, as in `[2 3 5]ₓ`, `[1.5 2.5]ₛ` and `$t $f`. The marker names the storage: `ₓ` for exact integers, `~` for floats, `j` for complex numbers, `─` for characters, `∊` for nested arrays and `+` for mixed storage, whose items keep their own kinds. Numbers inside an `ₓ` box carry no mark of their own. Without boxes, a matrix whose numbers share a marked kind shows as its literal laid out in rows, with one mark after the brackets. A keyed matrix shows that mark in its corner. Enter a function name to see its tree.
94
109
 
95
110
  An array of more than 1000 items shows only the first and last 3 positions of each long axis. `…` replaces the hidden columns, `⋮` the hidden rows, and `⋱` sits where they cross. The `limit` and `edges` settings of `•prefs` change these numbers. `⎕←` prints every item.
96
111
 
@@ -109,9 +124,6 @@ An array of more than 1000 items shows only the first and last 3 positions of ea
109
124
 
110
125
  | Command | Effect |
111
126
  |---|---|
112
- | `]help +` | Help for a name or glyph |
113
- | `]help mean -source` | Definition source |
114
- | `]help llms` | The index of BPL's documentation for LLMs, [llms.txt](llms.txt) |
115
127
  | `]Display [[1 2] [3 4]]` | Draw one array in a box, whatever the settings |
116
128
  | `]dissect expression` | Show the bound expression before its result |
117
129
  | `]clear` | Remove every name and restore the starting display settings |