ranger-compiler 3.5.0 → 3.5.2

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 (338) hide show
  1. package/CHANGELOG.md +1160 -19
  2. package/LICENSE +3 -1
  3. package/README.md +124 -29
  4. package/dist/Lang.rgr +1188 -290
  5. package/dist/api.d.ts +2343 -879
  6. package/dist/api.js +79924 -56922
  7. package/dist/lib/JSON.rgr +102 -91
  8. package/dist/lib/Shell.rgr +4 -4
  9. package/dist/lib/apple/AppleToolchain.rgr +4 -4
  10. package/dist/lib/apple/README.md +5 -4
  11. package/dist/lib/apple/apple_test.rgr +1 -1
  12. package/dist/lib/core/README.md +1 -1
  13. package/dist/lib/evg/EVG.rgr +12 -0
  14. package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
  15. package/dist/lib/evg/EVGA11yTree.rgr +894 -0
  16. package/dist/lib/evg/EVGBox.rgr +267 -0
  17. package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
  18. package/dist/lib/evg/EVGCodepoint.rgr +316 -0
  19. package/dist/lib/evg/EVGColor.rgr +700 -0
  20. package/dist/lib/evg/EVGCommands.rgr +177 -0
  21. package/dist/lib/evg/EVGComponent.rgr +331 -0
  22. package/dist/lib/evg/EVGComponentTest.rgr +387 -0
  23. package/dist/lib/evg/EVGConnector.rgr +541 -0
  24. package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
  25. package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
  26. package/dist/lib/evg/EVGEasing.rgr +370 -0
  27. package/dist/lib/evg/EVGEffectTest.rgr +253 -0
  28. package/dist/lib/evg/EVGElement.rgr +4914 -0
  29. package/dist/lib/evg/EVGFixedTest.rgr +289 -0
  30. package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
  31. package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
  32. package/dist/lib/evg/EVGFling.rgr +244 -0
  33. package/dist/lib/evg/EVGFocus.rgr +400 -0
  34. package/dist/lib/evg/EVGFocusTest.rgr +399 -0
  35. package/dist/lib/evg/EVGGradient.rgr +322 -0
  36. package/dist/lib/evg/EVGGrapheme.rgr +190 -0
  37. package/dist/lib/evg/EVGGrid.rgr +975 -0
  38. package/dist/lib/evg/EVGHitTest.rgr +208 -0
  39. package/dist/lib/evg/EVGHoles.rgr +294 -0
  40. package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
  41. package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
  42. package/dist/lib/evg/EVGHostTree.rgr +834 -0
  43. package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
  44. package/dist/lib/evg/EVGImageDecode.rgr +117 -0
  45. package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
  46. package/dist/lib/evg/EVGInspect.rgr +883 -0
  47. package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
  48. package/dist/lib/evg/EVGJsonTest.rgr +535 -0
  49. package/dist/lib/evg/EVGLayout.rgr +4220 -0
  50. package/dist/lib/evg/EVGMeasure.rgr +1267 -0
  51. package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
  52. package/dist/lib/evg/EVGPatch.rgr +1721 -0
  53. package/dist/lib/evg/EVGPatchTest.rgr +692 -0
  54. package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
  55. package/dist/lib/evg/EVGReconcile.rgr +226 -0
  56. package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
  57. package/dist/lib/evg/EVGReject.rgr +126 -0
  58. package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
  59. package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
  60. package/dist/lib/evg/EVGRuler.rgr +232 -0
  61. package/dist/lib/evg/EVGRulerTest.rgr +172 -0
  62. package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
  63. package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
  64. package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
  65. package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
  66. package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
  67. package/dist/lib/evg/EVGText.rgr +105 -0
  68. package/dist/lib/evg/EVGTextEngine.rgr +536 -0
  69. package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
  70. package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
  71. package/dist/lib/evg/EVGToolbar.rgr +1369 -0
  72. package/dist/lib/evg/EVGTransition.rgr +728 -0
  73. package/dist/lib/evg/EVGTreeJson.rgr +721 -0
  74. package/dist/lib/evg/EVGUnit.rgr +554 -0
  75. package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
  76. package/dist/lib/evg/EvgApp.rgr +189 -0
  77. package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
  78. package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
  79. package/dist/lib/evg/EvgHost.rgr +451 -0
  80. package/dist/lib/evg/EvgTest.rgr +91 -0
  81. package/dist/lib/evg/EvgTraceColor.rgr +236 -0
  82. package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
  83. package/dist/lib/evg/EvgTraceFit.rgr +767 -0
  84. package/dist/lib/evg/EvgTracePath.rgr +435 -0
  85. package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
  86. package/dist/lib/evg/EvgViewport.rgr +313 -0
  87. package/dist/lib/evg/FxDemoDoc.rgr +185 -0
  88. package/dist/lib/evg/HOSTS.md +227 -0
  89. package/dist/lib/evg/ISSUES.md +835 -0
  90. package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
  91. package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
  92. package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
  93. package/dist/lib/evg/PLAN_EVG.md +518 -0
  94. package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
  95. package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
  96. package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
  97. package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
  98. package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
  99. package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
  100. package/dist/lib/evg/PathBuilder.rgr +333 -0
  101. package/dist/lib/evg/README.md +1236 -0
  102. package/dist/lib/evg/SPEC.md +1252 -0
  103. package/dist/lib/evg/SVGPathParser.rgr +1199 -0
  104. package/dist/lib/evg/SvgParser.rgr +1736 -0
  105. package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
  106. package/dist/lib/evg/VectorShapes.rgr +331 -0
  107. package/dist/lib/evg/VectorStroke.rgr +107 -0
  108. package/dist/lib/evg/VectorViewBox.rgr +380 -0
  109. package/dist/lib/evg/agent/README.md +290 -0
  110. package/dist/lib/evg/agent/evg_agent.rgr +899 -0
  111. package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
  112. package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
  113. package/dist/lib/evg/agent/fixtures/connector.css +63 -0
  114. package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
  115. package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
  116. package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
  117. package/dist/lib/evg/agent/fixtures/popover.css +99 -0
  118. package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
  119. package/dist/lib/evg/agent/roundtrip.sh +74 -0
  120. package/dist/lib/evg/agent/smoke.sh +230 -0
  121. package/dist/lib/evg/android/README.md +97 -0
  122. package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
  123. package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
  124. package/dist/lib/evg/android/androidstubs/App.kt +30 -0
  125. package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
  126. package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
  127. package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
  128. package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
  129. package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
  130. package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
  131. package/dist/lib/evg/android/androidstubs/View.kt +113 -0
  132. package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
  133. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
  134. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
  135. package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
  136. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
  137. package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
  138. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
  139. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
  140. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
  141. package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
  142. package/dist/lib/evg/apple/README.md +128 -0
  143. package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
  144. package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
  145. package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
  146. package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
  147. package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
  148. package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
  149. package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
  150. package/dist/lib/evg/bench/README.md +64 -0
  151. package/dist/lib/evg/bench/layout-bench.mjs +316 -0
  152. package/dist/lib/evg/bench/layout-cases.mjs +510 -0
  153. package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
  154. package/dist/lib/evg/bin/.gitignore +17 -0
  155. package/dist/lib/evg/evg_test.rgr +313 -0
  156. package/dist/lib/evg/gl/README.md +198 -0
  157. package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
  158. package/dist/lib/evg/gl/blur-check.mjs +399 -0
  159. package/dist/lib/evg/gl/boxmodel.json +1 -0
  160. package/dist/lib/evg/gl/demo.html +46 -0
  161. package/dist/lib/evg/gl/effect-presets.css +285 -0
  162. package/dist/lib/evg/gl/effect-presets.js +63 -0
  163. package/dist/lib/evg/gl/effect-shots.mjs +135 -0
  164. package/dist/lib/evg/gl/evg-a11y.js +566 -0
  165. package/dist/lib/evg/gl/evg-binary.js +160 -0
  166. package/dist/lib/evg/gl/evg-engine.js +296 -0
  167. package/dist/lib/evg/gl/evg-fx.js +237 -0
  168. package/dist/lib/evg/gl/evg-gestures.js +209 -0
  169. package/dist/lib/evg/gl/evg-list.js +167 -0
  170. package/dist/lib/evg/gl/evg-measure.js +186 -0
  171. package/dist/lib/evg/gl/evg-textinput.js +303 -0
  172. package/dist/lib/evg/gl/evg-view.js +144 -0
  173. package/dist/lib/evg/gl/evg-webgl.js +3942 -0
  174. package/dist/lib/evg/gl/fx-check.mjs +998 -0
  175. package/dist/lib/evg/gl/fx-demo.html +166 -0
  176. package/dist/lib/evg/gl/fx-demo.js +2 -0
  177. package/dist/lib/evg/gl/fx-serve.mjs +47 -0
  178. package/dist/lib/evg/gl/gestures-check.mjs +189 -0
  179. package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
  180. package/dist/lib/evg/gl/measure-check.mjs +135 -0
  181. package/dist/lib/evg/gl/rotation-check.mjs +207 -0
  182. package/dist/lib/evg/gl/shift-check.mjs +113 -0
  183. package/dist/lib/evg/gl/stroke-check.mjs +168 -0
  184. package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
  185. package/dist/lib/evg/gl/view-check.mjs +343 -0
  186. package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
  187. package/dist/lib/evg/html/evg-dom.js +318 -0
  188. package/dist/lib/evg/html/evg-html.js +600 -0
  189. package/dist/lib/evg/inspect/README.md +415 -0
  190. package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
  191. package/dist/lib/evg/inspect/evg-inspect.js +947 -0
  192. package/dist/lib/evg/inspect/shots/css.png +0 -0
  193. package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
  194. package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
  195. package/dist/lib/evg/inspect/shots/state.png +0 -0
  196. package/dist/lib/evg/inspect/shots.mjs +226 -0
  197. package/dist/lib/evg/oracle/css-blur.json +576 -0
  198. package/dist/lib/evg/oracle/css-box.json +157 -0
  199. package/dist/lib/evg/oracle/css-timing.json +709 -0
  200. package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
  201. package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
  202. package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
  203. package/dist/lib/evg/original/EVGColor.clj +310 -0
  204. package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
  205. package/dist/lib/evg/original/SVGPath.rgr +627 -0
  206. package/dist/lib/evg/original/Vec2.crgr +103 -0
  207. package/dist/lib/evg/ranger.json +9 -0
  208. package/dist/lib/evg/showcase/README.md +246 -0
  209. package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
  210. package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
  211. package/dist/lib/evg/showcase/build.mjs +651 -0
  212. package/dist/lib/evg/showcase/pages/album.tsx +30 -0
  213. package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
  214. package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
  215. package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
  216. package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
  217. package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
  218. package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
  219. package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
  220. package/dist/lib/evg/showcase/pages/more.tsx +332 -0
  221. package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
  222. package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
  223. package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
  224. package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
  225. package/dist/lib/evg/showcase/pages/units.tsx +35 -0
  226. package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
  227. package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
  228. package/dist/lib/evg/showcase/pages/views.tsx +223 -0
  229. package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
  230. package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
  231. package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
  232. package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
  233. package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
  234. package/dist/lib/evg/showcase/themes/more-default.css +128 -0
  235. package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
  236. package/dist/lib/evg/showcase/themes/showcase.css +508 -0
  237. package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
  238. package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
  239. package/dist/lib/evg/showcase/themes/views-default.css +15 -0
  240. package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
  241. package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
  242. package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
  243. package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
  244. package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
  245. package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
  246. package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
  247. package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
  248. package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
  249. package/dist/lib/evg/web/responsive/README.md +97 -0
  250. package/dist/lib/evg/web/responsive/build.mjs +90 -0
  251. package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
  252. package/dist/lib/evg/web/responsive/index.html +177 -0
  253. package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
  254. package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
  255. package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
  256. package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
  257. package/dist/lib/evg/web/tools/minify.mjs +60 -0
  258. package/dist/lib/evg/web/tracer/build.mjs +87 -0
  259. package/dist/lib/evg/web/tracer/index.html +2805 -0
  260. package/dist/lib/evg/web/tracer/sample.png +0 -0
  261. package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
  262. package/dist/lib/evgr/Cargo.lock +21 -0
  263. package/dist/lib/evgr/Cargo.toml +19 -0
  264. package/dist/lib/evgr/README.md +140 -0
  265. package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
  266. package/dist/lib/evgr/bench/compare.mjs +252 -0
  267. package/dist/lib/evgr/bench/speed.mjs +277 -0
  268. package/dist/lib/evgr/bin/.gitignore +3 -0
  269. package/dist/lib/evgr/src/bin/bench.rs +106 -0
  270. package/dist/lib/evgr/src/bin/smoke.rs +13 -0
  271. package/dist/lib/evgr/src/grid.rs +730 -0
  272. package/dist/lib/evgr/src/lib.rs +1003 -0
  273. package/dist/lib/evgr/src/style.rs +468 -0
  274. package/dist/lib/evgr/src/text.rs +83 -0
  275. package/dist/lib/image/BitReader.rgr +171 -0
  276. package/dist/lib/image/Buffer.rgr +173 -0
  277. package/dist/lib/image/DCT.rgr +283 -0
  278. package/dist/lib/image/Deflate.rgr +339 -0
  279. package/dist/lib/image/HuffmanDecoder.rgr +181 -0
  280. package/dist/lib/image/ImageBuffer.rgr +706 -0
  281. package/dist/lib/image/JPEGDecoder.rgr +808 -0
  282. package/dist/lib/image/PNGDecoder.rgr +544 -0
  283. package/dist/lib/image/PNGEncoder.rgr +388 -0
  284. package/dist/lib/image/PPMImage.rgr +224 -0
  285. package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
  286. package/dist/lib/image/README.md +33 -0
  287. package/dist/lib/image/RasterBuffer.rgr +294 -0
  288. package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
  289. package/dist/lib/image/WebPDecoder.rgr +433 -0
  290. package/dist/lib/image/WebPLossless.rgr +1035 -0
  291. package/dist/lib/image/WebPLossy.rgr +1929 -0
  292. package/dist/lib/image/ranger.json +9 -0
  293. package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
  294. package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
  295. package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
  296. package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
  297. package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
  298. package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
  299. package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
  300. package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
  301. package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
  302. package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
  303. package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
  304. package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
  305. package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
  306. package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
  307. package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
  308. package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
  309. package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
  310. package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
  311. package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
  312. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
  313. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
  314. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
  315. package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
  316. package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
  317. package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
  318. package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
  319. package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
  320. package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
  321. package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
  322. package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
  323. package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
  324. package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
  325. package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
  326. package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
  327. package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
  328. package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
  329. package/dist/lib/image/tests/run_webp_tests.sh +39 -0
  330. package/dist/lib/rust/RsJson.rgr +468 -0
  331. package/dist/lib/rust/RsPrelude.rgr +1663 -0
  332. package/dist/lib/shell_test.rgr +7 -7
  333. package/dist/lib/stdlib.rgr +21 -5
  334. package/dist/lib/zip/ranger.json +6 -0
  335. package/dist/rgrc.js +87318 -67610
  336. package/package.json +1010 -1040
  337. package/dist/README.md +0 -117
  338. package/dist/package.json +0 -47
@@ -0,0 +1,1663 @@
1
+ ; SPDX-License-Identifier: MIT
2
+
3
+ ; Runtime support for Rust-syntax modules (PLAN_RUST_SYNTAX.md).
4
+ ;
5
+ ; A `.rs` module is translated to Ranger (compiler/frontend/rust/lower) and
6
+ ; imports this file. Rust fixes semantics that Ranger's own operators leave to
7
+ ; the target -- integer division and remainder truncate toward zero, `as`
8
+ ; truncates a float, `{}` prints a float in its shortest round-trip form and
9
+ ; never in exponent notation -- and every target must print what the native
10
+ ; Rust build prints. The operators here give each of those one meaning.
11
+ ;
12
+ ; Most are type-overloaded (`rs_div` on two ints, on two doubles), so the
13
+ ; translator can emit one name and leave the choice to Ranger's type checker.
14
+
15
+ operators {
16
+
17
+ ; ------------------------------------------------------------ arithmetic
18
+
19
+ ; Integer division truncates toward zero (Python's `//` floors). Every
20
+ ; target is spelled out: an operator with a `* @macro` template ignores its
21
+ ; per-target ones.
22
+ rs_div _:int (a:int b:int) {
23
+ templates {
24
+ ranger ( "(rs_div " (e 1) " " (e 2) ")" )
25
+ es6 ( "Math.trunc(" (e 1) " / " (e 2) ")" )
26
+ python ( "rs_idiv(" (e 1) ", " (e 2) ")"
27
+ (create_polyfill "
28
+ def rs_idiv(a, b):
29
+ q = abs(a) // abs(b)
30
+ return q if (a >= 0) == (b >= 0) else -q
31
+ "))
32
+ dart ( "(" (e 1) " ~/ " (e 2) ")" )
33
+ php ( "intdiv(" (e 1) ", " (e 2) ")" )
34
+ * ( "(" (e 1) " / " (e 2) ")" )
35
+ }
36
+ }
37
+ rs_div _:double (a:double b:double) {
38
+ templates {
39
+ * @macro(true) ( "(" "(" (e 1) ")" " / " "(" (e 2) ")" ")" )
40
+ }
41
+ }
42
+
43
+ ; The remainder has the sign of the dividend (Python's `%` has the sign of
44
+ ; the divisor).
45
+ rs_rem _:int (a:int b:int) {
46
+ templates {
47
+ ranger ( "(rs_rem " (e 1) " " (e 2) ")" )
48
+ python ( "rs_irem(" (e 1) ", " (e 2) ")"
49
+ (create_polyfill "
50
+ def rs_irem(a, b):
51
+ r = abs(a) % abs(b)
52
+ return r if a >= 0 else -r
53
+ "))
54
+ dart ( "(" (e 1) ").remainder(" (e 2) ")" )
55
+ * ( "(" (e 1) " % " (e 2) ")" )
56
+ }
57
+ }
58
+ rs_rem _:double (a:double b:double) {
59
+ templates {
60
+ ranger ( "(rs_rem" " " (e 1) " " (e 2) ")" )
61
+ python ( "math.fmod(" (e 1) ", " (e 2) ")" (imp "math") )
62
+ go ( "math.Mod(" (e 1) ", " (e 2) ")" (imp "math") )
63
+ cpp ( "std::fmod(" (e 1) ", " (e 2) ")" (imp "<cmath>") )
64
+ php ( "fmod(" (e 1) ", " (e 2) ")" )
65
+ * ( "(" (e 1) " % " (e 2) ")" )
66
+ }
67
+ }
68
+
69
+ rs_neg _:int (a:int) {
70
+ templates {
71
+ * @macro(true) ( "(0 - " "(" (e 1) ")" ")" )
72
+ }
73
+ }
74
+ rs_neg _:double (a:double) {
75
+ templates {
76
+ * @macro(true) ( "(0.0 - " "(" (e 1) ")" ")" )
77
+ }
78
+ }
79
+
80
+ rs_abs _:int (a:int) {
81
+ templates {
82
+ * @macro(true) ( "(? (" "(" (e 1) ")" " < 0) (0 - " "(" (e 1) ")" ") " "(" (e 1) ")" ")" )
83
+ }
84
+ }
85
+ rs_abs _:double (a:double) {
86
+ templates {
87
+ * @macro(true) ( "(? (" "(" (e 1) ")" " < 0.0) (0.0 - " "(" (e 1) ")" ") " "(" (e 1) ")" ")" )
88
+ }
89
+ }
90
+
91
+ rs_min _:int (a:int b:int) {
92
+ templates {
93
+ * @macro(true) ( "(? (" "(" (e 1) ")" " < " "(" (e 2) ")" ") " "(" (e 1) ")" " " "(" (e 2) ")" ")" )
94
+ }
95
+ }
96
+ rs_min _:double (a:double b:double) {
97
+ templates {
98
+ * @macro(true) ( "(? (" "(" (e 1) ")" " < " "(" (e 2) ")" ") " "(" (e 1) ")" " " "(" (e 2) ")" ")" )
99
+ }
100
+ }
101
+ rs_max _:int (a:int b:int) {
102
+ templates {
103
+ * @macro(true) ( "(? (" "(" (e 1) ")" " > " "(" (e 2) ")" ") " "(" (e 1) ")" " " "(" (e 2) ")" ")" )
104
+ }
105
+ }
106
+ rs_max _:double (a:double b:double) {
107
+ templates {
108
+ * @macro(true) ( "(? (" "(" (e 1) ")" " > " "(" (e 2) ")" ") " "(" (e 1) ")" " " "(" (e 2) ")" ")" )
109
+ }
110
+ }
111
+
112
+ rs_sqrt _:double (a:double) {
113
+ templates {
114
+ * @macro(true) ( "(sqrt " "(" (e 1) ")" ")" )
115
+ }
116
+ }
117
+ ; `f64::floor` / `ceil` answer a double (Ranger's `floor` / `ceil` an
118
+ ; int)
119
+ rs_floor _:double (a:double) {
120
+ templates {
121
+ ranger ( "(rs_floor " (e 1) ")" )
122
+ es6 ( "Math.floor(" (e 1) ")" )
123
+ python ( "float(math.floor(" (e 1) "))" (imp "math") )
124
+ go ( "math.Floor(" (e 1) ")" (imp "math") )
125
+ cpp ( "std::floor(" (e 1) ")" (imp "<cmath>") )
126
+ rust ( "(" (e 1) ").floor()" )
127
+ java7 ( "Math.floor(" (e 1) ")" )
128
+ kotlin ( "Math.floor(" (e 1) ")" )
129
+ csharp ( "System.Math.Floor(" (e 1) ")" )
130
+ dart ( "(" (e 1) ").floorToDouble()" )
131
+ scala ( "math.floor(" (e 1) ")" )
132
+ php ( "floor(" (e 1) ")" )
133
+ swift6 ( "(" (e 1) ").rounded(.down)" )
134
+ * ( "Math.floor(" (e 1) ")" )
135
+ }
136
+ }
137
+ rs_ceil _:double (a:double) {
138
+ templates {
139
+ ranger ( "(rs_ceil " (e 1) ")" )
140
+ es6 ( "Math.ceil(" (e 1) ")" )
141
+ python ( "float(math.ceil(" (e 1) "))" (imp "math") )
142
+ go ( "math.Ceil(" (e 1) ")" (imp "math") )
143
+ cpp ( "std::ceil(" (e 1) ")" (imp "<cmath>") )
144
+ rust ( "(" (e 1) ").ceil()" )
145
+ java7 ( "Math.ceil(" (e 1) ")" )
146
+ kotlin ( "Math.ceil(" (e 1) ")" )
147
+ csharp ( "System.Math.Ceiling(" (e 1) ")" )
148
+ dart ( "(" (e 1) ").ceilToDouble()" )
149
+ scala ( "math.ceil(" (e 1) ")" )
150
+ php ( "ceil(" (e 1) ")" )
151
+ swift6 ( "(" (e 1) ").rounded(.up)" )
152
+ * ( "Math.ceil(" (e 1) ")" )
153
+ }
154
+ }
155
+ rs_powi _:double (a:double n:int) {
156
+ templates {
157
+ ranger ( "(rs_powi" " " (e 1) " " (e 2) ")" )
158
+ es6 ( "Math.pow(" (e 1) ", " (e 2) ")" )
159
+ python ( "float(" (e 1) " ** " (e 2) ")" )
160
+ go ( "math.Pow(" (e 1) ", float64(" (e 2) "))" (imp "math") )
161
+ cpp ( "std::pow(" (e 1) ", (double)" (e 2) ")" (imp "<cmath>") )
162
+ kotlin ( "Math.pow(" (e 1) ", (" (e 2) ").toDouble())" )
163
+ csharp ( "System.Math.Pow(" (e 1) ", " (e 2) ")" )
164
+ dart ( "pow(" (e 1) ", " (e 2) ").toDouble()" (imp "dart:math") )
165
+ scala ( "math.pow(" (e 1) ", (" (e 2) ").toDouble)" )
166
+ php ( "((float)pow(" (e 1) ", " (e 2) "))" )
167
+ * ( "Math.pow(" (e 1) ", " (e 2) ")" )
168
+ }
169
+ }
170
+ rs_pow _:int (a:int n:int) {
171
+ templates {
172
+ ranger ( "(rs_pow" " " (e 1) " " (e 2) ")" )
173
+ es6 ( "Math.pow(" (e 1) ", " (e 2) ")" )
174
+ python ( "(" (e 1) " ** " (e 2) ")" )
175
+ go ( "rs_ipow(" (e 1) ", " (e 2) ")"
176
+ (create_polyfill "
177
+ func rs_ipow(a int64, n int64) int64 {
178
+ r := int64(1)
179
+ for i := int64(0); i < n; i++ {
180
+ r *= a
181
+ }
182
+ return r
183
+ }
184
+ "))
185
+ cpp ( "rs_ipow(" (e 1) ", " (e 2) ")"
186
+ (create_polyfill "
187
+ inline long long rs_ipow(long long a, long long n) {
188
+ long long r = 1;
189
+ for (long long i = 0; i < n; i++) { r *= a; }
190
+ return r;
191
+ }
192
+ "))
193
+ java7 ( "rs_ipow(" (e 1) ", " (e 2) ")"
194
+ (create_polyfill "
195
+ static int rs_ipow(int a, int n) {
196
+ int r = 1;
197
+ for (int i = 0; i < n; i++) { r *= a; }
198
+ return r;
199
+ }
200
+ "))
201
+ kotlin ( "rs_ipow(" (e 1) ", " (e 2) ")"
202
+ (create_polyfill "
203
+ fun rs_ipow(a: Int, n: Int): Int {
204
+ var r = 1
205
+ for (i in 0 until n) { r *= a }
206
+ return r
207
+ }
208
+ "))
209
+ csharp ( "rs_ipow(" (e 1) ", " (e 2) ")"
210
+ (create_polyfill "
211
+ static int rs_ipow(int a, int n) {
212
+ int r = 1;
213
+ for (int i = 0; i < n; i++) { r *= a; }
214
+ return r;
215
+ }
216
+ "))
217
+ dart ( "rs_ipow(" (e 1) ", " (e 2) ")"
218
+ (create_polyfill "
219
+ int rs_ipow(int a, int n) {
220
+ var r = 1;
221
+ for (var i = 0; i < n; i++) { r *= a; }
222
+ return r;
223
+ }
224
+ "))
225
+ scala ( "rs_ipow(" (e 1) ", " (e 2) ")"
226
+ (create_polyfill "
227
+ def rs_ipow(a: Int, n: Int): Int = {
228
+ var r = 1
229
+ var i = 0
230
+ while (i < n) { r *= a; i += 1 }
231
+ r
232
+ }
233
+ "))
234
+ php ( "rs_ipow(" (e 1) ", " (e 2) ")"
235
+ (create_polyfill "
236
+ function rs_ipow($a, $n) {
237
+ $r = 1;
238
+ for ($i = 0; $i < $n; $i++) { $r *= $a; }
239
+ return $r;
240
+ }
241
+ "))
242
+ * ( "Math.pow(" (e 1) ", " (e 2) ")" )
243
+ }
244
+ }
245
+
246
+ ; ----------------------------------------------------------------- casts
247
+
248
+ ; `x as i64` on a float truncates toward zero (`to_int` floors).
249
+ rs_f2i _:int (a:double) {
250
+ templates {
251
+ ranger ( "(rs_f2i" " " (e 1) ")" )
252
+ es6 ( "Math.trunc(" (e 1) ")" )
253
+ python ( "int(" (e 1) ")" )
254
+ go ( "rs_f2i(" (e 1) ")"
255
+ (create_polyfill "
256
+ func rs_f2i(x float64) int64 {
257
+ return int64(x)
258
+ }
259
+ "))
260
+ cpp ( "(long long)(" (e 1) ")" )
261
+ java7 ( "((int)(double)(" (e 1) "))" )
262
+ kotlin ( "(" (e 1) ").toInt()" )
263
+ csharp ( "((int)(" (e 1) "))" )
264
+ dart ( "(" (e 1) ").toInt()" )
265
+ scala ( "(" (e 1) ").toInt" )
266
+ php ( "((int)(" (e 1) "))" )
267
+ * ( "Math.trunc(" (e 1) ")" )
268
+ }
269
+ }
270
+ rs_i2f _:double (a:int) {
271
+ templates {
272
+ * @macro(true) ( "(to_double " "(" (e 1) ")" ")" )
273
+ }
274
+ }
275
+ rs_wrap_u8 _:int (a:int) {
276
+ templates {
277
+ * @macro(true) ( "(bit_and " "(" (e 1) ")" " 255)" )
278
+ }
279
+ }
280
+ rs_wrap_u16 _:int (a:int) {
281
+ templates {
282
+ * @macro(true) ( "(bit_and " "(" (e 1) ")" " 65535)" )
283
+ }
284
+ }
285
+
286
+ ; A Rust `char` is a one-character string here; these cross to and from
287
+ ; its code point.
288
+ rs_char_code _:int (c:string) {
289
+ templates {
290
+ * @macro(true) ( "(itemAt (to_chars " "(" (e 1) ")" ") 0)" )
291
+ }
292
+ }
293
+ rs_char_from _:string (code:int) {
294
+ templates {
295
+ es6 ( "String.fromCodePoint(" (e 1) ")" )
296
+ python ( "chr(" (e 1) ")" )
297
+ go ( "string(rune(" (e 1) "))" )
298
+ java7 ( "(new String(Character.toChars(" (e 1) ")))" )
299
+ kotlin ( "String(Character.toChars(" (e 1) "))" )
300
+ csharp ( "char.ConvertFromUtf32(" (e 1) ")" )
301
+ dart ( "String.fromCharCode(" (e 1) ")" )
302
+ scala ( "new String(Character.toChars(" (e 1) "))" )
303
+ php ( "mb_chr(" (e 1) ", 'UTF-8')" )
304
+ * @macro(true) ( "(strfromcode " "(" (e 1) ")" ")" )
305
+ }
306
+ }
307
+
308
+ ; ------------------------------------------------------------ formatting
309
+
310
+ ; `{}` of a float: shortest round-trip digits, never an exponent, no
311
+ ; trailing `.0` -- what Rust's Display writes.
312
+ rs_fmt _:string (a:double) {
313
+ templates {
314
+ ranger ( "(rs_fmt" " " (e 1) ")" )
315
+ es6 ( "rs_f64(" (e 1) ")"
316
+ (create_polyfill "
317
+ function rs_expand_exp(s) {
318
+ var neg = s.charAt(0) === '-';
319
+ if (neg) { s = s.slice(1); }
320
+ var parts = s.toLowerCase().split('e');
321
+ var mant = parts[0];
322
+ var exp = parseInt(parts[1], 10);
323
+ var dot = mant.indexOf('.');
324
+ var digits = mant.replace('.', '');
325
+ var intLen = (dot < 0 ? mant.length : dot) + exp;
326
+ var out;
327
+ if (intLen <= 0) { out = '0.' + '0'.repeat(-intLen) + digits; }
328
+ else if (intLen >= digits.length) { out = digits + '0'.repeat(intLen - digits.length); }
329
+ else { out = digits.slice(0, intLen) + '.' + digits.slice(intLen); }
330
+ return (neg ? '-' : '') + out;
331
+ }
332
+ function rs_f64(x) {
333
+ if (Number.isNaN(x)) { return 'NaN'; }
334
+ if (x === Infinity) { return 'inf'; }
335
+ if (x === -Infinity) { return '-inf'; }
336
+ if (x === 0 && 1 / x < 0) { return '-0'; }
337
+ var s = String(x);
338
+ return s.indexOf('e') < 0 ? s : rs_expand_exp(s);
339
+ }
340
+ "))
341
+ python ( "rs_f64(" (e 1) ")"
342
+ (create_polyfill "
343
+ def rs_f64(x):
344
+ import math
345
+ if math.isnan(x):
346
+ return 'NaN'
347
+ if math.isinf(x):
348
+ return 'inf' if x > 0 else '-inf'
349
+ s = repr(float(x))
350
+ if 'e' in s:
351
+ neg = s.startswith('-')
352
+ if neg:
353
+ s = s[1:]
354
+ mant, exp = s.split('e')
355
+ exp = int(exp)
356
+ dot = mant.find('.')
357
+ digits = mant.replace('.', '')
358
+ int_len = (len(mant) if dot < 0 else dot) + exp
359
+ if int_len <= 0:
360
+ s = '0.' + '0' * (-int_len) + digits
361
+ elif int_len >= len(digits):
362
+ s = digits + '0' * (int_len - len(digits))
363
+ else:
364
+ s = digits[:int_len] + '.' + digits[int_len:]
365
+ if neg:
366
+ s = '-' + s
367
+ if s.endswith('.0'):
368
+ s = s[:-2]
369
+ return s
370
+ "))
371
+ go ( "rs_f64(" (e 1) ")" (imp "strconv") (imp "math")
372
+ (create_polyfill "
373
+ func rs_f64(x float64) string {
374
+ if math.IsNaN(x) {
375
+ return \"NaN\"
376
+ }
377
+ if math.IsInf(x, 1) {
378
+ return \"inf\"
379
+ }
380
+ if math.IsInf(x, -1) {
381
+ return \"-inf\"
382
+ }
383
+ return strconv.FormatFloat(x, 'f', -1, 64)
384
+ }
385
+ "))
386
+ cpp ( "rs_f64(" (e 1) ")" (imp "<charconv>") (imp "<cmath>") (imp "<string>")
387
+ (create_polyfill "
388
+ inline std::string rs_f64(double x) {
389
+ if (std::isnan(x)) { return \"NaN\"; }
390
+ if (std::isinf(x)) { return x > 0 ? \"inf\" : \"-inf\"; }
391
+ char buf[400];
392
+ auto r = std::to_chars(buf, buf + sizeof(buf), x, std::chars_format::fixed);
393
+ return std::string(buf, r.ptr);
394
+ }
395
+ "))
396
+ rust ( "format!(\"{}\", " (e 1) ")" )
397
+ java7 ( "rs_f64(" (e 1) ")"
398
+ (create_polyfill "
399
+ static String rs_f64(double x) {
400
+ if (Double.isNaN(x)) { return \"NaN\"; }
401
+ if (Double.isInfinite(x)) { return x > 0 ? \"inf\" : \"-inf\"; }
402
+ if (x == 0.0) { return (1.0 / x < 0) ? \"-0\" : \"0\"; }
403
+ return new java.math.BigDecimal(Double.toString(x)).stripTrailingZeros().toPlainString();
404
+ }
405
+ "))
406
+ kotlin ( "rs_f64(" (e 1) ")"
407
+ (create_polyfill "
408
+ fun rs_f64(x: Double): String {
409
+ if (x.isNaN()) { return \"NaN\" }
410
+ if (x.isInfinite()) { return if (x > 0) \"inf\" else \"-inf\" }
411
+ if (x == 0.0) { return if (1.0 / x < 0) \"-0\" else \"0\" }
412
+ return java.math.BigDecimal(x.toString()).stripTrailingZeros().toPlainString()
413
+ }
414
+ "))
415
+ csharp ( "rs_f64(" (e 1) ")"
416
+ (create_polyfill "
417
+ // The decimal digits of mant * 2^e * 10^k, k = max(0, -e): exact, so no
418
+ // digit depends on the runtime's number formatting.
419
+ static string rs_exact(long mant, int e) {
420
+ var limbs = new System.Collections.Generic.List<ulong>();
421
+ while (mant > 0) { limbs.Add((ulong)(mant % 1000000000L)); mant /= 1000000000L; }
422
+ if (limbs.Count == 0) { limbs.Add(0); }
423
+ ulong f = e < 0 ? 5UL : 2UL;
424
+ for (int n = (e < 0 ? -e : e); n > 0; n--) {
425
+ ulong carry = 0;
426
+ for (int i = 0; i < limbs.Count; i++) {
427
+ ulong t = limbs[i] * f + carry;
428
+ limbs[i] = t % 1000000000UL;
429
+ carry = t / 1000000000UL;
430
+ }
431
+ if (carry > 0) { limbs.Add(carry); }
432
+ }
433
+ var sb = new System.Text.StringBuilder();
434
+ sb.Append(limbs[limbs.Count - 1]);
435
+ for (int i = limbs.Count - 2; i >= 0; i--) { sb.Append(limbs[i].ToString(\"D9\")); }
436
+ return sb.ToString();
437
+ }
438
+ // Adds one to a digit string; the result may be one digit longer.
439
+ static string rs_digits_inc(string s) {
440
+ char[] c = s.ToCharArray();
441
+ int i = c.Length - 1;
442
+ while (i >= 0 && c[i] == '9') { c[i] = '0'; i--; }
443
+ if (i < 0) { return \"1\" + new string(c); }
444
+ c[i]++;
445
+ return new string(c);
446
+ }
447
+ // Compares two digit strings as numbers.
448
+ static int rs_digits_cmp(string a, string b) {
449
+ a = a.TrimStart('0');
450
+ b = b.TrimStart('0');
451
+ if (a.Length != b.Length) { return a.Length < b.Length ? -1 : 1; }
452
+ return System.Math.Sign(string.CompareOrdinal(a, b));
453
+ }
454
+ // digits * 10^-k written without an exponent.
455
+ static string rs_place(string digits, int k) {
456
+ if (digits.Length <= k) { digits = new string('0', k - digits.Length + 1) + digits; }
457
+ string ip = digits.Substring(0, digits.Length - k).TrimStart('0');
458
+ if (ip.Length == 0) { ip = \"0\"; }
459
+ return k > 0 ? ip + \".\" + digits.Substring(digits.Length - k) : ip;
460
+ }
461
+ ")
462
+ (create_polyfill "
463
+ // Rust's Display: the shortest digits that read back as x (the one nearest
464
+ // x when there are two), never an exponent.
465
+ static string rs_f64(double x) {
466
+ if (double.IsNaN(x)) { return \"NaN\"; }
467
+ if (double.IsPositiveInfinity(x)) { return \"inf\"; }
468
+ if (double.IsNegativeInfinity(x)) { return \"-inf\"; }
469
+ if (x == 0.0) { return (1.0 / x < 0) ? \"-0\" : \"0\"; }
470
+ long bits = System.BitConverter.DoubleToInt64Bits(x);
471
+ int be = (int)((bits >> 52) & 0x7FF);
472
+ long m = bits & 0xFFFFFFFFFFFFFL;
473
+ if (be == 0) { be = 1; } else { m |= 1L << 52; }
474
+ int e = be - 1077;
475
+ // x and the halfway points to its neighbours, all times 2^e
476
+ string xs = rs_exact(4 * m, e);
477
+ string hi = rs_exact(4 * m + 2, e);
478
+ string lo = rs_exact((m == (1L << 52) && be > 1) ? 4 * m - 1 : 4 * m - 2, e);
479
+ bool incl = (m % 2) == 0;
480
+ int k = e < 0 ? -e : 0;
481
+ string res = xs;
482
+ for (int n = 1; n <= xs.Length; n++) {
483
+ string head = xs.Substring(0, n);
484
+ string tail = xs.Substring(n);
485
+ string zeros = new string('0', tail.Length);
486
+ string down = head + zeros;
487
+ string up = rs_digits_inc(head) + zeros;
488
+ string half = \"5\" + new string('0', tail.Length > 0 ? tail.Length - 1 : 0);
489
+ int c = tail.Length > 0 ? rs_digits_cmp(tail, half) : -1;
490
+ bool nearUp = c > 0 || (c == 0 && ((head[n - 1] - '0') % 2) == 1);
491
+ string first = nearUp ? up : down;
492
+ string second = nearUp ? down : up;
493
+ string pick = null;
494
+ foreach (string cand in new string[] { first, second }) {
495
+ int cl = rs_digits_cmp(cand, lo);
496
+ int ch = rs_digits_cmp(cand, hi);
497
+ if ((cl > 0 || (incl && cl == 0)) && (ch < 0 || (incl && ch == 0))) { pick = cand; break; }
498
+ }
499
+ if (pick != null) { res = pick; break; }
500
+ }
501
+ string o = rs_place(res, k);
502
+ if (o.IndexOf('.') >= 0) { o = o.TrimEnd('0').TrimEnd('.'); }
503
+ return bits < 0 ? \"-\" + o : o;
504
+ }
505
+ "))
506
+ dart ( "rs_f64(" (e 1) ")"
507
+ (create_polyfill "
508
+ String rs_f64(double x) {
509
+ if (x.isNaN) { return 'NaN'; }
510
+ if (x.isInfinite) { return x > 0 ? 'inf' : '-inf'; }
511
+ if (x == 0.0) { return x.isNegative ? '-0' : '0'; }
512
+ var s = x.toString();
513
+ if (s.contains('e')) {
514
+ var neg = s.startsWith('-');
515
+ if (neg) { s = s.substring(1); }
516
+ var parts = s.split('e');
517
+ var mant = parts[0];
518
+ var exp = int.parse(parts[1]);
519
+ var dot = mant.indexOf('.');
520
+ var digits = mant.replaceAll('.', '');
521
+ var intLen = (dot < 0 ? mant.length : dot) + exp;
522
+ if (intLen <= 0) { s = '0.' + ('0' * -intLen) + digits; }
523
+ else if (intLen >= digits.length) { s = digits + ('0' * (intLen - digits.length)); }
524
+ else { s = digits.substring(0, intLen) + '.' + digits.substring(intLen); }
525
+ if (neg) { s = '-' + s; }
526
+ }
527
+ if (s.endsWith('.0')) { s = s.substring(0, s.length - 2); }
528
+ return s;
529
+ }
530
+ "))
531
+ scala ( "rs_f64(" (e 1) ")"
532
+ (create_polyfill "
533
+ def rs_f64(x: Double): String = {
534
+ if (x.isNaN) \"NaN\"
535
+ else if (x.isInfinite) (if (x > 0) \"inf\" else \"-inf\")
536
+ else if (x == 0.0) (if (1.0 / x < 0) \"-0\" else \"0\")
537
+ else new java.math.BigDecimal(java.lang.Double.toString(x)).stripTrailingZeros().toPlainString()
538
+ }
539
+ "))
540
+ php ( "rs_f64(" (e 1) ")"
541
+ (create_polyfill "
542
+ function rs_f64($x) {
543
+ if (is_nan($x)) { return 'NaN'; }
544
+ if (is_infinite($x)) { return $x > 0 ? 'inf' : '-inf'; }
545
+ $s = var_export((float)$x, true);
546
+ $neg = $s[0] == '-';
547
+ if ($neg) { $s = substr($s, 1); }
548
+ $ep = strpos($s, 'E');
549
+ if ($ep !== false) {
550
+ $mant = substr($s, 0, $ep);
551
+ $exp = (int)substr($s, $ep + 1);
552
+ $dot = strpos($mant, '.');
553
+ $digits = rtrim(str_replace('.', '', $mant), '0');
554
+ if ($digits === '') { $digits = '0'; }
555
+ $intLen = ($dot === false ? strlen($mant) : $dot) + $exp;
556
+ if ($intLen <= 0) { $s = '0.' . str_repeat('0', -$intLen) . $digits; }
557
+ elseif ($intLen >= strlen($digits)) { $s = $digits . str_repeat('0', $intLen - strlen($digits)); }
558
+ else { $s = substr($digits, 0, $intLen) . '.' . substr($digits, $intLen); }
559
+ }
560
+ if (substr($s, -2) === '.0') { $s = substr($s, 0, -2); }
561
+ return $neg ? '-' . $s : $s;
562
+ }
563
+ "))
564
+ * ( "rs_f64(" (e 1) ")" )
565
+ }
566
+ }
567
+ rs_fmt _:string (a:int) {
568
+ templates {
569
+ ranger ( "(rs_fmt " (e 1) ")" )
570
+ python ( "str(" (e 1) ")" )
571
+ go ( "strconv.FormatInt(int64(" (e 1) "), 10)" (imp "strconv") )
572
+ cpp ( "std::to_string(" (e 1) ")" (imp "<string>") )
573
+ rust ( (e 1) ".to_string()" )
574
+ java7 ( "String.valueOf(" (e 1) ")" )
575
+ kotlin ( (e 1) ".toString()" )
576
+ scala ( (e 1) ".toString" )
577
+ dart ( (e 1) ".toString()" )
578
+ csharp ( (e 1) ".ToString()" )
579
+ swift3 ( "String(" (e 1) ")" )
580
+ swift6 ( "String(" (e 1) ")" )
581
+ php ( "strval(" (e 1) ")" )
582
+ * ( "String(" (e 1) ")" )
583
+ }
584
+ }
585
+ rs_fmt _:string (a:boolean) {
586
+ templates {
587
+ ranger ( "(rs_fmt " (e 1) ")" )
588
+ python ( "('true' if " (e 1) " else 'false')" )
589
+ go ( "strconv.FormatBool(" (e 1) ")" (imp "strconv") )
590
+ cpp ( "std::string(" (e 1) " ? \"true\" : \"false\")" (imp "<string>") )
591
+ rust ( (e 1) ".to_string()" )
592
+ php ( "(" (e 1) " ? 'true' : 'false')" )
593
+ * ( "(" (e 1) " ? \"true\" : \"false\")" )
594
+ }
595
+ }
596
+ rs_fmt _:string (a:string) {
597
+ templates {
598
+ ranger ( "(rs_fmt " (e 1) ")" )
599
+ * ( (e 1) )
600
+ }
601
+ }
602
+
603
+ ; `{:.N}` of a float: N decimals, a tie rounded to even as Rust does
604
+ ; (JavaScript's toFixed rounds a tie up).
605
+ rs_fmt_prec _:string (a:double p:int) {
606
+ templates {
607
+ ranger ( "(rs_fmt_prec" " " (e 1) " " (e 2) ")" )
608
+ es6 ( "rs_f64_prec(" (e 1) ", " (e 2) ")"
609
+ (create_polyfill "
610
+ function rs_f64_prec(x, p) {
611
+ var m = Math.pow(10, p);
612
+ var y = x * m;
613
+ var t = Math.trunc(y);
614
+ if (Math.abs(y - t) === 0.5 && Number.isSafeInteger(t)) {
615
+ var n = (Math.abs(t) % 2 === 0) ? t : t + Math.sign(y);
616
+ return (n / m).toFixed(p);
617
+ }
618
+ return x.toFixed(p);
619
+ }
620
+ "))
621
+ python ( "format(" (e 1) ", '.' + str(" (e 2) ") + 'f')" )
622
+ go ( "strconv.FormatFloat(" (e 1) ", 'f', int(" (e 2) "), 64)" (imp "strconv") )
623
+ cpp ( "rs_f64_prec(" (e 1) ", " (e 2) ")" (imp "<cstdio>") (imp "<string>")
624
+ (create_polyfill "
625
+ inline std::string rs_f64_prec(double x, long long p) {
626
+ char buf[400];
627
+ std::snprintf(buf, sizeof(buf), \"%.*f\", (int)p, x);
628
+ return std::string(buf);
629
+ }
630
+ "))
631
+ rust ( "format!(\"{:.*}\", " (e 2) " as usize, " (e 1) ")" )
632
+ java7 ( "rs_f64_prec(" (e 1) ", " (e 2) ")"
633
+ (create_polyfill "
634
+ static String rs_f64_prec(double x, int p) {
635
+ if (Double.isNaN(x)) { return \"NaN\"; }
636
+ if (Double.isInfinite(x)) { return x > 0 ? \"inf\" : \"-inf\"; }
637
+ java.math.BigDecimal r = new java.math.BigDecimal(x).setScale(p, java.math.RoundingMode.HALF_EVEN);
638
+ String s = r.toPlainString();
639
+ if ((x < 0 || (x == 0.0 && 1.0 / x < 0)) && r.signum() == 0) { s = \"-\" + s; }
640
+ return s;
641
+ }
642
+ "))
643
+ kotlin ( "rs_f64_prec(" (e 1) ", " (e 2) ")"
644
+ (create_polyfill "
645
+ fun rs_f64_prec(x: Double, p: Int): String {
646
+ if (x.isNaN()) { return \"NaN\" }
647
+ if (x.isInfinite()) { return if (x > 0) \"inf\" else \"-inf\" }
648
+ val r = java.math.BigDecimal(x).setScale(p, java.math.RoundingMode.HALF_EVEN)
649
+ var s = r.toPlainString()
650
+ if ((x < 0 || (x == 0.0 && 1.0 / x < 0)) && r.signum() == 0) { s = \"-\" + s }
651
+ return s
652
+ }
653
+ "))
654
+ csharp ( "rs_f64_prec(" (e 1) ", " (e 2) ")"
655
+ (create_polyfill "
656
+ // The decimal digits of mant * 2^e * 10^k, k = max(0, -e): exact, so no
657
+ // digit depends on the runtime's number formatting.
658
+ static string rs_exact(long mant, int e) {
659
+ var limbs = new System.Collections.Generic.List<ulong>();
660
+ while (mant > 0) { limbs.Add((ulong)(mant % 1000000000L)); mant /= 1000000000L; }
661
+ if (limbs.Count == 0) { limbs.Add(0); }
662
+ ulong f = e < 0 ? 5UL : 2UL;
663
+ for (int n = (e < 0 ? -e : e); n > 0; n--) {
664
+ ulong carry = 0;
665
+ for (int i = 0; i < limbs.Count; i++) {
666
+ ulong t = limbs[i] * f + carry;
667
+ limbs[i] = t % 1000000000UL;
668
+ carry = t / 1000000000UL;
669
+ }
670
+ if (carry > 0) { limbs.Add(carry); }
671
+ }
672
+ var sb = new System.Text.StringBuilder();
673
+ sb.Append(limbs[limbs.Count - 1]);
674
+ for (int i = limbs.Count - 2; i >= 0; i--) { sb.Append(limbs[i].ToString(\"D9\")); }
675
+ return sb.ToString();
676
+ }
677
+ // Adds one to a digit string; the result may be one digit longer.
678
+ static string rs_digits_inc(string s) {
679
+ char[] c = s.ToCharArray();
680
+ int i = c.Length - 1;
681
+ while (i >= 0 && c[i] == '9') { c[i] = '0'; i--; }
682
+ if (i < 0) { return \"1\" + new string(c); }
683
+ c[i]++;
684
+ return new string(c);
685
+ }
686
+ // Compares two digit strings as numbers.
687
+ static int rs_digits_cmp(string a, string b) {
688
+ a = a.TrimStart('0');
689
+ b = b.TrimStart('0');
690
+ if (a.Length != b.Length) { return a.Length < b.Length ? -1 : 1; }
691
+ return System.Math.Sign(string.CompareOrdinal(a, b));
692
+ }
693
+ // digits * 10^-k written without an exponent.
694
+ static string rs_place(string digits, int k) {
695
+ if (digits.Length <= k) { digits = new string('0', k - digits.Length + 1) + digits; }
696
+ string ip = digits.Substring(0, digits.Length - k).TrimStart('0');
697
+ if (ip.Length == 0) { ip = \"0\"; }
698
+ return k > 0 ? ip + \".\" + digits.Substring(digits.Length - k) : ip;
699
+ }
700
+ ")
701
+ (create_polyfill "
702
+ // `{:.N}`: the exact value rounded to N decimals, a tie to even.
703
+ static string rs_f64_prec(double x, int p) {
704
+ if (double.IsNaN(x)) { return \"NaN\"; }
705
+ if (double.IsPositiveInfinity(x)) { return \"inf\"; }
706
+ if (double.IsNegativeInfinity(x)) { return \"-inf\"; }
707
+ long bits = System.BitConverter.DoubleToInt64Bits(x);
708
+ int be = (int)((bits >> 52) & 0x7FF);
709
+ long m = bits & 0xFFFFFFFFFFFFFL;
710
+ if (be == 0) { be = 1; } else { m |= 1L << 52; }
711
+ int e = be - 1075;
712
+ int k = e < 0 ? -e : 0;
713
+ string digits = rs_exact(m, e);
714
+ if (k > p) {
715
+ string head = digits.Length > k - p ? digits.Substring(0, digits.Length - (k - p)) : \"0\";
716
+ string tail = digits.Length > k - p ? digits.Substring(digits.Length - (k - p)) : digits.PadLeft(k - p, '0');
717
+ int c = rs_digits_cmp(tail, \"5\" + new string('0', tail.Length - 1));
718
+ if (c > 0 || (c == 0 && ((head[head.Length - 1] - '0') % 2) == 1)) { head = rs_digits_inc(head); }
719
+ digits = head;
720
+ } else {
721
+ digits = digits + new string('0', p - k);
722
+ }
723
+ string res = rs_place(digits, p);
724
+ return bits < 0 ? \"-\" + res : res;
725
+ }
726
+ "))
727
+ dart ( "rs_f64_prec(" (e 1) ", " (e 2) ")" (imp "dart:typed_data")
728
+ (create_polyfill "
729
+ String rs_f64_prec(double x, int p) {
730
+ if (x.isNaN) { return 'NaN'; }
731
+ if (x.isInfinite) { return x > 0 ? 'inf' : '-inf'; }
732
+ var bd = ByteData(8)..setFloat64(0, x);
733
+ var hi = bd.getUint32(0);
734
+ var lo = bd.getUint32(4);
735
+ var neg = (hi >> 31) == 1;
736
+ var be = (hi >> 20) & 0x7FF;
737
+ var m = (BigInt.from(hi & 0xFFFFF) << 32) | BigInt.from(lo);
738
+ if (be == 0) { be = 1; } else { m = m | (BigInt.one << 52); }
739
+ var e = be - 1075;
740
+ // the exact value times 10^p, rounded half to even
741
+ var n = m * BigInt.from(10).pow(p);
742
+ if (e >= 0) {
743
+ n = n << e;
744
+ } else {
745
+ var q = n >> -e;
746
+ var r = n - (q << -e);
747
+ var half = BigInt.one << (-e - 1);
748
+ if (r > half || (r == half && q.isOdd)) { q = q + BigInt.one; }
749
+ n = q;
750
+ }
751
+ var s = n.toString();
752
+ if (p > 0) {
753
+ s = s.padLeft(p + 1, '0');
754
+ s = s.substring(0, s.length - p) + '.' + s.substring(s.length - p);
755
+ }
756
+ return neg ? '-' + s : s;
757
+ }
758
+ "))
759
+ scala ( "rs_f64_prec(" (e 1) ", " (e 2) ")"
760
+ (create_polyfill "
761
+ def rs_f64_prec(x: Double, p: Int): String = {
762
+ if (x.isNaN) { return \"NaN\" }
763
+ if (x.isInfinite) { return if (x > 0) \"inf\" else \"-inf\" }
764
+ val r = new java.math.BigDecimal(x).setScale(p, java.math.RoundingMode.HALF_EVEN)
765
+ val s = r.toPlainString()
766
+ if ((x < 0 || (x == 0.0 && 1.0 / x < 0)) && r.signum() == 0) \"-\" + s else s
767
+ }
768
+ "))
769
+ php ( "rs_f64_prec(" (e 1) ", " (e 2) ")"
770
+ (create_polyfill "
771
+ // The decimal digits of $m * 2^$e * 10^k, k = max(0, -$e), exact.
772
+ function rs_exact($m, $e) {
773
+ $limbs = [];
774
+ while ($m > 0) { $limbs[] = $m % 1000000000; $m = intdiv($m, 1000000000); }
775
+ if (count($limbs) == 0) { $limbs[] = 0; }
776
+ $f = $e < 0 ? 5 : 2;
777
+ for ($n = abs($e); $n > 0; $n--) {
778
+ $carry = 0;
779
+ $len = count($limbs);
780
+ for ($i = 0; $i < $len; $i++) {
781
+ $t = $limbs[$i] * $f + $carry;
782
+ $limbs[$i] = $t % 1000000000;
783
+ $carry = intdiv($t, 1000000000);
784
+ }
785
+ if ($carry > 0) { $limbs[] = $carry; }
786
+ }
787
+ $s = (string)$limbs[count($limbs) - 1];
788
+ for ($i = count($limbs) - 2; $i >= 0; $i--) { $s .= str_pad((string)$limbs[$i], 9, '0', STR_PAD_LEFT); }
789
+ return $s;
790
+ }
791
+ // Adds one to a digit string.
792
+ function rs_digits_inc($s) {
793
+ $i = strlen($s) - 1;
794
+ while ($i >= 0 && $s[$i] == '9') { $s[$i] = '0'; $i--; }
795
+ if ($i < 0) { return '1' . $s; }
796
+ $s[$i] = chr(ord($s[$i]) + 1);
797
+ return $s;
798
+ }
799
+ ")
800
+ (create_polyfill "
801
+ // `{:.N}`: the exact value rounded to N decimals, a tie to even.
802
+ function rs_f64_prec($x, $p) {
803
+ if (is_nan($x)) { return 'NaN'; }
804
+ if (is_infinite($x)) { return $x > 0 ? 'inf' : '-inf'; }
805
+ $w = unpack('N2', pack('E', (float)$x));
806
+ $hi = $w[1];
807
+ $lo = $w[2];
808
+ $neg = ($hi >> 31) == 1;
809
+ $be = ($hi >> 20) & 0x7FF;
810
+ $m = (($hi & 0xFFFFF) << 32) | $lo;
811
+ if ($be == 0) { $be = 1; } else { $m = $m | (1 << 52); }
812
+ $e = $be - 1075;
813
+ $k = $e < 0 ? -$e : 0;
814
+ $digits = rs_exact($m, $e);
815
+ if ($k > $p) {
816
+ $cut = $k - $p;
817
+ if (strlen($digits) <= $cut) { $digits = str_repeat('0', $cut - strlen($digits) + 1) . $digits; }
818
+ $head = substr($digits, 0, strlen($digits) - $cut);
819
+ $tail = substr($digits, strlen($digits) - $cut);
820
+ $half = '5' . str_repeat('0', $cut - 1);
821
+ $c = strcmp($tail, $half);
822
+ if ($c > 0 || ($c == 0 && ((int)$head[strlen($head) - 1]) % 2 == 1)) { $head = rs_digits_inc($head); }
823
+ $digits = $head;
824
+ } else {
825
+ $digits = $digits . str_repeat('0', $p - $k);
826
+ }
827
+ if (strlen($digits) <= $p) { $digits = str_repeat('0', $p - strlen($digits) + 1) . $digits; }
828
+ $ip = ltrim(substr($digits, 0, strlen($digits) - $p), '0');
829
+ if ($ip === '') { $ip = '0'; }
830
+ $res = $p > 0 ? $ip . '.' . substr($digits, strlen($digits) - $p) : $ip;
831
+ return $neg ? '-' . $res : $res;
832
+ }
833
+ "))
834
+ * ( "rs_f64_prec(" (e 1) ", " (e 2) ")" )
835
+ }
836
+ }
837
+
838
+ ; `{:?}` of a string: quoted, with Rust's escapes.
839
+ rs_dbg _:string (a:string) {
840
+ templates {
841
+ * @macro(true) ( "(\"\\\"\" + ((replace (replace (replace (replace " "(" (e 1) ")" " \"\\\\\" \"\\\\\\\\\") \"\\\"\" \"\\\\\\\"\") \"\\n\" \"\\\\n\") \"\\t\" \"\\\\t\") + \"\\\"\"))" )
842
+ }
843
+ }
844
+ rs_dbg _:string (a:double) {
845
+ templates {
846
+ * @macro(true) ( "(rs_fmt_dbg_f64 " "(" (e 1) ")" ")" )
847
+ }
848
+ }
849
+ rs_dbg _:string (a:int) {
850
+ templates {
851
+ * @macro(true) ( "(to_string " "(" (e 1) ")" ")" )
852
+ }
853
+ }
854
+ rs_dbg _:string (a:boolean) {
855
+ templates {
856
+ * @macro(true) ( "(? " "(" (e 1) ")" " \"true\" \"false\")" )
857
+ }
858
+ }
859
+
860
+ ; `{:?}` of a float keeps the `.0` Display drops.
861
+ rs_fmt_dbg_f64 _:string (a:double) {
862
+ templates {
863
+ * @macro(true) ( "(RsFmt.dbgF64(" "(" (e 1) ")" "))" )
864
+ }
865
+ }
866
+
867
+ ; `panic!`: the message on stderr and exit status 101, as Rust does. Not
868
+ ; a Ranger `throw`, which callers would have to catch.
869
+ rs_panic _:void (msg:string) {
870
+ templates {
871
+ ranger ( "rs_panic " (e 1) )
872
+ es6 ( "process.stderr.write(" (e 1) " + \"\\n\"); process.exit(101);" )
873
+ python ( "sys.stderr.write(" (e 1) " + \"\\n\"); sys.exit(101)" (imp "sys") )
874
+ go ( "fmt.Fprintln(os.Stderr, " (e 1) "); os.Exit(101)" (imp "fmt") (imp "os") )
875
+ cpp ( "std::cerr << " (e 1) " << std::endl; std::exit(101);" (imp "<iostream>") (imp "<cstdlib>") )
876
+ rust ( "panic!(\"{}\", " (e 1) ");" )
877
+ java7 ( "System.err.println(" (e 1) "); System.exit(101);" )
878
+ kotlin ( "System.err.println(" (e 1) "); kotlin.system.exitProcess(101)" )
879
+ csharp ( "System.Console.Error.WriteLine(" (e 1) "); System.Environment.Exit(101);" )
880
+ dart ( "stderr.writeln(" (e 1) "); exit(101);" (imp "dart:io") )
881
+ scala ( "System.err.println(" (e 1) "); sys.exit(101)" )
882
+ php ( "fwrite(STDERR, " (e 1) " . \"\\n\"); exit(101);" )
883
+ * ( "process.stderr.write(" (e 1) " + \"\\n\"); process.exit(101);" )
884
+ }
885
+ }
886
+
887
+ ; Ordering of strings: Ranger's `<` / `>` take numbers only.
888
+ rs_str_cmp _:int (a:string b:string) {
889
+ templates {
890
+ ranger ( "(rs_str_cmp " (e 1) " " (e 2) ")" )
891
+ es6 ( "(" (e 1) " < " (e 2) " ? -1 : (" (e 1) " > " (e 2) " ? 1 : 0))" )
892
+ python ( "(-1 if " (e 1) " < " (e 2) " else (1 if " (e 1) " > " (e 2) " else 0))" )
893
+ go ( "int64(strings.Compare(" (e 1) ", " (e 2) "))" (imp "strings") )
894
+ cpp ( "(long long)((" (e 1) ").compare(" (e 2) ") < 0 ? -1 : ((" (e 1) ").compare(" (e 2) ") > 0 ? 1 : 0))" )
895
+ rust ( "(match " (e 1) ".cmp(&" (e 2) ") { std::cmp::Ordering::Less => -1, std::cmp::Ordering::Equal => 0, _ => 1 })" )
896
+ java7 ( "Integer.signum(" (e 1) ".compareTo(" (e 2) "))" )
897
+ kotlin ( "Integer.signum(" (e 1) ".compareTo(" (e 2) "))" )
898
+ csharp ( "System.Math.Sign(string.CompareOrdinal(" (e 1) ", " (e 2) "))" )
899
+ dart ( "(" (e 1) ").compareTo(" (e 2) ").sign" )
900
+ scala ( "Integer.signum(" (e 1) ".compareTo(" (e 2) "))" )
901
+ php ( "max(-1, min(1, strcmp(" (e 1) ", " (e 2) ")))" )
902
+ * ( "(" (e 1) " < " (e 2) " ? -1 : (" (e 1) " > " (e 2) " ? 1 : 0))" )
903
+ }
904
+ }
905
+
906
+ rs_map_len _:int (m:[K:T]) {
907
+ templates {
908
+ ranger ( "(rs_map_len " (e 1) ")" )
909
+ es6 ( "Object.keys(" (e 1) ").length" )
910
+ python ( "len(" (e 1) ")" )
911
+ go ( "int64(len(" (e 1) "))" )
912
+ cpp ( "(long long)(" (e 1) ").size()" )
913
+ rust ( "(" (e 1) ".len() as i64)" )
914
+ java7 ( (e 1) ".size()" )
915
+ kotlin ( (e 1) ".size" )
916
+ csharp ( (e 1) ".Count" )
917
+ dart ( (e 1) ".length" )
918
+ php ( "count(" (e 1) ")" )
919
+ swift6 ( (e 1) ".count" )
920
+ scala ( (e 1) ".size" )
921
+ * ( "Object.keys(" (e 1) ").length" )
922
+ }
923
+ }
924
+
925
+ ; Removing a key: Ranger has no operator for it.
926
+ rs_map_remove _:void (m:[K:T] k:K) {
927
+ templates {
928
+ ranger ( "rs_map_remove " (e 1) " " (e 2) )
929
+ es6 ( "delete " (e 1) "[" (e 2) "];" )
930
+ python ( (e 1) ".pop(" (e 2) ", None)" )
931
+ go ( "delete(" (e 1) ", " (e 2) ")" )
932
+ cpp ( "rs_map_erase(" (e 1) ", " (e 2) ");"
933
+ (create_polyfill "
934
+ template <class M, class K>
935
+ inline void rs_map_erase(M& m, const K& k) {
936
+ for (auto it = m.entries.begin(); it != m.entries.end(); ++it) {
937
+ if (it->first == k) {
938
+ m.entries.erase(it);
939
+ m.rehash_();
940
+ return;
941
+ }
942
+ }
943
+ }
944
+ "))
945
+ rust ( (e 1) ".remove(&" (e 2) ");" )
946
+ java7 ( (e 1) ".remove(" (e 2) ");" )
947
+ kotlin ( (e 1) ".remove(" (e 2) ")" )
948
+ csharp ( (e 1) ".Remove(" (e 2) ");" )
949
+ dart ( (e 1) ".remove(" (e 2) ");" )
950
+ php ( "unset(" (e 1) "[" (e 2) "]);" )
951
+ swift6 ( (e 1) ".removeValue(forKey: " (e 2) ")" )
952
+ scala ( (e 1) ".remove(" (e 2) ")" )
953
+ * ( "delete " (e 1) "[" (e 2) "];" )
954
+ }
955
+ }
956
+
957
+ ; ---------------------------------------------------------------- strings
958
+
959
+ ; Rust's `find` answers a BYTE offset; `indexOf` answers the target's own
960
+ ; unit, so the prefix before the hit is measured in UTF-8.
961
+ rs_find_bytes _:int (s:string p:string) {
962
+ templates {
963
+ * @macro(true) ( "(RsStr.findBytes(" "(" (e 1) ")" " " "(" (e 2) ")" "))" )
964
+ }
965
+ }
966
+ rs_byte_slice _:string (s:string a:int b:int) {
967
+ templates {
968
+ * @macro(true) ( "(substring (to_charbuffer " "(" (e 1) ")" ") " "(" (e 2) ")" " " "(" (e 3) ")" ")" )
969
+ }
970
+ }
971
+ rs_byte_len _:int (s:string) {
972
+ templates {
973
+ * @macro(true) ( "(length (to_charbuffer " "(" (e 1) ")" "))" )
974
+ }
975
+ }
976
+ ; Unicode case mapping. The C++ target's to_uppercase maps ASCII only; the
977
+ ; polyfill covers Latin-1, Latin Extended-A, Greek and Cyrillic.
978
+ rs_upper _:string (s:string) {
979
+ templates {
980
+ ranger ( "(rs_upper " (e 1) ")" )
981
+ cpp ( "rs_case(" (e 1) ", true)" (imp "<string>")
982
+ (create_polyfill "
983
+ inline long rs_case_map(long c, bool up) {
984
+ if (up) {
985
+ if (c >= 'a' && c <= 'z') { return c - 32; }
986
+ if ((c >= 0xE0 && c <= 0xFE && c != 0xF7)) { return c - 32; }
987
+ if (c == 0xFF) { return 0x178; }
988
+ if (c >= 0x100 && c <= 0x17F && c != 0x130 && c != 0x131 && c != 0x138 && c != 0x149 && c != 0x17F) {
989
+ bool oddLow = (c >= 0x139 && c <= 0x148) || (c >= 0x179 && c <= 0x17E);
990
+ if (oddLow) { return (c % 2 == 0) ? c - 1 : c; }
991
+ return (c % 2 == 1) ? c - 1 : c;
992
+ }
993
+ if (c >= 0x3B1 && c <= 0x3C9 && c != 0x3C2) { return c - 32; }
994
+ if (c >= 0x430 && c <= 0x44F) { return c - 32; }
995
+ if (c >= 0x450 && c <= 0x45F) { return c - 80; }
996
+ return c;
997
+ }
998
+ if (c >= 'A' && c <= 'Z') { return c + 32; }
999
+ if ((c >= 0xC0 && c <= 0xDE && c != 0xD7)) { return c + 32; }
1000
+ if (c == 0x178) { return 0xFF; }
1001
+ if (c >= 0x100 && c <= 0x17F && c != 0x130 && c != 0x131 && c != 0x138 && c != 0x149 && c != 0x17F) {
1002
+ bool oddLow = (c >= 0x139 && c <= 0x148) || (c >= 0x179 && c <= 0x17E);
1003
+ if (oddLow) { return (c % 2 == 1) ? c + 1 : c; }
1004
+ return (c % 2 == 0) ? c + 1 : c;
1005
+ }
1006
+ if (c >= 0x391 && c <= 0x3A9 && c != 0x3A2) { return c + 32; }
1007
+ if (c >= 0x410 && c <= 0x42F) { return c + 32; }
1008
+ if (c >= 0x400 && c <= 0x40F) { return c + 80; }
1009
+ return c;
1010
+ }
1011
+ inline std::string rs_case(const std::string& s, bool up) {
1012
+ std::string out;
1013
+ size_t i = 0;
1014
+ while (i < s.size()) {
1015
+ unsigned char b = (unsigned char)s[i];
1016
+ long c = b;
1017
+ size_t n = 1;
1018
+ if (b >= 0xF0) { c = b & 0x07; n = 4; }
1019
+ else if (b >= 0xE0) { c = b & 0x0F; n = 3; }
1020
+ else if (b >= 0xC0) { c = b & 0x1F; n = 2; }
1021
+ for (size_t k = 1; k < n && i + k < s.size(); k++) { c = (c << 6) | ((unsigned char)s[i + k] & 0x3F); }
1022
+ i += n;
1023
+ if (up && c == 0xDF) { out += \"SS\"; continue; }
1024
+ long m = rs_case_map(c, up);
1025
+ if (m < 0x80) { out += (char)m; }
1026
+ else if (m < 0x800) { out += (char)(0xC0 | (m >> 6)); out += (char)(0x80 | (m & 0x3F)); }
1027
+ else if (m < 0x10000) { out += (char)(0xE0 | (m >> 12)); out += (char)(0x80 | ((m >> 6) & 0x3F)); out += (char)(0x80 | (m & 0x3F)); }
1028
+ else { out += (char)(0xF0 | (m >> 18)); out += (char)(0x80 | ((m >> 12) & 0x3F)); out += (char)(0x80 | ((m >> 6) & 0x3F)); out += (char)(0x80 | (m & 0x3F)); }
1029
+ }
1030
+ return out;
1031
+ }
1032
+ "))
1033
+ ; strings.ToUpper maps one rune to one rune; Rust special casing writes
1034
+ ; ß as SS
1035
+ go ( "strings.ReplaceAll(strings.ToUpper(" (e 1) "), \"ß\", \"SS\")" (imp "strings") )
1036
+ csharp ( "(" (e 1) ").ToUpperInvariant().Replace(\"ß\", \"SS\")" )
1037
+ dart ( "(" (e 1) ").toUpperCase().replaceAll(\"ß\", \"SS\")" )
1038
+ php ( "mb_strtoupper(" (e 1) ", 'UTF-8')" )
1039
+ * @macro(true) ( "(to_uppercase " "(" (e 1) ")" ")" )
1040
+ }
1041
+ }
1042
+ rs_lower _:string (s:string) {
1043
+ templates {
1044
+ ranger ( "(rs_lower " (e 1) ")" )
1045
+ cpp ( "rs_case(" (e 1) ", false)" (imp "<string>") )
1046
+ php ( "mb_strtolower(" (e 1) ", 'UTF-8')" )
1047
+ * @macro(true) ( "(to_lowercase " "(" (e 1) ")" ")" )
1048
+ }
1049
+ }
1050
+
1051
+ rs_char_count _:int (s:string) {
1052
+ templates {
1053
+ * @macro(true) ( "(array_length (to_chars " "(" (e 1) ")" "))" )
1054
+ }
1055
+ }
1056
+ ; ------------------------------------------------------- float methods
1057
+ ; `x.round()` rounds half away from zero; `x.trunc()`, `x.ln()`,
1058
+ ; `x.exp()`, `x.log10()`, `x.powf(y)` and `x.signum()` are the libm ones.
1059
+
1060
+ rs_round _:double (a:double) {
1061
+ templates {
1062
+ ranger ( "(rs_round " (e 1) ")" )
1063
+ es6 ( "rs_round(" (e 1) ")"
1064
+ (create_polyfill "
1065
+ function rs_round(x) {
1066
+ const a = Math.abs(x);
1067
+ let r = Math.floor(a);
1068
+ if (a - r >= 0.5) { r += 1; }
1069
+ return x < 0 ? -r : r;
1070
+ }
1071
+ "))
1072
+ python ( "rs_round(" (e 1) ")" (imp "math")
1073
+ (create_polyfill "
1074
+ def rs_round(x):
1075
+ if not math.isfinite(x):
1076
+ return x
1077
+ a = abs(x)
1078
+ r = math.floor(a)
1079
+ if a - r >= 0.5:
1080
+ r += 1
1081
+ return math.copysign(float(r), x)
1082
+ "))
1083
+ go ( "math.Round(" (e 1) ")" (imp "math") )
1084
+ cpp ( "std::round(" (e 1) ")" (imp "<cmath>") )
1085
+ java7 ( "rs_round(" (e 1) ")"
1086
+ (create_polyfill "
1087
+ static double rs_round(double x) {
1088
+ if (Double.isNaN(x) || Double.isInfinite(x)) { return x; }
1089
+ double a = Math.abs(x);
1090
+ double r = Math.floor(a);
1091
+ if (a - r >= 0.5) { r += 1; }
1092
+ return Math.copySign(r, x);
1093
+ }
1094
+ "))
1095
+ kotlin ( "rs_round(" (e 1) ")"
1096
+ (create_polyfill "
1097
+ fun rs_round(x: Double): Double {
1098
+ if (x.isNaN() || x.isInfinite()) { return x }
1099
+ val a = Math.abs(x)
1100
+ var r = Math.floor(a)
1101
+ if (a - r >= 0.5) { r += 1.0 }
1102
+ return Math.copySign(r, x)
1103
+ }
1104
+ "))
1105
+ csharp ( "System.Math.Round(" (e 1) ", System.MidpointRounding.AwayFromZero)" )
1106
+ dart ( "(" (e 1) ").roundToDouble()" )
1107
+ scala ( "rs_round(" (e 1) ")"
1108
+ (create_polyfill "
1109
+ def rs_round(x: Double): Double = {
1110
+ if (x.isNaN || x.isInfinite) { return x }
1111
+ val a = math.abs(x)
1112
+ var r = math.floor(a)
1113
+ if (a - r >= 0.5) { r += 1.0 }
1114
+ java.lang.Math.copySign(r, x)
1115
+ }
1116
+ "))
1117
+ php ( "round(" (e 1) ")" )
1118
+ * ( "Math.round(" (e 1) ")" )
1119
+ }
1120
+ }
1121
+ rs_trunc _:double (a:double) {
1122
+ templates {
1123
+ ranger ( "(rs_trunc " (e 1) ")" )
1124
+ es6 ( "Math.trunc(" (e 1) ")" )
1125
+ python ( "rs_trunc(" (e 1) ")" (imp "math")
1126
+ (create_polyfill "
1127
+ def rs_trunc(x):
1128
+ if not math.isfinite(x):
1129
+ return x
1130
+ return math.copysign(float(math.trunc(x)), x)
1131
+ "))
1132
+ go ( "math.Trunc(" (e 1) ")" (imp "math") )
1133
+ cpp ( "std::trunc(" (e 1) ")" (imp "<cmath>") )
1134
+ java7 ( "(" (e 1) " < 0 ? Math.ceil(" (e 1) ") : Math.floor(" (e 1) "))" )
1135
+ kotlin ( "(if (" (e 1) " < 0) Math.ceil(" (e 1) ") else Math.floor(" (e 1) "))" )
1136
+ csharp ( "System.Math.Truncate(" (e 1) ")" )
1137
+ dart ( "(" (e 1) ").truncateToDouble()" )
1138
+ scala ( "(if (" (e 1) " < 0) math.ceil(" (e 1) ") else math.floor(" (e 1) "))" )
1139
+ php ( "rs_trunc(" (e 1) ")"
1140
+ (create_polyfill "
1141
+ function rs_trunc($x) {
1142
+ return $x < 0 ? ceil($x) : floor($x);
1143
+ }
1144
+ "))
1145
+ * ( "Math.floor(" (e 1) ")" )
1146
+ }
1147
+ }
1148
+ rs_ln _:double (a:double) {
1149
+ templates {
1150
+ ranger ( "(rs_ln " (e 1) ")" )
1151
+ es6 ( "Math.log(" (e 1) ")" )
1152
+ python ( "math.log(" (e 1) ")" (imp "math") )
1153
+ go ( "math.Log(" (e 1) ")" (imp "math") )
1154
+ cpp ( "std::log(" (e 1) ")" (imp "<cmath>") )
1155
+ csharp ( "System.Math.Log(" (e 1) ")" )
1156
+ dart ( "log(" (e 1) ")" (imp "dart:math") )
1157
+ scala ( "math.log(" (e 1) ")" )
1158
+ php ( "log(" (e 1) ")" )
1159
+ * ( "Math.log(" (e 1) ")" )
1160
+ }
1161
+ }
1162
+ rs_exp _:double (a:double) {
1163
+ templates {
1164
+ ranger ( "(rs_exp " (e 1) ")" )
1165
+ es6 ( "Math.exp(" (e 1) ")" )
1166
+ python ( "math.exp(" (e 1) ")" (imp "math") )
1167
+ go ( "math.Exp(" (e 1) ")" (imp "math") )
1168
+ cpp ( "std::exp(" (e 1) ")" (imp "<cmath>") )
1169
+ csharp ( "System.Math.Exp(" (e 1) ")" )
1170
+ dart ( "exp(" (e 1) ")" (imp "dart:math") )
1171
+ scala ( "math.exp(" (e 1) ")" )
1172
+ php ( "exp(" (e 1) ")" )
1173
+ * ( "Math.exp(" (e 1) ")" )
1174
+ }
1175
+ }
1176
+ rs_log10 _:double (a:double) {
1177
+ templates {
1178
+ ranger ( "(rs_log10 " (e 1) ")" )
1179
+ es6 ( "Math.log10(" (e 1) ")" )
1180
+ python ( "math.log10(" (e 1) ")" (imp "math") )
1181
+ go ( "math.Log10(" (e 1) ")" (imp "math") )
1182
+ cpp ( "std::log10(" (e 1) ")" (imp "<cmath>") )
1183
+ csharp ( "System.Math.Log10(" (e 1) ")" )
1184
+ dart ( "rs_log10(" (e 1) ")" (imp "dart:math")
1185
+ (create_polyfill "
1186
+ double rs_log10(double x) {
1187
+ var r = log(x) / ln10;
1188
+ // exact powers of ten come out exact, as libm's log10 gives them
1189
+ var k = r.roundToDouble();
1190
+ if (k.abs() < 300 && pow(10.0, k) == x) { return k; }
1191
+ return r;
1192
+ }
1193
+ "))
1194
+ scala ( "math.log10(" (e 1) ")" )
1195
+ php ( "log10(" (e 1) ")" )
1196
+ * ( "Math.log10(" (e 1) ")" )
1197
+ }
1198
+ }
1199
+ rs_powf _:double (a:double b:double) {
1200
+ templates {
1201
+ ranger ( "(rs_powf " (e 1) " " (e 2) ")" )
1202
+ es6 ( "Math.pow(" (e 1) ", " (e 2) ")" )
1203
+ python ( "math.pow(" (e 1) ", " (e 2) ")" (imp "math") )
1204
+ go ( "math.Pow(" (e 1) ", " (e 2) ")" (imp "math") )
1205
+ cpp ( "std::pow(" (e 1) ", " (e 2) ")" (imp "<cmath>") )
1206
+ csharp ( "System.Math.Pow(" (e 1) ", " (e 2) ")" )
1207
+ dart ( "pow(" (e 1) ", " (e 2) ").toDouble()" (imp "dart:math") )
1208
+ scala ( "math.pow(" (e 1) ", " (e 2) ")" )
1209
+ php ( "((float)pow(" (e 1) ", " (e 2) "))" )
1210
+ * ( "Math.pow(" (e 1) ", " (e 2) ")" )
1211
+ }
1212
+ }
1213
+ ; 1.0 for +0.0 and positive numbers, -1.0 for -0.0 and negative ones, NaN
1214
+ ; for NaN
1215
+ rs_signum _:double (a:double) {
1216
+ templates {
1217
+ ranger ( "(rs_signum " (e 1) ")" )
1218
+ es6 ( "rs_signum(" (e 1) ")"
1219
+ (create_polyfill "
1220
+ function rs_signum(x) {
1221
+ if (x !== x) { return x; }
1222
+ return (x < 0 || Object.is(x, -0)) ? -1 : 1;
1223
+ }
1224
+ "))
1225
+ python ( "(" (e 1) " if math.isnan(" (e 1) ") else math.copysign(1.0, " (e 1) "))" (imp "math") )
1226
+ go ( "rs_signum(" (e 1) ")" (imp "math")
1227
+ (create_polyfill "
1228
+ func rs_signum(x float64) float64 {
1229
+ if math.IsNaN(x) {
1230
+ return x
1231
+ }
1232
+ return math.Copysign(1, x)
1233
+ }
1234
+ "))
1235
+ cpp ( "(std::isnan(" (e 1) ") ? " (e 1) " : std::copysign(1.0, " (e 1) "))" (imp "<cmath>") )
1236
+ java7 ( "(Double.isNaN(" (e 1) ") ? " (e 1) " : Math.copySign(1.0, " (e 1) "))" )
1237
+ kotlin ( "(if ((" (e 1) ").isNaN()) " (e 1) " else Math.copySign(1.0, " (e 1) "))" )
1238
+ csharp ( "(double.IsNaN(" (e 1) ") ? " (e 1) " : ((" (e 1) " < 0 || (" (e 1) " == 0 && 1.0 / " (e 1) " < 0)) ? -1.0 : 1.0))" )
1239
+ dart ( "((" (e 1) ").isNaN ? " (e 1) " : ((" (e 1) ").isNegative ? -1.0 : 1.0))" )
1240
+ scala ( "(if ((" (e 1) ").isNaN) " (e 1) " else java.lang.Math.copySign(1.0, " (e 1) "))" )
1241
+ php ( "rs_signum(" (e 1) ")"
1242
+ (create_polyfill "
1243
+ function rs_signum($x) {
1244
+ if (is_nan($x)) { return $x; }
1245
+ return ($x < 0 || ($x == 0 && fdiv(1, $x) < 0)) ? -1.0 : 1.0;
1246
+ }
1247
+ "))
1248
+ * ( "Math.signum(" (e 1) ")" )
1249
+ }
1250
+ }
1251
+
1252
+ ; ------------------------------------------------------------ map keys
1253
+
1254
+ ; The keys of an int-keyed map (Ranger's `keys` takes string keys). On
1255
+ ; JavaScript the map is an object, whose keys come back as strings.
1256
+ rs_int_keys _:[int] (m:[int:T]) {
1257
+ templates {
1258
+ ranger ( "(rs_int_keys " (e 1) ")" )
1259
+ es6 ( "Object.keys(" (e 1) ").map(Number)" )
1260
+ python ( "list(" (e 1) ".keys())" )
1261
+ go ( "rs_int_keys(" (e 1) ")"
1262
+ (create_polyfill "
1263
+ func rs_int_keys[V any](m map[int64]V) []int64 {
1264
+ res := make([]int64, 0, len(m))
1265
+ for k := range m {
1266
+ res = append(res, k)
1267
+ }
1268
+ return res
1269
+ }
1270
+ "))
1271
+ cpp ( "rs_int_keys(" (e 1) ")" (imp "<vector>")
1272
+ (create_polyfill "
1273
+ template< typename M >
1274
+ std::vector<int> rs_int_keys( const M & m ) {
1275
+ std::vector<int> res;
1276
+ for (auto it = m.begin(); it != m.end(); ++it) {
1277
+ res.push_back(it->first);
1278
+ }
1279
+ return res;
1280
+ }
1281
+ "))
1282
+ rust ( (e 1) ".keys().cloned().collect::<Vec<i64>>()" )
1283
+ kotlin ( "ArrayList(" (e 1) ".keys)" )
1284
+ csharp ( "new System.Collections.Generic.List<int>(" (e 1) ".Keys)" )
1285
+ dart ( "(" (e 1) ").keys.toList()" )
1286
+ scala ( "(" (e 1) ").keys.to[collection.mutable.ArrayBuffer]" )
1287
+ php ( "array_keys(" (e 1) ")" )
1288
+ * ( "new ArrayList<>(" (e 1) ".keySet())" )
1289
+ }
1290
+ }
1291
+
1292
+ ; ---------------------------------------------------------------- stderr
1293
+
1294
+ ; `eprintln!`: a line on standard error.
1295
+ rs_eprint _:void (s:string) {
1296
+ templates {
1297
+ ranger ( "rs_eprint " (e 1) nl )
1298
+ es6 ( "console.error(" (e 1) ");" nl )
1299
+ python ( "print(" (e 1) ", file=sys.stderr)" nl (imp "sys") )
1300
+ go ( "fmt.Fprintln(os.Stderr, " (e 1) ")" nl (imp "fmt") (imp "os") )
1301
+ cpp ( "std::cerr << " (e 1) " << std::endl;" nl (imp "<iostream>") )
1302
+ kotlin ( "System.err.println(" (e 1) ")" nl )
1303
+ csharp ( "System.Console.Error.WriteLine(" (e 1) ");" nl )
1304
+ dart ( "stderr.writeln(" (e 1) ");" nl (imp "dart:io") )
1305
+ scala ( "System.err.println(" (e 1) ")" nl )
1306
+ php ( "fwrite(STDERR, " (e 1) " . \"\\n\");" nl )
1307
+ * ( "System.err.println(" (e 1) ");" nl )
1308
+ }
1309
+ }
1310
+ }
1311
+
1312
+
1313
+ class RsFmt {
1314
+ ; `{:?}` of a char: quoted with ', escapes as Rust writes them.
1315
+ sfn dbgChar:string (c:string) {
1316
+ if (c == "\\") {
1317
+ return "'\\\\'"
1318
+ }
1319
+ if (c == "'") {
1320
+ return "'\\''"
1321
+ }
1322
+ if (c == "\n") {
1323
+ return "'\\n'"
1324
+ }
1325
+ if (c == "\t") {
1326
+ return "'\\t'"
1327
+ }
1328
+ if (c == "\r") {
1329
+ return "'\\r'"
1330
+ }
1331
+ return (("'" + c) + "'")
1332
+ }
1333
+
1334
+ ; `{:>8}`, `{:<8}`, `{:^8}` with a fill character; the width counts code
1335
+ ; points, as Rust's does.
1336
+ sfn pad:string (s:string width:int align:string fill:string) {
1337
+ def n:int (rs_char_count s)
1338
+ if (n >= width) {
1339
+ return s
1340
+ }
1341
+ def total:int (width - n)
1342
+ def left:int 0
1343
+ if (align == ">") {
1344
+ left = total
1345
+ }
1346
+ if (align == "^") {
1347
+ left = (rs_div total 2)
1348
+ }
1349
+ def right:int (total - left)
1350
+ return (((RsStr.repeat(fill left)) + s) + (RsStr.repeat(fill right)))
1351
+ }
1352
+
1353
+ ; `{:08}`: zeros after the sign.
1354
+ sfn padZero:string (s:string width:int) {
1355
+ def n:int (rs_char_count s)
1356
+ if (n >= width) {
1357
+ return s
1358
+ }
1359
+ def zeros:string (RsStr.repeat("0" (width - n)))
1360
+ if ((strlen s) > 0) {
1361
+ def first:string (substring s 0 1)
1362
+ if ((first == "-") || (first == "+")) {
1363
+ return ((first + zeros) + (substring s 1 (strlen s)))
1364
+ }
1365
+ }
1366
+ return (zeros + s)
1367
+ }
1368
+
1369
+ sfn dbgF64:string (x:double) {
1370
+ def s:string (rs_fmt x)
1371
+ if ((indexOf s ".") >= 0) {
1372
+ return s
1373
+ }
1374
+ if ((s == "NaN") || (s == "inf") || (s == "-inf")) {
1375
+ return s
1376
+ }
1377
+ return (s + ".0")
1378
+ }
1379
+ }
1380
+
1381
+ class RsStr {
1382
+ ; `s.parse::<i64>()`: an optional sign and decimal digits, nothing else
1383
+ ; (no spaces, no trailing text), within i64.
1384
+ sfn parseI64@(optional):int (s:string) {
1385
+ def none@(optional):int
1386
+ def cs:[int] (to_chars s)
1387
+ def n:int (array_length cs)
1388
+ if (n == 0) {
1389
+ return none
1390
+ }
1391
+ def i:int 0
1392
+ def first:int (itemAt cs 0)
1393
+ if ((first == 43) || (first == 45)) {
1394
+ i = 1
1395
+ }
1396
+ if (i >= n) {
1397
+ return none
1398
+ }
1399
+ if ((n - i) > 19) {
1400
+ return none
1401
+ }
1402
+ while (i < n) {
1403
+ def c:int (itemAt cs i)
1404
+ if ((c < 48) || (c > 57)) {
1405
+ return none
1406
+ }
1407
+ i = i + 1
1408
+ }
1409
+ def r@(optional):int (to_int s)
1410
+ return r
1411
+ }
1412
+
1413
+ ; Rust's ParseIntError text for `s`.
1414
+ sfn parseIntErr:string (s:string) {
1415
+ if ((strlen s) == 0) {
1416
+ return "cannot parse integer from empty string"
1417
+ }
1418
+ if ((s == "-") || (s == "+")) {
1419
+ return "invalid digit found in string"
1420
+ }
1421
+ def cs:[int] (to_chars s)
1422
+ def i:int 0
1423
+ def n:int (array_length cs)
1424
+ def first:int (itemAt cs 0)
1425
+ if ((first == 43) || (first == 45)) {
1426
+ i = 1
1427
+ }
1428
+ while (i < n) {
1429
+ def c:int (itemAt cs i)
1430
+ if ((c < 48) || (c > 57)) {
1431
+ return "invalid digit found in string"
1432
+ }
1433
+ i = i + 1
1434
+ }
1435
+ if (first == 45) {
1436
+ return "number too small to fit in target type"
1437
+ }
1438
+ return "number too large to fit in target type"
1439
+ }
1440
+
1441
+ ; `s.parse::<f64>()`: sign, digits with at most one dot, an optional
1442
+ ; exponent; "inf", "infinity" and "NaN" as Rust spells them.
1443
+ sfn parseF64@(optional):double (s:string) {
1444
+ def none@(optional):double
1445
+ def low:string (to_lowercase s)
1446
+ def body:string low
1447
+ if (((strlen low) > 0) && (((substring low 0 1) == "+") || ((substring low 0 1) == "-"))) {
1448
+ body = (substring low 1 (strlen low))
1449
+ }
1450
+ if ((body == "inf") || (body == "infinity") || (body == "nan")) {
1451
+ def sp@(optional):double (to_double s)
1452
+ if (null? sp) {
1453
+ def neg:boolean ((substring low 0 1) == "-")
1454
+ if (body == "nan") {
1455
+ return none
1456
+ }
1457
+ def big:double 1.0
1458
+ def k:int 0
1459
+ while (k < 400) {
1460
+ big = (big * 10.0)
1461
+ k = k + 1
1462
+ }
1463
+ if neg {
1464
+ big = (0.0 - big)
1465
+ }
1466
+ def bo@(optional):double big
1467
+ return bo
1468
+ }
1469
+ return sp
1470
+ }
1471
+ def cs:[int] (to_chars body)
1472
+ def n:int (array_length cs)
1473
+ def digits:int 0
1474
+ def dots:int 0
1475
+ def i:int 0
1476
+ while ((i < n) && ((itemAt cs i) != 101)) {
1477
+ def c:int (itemAt cs i)
1478
+ if (c == 46) {
1479
+ dots = dots + 1
1480
+ } {
1481
+ if ((c < 48) || (c > 57)) {
1482
+ return none
1483
+ }
1484
+ digits = digits + 1
1485
+ }
1486
+ i = i + 1
1487
+ }
1488
+ if ((digits == 0) || (dots > 1)) {
1489
+ return none
1490
+ }
1491
+ if (i < n) {
1492
+ i = i + 1
1493
+ if ((i < n) && (((itemAt cs i) == 43) || ((itemAt cs i) == 45))) {
1494
+ i = i + 1
1495
+ }
1496
+ if (i >= n) {
1497
+ return none
1498
+ }
1499
+ while (i < n) {
1500
+ def e:int (itemAt cs i)
1501
+ if ((e < 48) || (e > 57)) {
1502
+ return none
1503
+ }
1504
+ i = i + 1
1505
+ }
1506
+ }
1507
+ def r@(optional):double (to_double s)
1508
+ return r
1509
+ }
1510
+
1511
+ sfn parseFloatErr:string (s:string) {
1512
+ if ((strlen s) == 0) {
1513
+ return "cannot parse float from empty string"
1514
+ }
1515
+ return "invalid float literal"
1516
+ }
1517
+
1518
+ ; `s.repeat(n)`
1519
+ sfn repeat:string (s:string n:int) {
1520
+ def r:string ""
1521
+ def i:int 0
1522
+ while (i < n) {
1523
+ r = r + s
1524
+ i = i + 1
1525
+ }
1526
+ return r
1527
+ }
1528
+
1529
+ ; Code points `a` up to `b` of `s`.
1530
+ sfn codeSlice:string (s:string a:int b:int) {
1531
+ return (utf8_substring s a b)
1532
+ }
1533
+
1534
+ ; `s.split_whitespace()`: the runs between White_Space characters.
1535
+ sfn splitWhitespace:[string] (s:string) {
1536
+ def res:[string]
1537
+ def cs:[int] (to_chars s)
1538
+ def n:int (array_length cs)
1539
+ def start:int -1
1540
+ def i:int 0
1541
+ while (i < n) {
1542
+ def ch:string (rs_char_from (itemAt cs i))
1543
+ if (RsChar.isWhitespace(ch)) {
1544
+ if (start >= 0) {
1545
+ push res (utf8_substring s start i)
1546
+ start = -1
1547
+ }
1548
+ } {
1549
+ if (start < 0) {
1550
+ start = i
1551
+ }
1552
+ }
1553
+ i = i + 1
1554
+ }
1555
+ if (start >= 0) {
1556
+ push res (utf8_substring s start n)
1557
+ }
1558
+ return res
1559
+ }
1560
+
1561
+ ; The UTF-8 byte offset of the first `p` in `s`, or -1.
1562
+ sfn findBytes:int (s:string p:string) {
1563
+ def idx:int (indexOf s p)
1564
+ if (idx < 0) {
1565
+ return -1
1566
+ }
1567
+ def head:string (substring s 0 idx)
1568
+ return (length (to_charbuffer head))
1569
+ }
1570
+ }
1571
+
1572
+ class RsChar {
1573
+ ; `c.is_ascii_digit()`, `c.is_numeric()` (for the digits Rust's is_numeric
1574
+ ; and ASCII agree on)
1575
+ sfn isAsciiDigit:boolean (c:string) {
1576
+ def k:int (rs_char_code c)
1577
+ return ((k >= 48) && (k <= 57))
1578
+ }
1579
+
1580
+ sfn isAsciiAlpha:boolean (c:string) {
1581
+ def k:int (rs_char_code c)
1582
+ return (((k >= 65) && (k <= 90)) || ((k >= 97) && (k <= 122)))
1583
+ }
1584
+
1585
+ sfn isAsciiUpper:boolean (c:string) {
1586
+ def k:int (rs_char_code c)
1587
+ return ((k >= 65) && (k <= 90))
1588
+ }
1589
+
1590
+ sfn isAsciiLower:boolean (c:string) {
1591
+ def k:int (rs_char_code c)
1592
+ return ((k >= 97) && (k <= 122))
1593
+ }
1594
+
1595
+ sfn isAsciiAlnum:boolean (c:string) {
1596
+ return ((RsChar.isAsciiAlpha(c)) || (RsChar.isAsciiDigit(c)))
1597
+ }
1598
+
1599
+ sfn asciiUpper:string (c:string) {
1600
+ if (RsChar.isAsciiLower(c)) {
1601
+ return (rs_char_from ((rs_char_code c) - 32))
1602
+ }
1603
+ return c
1604
+ }
1605
+
1606
+ sfn asciiLower:string (c:string) {
1607
+ if (RsChar.isAsciiUpper(c)) {
1608
+ return (rs_char_from ((rs_char_code c) + 32))
1609
+ }
1610
+ return c
1611
+ }
1612
+
1613
+ sfn isAsciiSpace:boolean (c:string) {
1614
+ def k:int (rs_char_code c)
1615
+ return ((k == 32) || (k == 9) || (k == 10) || (k == 12) || (k == 13))
1616
+ }
1617
+
1618
+ ; Rust's White_Space property.
1619
+ sfn isWhitespace:boolean (c:string) {
1620
+ def k:int (rs_char_code c)
1621
+ if (((k >= 9) && (k <= 13)) || (k == 32) || (k == 133) || (k == 160) || (k == 5760)) {
1622
+ return true
1623
+ }
1624
+ if (((k >= 8192) && (k <= 8202)) || (k == 8232) || (k == 8233) || (k == 8239) || (k == 8287) || (k == 12288)) {
1625
+ return true
1626
+ }
1627
+ return false
1628
+ }
1629
+
1630
+ ; A cased letter changes under one of the case maps; letters without case
1631
+ ; are taken from the large scripts that have none (kana, CJK, Hangul).
1632
+ ; Rust's `is_alphabetic` covers every script: this is the subset the
1633
+ ; targets can test without a Unicode table.
1634
+ sfn isAlphabetic:boolean (c:string) {
1635
+ def k:int (rs_char_code c)
1636
+ if (k < 128) {
1637
+ return (RsChar.isAsciiAlpha(c))
1638
+ }
1639
+ if ((rs_upper c) != (rs_lower c)) {
1640
+ return true
1641
+ }
1642
+ if ((k == 170) || (k == 186) || (k == 223)) {
1643
+ return true
1644
+ }
1645
+ return (((k >= 12353) && (k <= 12543)) || ((k >= 13312) && (k <= 40959)) || ((k >= 44032) && (k <= 55215)))
1646
+ }
1647
+
1648
+ sfn isAlphanumeric:boolean (c:string) {
1649
+ return ((RsChar.isAlphabetic(c)) || (RsChar.isAsciiDigit(c)))
1650
+ }
1651
+
1652
+ sfn isUppercase:boolean (c:string) {
1653
+ return ((rs_lower c) != c)
1654
+ }
1655
+
1656
+ sfn isLowercase:boolean (c:string) {
1657
+ def k:int (rs_char_code c)
1658
+ if (k == 223) {
1659
+ return true
1660
+ }
1661
+ return ((rs_upper c) != c)
1662
+ }
1663
+ }