ranger-compiler 3.5.1 → 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.
- package/CHANGELOG.md +1064 -20
- package/LICENSE +3 -1
- package/README.md +123 -28
- package/dist/Lang.rgr +1188 -290
- package/dist/api.d.ts +2343 -879
- package/dist/api.js +79923 -56921
- package/dist/lib/JSON.rgr +102 -91
- package/dist/lib/Shell.rgr +4 -4
- package/dist/lib/apple/AppleToolchain.rgr +4 -4
- package/dist/lib/apple/README.md +5 -4
- package/dist/lib/apple/apple_test.rgr +1 -1
- package/dist/lib/core/README.md +1 -1
- package/dist/lib/evg/EVG.rgr +12 -0
- package/dist/lib/evg/EVGA11yFromTree.rgr +302 -0
- package/dist/lib/evg/EVGA11yTree.rgr +894 -0
- package/dist/lib/evg/EVGBox.rgr +267 -0
- package/dist/lib/evg/EVGBoxShorthandTest.rgr +220 -0
- package/dist/lib/evg/EVGCodepoint.rgr +316 -0
- package/dist/lib/evg/EVGColor.rgr +700 -0
- package/dist/lib/evg/EVGCommands.rgr +177 -0
- package/dist/lib/evg/EVGComponent.rgr +331 -0
- package/dist/lib/evg/EVGComponentTest.rgr +387 -0
- package/dist/lib/evg/EVGConnector.rgr +541 -0
- package/dist/lib/evg/EVGConnectorTest.rgr +306 -0
- package/dist/lib/evg/EVGDisplayList.rgr +4186 -0
- package/dist/lib/evg/EVGEasing.rgr +370 -0
- package/dist/lib/evg/EVGEffectTest.rgr +253 -0
- package/dist/lib/evg/EVGElement.rgr +4914 -0
- package/dist/lib/evg/EVGFixedTest.rgr +289 -0
- package/dist/lib/evg/EVGFlexRulesTest.rgr +317 -0
- package/dist/lib/evg/EVGFlexWrapTest.rgr +246 -0
- package/dist/lib/evg/EVGFling.rgr +244 -0
- package/dist/lib/evg/EVGFocus.rgr +400 -0
- package/dist/lib/evg/EVGFocusTest.rgr +399 -0
- package/dist/lib/evg/EVGGradient.rgr +322 -0
- package/dist/lib/evg/EVGGrapheme.rgr +190 -0
- package/dist/lib/evg/EVGGrid.rgr +975 -0
- package/dist/lib/evg/EVGHitTest.rgr +208 -0
- package/dist/lib/evg/EVGHoles.rgr +294 -0
- package/dist/lib/evg/EVGHostMeasurerTest.rgr +281 -0
- package/dist/lib/evg/EVGHostTextMeasurer.rgr +331 -0
- package/dist/lib/evg/EVGHostTree.rgr +834 -0
- package/dist/lib/evg/EVGHostTreeTest.rgr +447 -0
- package/dist/lib/evg/EVGImageDecode.rgr +117 -0
- package/dist/lib/evg/EVGImageMeasurer.rgr +86 -0
- package/dist/lib/evg/EVGInspect.rgr +883 -0
- package/dist/lib/evg/EVGInvalidateTest.rgr +432 -0
- package/dist/lib/evg/EVGJsonTest.rgr +535 -0
- package/dist/lib/evg/EVGLayout.rgr +4220 -0
- package/dist/lib/evg/EVGMeasure.rgr +1267 -0
- package/dist/lib/evg/EVGOverlayTest.rgr +626 -0
- package/dist/lib/evg/EVGPatch.rgr +1721 -0
- package/dist/lib/evg/EVGPatchTest.rgr +692 -0
- package/dist/lib/evg/EVGPopoverTest.rgr +395 -0
- package/dist/lib/evg/EVGReconcile.rgr +226 -0
- package/dist/lib/evg/EVGReconcileTest.rgr +421 -0
- package/dist/lib/evg/EVGReject.rgr +126 -0
- package/dist/lib/evg/EVGRelayoutTest.rgr +375 -0
- package/dist/lib/evg/EVGRtlLayoutTest.rgr +319 -0
- package/dist/lib/evg/EVGRuler.rgr +232 -0
- package/dist/lib/evg/EVGRulerTest.rgr +172 -0
- package/dist/lib/evg/EVGSelectChrome.rgr +178 -0
- package/dist/lib/evg/EVGStyleCacheTest.rgr +419 -0
- package/dist/lib/evg/EVGStyleSheet.rgr +2148 -0
- package/dist/lib/evg/EVGStyleStateTest.rgr +407 -0
- package/dist/lib/evg/EVGStyleVarTest.rgr +471 -0
- package/dist/lib/evg/EVGText.rgr +105 -0
- package/dist/lib/evg/EVGTextEngine.rgr +536 -0
- package/dist/lib/evg/EVGTextMeasurer.rgr +720 -0
- package/dist/lib/evg/EVGTimingTest.rgr +1417 -0
- package/dist/lib/evg/EVGToolbar.rgr +1369 -0
- package/dist/lib/evg/EVGTransition.rgr +728 -0
- package/dist/lib/evg/EVGTreeJson.rgr +721 -0
- package/dist/lib/evg/EVGUnit.rgr +554 -0
- package/dist/lib/evg/EVGViewportUnitTest.rgr +236 -0
- package/dist/lib/evg/EvgApp.rgr +189 -0
- package/dist/lib/evg/EvgBitmapTracer.rgr +4277 -0
- package/dist/lib/evg/EvgBitmapTracerTest.rgr +2119 -0
- package/dist/lib/evg/EvgHost.rgr +451 -0
- package/dist/lib/evg/EvgTest.rgr +91 -0
- package/dist/lib/evg/EvgTraceColor.rgr +236 -0
- package/dist/lib/evg/EvgTraceCurve.rgr +648 -0
- package/dist/lib/evg/EvgTraceFit.rgr +767 -0
- package/dist/lib/evg/EvgTracePath.rgr +435 -0
- package/dist/lib/evg/EvgTraceTypes.rgr +559 -0
- package/dist/lib/evg/EvgViewport.rgr +313 -0
- package/dist/lib/evg/FxDemoDoc.rgr +185 -0
- package/dist/lib/evg/HOSTS.md +227 -0
- package/dist/lib/evg/ISSUES.md +835 -0
- package/dist/lib/evg/PLAN_ACCESSIBILITY.md +650 -0
- package/dist/lib/evg/PLAN_CSS_LAYOUT_AND_FONTS.md +1124 -0
- package/dist/lib/evg/PLAN_EFFECTS.md +431 -0
- package/dist/lib/evg/PLAN_EVG.md +518 -0
- package/dist/lib/evg/PLAN_EVG_RENDERER.md +1674 -0
- package/dist/lib/evg/PLAN_INSPECTOR.md +788 -0
- package/dist/lib/evg/PLAN_LINKS_AND_FORMS.md +157 -0
- package/dist/lib/evg/PLAN_NATIVE_HOSTS.md +671 -0
- package/dist/lib/evg/PLAN_VECTOR_IR.md +664 -0
- package/dist/lib/evg/PLAN_VIEW_TRANSFORM.md +322 -0
- package/dist/lib/evg/PathBuilder.rgr +333 -0
- package/dist/lib/evg/README.md +1236 -0
- package/dist/lib/evg/SPEC.md +1252 -0
- package/dist/lib/evg/SVGPathParser.rgr +1199 -0
- package/dist/lib/evg/SvgParser.rgr +1736 -0
- package/dist/lib/evg/TODO_EVG_RENDERER.md +595 -0
- package/dist/lib/evg/VectorShapes.rgr +331 -0
- package/dist/lib/evg/VectorStroke.rgr +107 -0
- package/dist/lib/evg/VectorViewBox.rgr +380 -0
- package/dist/lib/evg/agent/README.md +290 -0
- package/dist/lib/evg/agent/evg_agent.rgr +899 -0
- package/dist/lib/evg/agent/fixtures/broken.evg.json +7 -0
- package/dist/lib/evg/agent/fixtures/card.evg.json +9 -0
- package/dist/lib/evg/agent/fixtures/connector.css +63 -0
- package/dist/lib/evg/agent/fixtures/connector.evg.json +14 -0
- package/dist/lib/evg/agent/fixtures/drawn.evg.json +129 -0
- package/dist/lib/evg/agent/fixtures/gradient.evg.json +4 -0
- package/dist/lib/evg/agent/fixtures/popover.css +99 -0
- package/dist/lib/evg/agent/fixtures/popover.evg.json +30 -0
- package/dist/lib/evg/agent/roundtrip.sh +74 -0
- package/dist/lib/evg/agent/smoke.sh +230 -0
- package/dist/lib/evg/android/README.md +97 -0
- package/dist/lib/evg/android/androidstubs/AndroidStubs.kt +175 -0
- package/dist/lib/evg/android/androidstubs/Annotation.kt +10 -0
- package/dist/lib/evg/android/androidstubs/App.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Content.kt +41 -0
- package/dist/lib/evg/android/androidstubs/ContentRes.kt +12 -0
- package/dist/lib/evg/android/androidstubs/InputMethod.kt +46 -0
- package/dist/lib/evg/android/androidstubs/Net.kt +6 -0
- package/dist/lib/evg/android/androidstubs/Os.kt +30 -0
- package/dist/lib/evg/android/androidstubs/Util.kt +15 -0
- package/dist/lib/evg/android/androidstubs/View.kt +113 -0
- package/dist/lib/evg/android/androidstubs/Widget.kt +16 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidEvgSurface.kt +323 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/AndroidTextMeasurer.kt +56 -0
- package/dist/lib/evg/android/src/android/kotlin/fi/ranger/evg/RippleEffect.kt +262 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtEvgSurface.kt +238 -0
- package/dist/lib/evg/android/src/awt/kotlin/fi/ranger/evg/AwtTextMeasurer.kt +85 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgEngineThread.kt +115 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgPainter.kt +231 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/EvgSurface.kt +117 -0
- package/dist/lib/evg/android/src/main/kotlin/fi/ranger/evg/RecordingSurface.kt +94 -0
- package/dist/lib/evg/apple/README.md +128 -0
- package/dist/lib/evg/apple/Sources/CoreGraphicsEvgSurface.swift +329 -0
- package/dist/lib/evg/apple/Sources/CoreTextMeasurer.swift +70 -0
- package/dist/lib/evg/apple/Sources/EvgEngineQueue.swift +105 -0
- package/dist/lib/evg/apple/Sources/EvgPainter.swift +225 -0
- package/dist/lib/evg/apple/Sources/EvgSurface.swift +163 -0
- package/dist/lib/evg/apple/Sources/RecordingSurface.swift +110 -0
- package/dist/lib/evg/bench/EvgLayoutBench.rgr +34 -0
- package/dist/lib/evg/bench/README.md +64 -0
- package/dist/lib/evg/bench/layout-bench.mjs +316 -0
- package/dist/lib/evg/bench/layout-cases.mjs +510 -0
- package/dist/lib/evg/bench/layout-conformance.mjs +254 -0
- package/dist/lib/evg/bin/.gitignore +17 -0
- package/dist/lib/evg/evg_test.rgr +313 -0
- package/dist/lib/evg/gl/README.md +198 -0
- package/dist/lib/evg/gl/a11y-paint-check.mjs +73 -0
- package/dist/lib/evg/gl/blur-check.mjs +399 -0
- package/dist/lib/evg/gl/boxmodel.json +1 -0
- package/dist/lib/evg/gl/demo.html +46 -0
- package/dist/lib/evg/gl/effect-presets.css +285 -0
- package/dist/lib/evg/gl/effect-presets.js +63 -0
- package/dist/lib/evg/gl/effect-shots.mjs +135 -0
- package/dist/lib/evg/gl/evg-a11y.js +566 -0
- package/dist/lib/evg/gl/evg-binary.js +160 -0
- package/dist/lib/evg/gl/evg-engine.js +296 -0
- package/dist/lib/evg/gl/evg-fx.js +237 -0
- package/dist/lib/evg/gl/evg-gestures.js +209 -0
- package/dist/lib/evg/gl/evg-list.js +167 -0
- package/dist/lib/evg/gl/evg-measure.js +186 -0
- package/dist/lib/evg/gl/evg-textinput.js +303 -0
- package/dist/lib/evg/gl/evg-view.js +144 -0
- package/dist/lib/evg/gl/evg-webgl.js +3942 -0
- package/dist/lib/evg/gl/fx-check.mjs +998 -0
- package/dist/lib/evg/gl/fx-demo.html +166 -0
- package/dist/lib/evg/gl/fx-demo.js +2 -0
- package/dist/lib/evg/gl/fx-serve.mjs +47 -0
- package/dist/lib/evg/gl/gestures-check.mjs +189 -0
- package/dist/lib/evg/gl/list-binary-check.mjs +152 -0
- package/dist/lib/evg/gl/measure-check.mjs +135 -0
- package/dist/lib/evg/gl/rotation-check.mjs +207 -0
- package/dist/lib/evg/gl/shift-check.mjs +113 -0
- package/dist/lib/evg/gl/stroke-check.mjs +168 -0
- package/dist/lib/evg/gl/text-snap-check.mjs +139 -0
- package/dist/lib/evg/gl/view-check.mjs +343 -0
- package/dist/lib/evg/gl/view-policy-check.mjs +184 -0
- package/dist/lib/evg/html/evg-dom.js +318 -0
- package/dist/lib/evg/html/evg-html.js +600 -0
- package/dist/lib/evg/inspect/README.md +415 -0
- package/dist/lib/evg/inspect/browser-smoke.mjs +115 -0
- package/dist/lib/evg/inspect/evg-inspect.js +947 -0
- package/dist/lib/evg/inspect/shots/css.png +0 -0
- package/dist/lib/evg/inspect/shots/dashboard.png +0 -0
- package/dist/lib/evg/inspect/shots/pptx-slide.png +0 -0
- package/dist/lib/evg/inspect/shots/state.png +0 -0
- package/dist/lib/evg/inspect/shots.mjs +226 -0
- package/dist/lib/evg/oracle/css-blur.json +576 -0
- package/dist/lib/evg/oracle/css-box.json +157 -0
- package/dist/lib/evg/oracle/css-timing.json +709 -0
- package/dist/lib/evg/oracle/css_blur_oracle.mjs +529 -0
- package/dist/lib/evg/oracle/css_box_oracle.mjs +106 -0
- package/dist/lib/evg/oracle/css_timing_oracle.mjs +389 -0
- package/dist/lib/evg/original/EVGColor.clj +310 -0
- package/dist/lib/evg/original/EVGColorContext.rgr +178 -0
- package/dist/lib/evg/original/SVGPath.rgr +627 -0
- package/dist/lib/evg/original/Vec2.crgr +103 -0
- package/dist/lib/evg/ranger.json +9 -0
- package/dist/lib/evg/showcase/README.md +246 -0
- package/dist/lib/evg/showcase/assets/emblem.svg +30 -0
- package/dist/lib/evg/showcase/assets/rosette.svg +22 -0
- package/dist/lib/evg/showcase/build.mjs +651 -0
- package/dist/lib/evg/showcase/pages/album.tsx +30 -0
- package/dist/lib/evg/showcase/pages/boxmodel.tsx +37 -0
- package/dist/lib/evg/showcase/pages/cards.tsx +41 -0
- package/dist/lib/evg/showcase/pages/chart_api.tsx +170 -0
- package/dist/lib/evg/showcase/pages/charts.tsx +219 -0
- package/dist/lib/evg/showcase/pages/drawing.tsx +160 -0
- package/dist/lib/evg/showcase/pages/emoji.tsx +91 -0
- package/dist/lib/evg/showcase/pages/flex.tsx +46 -0
- package/dist/lib/evg/showcase/pages/more.tsx +332 -0
- package/dist/lib/evg/showcase/pages/plots.tsx +262 -0
- package/dist/lib/evg/showcase/pages/svg.tsx +63 -0
- package/dist/lib/evg/showcase/pages/tables.tsx +209 -0
- package/dist/lib/evg/showcase/pages/typography.tsx +43 -0
- package/dist/lib/evg/showcase/pages/units.tsx +35 -0
- package/dist/lib/evg/showcase/pages/variants.tsx +233 -0
- package/dist/lib/evg/showcase/pages/vector.tsx +75 -0
- package/dist/lib/evg/showcase/pages/views.tsx +223 -0
- package/dist/lib/evg/showcase/tests/chart_api_smoke.mjs +339 -0
- package/dist/lib/evg/showcase/tests/gl_smoke.mjs +125 -0
- package/dist/lib/evg/showcase/themes/chart_api-default.css +15 -0
- package/dist/lib/evg/showcase/themes/charts-default.css +29 -0
- package/dist/lib/evg/showcase/themes/drawing-default.css +35 -0
- package/dist/lib/evg/showcase/themes/more-default.css +128 -0
- package/dist/lib/evg/showcase/themes/plots-default.css +18 -0
- package/dist/lib/evg/showcase/themes/showcase.css +508 -0
- package/dist/lib/evg/showcase/themes/tables-default.css +123 -0
- package/dist/lib/evg/showcase/themes/variants-default.css +15 -0
- package/dist/lib/evg/showcase/themes/views-default.css +15 -0
- package/dist/lib/evg/tools/bench_vs_potrace.mjs +290 -0
- package/dist/lib/evg/tools/evg_image_tool.rgr +488 -0
- package/dist/lib/evg/tools/evg_trace_bench.rgr +114 -0
- package/dist/lib/evg/tools/evg_trace_cli.rgr +662 -0
- package/dist/lib/evg/tools/evg_trace_cpp_bench.rgr +83 -0
- package/dist/lib/evg/tools/run_trace_bench.sh +74 -0
- package/dist/lib/evg/tools/run_trace_cli_smoke.sh +128 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveCheck.rgr +271 -0
- package/dist/lib/evg/web/responsive/EvgResponsiveDemo.rgr +531 -0
- package/dist/lib/evg/web/responsive/README.md +97 -0
- package/dist/lib/evg/web/responsive/build.mjs +90 -0
- package/dist/lib/evg/web/responsive/dom-check.mjs +169 -0
- package/dist/lib/evg/web/responsive/index.html +177 -0
- package/dist/lib/evg/web/responsive/smoke.mjs +221 -0
- package/dist/lib/evg/web/tools/assets-client.mjs +95 -0
- package/dist/lib/evg/web/tools/boot-bench.mjs +189 -0
- package/dist/lib/evg/web/tools/inline-assets.mjs +119 -0
- package/dist/lib/evg/web/tools/minify.mjs +60 -0
- package/dist/lib/evg/web/tracer/build.mjs +87 -0
- package/dist/lib/evg/web/tracer/index.html +2805 -0
- package/dist/lib/evg/web/tracer/sample.png +0 -0
- package/dist/lib/evg/web/tracer/smoke.mjs +1162 -0
- package/dist/lib/evgr/Cargo.lock +21 -0
- package/dist/lib/evgr/Cargo.toml +19 -0
- package/dist/lib/evgr/README.md +140 -0
- package/dist/lib/evgr/bench/NativeBench.rgr +246 -0
- package/dist/lib/evgr/bench/compare.mjs +252 -0
- package/dist/lib/evgr/bench/speed.mjs +277 -0
- package/dist/lib/evgr/bin/.gitignore +3 -0
- package/dist/lib/evgr/src/bin/bench.rs +106 -0
- package/dist/lib/evgr/src/bin/smoke.rs +13 -0
- package/dist/lib/evgr/src/grid.rs +730 -0
- package/dist/lib/evgr/src/lib.rs +1003 -0
- package/dist/lib/evgr/src/style.rs +468 -0
- package/dist/lib/evgr/src/text.rs +83 -0
- package/dist/lib/image/BitReader.rgr +171 -0
- package/dist/lib/image/Buffer.rgr +173 -0
- package/dist/lib/image/DCT.rgr +283 -0
- package/dist/lib/image/Deflate.rgr +339 -0
- package/dist/lib/image/HuffmanDecoder.rgr +181 -0
- package/dist/lib/image/ImageBuffer.rgr +706 -0
- package/dist/lib/image/JPEGDecoder.rgr +808 -0
- package/dist/lib/image/PNGDecoder.rgr +544 -0
- package/dist/lib/image/PNGEncoder.rgr +388 -0
- package/dist/lib/image/PPMImage.rgr +224 -0
- package/dist/lib/image/ProgressiveJPEGDecoder.rgr +1154 -0
- package/dist/lib/image/README.md +33 -0
- package/dist/lib/image/RasterBuffer.rgr +294 -0
- package/dist/lib/image/VP8BoolDecoder.rgr +163 -0
- package/dist/lib/image/WebPDecoder.rgr +433 -0
- package/dist/lib/image/WebPLossless.rgr +1035 -0
- package/dist/lib/image/WebPLossy.rgr +1929 -0
- package/dist/lib/image/ranger.json +9 -0
- package/dist/lib/image/testdata/webp/anim_2f_24x16.webp +0 -0
- package/dist/lib/image/testdata/webp/fixtures.txt +33 -0
- package/dist/lib/image/testdata/webp/gen_fixtures.py +261 -0
- package/dist/lib/image/testdata/webp/ll_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_alpha_29x21.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_gradient_64x64.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_meta_32x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_noise_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal11_23x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal2_19x7.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal40_16x16.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_pal4_13x5.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_photo_40x30.webp +0 -0
- package/dist/lib/image/testdata/webp/ll_predictors_64x32.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_1x1.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_raw_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f0_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f1_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f2_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alph_vp8l_f3_21x13.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_alpha_33x17.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_exif_15x11.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_i16_96x80.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_nofilter_24x20.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_odd_17x9.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_photo_48x40.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_q100_20x18.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_sharp_40x36.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_simple_filter_33x31.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_parts8_37x45.webp +0 -0
- package/dist/lib/image/testdata/webp/ly_vpx_skip_96x80.webp +0 -0
- package/dist/lib/image/tests/WebPDecodeTool.rgr +81 -0
- package/dist/lib/image/tests/WebPDecoderTest.rgr +1162 -0
- package/dist/lib/image/tests/run_webp_tests.sh +39 -0
- package/dist/lib/rust/RsJson.rgr +468 -0
- package/dist/lib/rust/RsPrelude.rgr +1663 -0
- package/dist/lib/shell_test.rgr +7 -7
- package/dist/lib/stdlib.rgr +21 -5
- package/dist/lib/zip/ranger.json +6 -0
- package/dist/rgrc.js +87318 -67610
- package/package.json +1010 -1040
- package/dist/README.md +0 -117
- package/dist/package.json +0 -47
package/dist/Lang.rgr
CHANGED
|
@@ -1290,7 +1290,7 @@ func rg_sha256_hex(_ input: String) -> String {
|
|
|
1290
1290
|
llvm ( nl "nullify " (e 1) nl)
|
|
1291
1291
|
es6 ( (e 1) " = undefined;" nl)
|
|
1292
1292
|
java7 ( (e 1) " = null;" nl)
|
|
1293
|
-
cpp ( (e 1) "=
|
|
1293
|
+
cpp ( (e 1) " = std::nullopt;" nl (imp "<optional>"))
|
|
1294
1294
|
; Optionals ride a *GoNullable wrapper the constructor
|
|
1295
1295
|
; allocates once; clearing means emptying the wrapper, never
|
|
1296
1296
|
; nilling the wrapper pointer itself -- readers dereference it.
|
|
@@ -1513,7 +1513,19 @@ func r_io_get_env( name string) *GoNullable {
|
|
|
1513
1513
|
; optional this operator returns
|
|
1514
1514
|
python ( "os.environ.get(" (e 1) ")" (imp "os") )
|
|
1515
1515
|
dart ( "Platform.environment[" (e 1) "]" (imp "dart:io") )
|
|
1516
|
-
|
|
1516
|
+
; same story as read_file: the operator is optional and Python
|
|
1517
|
+
; already answers None for a name that is not set. C++ handed
|
|
1518
|
+
; back the empty string for unset and for set-to-empty alike.
|
|
1519
|
+
cpp ( "r_cpp_env_var(" (e 1) ")" (imp "<cstdlib>") (imp "<optional>")
|
|
1520
|
+
(create_polyfill "
|
|
1521
|
+
inline std::optional<std::string> r_cpp_env_var(const std::string& name) {
|
|
1522
|
+
std::optional<std::string> res;
|
|
1523
|
+
const char* v = std::getenv(name.c_str());
|
|
1524
|
+
if (v) { res = std::string(v); }
|
|
1525
|
+
return res;
|
|
1526
|
+
}
|
|
1527
|
+
")
|
|
1528
|
+
)
|
|
1517
1529
|
; * ("/* environment variable reading not implemented */")
|
|
1518
1530
|
}
|
|
1519
1531
|
}
|
|
@@ -1524,7 +1536,11 @@ func r_io_get_env( name string) *GoNullable {
|
|
|
1524
1536
|
llvm ( "(shell_arg " (e 1) ")")
|
|
1525
1537
|
cpp ( "std::string(__g_argv[" (e 1) " + 1])")
|
|
1526
1538
|
php ( "$argv[" (e 1) " + 1]" )
|
|
1527
|
-
|
|
1539
|
+
; `args` is in scope only inside main on Java, and a class
|
|
1540
|
+
; method that reads the command line is not. main copies it
|
|
1541
|
+
; into a static holder the writer emits (RgArgs.java), the
|
|
1542
|
+
; same shape as __g_args on Kotlin and Dart.
|
|
1543
|
+
java7 ( "RgArgs.args[" (e 1) "]")
|
|
1528
1544
|
csharp ('Environment.GetCommandLineArgs()[' (e 1) ' + 1]' (imp "System"))
|
|
1529
1545
|
go ( "os.Args[" (e 1) " + 1]" (imp "os"))
|
|
1530
1546
|
swift3 ("CommandLine.arguments[" (e 1) " + 1]")
|
|
@@ -1552,7 +1568,7 @@ func r_io_get_env( name string) *GoNullable {
|
|
|
1552
1568
|
swift6 ("CommandLine.arguments.count - 1")
|
|
1553
1569
|
csharp ('Environment.GetCommandLineArgs().Length - 1' (imp "System"))
|
|
1554
1570
|
php ( "(count($argv) - 1)" )
|
|
1555
|
-
java7 ( "args.length")
|
|
1571
|
+
java7 ( "RgArgs.args.length")
|
|
1556
1572
|
go ( "int64( len( os.Args) - 1 )" (imp "os"))
|
|
1557
1573
|
es6 ( "(process.argv.length - 2)" )
|
|
1558
1574
|
rust ( "(std::env::args().len() as i64 - 1)")
|
|
@@ -3231,7 +3247,7 @@ func r_file_exists ( fileName:String ) -> Bool {
|
|
|
3231
3247
|
}
|
|
3232
3248
|
")
|
|
3233
3249
|
)
|
|
3234
|
-
es6 ("require(\"fs\").existsSync(" (e 1) "
|
|
3250
|
+
es6 ("require(\"fs\").existsSync( require(\"path\").join(" (e 1) ", " (e 2) ") )")
|
|
3235
3251
|
python ( "os.path.isfile(" (e 1) " + \"/\" + " (e 2) ")" (imp "os") )
|
|
3236
3252
|
ranger ("( file_exists " (e 1) " + \"/\" + " (e 2) " )")
|
|
3237
3253
|
java7 ( "new File(" (e 1) " + '/' + " (e 2) ").exists()" (imp "java.io.File") )
|
|
@@ -3379,7 +3395,7 @@ func r_file_mtime(pathName string, fileName string) int64 {
|
|
|
3379
3395
|
"
|
|
3380
3396
|
)
|
|
3381
3397
|
)
|
|
3382
|
-
es6 ( "require('fs').statSync(" (e 1) "
|
|
3398
|
+
es6 ( "require('fs').statSync( require('path').join(" (e 1) ", " (e 2) ") ).mtimeMs" )
|
|
3383
3399
|
cpp ( "r_file_mtime(" (e 1) ", " (e 2) ")" (imp "<sys/stat.h>") (imp "<string>")
|
|
3384
3400
|
(create_polyfill "
|
|
3385
3401
|
int64_t r_file_mtime(const std::string& path, const std::string& filename) {
|
|
@@ -3448,7 +3464,7 @@ func r_file_mtime ( path:String, name:String ) -> Int {
|
|
|
3448
3464
|
python ( "int(os.path.getmtime(" (e 1) " + \"/\" + " (e 2) ") * 1000)" (imp "os") )
|
|
3449
3465
|
java7 ( "((int)(new File(" (e 1) " + \"/\" + " (e 2) ").lastModified()))" (imp "java.io.File") )
|
|
3450
3466
|
csharp ( "((int)(long)(System.IO.File.GetLastWriteTimeUtc(" (e 1) " + \"/\" + " (e 2) ") - new System.DateTime(1970, 1, 1)).TotalMilliseconds)" )
|
|
3451
|
-
scala ( "new java.io.File(" (e 1) " + \"/\" + " (e 2) ").lastModified().toInt
|
|
3467
|
+
scala ( "new java.io.File(" (e 1) " + \"/\" + " (e 2) ").lastModified().toInt" )
|
|
3452
3468
|
php ( "(filemtime(" (e 1) ".'/'." (e 2) ") * 1000)" )
|
|
3453
3469
|
ranger ( "(file_mtime " (e 1) " " (e 2) ")" )
|
|
3454
3470
|
dart ( (imp "dart:io") "(() { try { return File((" (e 1) ") + \"/\" + (" (e 2) ")).lastModifiedSync().millisecondsSinceEpoch; } catch (_) { return 0; } })()" )
|
|
@@ -3490,6 +3506,14 @@ fn r_wall_clock_ms() -> f64 {
|
|
|
3490
3506
|
csharp ( "(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds" )
|
|
3491
3507
|
kotlin ( "System.currentTimeMillis().toDouble()" )
|
|
3492
3508
|
java7 ( "((double)System.currentTimeMillis())" )
|
|
3509
|
+
php ( "(microtime(true) * 1000.0)" )
|
|
3510
|
+
dart ( "(DateTime.now().microsecondsSinceEpoch / 1000.0)" )
|
|
3511
|
+
scala ( "(System.currentTimeMillis().toDouble)" )
|
|
3512
|
+
swift3 ( "(Date().timeIntervalSince1970 * 1000.0)" (imp "Foundation") )
|
|
3513
|
+
swift6 ( "(Date().timeIntervalSince1970 * 1000.0)" (imp "Foundation") )
|
|
3514
|
+
; `*` is 0.0: a target with no clock reports every duration as
|
|
3515
|
+
; zero rather than refusing to compile, which is what a program
|
|
3516
|
+
; that only prints a timing wants.
|
|
3493
3517
|
* ( "0.0" )
|
|
3494
3518
|
}
|
|
3495
3519
|
}
|
|
@@ -3768,7 +3792,7 @@ fn r_write_file(path: &str, filename: &str, data: &str) {
|
|
|
3768
3792
|
|
|
3769
3793
|
async_read_file _@(optional async):string (path:string filename:string) {
|
|
3770
3794
|
templates {
|
|
3771
|
-
es6 @flags('typescript') ( "await (new Promise<string>(resolve => { require('fs').readFile( " (e 1) "
|
|
3795
|
+
es6 @flags('typescript') ( "await (new Promise<string>(resolve => { require('fs').readFile( require('path').join(" (e 1) ", " (e 2) ") , 'utf8', (err,data)=>{ resolve(data) }) } ))" )
|
|
3772
3796
|
es6 ( "await (new Promise(resolve => { require('fs').readFile( " (e 1) " + '/' + " (e 2) " , 'utf8', (err,data)=>{ resolve(data) }) } ))" )
|
|
3773
3797
|
}
|
|
3774
3798
|
}
|
|
@@ -3777,8 +3801,8 @@ fn r_write_file(path: &str, filename: &str, data: &str) {
|
|
|
3777
3801
|
|
|
3778
3802
|
templates {
|
|
3779
3803
|
llvm ( "(read_file " (e 1) " " (e 2) ")")
|
|
3780
|
-
ts ( "await (new Promise<string>(resolve => { require('fs').readFile( " (e 1) "
|
|
3781
|
-
es6 ( "await (new Promise(resolve => { require('fs').readFile( " (e 1) "
|
|
3804
|
+
ts ( "await (new Promise<string>(resolve => { require('fs').readFile( require('path').join(" (e 1) ", " (e 2) ") , 'utf8', (err,data)=>{ resolve(data) }) } ))" )
|
|
3805
|
+
es6 ( "await (new Promise(resolve => { require('fs').readFile( require('path').join(" (e 1) ", " (e 2) ") , 'utf8', (err,data)=>{ resolve(data) }) } ))" )
|
|
3782
3806
|
ranger ( "(read_file " (e 1) " " (e 2) ")" )
|
|
3783
3807
|
; returns the optional: None is how Python spells absent, which
|
|
3784
3808
|
; is what a missing or unreadable file has to answer
|
|
@@ -3792,17 +3816,186 @@ def rg_read_file(path, filename):
|
|
|
3792
3816
|
return None
|
|
3793
3817
|
")
|
|
3794
3818
|
)
|
|
3819
|
+
; read_file is declared optional, and Python already answers
|
|
3820
|
+
; None for a file it cannot read. C++ used to hand back the
|
|
3821
|
+
; empty string for both a missing file and an empty one.
|
|
3795
3822
|
cpp ( "r_cpp_readFile( " (e 1) " , " (e 2) ")" (imp "<fstream>")
|
|
3823
|
+
|
|
3796
3824
|
(create_polyfill "
|
|
3797
|
-
std::string r_cpp_readFile(const std::string& path, const std::string& filename)
|
|
3825
|
+
std::optional<std::string> r_cpp_readFile(const std::string& path, const std::string& filename)
|
|
3798
3826
|
{
|
|
3827
|
+
std::optional<std::string> res;
|
|
3799
3828
|
std::ifstream ifs(path + \"/\" + filename);
|
|
3829
|
+
if (!ifs) { return res; }
|
|
3800
3830
|
std::string content( (std::istreambuf_iterator<char>(ifs) ),
|
|
3801
3831
|
(std::istreambuf_iterator<char>() ) );
|
|
3802
|
-
|
|
3832
|
+
res = content;
|
|
3833
|
+
return res;
|
|
3834
|
+
}
|
|
3835
|
+
")
|
|
3836
|
+
|
|
3837
|
+
)
|
|
3838
|
+
php ("file_get_contents(" (e 1) " . \"/\" . " (e 2) ") " )
|
|
3839
|
+
swift3 ("r_read_file(dirName: " (e 1) " + \"/\" + " (e 2) ") "
|
|
3840
|
+
(create_polyfill "
|
|
3841
|
+
func r_read_file ( dirName:String ) -> String? {
|
|
3842
|
+
let res: String?
|
|
3843
|
+
do {
|
|
3844
|
+
res = try String(contentsOfFile:dirName)
|
|
3845
|
+
} catch {
|
|
3846
|
+
res = nil
|
|
3847
|
+
}
|
|
3848
|
+
return res
|
|
3849
|
+
}
|
|
3850
|
+
")
|
|
3851
|
+
)
|
|
3852
|
+
swift6 ("r_read_file(dirName: " (e 1) " + \"/\" + " (e 2) ") "
|
|
3853
|
+
(imp "Foundation")
|
|
3854
|
+
(create_polyfill "
|
|
3855
|
+
func r_read_file ( dirName:String ) -> String? {
|
|
3856
|
+
let res: String?
|
|
3857
|
+
do {
|
|
3858
|
+
res = try String(contentsOfFile:dirName, encoding: .utf8)
|
|
3859
|
+
} catch let error {
|
|
3860
|
+
print(\"Error reading file: \\(dirName)\")
|
|
3861
|
+
print(\"Error: \\(error.localizedDescription)\")
|
|
3862
|
+
res = nil
|
|
3863
|
+
}
|
|
3864
|
+
return res
|
|
3865
|
+
}
|
|
3866
|
+
")
|
|
3867
|
+
)
|
|
3868
|
+
java7 ( "readFile(" (e 1) " + \"/\" + " (e 2) " , StandardCharsets.UTF_8 )"
|
|
3869
|
+
(imp "java.nio.file.Paths")
|
|
3870
|
+
(imp "java.io.File")
|
|
3871
|
+
(imp "java.nio.file.Files")
|
|
3872
|
+
(imp 'java.io.IOException')
|
|
3873
|
+
(imp "java.nio.charset.Charset")
|
|
3874
|
+
(imp "java.nio.charset.StandardCharsets")
|
|
3875
|
+
(create_polyfill "
|
|
3876
|
+
static String readFile(String path, Charset encoding)
|
|
3877
|
+
{
|
|
3878
|
+
try {
|
|
3879
|
+
byte[] encoded = Files.readAllBytes(Paths.get(path));
|
|
3880
|
+
return new String(encoded, encoding);
|
|
3881
|
+
} catch(IOException e) {
|
|
3882
|
+
return \"\";
|
|
3883
|
+
}
|
|
3803
3884
|
}
|
|
3804
3885
|
")
|
|
3805
|
-
|
|
3886
|
+
|
|
3887
|
+
)
|
|
3888
|
+
scala ( "Try(Source.fromFile(" (e 1) " + \"/\" + " (e 2) ").getLines.mkString).toOption" (imp "scala.io.Source") (imp "scala.util.Try"))
|
|
3889
|
+
go ( "r_io_read_file(" (e 1) ", " (e 2) ")" (imp "io/ioutil")
|
|
3890
|
+
(create_polyfill "
|
|
3891
|
+
|
|
3892
|
+
// polyfill for reading files
|
|
3893
|
+
func r_io_read_file( path string , fileName string ) *GoNullable {
|
|
3894
|
+
res := new(GoNullable);
|
|
3895
|
+
if v, err := ioutil.ReadFile(path + \"/\" + fileName); err == nil {
|
|
3896
|
+
res.has_value = true
|
|
3897
|
+
res.value = string(v)
|
|
3898
|
+
} else {
|
|
3899
|
+
res.has_value = false
|
|
3900
|
+
}
|
|
3901
|
+
return res
|
|
3902
|
+
}
|
|
3903
|
+
"))
|
|
3904
|
+
rust ( "r_read_file(&" (e 1) ", &" (e 2) ")"
|
|
3905
|
+
(create_polyfill "
|
|
3906
|
+
fn r_read_file(path: &str, filename: &str) -> Option<String> {
|
|
3907
|
+
let full_path = format!(\"{}/{}\", path, filename);
|
|
3908
|
+
std::fs::read_to_string(full_path).ok()
|
|
3909
|
+
}
|
|
3910
|
+
"))
|
|
3911
|
+
es6 ( "(require('fs').readFileSync( require('path').join(" (e 1) ", " (e 2) ") , 'utf8'))" )
|
|
3912
|
+
kotlin ( "try { java.io.File(if (" (e 1) ".isEmpty()) " (e 2) " else " (e 1) " + \"/\" + " (e 2) ").readText() } catch (_: Exception) { null }" (imp "java.io.File") )
|
|
3913
|
+
dart ( (imp "dart:io") "(() { try { final __p = (" (e 1) ").isEmpty ? (" (e 2) ") : ((" (e 1) ") + \"/\" + (" (e 2) ")); return File(__p).readAsStringSync(); } catch (_) { return null; } })()" )
|
|
3914
|
+
csharp ( "RgFiles.ReadFile(" (e 1) ", " (e 2) ")"
|
|
3915
|
+
(polyfill "after_imports" "
|
|
3916
|
+
// Files on the C# target. System.IO says all of this, but each operator needs
|
|
3917
|
+
// one expression and several need a try/catch, so they are wrapped here.
|
|
3918
|
+
static class RgFiles {
|
|
3919
|
+
static string Join(string path, string name) {
|
|
3920
|
+
if (path.Length == 0) { return name; }
|
|
3921
|
+
return path + \"/\" + name;
|
|
3922
|
+
}
|
|
3923
|
+
// The optional this operator returns: null is how C# spells absent, which is
|
|
3924
|
+
// what a missing or unreadable file has to answer.
|
|
3925
|
+
public static string ReadFile(string path, string name) {
|
|
3926
|
+
try {
|
|
3927
|
+
return System.IO.File.ReadAllText(Join(path, name), new System.Text.UTF8Encoding(false));
|
|
3928
|
+
} catch (System.Exception) {
|
|
3929
|
+
return null;
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
public static void WriteFile(string path, string name, string data) {
|
|
3933
|
+
string full = Join(path, name);
|
|
3934
|
+
string dir = System.IO.Path.GetDirectoryName(full);
|
|
3935
|
+
if (dir != null && dir.Length > 0) { System.IO.Directory.CreateDirectory(dir); }
|
|
3936
|
+
// No BOM: every other target writes plain UTF-8 and the compiler compares
|
|
3937
|
+
// its own output byte for byte.
|
|
3938
|
+
System.IO.File.WriteAllText(full, data, new System.Text.UTF8Encoding(false));
|
|
3939
|
+
}
|
|
3940
|
+
public static void CreateDir(string path) {
|
|
3941
|
+
try { System.IO.Directory.CreateDirectory(path); } catch (System.Exception) { }
|
|
3942
|
+
}
|
|
3943
|
+
public static bool DirExists(string path) {
|
|
3944
|
+
return System.IO.Directory.Exists(path);
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
")
|
|
3948
|
+
)
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
|
|
3952
|
+
; read_file, but not async on JavaScript. read_file awaits fs.readFile,
|
|
3953
|
+
; so on JavaScript every function that reads a file, and every function
|
|
3954
|
+
; that can reach one, is emitted async: in the compiler that was the
|
|
3955
|
+
; whole import, analysis and writer chain, and each call then paid for
|
|
3956
|
+
; a promise and a heap frame -- three seconds of a twelve second
|
|
3957
|
+
; compile, all of it garbage. This one reads with readFileSync and
|
|
3958
|
+
; answers absent on failure, as read_file does. The other targets read
|
|
3959
|
+
; synchronously either way and share read_file's polyfills, which the
|
|
3960
|
+
; writer emits once per text. Use it where blocking the event loop is
|
|
3961
|
+
; fine: a command line tool, not a server.
|
|
3962
|
+
read_file_sync cmdReadFileSync@(optional):string (path:string filename:string) {
|
|
3963
|
+
|
|
3964
|
+
templates {
|
|
3965
|
+
llvm ( "(read_file " (e 1) " " (e 2) ")")
|
|
3966
|
+
ts ( "(() => { try { return require('fs').readFileSync( require('path').join(" (e 1) ", " (e 2) ") , 'utf8'); } catch (e) { return undefined; } })()" )
|
|
3967
|
+
es6 ( "(() => { try { return require('fs').readFileSync( require('path').join(" (e 1) ", " (e 2) ") , 'utf8'); } catch (e) { return undefined; } })()" )
|
|
3968
|
+
ranger ( "(read_file " (e 1) " " (e 2) ")" )
|
|
3969
|
+
; returns the optional: None is how Python spells absent, which
|
|
3970
|
+
; is what a missing or unreadable file has to answer
|
|
3971
|
+
python ( "rg_read_file(" (e 1) ", " (e 2) ")" (imp "os")
|
|
3972
|
+
(create_polyfill "
|
|
3973
|
+
def rg_read_file(path, filename):
|
|
3974
|
+
try:
|
|
3975
|
+
with open(os.path.join(path, filename), \"r\", encoding=\"utf-8\") as f:
|
|
3976
|
+
return f.read()
|
|
3977
|
+
except Exception:
|
|
3978
|
+
return None
|
|
3979
|
+
")
|
|
3980
|
+
)
|
|
3981
|
+
; read_file is declared optional, and Python already answers
|
|
3982
|
+
; None for a file it cannot read. C++ used to hand back the
|
|
3983
|
+
; empty string for both a missing file and an empty one.
|
|
3984
|
+
cpp ( "r_cpp_readFile( " (e 1) " , " (e 2) ")" (imp "<fstream>")
|
|
3985
|
+
|
|
3986
|
+
(create_polyfill "
|
|
3987
|
+
std::optional<std::string> r_cpp_readFile(const std::string& path, const std::string& filename)
|
|
3988
|
+
{
|
|
3989
|
+
std::optional<std::string> res;
|
|
3990
|
+
std::ifstream ifs(path + \"/\" + filename);
|
|
3991
|
+
if (!ifs) { return res; }
|
|
3992
|
+
std::string content( (std::istreambuf_iterator<char>(ifs) ),
|
|
3993
|
+
(std::istreambuf_iterator<char>() ) );
|
|
3994
|
+
res = content;
|
|
3995
|
+
return res;
|
|
3996
|
+
}
|
|
3997
|
+
")
|
|
3998
|
+
|
|
3806
3999
|
)
|
|
3807
4000
|
php ("file_get_contents(" (e 1) " . \"/\" . " (e 2) ") " )
|
|
3808
4001
|
swift3 ("r_read_file(dirName: " (e 1) " + \"/\" + " (e 2) ") "
|
|
@@ -3877,7 +4070,6 @@ fn r_read_file(path: &str, filename: &str) -> Option<String> {
|
|
|
3877
4070
|
std::fs::read_to_string(full_path).ok()
|
|
3878
4071
|
}
|
|
3879
4072
|
"))
|
|
3880
|
-
es6 ( "(require('fs').readFileSync( " (e 1) " + '/' + " (e 2) " , 'utf8'))" )
|
|
3881
4073
|
kotlin ( "try { java.io.File(if (" (e 1) ".isEmpty()) " (e 2) " else " (e 1) " + \"/\" + " (e 2) ").readText() } catch (_: Exception) { null }" (imp "java.io.File") )
|
|
3882
4074
|
dart ( (imp "dart:io") "(() { try { final __p = (" (e 1) ").isEmpty ? (" (e 2) ") : ((" (e 1) ") + \"/\" + (" (e 2) ")); return File(__p).readAsStringSync(); } catch (_) { return null; } })()" )
|
|
3883
4075
|
csharp ( "RgFiles.ReadFile(" (e 1) ", " (e 2) ")"
|
|
@@ -4032,7 +4224,7 @@ static class RgFiles {
|
|
|
4032
4224
|
|
|
4033
4225
|
unwrap cmdUnwrap:int ( arg@(optional):int ) {
|
|
4034
4226
|
templates {
|
|
4035
|
-
cpp (
|
|
4227
|
+
cpp ( (e 1) ".value()" )
|
|
4036
4228
|
; an optional int is `int?` on C#, and Nullable<T> does not
|
|
4037
4229
|
; convert back to T on its own
|
|
4038
4230
|
csharp ( "(" (e 1) ").Value" )
|
|
@@ -4040,16 +4232,37 @@ static class RgFiles {
|
|
|
4040
4232
|
}
|
|
4041
4233
|
unwrap cmdUnwrap:double ( arg@(optional):double ) {
|
|
4042
4234
|
templates {
|
|
4043
|
-
cpp (
|
|
4235
|
+
cpp ( (e 1) ".value()" )
|
|
4044
4236
|
csharp ( "(" (e 1) ").Value" )
|
|
4045
4237
|
}
|
|
4046
4238
|
}
|
|
4239
|
+
; see the null? overload: an optional string carries its own presence
|
|
4240
|
+
; bit on C++, so reading the value out of one is not a no-op.
|
|
4241
|
+
unwrap cmdUnwrap:string ( arg@(optional):string ) {
|
|
4242
|
+
templates {
|
|
4243
|
+
cpp ( (e 1) ".value()" )
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4047
4246
|
; `bool?` is a Nullable<bool> like the two above, and `if (unwrap ok)`
|
|
4048
4247
|
; without the .Value does not compile. Only C# has an entry, so every
|
|
4049
4248
|
; other target keeps reaching the generic overload below.
|
|
4050
4249
|
unwrap cmdUnwrap:boolean ( arg@(optional):boolean ) {
|
|
4051
4250
|
templates {
|
|
4052
4251
|
csharp ( "(" (e 1) ").Value" )
|
|
4252
|
+
; an optional boolean VARIABLE is a bare `bool` on C++ (see
|
|
4253
|
+
; null?), but a map read (`get`) hands back std::optional<bool>
|
|
4254
|
+
cpp ( "rg_opt_bool(" (e 1) ")" (imp "<optional>") (create_polyfill "
|
|
4255
|
+
inline bool rg_opt_bool(bool b) { return b; }
|
|
4256
|
+
inline bool rg_opt_bool(const std::optional<bool> & b) { return b.value(); }
|
|
4257
|
+
") )
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
|
|
4261
|
+
; an optional charbuffer is a bare `const char*` on C++ (writeTypeDef
|
|
4262
|
+
; does not wrap it), so there is no optional to read the value out of
|
|
4263
|
+
unwrap cmdUnwrap:charbuffer ( arg@(optional):charbuffer ) {
|
|
4264
|
+
templates {
|
|
4265
|
+
cpp ( (e 1) )
|
|
4053
4266
|
}
|
|
4054
4267
|
}
|
|
4055
4268
|
|
|
@@ -4066,7 +4279,7 @@ static class RgFiles {
|
|
|
4066
4279
|
swift3 ( (e 1) "!" )
|
|
4067
4280
|
swift6 ( (e 1) "!" )
|
|
4068
4281
|
go ( (e 1) ".value.(" (typeof 1) ")" )
|
|
4069
|
-
cpp ( (e 1) )
|
|
4282
|
+
cpp ( (e 1) ".value()" )
|
|
4070
4283
|
|
|
4071
4284
|
* ( (e 1) )
|
|
4072
4285
|
}
|
|
@@ -4234,12 +4447,15 @@ static class RgFiles {
|
|
|
4234
4447
|
; An enum value is an int on every target, and Python does
|
|
4235
4448
|
; not concatenate an int onto a str.
|
|
4236
4449
|
python ( (e 1) " + str(" (e 2) ")" )
|
|
4237
|
-
|
|
4450
|
+
; the operand is parenthesised because `.toString()` binds
|
|
4451
|
+
; to the last TOKEN, not to the expression: `"" + i * 4`
|
|
4452
|
+
; came out as `"" + i * 4.toString()`, which is Int * String.
|
|
4453
|
+
kotlin ( (e 1) " + (" (e 2) ").toString()" )
|
|
4238
4454
|
; an enum is an int on Dart, and Dart has no String + int
|
|
4239
|
-
dart ( (e 1) " + " (e 2) ".toString()" )
|
|
4455
|
+
dart ( (e 1) " + (" (e 2) ").toString()" )
|
|
4240
4456
|
java7 ( (e 1) " + String.valueOf(" (e 2) ")" )
|
|
4241
|
-
csharp ( (e 1) " + " (e 2) ".ToString()" )
|
|
4242
|
-
scala ( (e 1) " + " (e 2) ".toString" )
|
|
4457
|
+
csharp ( (e 1) " + (" (e 2) ").ToString()" )
|
|
4458
|
+
scala ( (e 1) " + (" (e 2) ").toString" )
|
|
4243
4459
|
* ( (e 1) " + " (e 2) )
|
|
4244
4460
|
}
|
|
4245
4461
|
}
|
|
@@ -4265,8 +4481,8 @@ static class RgFiles {
|
|
|
4265
4481
|
rust ( (custom _) )
|
|
4266
4482
|
swift3 ( (e 1) " + String(" (e 2)")" )
|
|
4267
4483
|
swift6 ( (e 1) " + String(" (e 2)")" )
|
|
4268
|
-
kotlin ( (e 1) " + " (e 2)".toString()" )
|
|
4269
|
-
dart ( (e 1) " + " (e 2)".toString()" )
|
|
4484
|
+
kotlin ( (e 1) " + (" (e 2) ").toString()" )
|
|
4485
|
+
dart ( (e 1) " + (" (e 2) ").toString()" )
|
|
4270
4486
|
cpp ( (e 1 ) " + " "r_double_to_string(" (e 2) ")" (imp "<sstream>") (imp "<iomanip>") (imp "<string>") (imp "<cstdlib>")
|
|
4271
4487
|
(create_polyfill "
|
|
4272
4488
|
inline std::string r_double_to_string(double v) {
|
|
@@ -4298,8 +4514,8 @@ inline std::string r_double_to_string(double v) {
|
|
|
4298
4514
|
go ( "strings.Join([]string{ " (e 1) ",strconv.FormatInt(" (e 2) ", 10) }, \"\")" (imp "strings") (imp "strconv"))
|
|
4299
4515
|
swift3 ( (e 1) " + String(" (e 2)")" )
|
|
4300
4516
|
swift6 ( (e 1) " + String(" (e 2)")" )
|
|
4301
|
-
kotlin ( (e 1) " + " (e 2)".toString()" )
|
|
4302
|
-
dart ( (e 1) " + " (e 2)".toString()" )
|
|
4517
|
+
kotlin ( (e 1) " + (" (e 2) ").toString()" )
|
|
4518
|
+
dart ( (e 1) " + (" (e 2) ").toString()" )
|
|
4303
4519
|
rust ( (custom _) )
|
|
4304
4520
|
cpp ( (e 1 ) " + std::to_string(" (e 2) ")")
|
|
4305
4521
|
php ( (e 1) " . " (e 2) )
|
|
@@ -4323,7 +4539,10 @@ inline std::string r_double_to_string(double v) {
|
|
|
4323
4539
|
llvm ( "(idiv " (e 1) " " (e 2) ")" )
|
|
4324
4540
|
es6 ( "((" (e 1) " / " (e 2) ") | 0)" )
|
|
4325
4541
|
go ( (e 1) " / " (e 2) )
|
|
4326
|
-
|
|
4542
|
+
; (custom _): the template's own pair plus the one each
|
|
4543
|
+
; operand writes for itself gave `(((sum * pct)) / (100))`.
|
|
4544
|
+
; RustOperators writes it as `sum * pct / 100`.
|
|
4545
|
+
rust ( (custom _) )
|
|
4327
4546
|
kotlin ( (e 1) " / " (e 2) )
|
|
4328
4547
|
dart ( "((" (e 1) ") ~/ (" (e 2) "))" )
|
|
4329
4548
|
python ( "((" (e 1) ") // (" (e 2) "))" )
|
|
@@ -4462,8 +4681,8 @@ inline std::string r_double_to_string(double v) {
|
|
|
4462
4681
|
templates {
|
|
4463
4682
|
swift3 ( "String(" (e 1) ") + " (e 2) )
|
|
4464
4683
|
swift6 ( "String(" (e 1) ") + " (e 2) )
|
|
4465
|
-
kotlin ( (e 1) ".toString() + " (e 2) )
|
|
4466
|
-
dart ( (e 1) ".toString() + " (e 2) )
|
|
4684
|
+
kotlin ( "(" (e 1) ").toString() + " (e 2) )
|
|
4685
|
+
dart ( "(" (e 1) ").toString() + " (e 2) )
|
|
4467
4686
|
go ( "strings.Join([]string{ strconv.FormatFloat(" (e 1) ",'f', -1, 64)," (e 2) " }, \"\")" (imp "strings") (imp "strconv"))
|
|
4468
4687
|
cpp ( "r_double_to_string(" (e 1) ")" (imp "<sstream>") (imp "<iomanip>") (imp "<string>") (imp "<cstdlib>")
|
|
4469
4688
|
(create_polyfill "
|
|
@@ -4496,8 +4715,8 @@ inline std::string r_double_to_string(double v) {
|
|
|
4496
4715
|
go ( "strings.Join([]string{ strconv.FormatInt(" (e 1) ", 10)," (e 2) " }, \"\")" (imp "strings") (imp "strconv"))
|
|
4497
4716
|
swift3 ( "String(" (e 1) ") + " (e 2) )
|
|
4498
4717
|
swift6 ( "String(" (e 1) ") + " (e 2) )
|
|
4499
|
-
kotlin ( (e 1) ".toString() + " (e 2) )
|
|
4500
|
-
dart ( (e 1) ".toString() + " (e 2) )
|
|
4718
|
+
kotlin ( "(" (e 1) ").toString() + " (e 2) )
|
|
4719
|
+
dart ( "(" (e 1) ").toString() + " (e 2) )
|
|
4501
4720
|
rust ( "format!(\"{}{}\", " (e 1) ", " (e 2) ")" )
|
|
4502
4721
|
cpp ( "std::to_string(" (e 1) ") + " (e 2) )
|
|
4503
4722
|
php ( (e 1) " . " (e 2) )
|
|
@@ -4605,8 +4824,25 @@ def r_div_f64(a, b):
|
|
|
4605
4824
|
}
|
|
4606
4825
|
|
|
4607
4826
|
|
|
4827
|
+
; Every target reached this through the `*` macro, which expands to a
|
|
4828
|
+
; ternary over an explicit presence test. On JavaScript that is
|
|
4829
|
+
; (((typeof(hit) !== "undefined" && hit != null ) ) ? hit : "unknown")
|
|
4830
|
+
; where `hit ?? "unknown"` says the same thing -- and says it once,
|
|
4831
|
+
; rather than naming the operand twice. Every entry below triggers on
|
|
4832
|
+
; exactly what that target's `null?` tests, so the meaning is
|
|
4833
|
+
; unchanged; the macro stays for the targets with no such operator
|
|
4834
|
+
; (Java, Go, Python, C++, Rust), which keep the ternary.
|
|
4608
4835
|
?? elvis:T ( left@(optional):T right:T ) {
|
|
4609
4836
|
templates {
|
|
4837
|
+
es6 ( "(" (e 1) " ?? " (e 2) ")" )
|
|
4838
|
+
dart ( "(" (e 1) " ?? " (e 2) ")" )
|
|
4839
|
+
csharp ( "(" (e 1) " ?? " (e 2) ")" )
|
|
4840
|
+
swift3 ( "(" (e 1) " ?? " (e 2) ")" )
|
|
4841
|
+
swift6 ( "(" (e 1) " ?? " (e 2) ")" )
|
|
4842
|
+
php ( "(" (e 1) " ?? " (e 2) ")" )
|
|
4843
|
+
kotlin ( "(" (e 1) " ?: " (e 2) ")" )
|
|
4844
|
+
; an optional is an Option[T] here, not a nullable reference
|
|
4845
|
+
scala ( "(" (e 1) ").getOrElse(" (e 2) ")" )
|
|
4610
4846
|
* @macro(true) ( '(? (!null? ' (e 1) ') (unwrap ' (e 1) ') ' (e 2) ')' )
|
|
4611
4847
|
}
|
|
4612
4848
|
}
|
|
@@ -4662,7 +4898,7 @@ def r_div_f64(a, b):
|
|
|
4662
4898
|
kotlin ( "(Math.ceil(" (e 1) ")).toInt()" (imp "java.lang.Math"))
|
|
4663
4899
|
dart ( "(" (e 1) ").ceil()" )
|
|
4664
4900
|
cpp ( "(int)ceil(" (e 1) ")" (imp "<cmath>"))
|
|
4665
|
-
csharp ( "(int)Math.
|
|
4901
|
+
csharp ( "(int)Math.Ceiling(" (e 1) ")" (imp "System"))
|
|
4666
4902
|
go ( "int64(math.Ceil(" (e 1) "))" (imp "math"))
|
|
4667
4903
|
php ( "ceil(" (e 1) ")" )
|
|
4668
4904
|
rust ( "" (e 1) ".ceil() as i64" )
|
|
@@ -4811,6 +5047,7 @@ def r_div_f64(a, b):
|
|
|
4811
5047
|
|
|
4812
5048
|
if! cmdIf:void ( condition:boolean then_block:block ) {
|
|
4813
5049
|
templates {
|
|
5050
|
+
cpp ( (custom _) )
|
|
4814
5051
|
* @macro(true) ('if (false == (' (e 1) ' ) ) { ' (block 2) ' } ' )
|
|
4815
5052
|
}
|
|
4816
5053
|
}
|
|
@@ -4827,24 +5064,31 @@ def r_div_f64(a, b):
|
|
|
4827
5064
|
}
|
|
4828
5065
|
|
|
4829
5066
|
if cmdIf:void ( condition:boolean then_block:block ) {
|
|
5067
|
+
; NOTE: this is triggered in normal C++ execution
|
|
4830
5068
|
templates {
|
|
4831
5069
|
ranger ( "if (" (e 1) ") {" I nl (block 2) nl i "}" nl )
|
|
4832
5070
|
rust ( "if " (e 1) " {" I nl (block 2) nl i "}" nl )
|
|
4833
5071
|
go ( "if " (e 1) " {" I nl (block 2) nl i "}" nl )
|
|
4834
5072
|
python ( "if " (e 1) ":" I nl (block 2) nl i nl )
|
|
5073
|
+
cpp ((custom _))
|
|
4835
5074
|
* ( "if ( " (e 1) " ) {" I nl (block 2) nl i "}" nl )
|
|
4836
5075
|
}
|
|
4837
5076
|
}
|
|
4838
5077
|
|
|
4839
5078
|
if cmdIf:void ( condition@(optional):int then_block:block ) {
|
|
4840
5079
|
templates {
|
|
4841
|
-
cpp ( "if ( " (e 1) ".has_value ) {" nl I (block 2) i nl "}" nl )
|
|
5080
|
+
cpp ( "if ( " (e 1) ".has_value() ) {" nl I (block 2) i nl "}" nl )
|
|
4842
5081
|
ranger ( "if ( " (e 1) " ) {" I nl (block 2) i nl "}" nl )
|
|
4843
5082
|
scala ( "if ( " (e 1) ".isDefined ) {" nl I (block 2) i nl "}" nl )
|
|
4844
5083
|
swift3 ( "if ( " (e 1) " != nil ) {" nl I (block 2) i nl "}" nl )
|
|
4845
5084
|
swift6 ( "if ( " (e 1) " != nil ) {" nl I (block 2) i nl "}" nl )
|
|
4846
5085
|
kotlin ( "if ( " (e 1) " != null ) {" nl I (block 2) i nl "}" nl )
|
|
4847
|
-
|
|
5086
|
+
; NOT Optional.isPresent(): java.util.Optional is Java 8, and
|
|
5087
|
+
; an optional on this target is a nullable reference or a boxed
|
|
5088
|
+
; primitive -- which is what `null?` already compares against.
|
|
5089
|
+
; The six `isPresent()` entries were the only thing that
|
|
5090
|
+
; disagreed, and each one was a "cannot find symbol".
|
|
5091
|
+
java7 ( "if ( " (e 1) " != null) {" nl I (block 2) i nl "}" nl )
|
|
4848
5092
|
csharp ( "if ( " (e 1) " != null) {" nl I (block 2) i nl "}" nl )
|
|
4849
5093
|
php ( "if ( isset( " (e 1) " ) ) {" nl I (block 2) i nl "}" nl )
|
|
4850
5094
|
go ( "if ( " (e 1) ".has_value) {" nl I (block 2) i nl "}" nl )
|
|
@@ -4857,13 +5101,13 @@ def r_div_f64(a, b):
|
|
|
4857
5101
|
|
|
4858
5102
|
if cmdIf:void ( condition@(optional):double then_block:block ) {
|
|
4859
5103
|
templates {
|
|
4860
|
-
cpp ( "if ( " (e 1) ".has_value ) {" nl I (block 2) i nl "}" nl )
|
|
5104
|
+
cpp ( "if ( " (e 1) ".has_value() ) {" nl I (block 2) i nl "}" nl )
|
|
4861
5105
|
ranger ( "if ( " (e 1) " ) {" I nl (block 2) i nl "}" nl )
|
|
4862
5106
|
scala ( "if ( " (e 1) ".isDefined ) {" nl I (block 2) i nl "}" nl )
|
|
4863
5107
|
swift3 ( "if ( " (e 1) " != nil ) {" nl I (block 2) i nl "}" nl )
|
|
4864
5108
|
swift6 ( "if ( " (e 1) " != nil ) {" nl I (block 2) i nl "}" nl )
|
|
4865
5109
|
kotlin ( "if ( " (e 1) " != null ) {" nl I (block 2) i nl "}" nl )
|
|
4866
|
-
java7 ( "if ( " (e 1) "
|
|
5110
|
+
java7 ( "if ( " (e 1) " != null) {" nl I (block 2) i nl "}" nl )
|
|
4867
5111
|
csharp ( "if ( " (e 1) " != null) {" nl I (block 2) i nl "}" nl )
|
|
4868
5112
|
php ( "if ( isset( " (e 1) " ) ) {" nl I (block 2) i nl "}" nl )
|
|
4869
5113
|
go ( "if ( " (e 1) ".has_value) {" nl I (block 2) i nl "}" nl )
|
|
@@ -4874,16 +5118,15 @@ def r_div_f64(a, b):
|
|
|
4874
5118
|
}
|
|
4875
5119
|
}
|
|
4876
5120
|
|
|
4877
|
-
; typed optional int/double with an else branch:
|
|
4878
|
-
;
|
|
4879
|
-
; `!= NULL` form below does not compile under clang. Emit `.has_value`.
|
|
5121
|
+
; typed optional int/double with an else branch: a std::optional is a
|
|
5122
|
+
; value, not a pointer, so the check is `.has_value()`.
|
|
4880
5123
|
if cmdIf:void ( condition@(optional):int then_block:block else_block ) {
|
|
4881
5124
|
templates {
|
|
4882
|
-
cpp ( "if ( " (e 1) ".has_value ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl )
|
|
5125
|
+
cpp ( "if ( " (e 1) ".has_value() ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl )
|
|
4883
5126
|
ranger ( "if ( " (e 1) " ) {" I nl (block 2) i nl "} {" nl I (block 3) i "}" nl)
|
|
4884
5127
|
php ( "if ( isset(" (e 1) ") ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4885
5128
|
scala ( "if ( " (e 1) ".isDefined ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4886
|
-
java7 ( "if ( " (e 1) "
|
|
5129
|
+
java7 ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4887
5130
|
csharp ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4888
5131
|
kotlin ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4889
5132
|
rust ( "if " (e 1) ".is_some() {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
@@ -4898,11 +5141,11 @@ def r_div_f64(a, b):
|
|
|
4898
5141
|
|
|
4899
5142
|
if cmdIf:void ( condition@(optional):double then_block:block else_block ) {
|
|
4900
5143
|
templates {
|
|
4901
|
-
cpp ( "if ( " (e 1) ".has_value ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl )
|
|
5144
|
+
cpp ( "if ( " (e 1) ".has_value() ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl )
|
|
4902
5145
|
ranger ( "if ( " (e 1) " ) {" I nl (block 2) i nl "} {" nl I (block 3) i "}" nl)
|
|
4903
5146
|
php ( "if ( isset(" (e 1) ") ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4904
5147
|
scala ( "if ( " (e 1) ".isDefined ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4905
|
-
java7 ( "if ( " (e 1) "
|
|
5148
|
+
java7 ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4906
5149
|
csharp ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4907
5150
|
kotlin ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4908
5151
|
rust ( "if " (e 1) ".is_some() {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
@@ -4923,13 +5166,13 @@ def r_div_f64(a, b):
|
|
|
4923
5166
|
swift6 ( "if ( " (e 1) " != nil ) {" nl I (block 2) i nl "}" nl )
|
|
4924
5167
|
kotlin ( "if ( " (e 1) " != null ) {" nl I (block 2) i nl "}" nl )
|
|
4925
5168
|
dart ( "if ( " (e 1) " != null ) {" nl I (block 2) i nl "}" nl )
|
|
4926
|
-
java7 ( "if ( " (e 1) "
|
|
5169
|
+
java7 ( "if ( " (e 1) " != null) {" nl I (block 2) i nl "}" nl )
|
|
4927
5170
|
csharp ( "if ( " (e 1) " != null) {" nl I (block 2) i nl "}" nl )
|
|
4928
5171
|
; go ( "" (e 1 ) " == nil " )
|
|
4929
5172
|
; is_some
|
|
4930
5173
|
php ( "if ( isset( " (e 1) " ) ) {" nl I (block 2) i nl "}" nl )
|
|
4931
5174
|
go ( "if ( " (e 1) ".has_value) {" nl I (block 2) i nl "}" nl )
|
|
4932
|
-
cpp ( "if ( " (e 1) "
|
|
5175
|
+
cpp ( "if ( " (e 1) ".has_value() ) {" nl I (block 2) i nl "}" nl )
|
|
4933
5176
|
rust ( "if " (e 1) ".is_some() {" nl I (block 2) i nl "}" nl )
|
|
4934
5177
|
python ( "if " (e 1) " is not None:" nl I (block 2) i nl )
|
|
4935
5178
|
* ( "if ( typeof(" ( e 1 ) ") != \"undefined\" ) {" nl I (block 2) i nl "}" nl )
|
|
@@ -4942,7 +5185,7 @@ def r_div_f64(a, b):
|
|
|
4942
5185
|
ranger ( "if ( " (e 1) " ) {" I nl (block 2) i nl "} {" nl I (block 3) i "}" nl)
|
|
4943
5186
|
php ( "if ( isset(" (e 1) ") ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4944
5187
|
scala ( "if ( " (e 1) ".isDefined ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4945
|
-
java7 ( "if ( " (e 1) "
|
|
5188
|
+
java7 ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4946
5189
|
csharp ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4947
5190
|
kotlin ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4948
5191
|
dart ( "if ( " (e 1) " != null ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl )
|
|
@@ -4950,7 +5193,7 @@ def r_div_f64(a, b):
|
|
|
4950
5193
|
swift3 ( "if ( " (e 1) " != nil ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4951
5194
|
swift6 ( "if ( " (e 1) " != nil ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4952
5195
|
go ( "if ( " (e 1) ".has_value ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4953
|
-
cpp ( "if ( " (e 1) "
|
|
5196
|
+
cpp ( "if ( " (e 1) ".has_value() ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4954
5197
|
python ( "if " (e 1) " is not None:" I nl (block 2) i nl "else:" I nl (block 3) i nl)
|
|
4955
5198
|
* ( "if ( typeof(" ( e 1 ) ") != \"undefined\" ) {" I nl (block 2) i nl "} else {" nl I (block 3) i "}" nl)
|
|
4956
5199
|
}
|
|
@@ -4984,7 +5227,7 @@ def r_div_f64(a, b):
|
|
|
4984
5227
|
switch cmdSwitch:void ( condition:int case_list:block ) {
|
|
4985
5228
|
templates {
|
|
4986
5229
|
scala ( (e 1) " match { " I (block 2) i "}" )
|
|
4987
|
-
kotlin (
|
|
5230
|
+
kotlin ( (custom _) )
|
|
4988
5231
|
python ( nl "match (" (e 1) "):" I (block 2) i nl )
|
|
4989
5232
|
; Rust demands an exhaustive match, and a Ranger `switch` need not
|
|
4990
5233
|
; have a `default`. The catch-all goes in unconditionally: where
|
|
@@ -5037,7 +5280,7 @@ def r_div_f64(a, b):
|
|
|
5037
5280
|
templates {
|
|
5038
5281
|
cpp ( (custom _) )
|
|
5039
5282
|
scala ( (e 1) " match { " I (block 2) i "}" )
|
|
5040
|
-
kotlin (
|
|
5283
|
+
kotlin ( (custom _) )
|
|
5041
5284
|
python ( nl "match (" (e 1) "):" I (block 2) i nl )
|
|
5042
5285
|
; Rust matches a &str, so a String subject needs as_str().
|
|
5043
5286
|
; `&*x` is a &str whether x is a String or already a &str;
|
|
@@ -5054,7 +5297,7 @@ def r_div_f64(a, b):
|
|
|
5054
5297
|
templates {
|
|
5055
5298
|
|
|
5056
5299
|
scala ( (e 1) " match { " I (block 2) i "}" )
|
|
5057
|
-
kotlin (
|
|
5300
|
+
kotlin ( (custom _) )
|
|
5058
5301
|
; An ENUM condition lands here, not on the int overload above,
|
|
5059
5302
|
; and Python and Rust have no C style switch -- without these two
|
|
5060
5303
|
; the `*` fallback wrote a C `switch` into a Python file. The
|
|
@@ -5076,8 +5319,10 @@ def r_div_f64(a, b):
|
|
|
5076
5319
|
|
|
5077
5320
|
; A case over a string needs its own entry for Rust only: a match arm is
|
|
5078
5321
|
; a pattern, and the Rust writer gives a string literal in expression
|
|
5079
|
-
; position a `.to_string()`, which a pattern does not take. `(
|
|
5080
|
-
; writes the text of the literal and
|
|
5322
|
+
; position a `.to_string()`, which a pattern does not take. `(estr 1)`
|
|
5323
|
+
; writes the text of the literal, escaped and unquoted -- escaped
|
|
5324
|
+
; because a pattern holding a raw quote, backslash or newline ends
|
|
5325
|
+
; early, which is how `case "\""` became `"""`. Every other target
|
|
5081
5326
|
; keeps the spelling of the case above.
|
|
5082
5327
|
case cmdCase:void ( condition:string case_block:block ) {
|
|
5083
5328
|
templates {
|
|
@@ -5091,7 +5336,7 @@ def r_div_f64(a, b):
|
|
|
5091
5336
|
es6 ( nl "case " (e 1)" : " nl I (java_case 2) nl i )
|
|
5092
5337
|
cpp ( nl "case " (e 1)" : " nl I "{" nl I (block 2) nl "break;" i nl "}" i )
|
|
5093
5338
|
python ( nl "case " (e 1) ":" nl I "pass" nl (block 2) nl i )
|
|
5094
|
-
rust ( nl "\"" (
|
|
5339
|
+
rust ( nl "\"" (estr 1) "\" => {" nl I (block 2) nl i "}" nl )
|
|
5095
5340
|
* ( nl "case " (e 1)" : " nl I (block 2) nl "break;" i )
|
|
5096
5341
|
}
|
|
5097
5342
|
}
|
|
@@ -5232,17 +5477,23 @@ std::vector<T> r_make_vector_from_array( const T (&data)[N] )
|
|
|
5232
5477
|
}
|
|
5233
5478
|
null? cmdIsNotNull:boolean ( arg@(optional):int ) {
|
|
5234
5479
|
templates {
|
|
5235
|
-
cpp ((e 1) ".has_value == false")
|
|
5480
|
+
cpp ("(" (e 1) ".has_value() == false)" )
|
|
5236
5481
|
}
|
|
5237
5482
|
}
|
|
5238
5483
|
null? cmdIsNotNull:boolean ( arg@(optional):double ) {
|
|
5239
5484
|
templates {
|
|
5240
|
-
cpp ((e 1) ".has_value == false")
|
|
5485
|
+
cpp ("(" (e 1) ".has_value() == false)" )
|
|
5241
5486
|
}
|
|
5242
5487
|
}
|
|
5488
|
+
; an optional string used to be a bare std::string on C++, with ""
|
|
5489
|
+
; standing in for absent. That is the one place the C++ output
|
|
5490
|
+
; disagreed with every other target: `s = ""` then `null? s` answered
|
|
5491
|
+
; true here and false on JS, Python, Go and Rust. It is an
|
|
5492
|
+
; std::optional<std::string> now, so "" is a value like any
|
|
5493
|
+
; other and the presence bit is its own.
|
|
5243
5494
|
null? cmdIsNotNull:boolean ( arg@(optional):string ) {
|
|
5244
5495
|
templates {
|
|
5245
|
-
cpp ((e 1) ".
|
|
5496
|
+
cpp ((e 1) ".has_value() == false")
|
|
5246
5497
|
}
|
|
5247
5498
|
}
|
|
5248
5499
|
|
|
@@ -5270,7 +5521,7 @@ std::vector<T> r_make_vector_from_array( const T (&data)[N] )
|
|
|
5270
5521
|
templates {
|
|
5271
5522
|
ranger ("(null? " (e 1) ")")
|
|
5272
5523
|
php ( "(!isset(" (e 1) "))")
|
|
5273
|
-
cpp ((e 1) "
|
|
5524
|
+
cpp ("!" (e 1) ".has_value()")
|
|
5274
5525
|
swift3 ((e 1) " == nil")
|
|
5275
5526
|
swift6 ((e 1) " == nil")
|
|
5276
5527
|
java7 ( (e 1) " == null")
|
|
@@ -5287,17 +5538,17 @@ std::vector<T> r_make_vector_from_array( const T (&data)[N] )
|
|
|
5287
5538
|
}
|
|
5288
5539
|
!null? cmdIsNotNull:boolean ( arg@(optional):int ) {
|
|
5289
5540
|
templates {
|
|
5290
|
-
cpp ((e 1) ".has_value")
|
|
5541
|
+
cpp ((e 1) ".has_value()" )
|
|
5291
5542
|
}
|
|
5292
5543
|
}
|
|
5293
5544
|
!null? cmdIsNotNull:boolean ( arg@(optional):double ) {
|
|
5294
5545
|
templates {
|
|
5295
|
-
cpp ((e 1) ".has_value")
|
|
5546
|
+
cpp ((e 1) ".has_value()" )
|
|
5296
5547
|
}
|
|
5297
5548
|
}
|
|
5298
5549
|
!null? cmdIsNotNull:boolean ( arg@(optional):string ) {
|
|
5299
5550
|
templates {
|
|
5300
|
-
cpp ((e 1) ".
|
|
5551
|
+
cpp ((e 1) ".has_value()")
|
|
5301
5552
|
}
|
|
5302
5553
|
}
|
|
5303
5554
|
|
|
@@ -5324,7 +5575,7 @@ std::vector<T> r_make_vector_from_array( const T (&data)[N] )
|
|
|
5324
5575
|
scala ((e 1) ".isDefined")
|
|
5325
5576
|
swift3 ((e 1) " != nil ")
|
|
5326
5577
|
swift6 ((e 1) " != nil ")
|
|
5327
|
-
cpp ((e 1) "
|
|
5578
|
+
cpp ((e 1) ".has_value()")
|
|
5328
5579
|
java7 ((e 1) " != null ")
|
|
5329
5580
|
csharp ("" (e 1) " != null")
|
|
5330
5581
|
rust ((e 1) ".is_some()")
|
|
@@ -5347,7 +5598,8 @@ std::vector<T> r_make_vector_from_array( const T (&data)[N] )
|
|
|
5347
5598
|
es6 ( "( e.toString())" )
|
|
5348
5599
|
php ( "( $e->getMessage())" )
|
|
5349
5600
|
java7 ( "( e.getMessage())" )
|
|
5350
|
-
|
|
5601
|
+
; the local the try template binds in its handler
|
|
5602
|
+
cpp ( "__rg_err_msg" )
|
|
5351
5603
|
; Dart has no `try` entry of its own and takes the `*` one, which
|
|
5352
5604
|
; binds `e`.
|
|
5353
5605
|
dart ( "e.toString()" )
|
|
@@ -5372,6 +5624,17 @@ std::vector<T> r_make_vector_from_array( const T (&data)[N] )
|
|
|
5372
5624
|
php ( "throw new Exception(" (e 1) ");")
|
|
5373
5625
|
csharp ( "throw new ConfigurationErrorsException(" (e 1) ");" (imp "System.Configuration"))
|
|
5374
5626
|
java7 ( "throw new IllegalArgumentException(" (e 1) ");")
|
|
5627
|
+
; `throw "negative"` in C++ throws a `const char*`, which the
|
|
5628
|
+
; catch-all below caught and could say nothing about — every
|
|
5629
|
+
; error came out as "unspecified error". A std::exception
|
|
5630
|
+
; carries the text, and the try template asks it for one.
|
|
5631
|
+
cpp ( "throw std::runtime_error(" (e 1) ");" (imp "<stdexcept>"))
|
|
5632
|
+
; Kotlin has no checked exceptions and needs no `throws` on the
|
|
5633
|
+
; signature, but what is thrown must be a Throwable — a String
|
|
5634
|
+
; is not, and `throw "negative"` is a kotlinc error, not a
|
|
5635
|
+
; warning. Exception(msg) puts the text where `e.message` reads
|
|
5636
|
+
; it, which is what the `error_msg` template already expects.
|
|
5637
|
+
kotlin ( "throw Exception(" (e 1) ")")
|
|
5375
5638
|
swift3 (
|
|
5376
5639
|
nl "throw " (e 1) ";" nl
|
|
5377
5640
|
(create_polyfill
|
|
@@ -5379,6 +5642,26 @@ std::vector<T> r_make_vector_from_array( const T (&data)[N] )
|
|
|
5379
5642
|
extension String: Error {}
|
|
5380
5643
|
"
|
|
5381
5644
|
)
|
|
5645
|
+
)
|
|
5646
|
+
; swift6 had no entry of its own and fell through to `*`, which
|
|
5647
|
+
; writes `throw "negative"` — a String is not an Error, and
|
|
5648
|
+
; swiftc refuses it. A small error type rather than
|
|
5649
|
+
; `extension String: Error {}` (what swift3 does): extending a
|
|
5650
|
+
; stdlib type with a stdlib protocol is a retroactive
|
|
5651
|
+
; conformance, which Swift 6 language mode warns about.
|
|
5652
|
+
; CustomStringConvertible is what keeps `error_msg` correct
|
|
5653
|
+
; without a template of its own — `String(describing: error)`
|
|
5654
|
+
; is the message, not `RgError(message: "…")`.
|
|
5655
|
+
swift6 (
|
|
5656
|
+
nl "throw RgError(message: " (e 1) ")" nl
|
|
5657
|
+
(create_polyfill
|
|
5658
|
+
"
|
|
5659
|
+
struct RgError: Error, CustomStringConvertible {
|
|
5660
|
+
let message: String
|
|
5661
|
+
var description: String { message }
|
|
5662
|
+
}
|
|
5663
|
+
"
|
|
5664
|
+
)
|
|
5382
5665
|
)
|
|
5383
5666
|
scala ( "throw new customException(" (e 1) ")"
|
|
5384
5667
|
|
|
@@ -5424,7 +5707,18 @@ case class customException(smth:String) extends Exception
|
|
|
5424
5707
|
; with swift there is no do without try...
|
|
5425
5708
|
swift3 ( "do {" nl I (block 1) i nl "} catch { " nl I (block 2) i nl "}" )
|
|
5426
5709
|
swift6 ( "do {" nl I (block 1) i nl "} catch { " nl I (block 2) i nl "}" )
|
|
5427
|
-
|
|
5710
|
+
; The catch stays a catch-ALL — a Ranger `try` block has to
|
|
5711
|
+
; survive whatever crosses it, including a throw from a
|
|
5712
|
+
; polyfill or a library that is not a std::exception. Asking
|
|
5713
|
+
; what it was is the rethrow idiom: re-throw inside the
|
|
5714
|
+
; handler and catch it again by type. That gives `error_msg`
|
|
5715
|
+
; the real text without narrowing what is caught, and without
|
|
5716
|
+
; writing the user's catch block out twice.
|
|
5717
|
+
cpp ( nl "try {" nl I (block 1) i nl "} catch( ... ) {" nl I
|
|
5718
|
+
"std::string __rg_err_msg = \"unspecified error\";" nl
|
|
5719
|
+
"try { throw; } catch( const std::exception& __rg_e ) { __rg_err_msg = __rg_e.what(); } catch( ... ) {}" nl
|
|
5720
|
+
"(void)__rg_err_msg;" nl
|
|
5721
|
+
(block 2) i nl "}" nl (imp "<stdexcept>") (imp "<string>") )
|
|
5428
5722
|
; Python needs a statement in each suite, and a generated catch
|
|
5429
5723
|
; block is often empty (the @serialize writer emits one), so both
|
|
5430
5724
|
; suites open with `pass`.
|
|
@@ -5448,9 +5742,13 @@ case class customException(smth:String) extends Exception
|
|
|
5448
5742
|
; body wants one. swift_rc writes `_` for either name when its
|
|
5449
5743
|
; ref_cnt is 0 -- the swift3 template already did this for the
|
|
5450
5744
|
; index, and the item needs it just as much.
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5745
|
+
; PLAN_CPP_IDIOMS C4: `for v in xs` when the body reads
|
|
5746
|
+
; neither the index nor the collection.
|
|
5747
|
+
swift6 ( (forkctx _ ) (def 2) (def 3) nl (custom _) )
|
|
5748
|
+
; PLAN_CPP_IDIOMS C4: `for (v in xs)` when the body reads
|
|
5749
|
+
; neither the index nor the collection.
|
|
5750
|
+
kotlin ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5751
|
+
dart ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5454
5752
|
|
|
5455
5753
|
; Use index-based loop for Rust with cloned item - no reassignment needed as item is cloned.
|
|
5456
5754
|
; The index counts in i64, because Ranger declares it `int` and the
|
|
@@ -5462,7 +5760,12 @@ case class customException(smth:String) extends Exception
|
|
|
5462
5760
|
; borrow alive for the whole loop, and a body that borrows the
|
|
5463
5761
|
; same thing mutably cannot run. The temporary is named after
|
|
5464
5762
|
; the index, so nested loops do not collide.
|
|
5465
|
-
|
|
5763
|
+
; PLAN_RUST_SEMANTIC_IDIOMS K: the writer picks between the
|
|
5764
|
+
; index loop this used to be and `for v in xs.iter().copied()`
|
|
5765
|
+
; (or `.cloned()`), because only it can ask whether the body
|
|
5766
|
+
; reads the index or touches the collection.
|
|
5767
|
+
; See RustOperators.rustWriteForLoop.
|
|
5768
|
+
rust ( (forkctx _ ) (def 2) (def 3) nl (custom _) )
|
|
5466
5769
|
|
|
5467
5770
|
; idea of go for macro implementation, not working yet...
|
|
5468
5771
|
go_idea @macro(true) (nl
|
|
@@ -5476,17 +5779,35 @@ case class customException(smth:String) extends Exception
|
|
|
5476
5779
|
i
|
|
5477
5780
|
"}" nl
|
|
5478
5781
|
)
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5782
|
+
; PLAN_CPP_IDIOMS C4, the Go half: the writer picks between the
|
|
5783
|
+
; index loop this used to be and `for _, v := range xs`, because
|
|
5784
|
+
; only it can ask whether the body reads the index or touches
|
|
5785
|
+
; the collection. See RangerGolangClassWriter.goWriteForLoop.
|
|
5786
|
+
go ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5787
|
+
|
|
5788
|
+
; PLAN_CPP_IDIOMS C4, the PHP half: `foreach ($xs as $v)` when the
|
|
5789
|
+
; body reads neither the index nor the collection.
|
|
5790
|
+
php ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5791
|
+
; PLAN_CPP_IDIOMS C4: `for (T v : xs)` when the body reads
|
|
5792
|
+
; neither the index nor the collection.
|
|
5793
|
+
java7 ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5794
|
+
csharp ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5484
5795
|
scala ( (custom _) )
|
|
5485
|
-
|
|
5486
|
-
|
|
5796
|
+
; PLAN_CPP_IDIOMS C4: the writer picks between the index loop
|
|
5797
|
+
; this used to be and `for ( const T& v : xs )`, because only it
|
|
5798
|
+
; can ask whether the body reads the index or touches the
|
|
5799
|
+
; collection. See RangerCppClassWriter.cppWriteForLoop.
|
|
5800
|
+
cpp ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5487
5801
|
cpp.old ( (forkctx _ ) (def 2) (def 3) "for ( std::vector< " (typeof 2) ">::size_type " (e 3) " = 0; " (e 3) " != " (e 1) ".size(); " (e 3) "++) {" nl
|
|
5488
5802
|
I (typeof 2) " " (e 2) " = " (e 1) ".at(" (e 3) ");" nl (block 4) nl i "}" )
|
|
5489
|
-
|
|
5803
|
+
; PLAN_CPP_IDIOMS C4: `for v in xs:` when the body never
|
|
5804
|
+
; reads the index enumerate() was handing it.
|
|
5805
|
+
python ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5806
|
+
; PLAN_CPP_IDIOMS C4: `for (const v of xs)` when the body reads
|
|
5807
|
+
; neither the index nor the collection. es5 is left on the `*`
|
|
5808
|
+
; template below -- `for...of` is ES6.
|
|
5809
|
+
es6 ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5810
|
+
ts ( (forkctx _ ) (def 2) (def 3) (custom _) )
|
|
5490
5811
|
* ( (forkctx _ ) (def 2) (def 3) "for ( let " (e 3) " = 0; " (e 3) " < " (e 1) ".length; " (e 3) "++) {" nl I "var " (e 2) " = " (e 1) "[" (e 3) "];" nl (block 4) nl i "}" )
|
|
5491
5812
|
}
|
|
5492
5813
|
}
|
|
@@ -5502,7 +5823,7 @@ case class customException(smth:String) extends Exception
|
|
|
5502
5823
|
llvm ( nl "for " (e 1) " " (e 2) ":" (typeof 2) " " (e 3) " {" nl I (block 4) nl i "}" )
|
|
5503
5824
|
es6 ("for( var " (e 3) " in " (e 1) ") {" nl I "if(" (e 1) ".hasOwnProperty(" (e 3) ")) {"
|
|
5504
5825
|
nl I "var " (e 2) " = " (e 1) "[" (e 3) "] " nl (block 4)
|
|
5505
|
-
nl i "} }"
|
|
5826
|
+
nl i "}" nl i "}"
|
|
5506
5827
|
)
|
|
5507
5828
|
dart ( (forkctx _ ) (def 2) (def 3) "for ( var " (e 3) " in " (e 1) ".keys ) {" nl I "var " (e 2) " = " (e 1) "[" (e 3) "]!; " nl (block 4) nl i "}" )
|
|
5508
5829
|
; Go rejects a declared and unused loop variable, so both names
|
|
@@ -5771,9 +6092,10 @@ func r_last_index_of(_ s: String, _ needle: String) -> Int {
|
|
|
5771
6092
|
)
|
|
5772
6093
|
csharp ( (e 1) ".Length")
|
|
5773
6094
|
php ( "strlen(" (e 1) ")")
|
|
5774
|
-
|
|
6095
|
+
; bytes, not runes -- see the note on `charAt`
|
|
6096
|
+
go ( "int64(len(" (e 1) "))")
|
|
5775
6097
|
python ( "len(" (e 1) ")")
|
|
5776
|
-
rust ( (e 1) ".
|
|
6098
|
+
rust ( "(" (e 1) ".len() as i64)")
|
|
5777
6099
|
* ( (e 1) ".length")
|
|
5778
6100
|
}
|
|
5779
6101
|
}
|
|
@@ -5904,24 +6226,113 @@ static bool r_regex_test_i(string pattern, string s) {
|
|
|
5904
6226
|
; swift:
|
|
5905
6227
|
; String(data: Data(bytes: s[sp ..< i]) , encoding: .utf8)!
|
|
5906
6228
|
|
|
6229
|
+
; ===================================================================
|
|
6230
|
+
; `charbuffer` IS A BUFFER OF BYTES.
|
|
6231
|
+
; ===================================================================
|
|
6232
|
+
;
|
|
6233
|
+
; One element is one OCTET, 0..255. It is not a character, it is not
|
|
6234
|
+
; a code point, and it is not "a string that happens to hold bytes".
|
|
6235
|
+
; `Vec<u8>` on Rust, `[]byte` on Go, `Uint8Array` on JavaScript,
|
|
6236
|
+
; `bytes` on Python, `byte[]` on the JVM and .NET, `[UInt8]` on
|
|
6237
|
+
; Swift, `List<int>` on Dart. That is the whole of the type, and it
|
|
6238
|
+
; is the same type whether the bytes came from a file, a socket, a
|
|
6239
|
+
; JPEG or a piece of text.
|
|
6240
|
+
;
|
|
6241
|
+
; TEXT IS A SEPARATE THING, AND THE CONVERSION NAMES ITS ENCODING.
|
|
6242
|
+
; `string` is text; `charbuffer` is bytes; nothing turns one into the
|
|
6243
|
+
; other by itself. Three operators cross that line, and because a
|
|
6244
|
+
; text<->bytes conversion cannot be done without choosing an
|
|
6245
|
+
; encoding, all three are defined to use UTF-8:
|
|
6246
|
+
;
|
|
6247
|
+
; (to_charbuffer s) text -> its UTF-8 bytes
|
|
6248
|
+
; (to_string buf) bytes -> the text they are the UTF-8 of
|
|
6249
|
+
; (substring buf a b) bytes -> the text THAT RANGE is the UTF-8 of
|
|
6250
|
+
;
|
|
6251
|
+
; UTF-8 is a property of those three conversions. It is NOT a
|
|
6252
|
+
; property of the buffer: a `charbuffer` holding a PNG is not
|
|
6253
|
+
; "UTF-8 bytes", it is bytes, and `to_string` on it is meaningless.
|
|
6254
|
+
;
|
|
6255
|
+
; THE MISTAKE THIS COMMENT EXISTS TO STOP. `(charAt buf i)` answers
|
|
6256
|
+
; ONE BYTE. A character outside ASCII is two, three or four of them,
|
|
6257
|
+
; so a loop that copies a buffer back into text one element at a time
|
|
6258
|
+
;
|
|
6259
|
+
; while (i < (length buf)) { ; WRONG
|
|
6260
|
+
; out = out + (substring buf i (i + 1))
|
|
6261
|
+
; i = i + 1
|
|
6262
|
+
; }
|
|
6263
|
+
;
|
|
6264
|
+
; decodes each byte of a multi-byte character on its own and gets a
|
|
6265
|
+
; replacement character for each. That is a real defect this
|
|
6266
|
+
; compiler shipped: `RangerLispParser` decoded escapes that way, and
|
|
6267
|
+
; every literal holding both a backslash escape and a non-ASCII
|
|
6268
|
+
; character came out broken. Walk the STRING when the subject is
|
|
6269
|
+
; text (`strlen`, `charAt` and `substring` on a `string` agree with
|
|
6270
|
+
; each other on any one target), and reach for a `charbuffer` when
|
|
6271
|
+
; the subject really is bytes.
|
|
6272
|
+
;
|
|
6273
|
+
; WHY BYTES AND NOT THE HOST'S OWN UNIT. A `charbuffer` used to be
|
|
6274
|
+
; whatever each host's string was made of -- UTF-16 units on
|
|
6275
|
+
; JavaScript, Kotlin and Dart, code points on Python, bytes
|
|
6276
|
+
; elsewhere, and on Scala a `toCharArray.map(_.toByte)` that
|
|
6277
|
+
; silently truncated anything above U+00FF. A byte is the one unit
|
|
6278
|
+
; every host can hold exactly: a UTF-16 target cannot hold a lone
|
|
6279
|
+
; code point above the BMP in one unit, and a code-point target
|
|
6280
|
+
; cannot hold a surrogate half. Every one of them can hold a byte.
|
|
6281
|
+
; docs/plans/PLAN_STRING_INDEXING.md 2.3.
|
|
6282
|
+
;
|
|
6283
|
+
; THE VIEWS OF TEXT, for when a byte is not what is wanted:
|
|
6284
|
+
;
|
|
6285
|
+
; (to_chars s) [int], Unicode CODE POINTS, one per character,
|
|
6286
|
+
; the same sequence on every target
|
|
6287
|
+
; (char_length s) how many characters, without building that
|
|
6288
|
+
; array
|
|
6289
|
+
; (strlen s) / (charAt s i) / (substring s a b)
|
|
6290
|
+
; the TARGET'S OWN unit -- a byte, a UTF-16 code
|
|
6291
|
+
; unit or a code point, depending on where it
|
|
6292
|
+
; runs. Right for a scan over ASCII structure,
|
|
6293
|
+
; wrong for a column or a width. `-strict-strings`
|
|
6294
|
+
; reports the sites where the difference shows.
|
|
6295
|
+
; ===================================================================
|
|
6296
|
+
|
|
6297
|
+
; The TEXT that this range of bytes is the UTF-8 of. One of the
|
|
6298
|
+
; three places the line between bytes and text is crossed, so it
|
|
6299
|
+
; decodes: a range that cuts a character in half gives a replacement
|
|
6300
|
+
; character, which is what makes a one-byte-at-a-time copy of a
|
|
6301
|
+
; buffer back into a string wrong. See the block above.
|
|
5907
6302
|
substring cmdSubstring:string ( text:charbuffer start:int end:int ) {
|
|
5908
6303
|
templates {
|
|
5909
6304
|
ranger ( "(substring " (e 1) " " (e 2) " " (e 3) ")")
|
|
5910
6305
|
csharp ( "System.Text.Encoding.UTF8.GetString(" (e 1) ", " (e 2) ", " (e 3) " - " (e 2) ")" )
|
|
5911
|
-
|
|
5912
|
-
|
|
6306
|
+
; the bytes are UTF-8, so they are decoded as UTF-8 -- a
|
|
6307
|
+
; byte-to-char cast reads them as Latin-1 and mangles
|
|
6308
|
+
; everything above U+007F
|
|
6309
|
+
scala ( "new String(" (e 1) ".slice(" (e 2) ", " (e 3) "), \"UTF-8\")")
|
|
6310
|
+
java7 ( "new String(" (e 1) "," (e 2) ", " (e 3) " - " (e 2) ", java.nio.charset.StandardCharsets.UTF_8)")
|
|
5913
6311
|
swift3 ( "String(data: Data(bytes:" (e 1) "[" (e 2) " ..< " (e 3) "]), encoding: .utf8)!" (imp "Foundation"))
|
|
5914
6312
|
swift6 ( "String(data: Data(" (e 1) "[" (e 2) " ..< " (e 3) "]), encoding: .utf8)!" (imp "Foundation"))
|
|
5915
|
-
kotlin ( "String(" (e 1) "," (e 2) ", " (e 3) " - " (e 2) " )")
|
|
6313
|
+
kotlin ( "String(" (e 1) "," (e 2) ", " (e 3) " - " (e 2) ", Charsets.UTF_8)")
|
|
5916
6314
|
go ( "fmt.Sprintf(\"%s\", " (e 1) "[" (e 2) ":" (e 3) "])"
|
|
5917
6315
|
(imp "fmt")
|
|
5918
6316
|
)
|
|
5919
6317
|
cpp ( "std::string( " (e 1) " + " (e 2) ", " (e 3) " - " (e 2) " )")
|
|
5920
|
-
; a charbuffer is List<int> on Dart, so the `*`
|
|
5921
|
-
; JavaScript String.substring) does not apply to
|
|
5922
|
-
|
|
5923
|
-
;
|
|
5924
|
-
|
|
6318
|
+
; a charbuffer is a List<int> of BYTES on Dart, so the `*`
|
|
6319
|
+
; fallback (the JavaScript String.substring) does not apply to
|
|
6320
|
+
; it, and the bytes have to be decoded rather than read as
|
|
6321
|
+
; code units
|
|
6322
|
+
dart ( (imp "dart:convert") "utf8.decode(" (e 1) ".sublist(" (e 2) ", " (e 3) "))" )
|
|
6323
|
+
; ...and `bytes` on Python, where slicing gives bytes back
|
|
6324
|
+
python ( (e 1) "[" (e 2) ":" (e 3) "].decode(\"utf-8\")" )
|
|
6325
|
+
; ...and a Uint8Array on JavaScript, where it is neither a
|
|
6326
|
+
; string nor sliceable with String.substring
|
|
6327
|
+
es6 ( "r_cb_dec.decode(" (e 1) ".subarray(" (e 2) ", " (e 3) "))"
|
|
6328
|
+
(create_polyfill "
|
|
6329
|
+
// A charbuffer is a buffer of BYTES, so it is a Uint8Array here
|
|
6330
|
+
// rather than the string it used to be. One encoder and one decoder for the
|
|
6331
|
+
// process: constructing them per call is most of the cost of a short slice.
|
|
6332
|
+
const r_cb_enc = new TextEncoder();
|
|
6333
|
+
const r_cb_dec = new TextDecoder();
|
|
6334
|
+
")
|
|
6335
|
+
)
|
|
5925
6336
|
php ( "substr(" (e 1) ", " (e 2) ", " (e 3) " - " (e 2) ")")
|
|
5926
6337
|
; a charbuffer is Vec<u8> on Rust: slice the bytes and read
|
|
5927
6338
|
; them back as UTF-8. The `*` fallback is JavaScript's String
|
|
@@ -5931,40 +6342,345 @@ static bool r_regex_test_i(string pattern, string s) {
|
|
|
5931
6342
|
}
|
|
5932
6343
|
}
|
|
5933
6344
|
|
|
6345
|
+
; The TEXT these bytes are the UTF-8 of -- the other direction of
|
|
6346
|
+
; `to_charbuffer`. Bytes that are not valid UTF-8 come back as
|
|
6347
|
+
; replacement characters; a buffer holding a PNG has no text in it
|
|
6348
|
+
; and this operator has nothing to say about one.
|
|
5934
6349
|
to_string bufferToString:string ( text:charbuffer ) {
|
|
5935
6350
|
templates {
|
|
5936
6351
|
ranger ( "(to_string " (e 1) ")")
|
|
5937
6352
|
go ( "string(" (e 1) ")" )
|
|
5938
|
-
dart ( "
|
|
6353
|
+
dart ( (imp "dart:convert") "utf8.decode(" (e 1) ")" )
|
|
5939
6354
|
csharp ( "System.Text.Encoding.UTF8.GetString(" (e 1) ")" )
|
|
6355
|
+
python ( (e 1) ".decode(\"utf-8\")" )
|
|
6356
|
+
es6 ( "r_cb_dec.decode(" (e 1) ")"
|
|
6357
|
+
(create_polyfill "
|
|
6358
|
+
// A charbuffer is a buffer of BYTES, so it is a Uint8Array here
|
|
6359
|
+
// rather than the string it used to be. One encoder and one decoder for the
|
|
6360
|
+
// process: constructing them per call is most of the cost of a short slice.
|
|
6361
|
+
const r_cb_enc = new TextEncoder();
|
|
6362
|
+
const r_cb_dec = new TextDecoder();
|
|
6363
|
+
")
|
|
6364
|
+
)
|
|
6365
|
+
rust ( "String::from_utf8_lossy(&" (e 1) ").to_string()" )
|
|
6366
|
+
java7 ( "new String(" (e 1) ", java.nio.charset.StandardCharsets.UTF_8)" )
|
|
6367
|
+
kotlin ( "String(" (e 1) ", Charsets.UTF_8)" )
|
|
6368
|
+
scala ( "new String(" (e 1) ", \"UTF-8\")" )
|
|
6369
|
+
swift3 ( "String(decoding: " (e 1) ", as: UTF8.self)" )
|
|
6370
|
+
swift6 ( "String(decoding: " (e 1) ", as: UTF8.self)" )
|
|
6371
|
+
; cpp (const char*) and php (a byte string) already ARE the
|
|
6372
|
+
; text; everything else has to decode it
|
|
5940
6373
|
* ( (e 1) )
|
|
5941
6374
|
}
|
|
5942
6375
|
}
|
|
5943
6376
|
|
|
6377
|
+
; ...and the same thing under the method-call spelling.
|
|
5944
6378
|
toString bufferToString:string ( text:charbuffer ) {
|
|
5945
6379
|
templates {
|
|
5946
6380
|
go ( "string(" (e 1) ")" )
|
|
5947
|
-
dart ( "
|
|
6381
|
+
dart ( (imp "dart:convert") "utf8.decode(" (e 1) ")" )
|
|
5948
6382
|
csharp ( "System.Text.Encoding.UTF8.GetString(" (e 1) ")" )
|
|
6383
|
+
python ( (e 1) ".decode(\"utf-8\")" )
|
|
6384
|
+
es6 ( "r_cb_dec.decode(" (e 1) ")"
|
|
6385
|
+
(create_polyfill "
|
|
6386
|
+
// A charbuffer is a buffer of BYTES, so it is a Uint8Array here
|
|
6387
|
+
// rather than the string it used to be. One encoder and one decoder for the
|
|
6388
|
+
// process: constructing them per call is most of the cost of a short slice.
|
|
6389
|
+
const r_cb_enc = new TextEncoder();
|
|
6390
|
+
const r_cb_dec = new TextDecoder();
|
|
6391
|
+
")
|
|
6392
|
+
)
|
|
6393
|
+
rust ( "String::from_utf8_lossy(&" (e 1) ").to_string()" )
|
|
6394
|
+
java7 ( "new String(" (e 1) ", java.nio.charset.StandardCharsets.UTF_8)" )
|
|
6395
|
+
kotlin ( "String(" (e 1) ", Charsets.UTF_8)" )
|
|
6396
|
+
scala ( "new String(" (e 1) ", \"UTF-8\")" )
|
|
6397
|
+
swift3 ( "String(decoding: " (e 1) ", as: UTF8.self)" )
|
|
6398
|
+
swift6 ( "String(decoding: " (e 1) ", as: UTF8.self)" )
|
|
6399
|
+
; cpp (const char*) and php (a byte string) already ARE the
|
|
6400
|
+
; text; everything else has to decode it
|
|
5949
6401
|
* ( (e 1) )
|
|
5950
6402
|
}
|
|
5951
6403
|
}
|
|
5952
6404
|
|
|
6405
|
+
; A `charbuffer` is a buffer of BYTES -- see the block above the
|
|
6406
|
+
; charbuffer overloads for what that does and does not mean. This
|
|
6407
|
+
; operator is one of the two places the line between text and bytes
|
|
6408
|
+
; is crossed, so it is the place that names the encoding: the bytes
|
|
6409
|
+
; are the UTF-8 of the text, on every target.
|
|
6410
|
+
; docs/plans/PLAN_STRING_INDEXING.md 2.3.
|
|
6411
|
+
; The portable indexable view of text: Unicode CODE POINTS, the same
|
|
6412
|
+
; sequence on every target, built once in O(n) and read in O(1).
|
|
6413
|
+
;
|
|
6414
|
+
; `charAt` on a `string` is the target's own unit -- a UTF-16 code
|
|
6415
|
+
; unit, a code point or a UTF-8 byte, depending on where it runs --
|
|
6416
|
+
; and that is what makes it O(1) there. It is right for a scanner over
|
|
6417
|
+
; ASCII structure and wrong for anything a human wrote. `to_chars` is
|
|
6418
|
+
; the conversion that makes an index mean one thing everywhere, and
|
|
6419
|
+
; because the program names it, the allocation is asked for rather
|
|
6420
|
+
; than hidden.
|
|
6421
|
+
;
|
|
6422
|
+
; def cs:[int] (to_chars s)
|
|
6423
|
+
; def n:int (array_length cs)
|
|
6424
|
+
; def c:int (itemAt cs 0)
|
|
6425
|
+
;
|
|
6426
|
+
; Above the Basic Multilingual Plane this is the only view that agrees
|
|
6427
|
+
; with itself: an emoji is ONE element here and two UTF-16 units or
|
|
6428
|
+
; four UTF-8 bytes in the other views.
|
|
6429
|
+
; docs/plans/PLAN_STRING_INDEXING.md 2.2.
|
|
6430
|
+
to_chars cmdToChars:[int] ( text:string ) {
|
|
6431
|
+
templates {
|
|
6432
|
+
ranger ( "(to_chars " (e 1) ")" )
|
|
6433
|
+
; Array.from walks a string by code point, not by code unit,
|
|
6434
|
+
; which is exactly the difference this operator exists for
|
|
6435
|
+
es6 ( "Array.from(" (e 1) ", (rg_c) => rg_c.codePointAt(0))" )
|
|
6436
|
+
; a Python str IS a sequence of code points
|
|
6437
|
+
python ( "[ord(rg_c) for rg_c in " (e 1) "]" )
|
|
6438
|
+
; a Dart String indexes UTF-16, but `runes` is the code points
|
|
6439
|
+
dart ( (e 1) ".runes.toList()" )
|
|
6440
|
+
; a Rust char IS a code point
|
|
6441
|
+
rust ( (e 1) ".chars().map(|c| c as i64).collect::<Vec<i64>>()" )
|
|
6442
|
+
swift3 ( "Array(" (e 1) ".unicodeScalars.map { Int($0.value) })" )
|
|
6443
|
+
swift6 ( "Array(" (e 1) ".unicodeScalars.map { Int($0.value) })" )
|
|
6444
|
+
php ( "array_map('mb_ord', preg_split('//u', " (e 1) ", -1, PREG_SPLIT_NO_EMPTY))" )
|
|
6445
|
+
; a Go rune IS a code point; the loop is only the int64 the
|
|
6446
|
+
; Ranger `[int]` is written as
|
|
6447
|
+
go ( "r_to_chars(" (e 1) ")"
|
|
6448
|
+
(create_polyfill "
|
|
6449
|
+
func r_to_chars(s string) []int64 {
|
|
6450
|
+
rs := []rune(s)
|
|
6451
|
+
out := make([]int64, len(rs))
|
|
6452
|
+
for i, r := range rs {
|
|
6453
|
+
out[i] = int64(r)
|
|
6454
|
+
}
|
|
6455
|
+
return out
|
|
6456
|
+
}
|
|
6457
|
+
")
|
|
6458
|
+
)
|
|
6459
|
+
; the JVM and .NET store UTF-16, so a surrogate pair has to be
|
|
6460
|
+
; folded back into the one code point it encodes
|
|
6461
|
+
java7 ( "rg_to_chars(" (e 1) ")"
|
|
6462
|
+
(create_polyfill "
|
|
6463
|
+
static java.util.ArrayList<Integer> rg_to_chars(String s) {
|
|
6464
|
+
java.util.ArrayList<Integer> out = new java.util.ArrayList<Integer>();
|
|
6465
|
+
int i = 0;
|
|
6466
|
+
while (i < s.length()) {
|
|
6467
|
+
int cp = s.codePointAt(i);
|
|
6468
|
+
out.add(cp);
|
|
6469
|
+
i += Character.charCount(cp);
|
|
6470
|
+
}
|
|
6471
|
+
return out;
|
|
6472
|
+
}
|
|
6473
|
+
")
|
|
6474
|
+
)
|
|
6475
|
+
kotlin ( "rg_to_chars(" (e 1) ")"
|
|
6476
|
+
(create_polyfill "
|
|
6477
|
+
fun rg_to_chars(s: String): MutableList<Int> {
|
|
6478
|
+
val out = mutableListOf<Int>()
|
|
6479
|
+
var i = 0
|
|
6480
|
+
while (i < s.length) {
|
|
6481
|
+
val cp = s.codePointAt(i)
|
|
6482
|
+
out.add(cp)
|
|
6483
|
+
i += Character.charCount(cp)
|
|
6484
|
+
}
|
|
6485
|
+
return out
|
|
6486
|
+
}
|
|
6487
|
+
")
|
|
6488
|
+
)
|
|
6489
|
+
csharp ( "RgChars.ToChars(" (e 1) ")"
|
|
6490
|
+
(polyfill "after_imports" "
|
|
6491
|
+
static class RgChars {
|
|
6492
|
+
public static System.Collections.Generic.List<int> ToChars(string s) {
|
|
6493
|
+
System.Collections.Generic.List<int> res = new System.Collections.Generic.List<int>();
|
|
6494
|
+
for (int i = 0; i < s.Length; i++) {
|
|
6495
|
+
if (char.IsHighSurrogate(s[i]) && (i + 1) < s.Length && char.IsLowSurrogate(s[i + 1])) {
|
|
6496
|
+
res.Add(char.ConvertToUtf32(s[i], s[i + 1]));
|
|
6497
|
+
i++;
|
|
6498
|
+
} else {
|
|
6499
|
+
res.Add((int)s[i]);
|
|
6500
|
+
}
|
|
6501
|
+
}
|
|
6502
|
+
return res;
|
|
6503
|
+
}
|
|
6504
|
+
}
|
|
6505
|
+
")
|
|
6506
|
+
)
|
|
6507
|
+
scala ( "rg_to_chars(" (e 1) ")"
|
|
6508
|
+
(create_polyfill "
|
|
6509
|
+
def rg_to_chars(s: String): collection.mutable.ArrayBuffer[Int] = {
|
|
6510
|
+
val out = collection.mutable.ArrayBuffer[Int]()
|
|
6511
|
+
var i = 0
|
|
6512
|
+
while (i < s.length) {
|
|
6513
|
+
val cp = s.codePointAt(i)
|
|
6514
|
+
out += cp
|
|
6515
|
+
i += Character.charCount(cp)
|
|
6516
|
+
}
|
|
6517
|
+
out
|
|
6518
|
+
}
|
|
6519
|
+
")
|
|
6520
|
+
)
|
|
6521
|
+
; a std::string is UTF-8 bytes, so this is the decode
|
|
6522
|
+
cpp ( "r_to_chars(" (e 1) ")" (imp "<vector>") (imp "<string>")
|
|
6523
|
+
(create_polyfill "
|
|
6524
|
+
static std::vector<int> r_to_chars(const std::string & s) {
|
|
6525
|
+
std::vector<int> out;
|
|
6526
|
+
size_t i = 0;
|
|
6527
|
+
while (i < s.size()) {
|
|
6528
|
+
unsigned char c = (unsigned char)s[i];
|
|
6529
|
+
int cp = 0;
|
|
6530
|
+
size_t n = 1;
|
|
6531
|
+
if ((c & 0x80) == 0) { cp = c; n = 1; }
|
|
6532
|
+
else if ((c & 0xE0) == 0xC0) { cp = c & 0x1F; n = 2; }
|
|
6533
|
+
else if ((c & 0xF0) == 0xE0) { cp = c & 0x0F; n = 3; }
|
|
6534
|
+
else if ((c & 0xF8) == 0xF0) { cp = c & 0x07; n = 4; }
|
|
6535
|
+
else { out.push_back(0xFFFD); i += 1; continue; }
|
|
6536
|
+
if ((i + n) > s.size()) { out.push_back(0xFFFD); break; }
|
|
6537
|
+
bool bad = false;
|
|
6538
|
+
for (size_t k = 1; k < n; k++) {
|
|
6539
|
+
unsigned char cc = (unsigned char)s[i + k];
|
|
6540
|
+
if ((cc & 0xC0) != 0x80) { bad = true; break; }
|
|
6541
|
+
cp = (cp << 6) | (cc & 0x3F);
|
|
6542
|
+
}
|
|
6543
|
+
out.push_back(bad ? 0xFFFD : cp);
|
|
6544
|
+
i += n;
|
|
6545
|
+
}
|
|
6546
|
+
return out;
|
|
6547
|
+
}
|
|
6548
|
+
")
|
|
6549
|
+
)
|
|
6550
|
+
}
|
|
6551
|
+
}
|
|
6552
|
+
|
|
6553
|
+
; How many CHARACTERS are in this string -- the same number on every
|
|
6554
|
+
; target, whatever unit that target happens to index in.
|
|
6555
|
+
;
|
|
6556
|
+
; `strlen` counts the target's own unit: UTF-16 code units on
|
|
6557
|
+
; JavaScript, Java, Kotlin, C#, Scala, Dart and Swift 6, UTF-8 bytes
|
|
6558
|
+
; on Rust, Go, C++ and PHP, code points on Python.
|
|
6559
|
+
; That is the right number for a scan -- `while (i < (strlen s))` with
|
|
6560
|
+
; `charAt s i` reads the same string either way -- and the wrong one
|
|
6561
|
+
; for anything a person sees: a column, a width, a padding count, a
|
|
6562
|
+
; truncation point. Those differ per target the moment the text stops
|
|
6563
|
+
; being ASCII, and they differ silently.
|
|
6564
|
+
;
|
|
6565
|
+
; `char_length` is the count that does not: Unicode code points, the
|
|
6566
|
+
; length of `(to_chars s)` without building the array.
|
|
6567
|
+
;
|
|
6568
|
+
; def w:int (char_length line) ; a column
|
|
6569
|
+
; def n:int (strlen line) ; a scan bound
|
|
6570
|
+
;
|
|
6571
|
+
; For ASCII the two are equal, so the cost of choosing the honest one
|
|
6572
|
+
; is nothing on the input that dominates.
|
|
6573
|
+
; docs/plans/PLAN_STRING_INDEXING.md 3.3.
|
|
6574
|
+
char_length cmdCharLength:int ( text:string ) {
|
|
6575
|
+
templates {
|
|
6576
|
+
ranger ( "(char_length " (e 1) ")" )
|
|
6577
|
+
; a Python str IS a sequence of code points
|
|
6578
|
+
python ( "len(" (e 1) ")" )
|
|
6579
|
+
; a Rust char IS a code point
|
|
6580
|
+
rust ( "(" (e 1) ".chars().count() as i64)" )
|
|
6581
|
+
; a Go rune IS a code point
|
|
6582
|
+
go ( "int64(utf8.RuneCountInString(" (e 1) "))" (imp "unicode/utf8") )
|
|
6583
|
+
dart ( (e 1) ".runes.length" )
|
|
6584
|
+
swift3 ( (e 1) ".unicodeScalars.count" )
|
|
6585
|
+
swift6 ( (e 1) ".unicodeScalars.count" )
|
|
6586
|
+
php ( "mb_strlen(" (e 1) ", 'UTF-8')" )
|
|
6587
|
+
; the JVM stores UTF-16: codePointCount folds each surrogate
|
|
6588
|
+
; pair back into the one code point it encodes. The helper is
|
|
6589
|
+
; there so the argument is evaluated once
|
|
6590
|
+
java7 ( "rg_char_length(" (e 1) ")"
|
|
6591
|
+
(create_polyfill "
|
|
6592
|
+
static int rg_char_length(String s) {
|
|
6593
|
+
return s.codePointCount(0, s.length());
|
|
6594
|
+
}
|
|
6595
|
+
")
|
|
6596
|
+
)
|
|
6597
|
+
kotlin ( "rg_char_length(" (e 1) ")"
|
|
6598
|
+
(create_polyfill "
|
|
6599
|
+
fun rg_char_length(s: String): Int {
|
|
6600
|
+
return s.codePointCount(0, s.length)
|
|
6601
|
+
}
|
|
6602
|
+
")
|
|
6603
|
+
)
|
|
6604
|
+
scala ( "rg_char_length(" (e 1) ")"
|
|
6605
|
+
(create_polyfill "
|
|
6606
|
+
def rg_char_length(s: String): Int = s.codePointCount(0, s.length)
|
|
6607
|
+
")
|
|
6608
|
+
)
|
|
6609
|
+
; .NET is UTF-16 as well, but EnumerateRunes is too new for
|
|
6610
|
+
; every runtime this targets -- counting everything that is
|
|
6611
|
+
; not the low half of a pair is the same answer
|
|
6612
|
+
csharp ( "RgCharLength.Of(" (e 1) ")"
|
|
6613
|
+
(polyfill "after_imports" "
|
|
6614
|
+
static class RgCharLength {
|
|
6615
|
+
public static int Of(string s) {
|
|
6616
|
+
int n = 0;
|
|
6617
|
+
for (int i = 0; i < s.Length; i++) {
|
|
6618
|
+
if (char.IsLowSurrogate(s[i])) { continue; }
|
|
6619
|
+
n++;
|
|
6620
|
+
}
|
|
6621
|
+
return n;
|
|
6622
|
+
}
|
|
6623
|
+
}
|
|
6624
|
+
")
|
|
6625
|
+
)
|
|
6626
|
+
; a std::string is UTF-8 bytes: every byte that is not a
|
|
6627
|
+
; continuation byte starts a new code point
|
|
6628
|
+
cpp ( "r_char_length(" (e 1) ")" (imp "<string>")
|
|
6629
|
+
(create_polyfill "
|
|
6630
|
+
static int r_char_length(const std::string & s) {
|
|
6631
|
+
int n = 0;
|
|
6632
|
+
for (size_t i = 0; i < s.size(); i++) {
|
|
6633
|
+
if (((unsigned char)s[i] & 0xC0) != 0x80) { n++; }
|
|
6634
|
+
}
|
|
6635
|
+
return n;
|
|
6636
|
+
}
|
|
6637
|
+
")
|
|
6638
|
+
)
|
|
6639
|
+
; a JavaScript string is UTF-16: skip the low half of every
|
|
6640
|
+
; surrogate pair. Array.from(s).length is the same number and
|
|
6641
|
+
; allocates the array this exists to avoid
|
|
6642
|
+
es6 ( "r_char_length(" (e 1) ")"
|
|
6643
|
+
(create_polyfill "
|
|
6644
|
+
function r_char_length(s) {
|
|
6645
|
+
let n = 0;
|
|
6646
|
+
for (let i = 0; i < s.length; i++) {
|
|
6647
|
+
const c = s.charCodeAt(i);
|
|
6648
|
+
if (c >= 0xDC00 && c <= 0xDFFF) { continue; }
|
|
6649
|
+
n++;
|
|
6650
|
+
}
|
|
6651
|
+
return n;
|
|
6652
|
+
}
|
|
6653
|
+
")
|
|
6654
|
+
)
|
|
6655
|
+
}
|
|
6656
|
+
}
|
|
6657
|
+
|
|
5953
6658
|
to_charbuffer cmdToCharBuffer:charbuffer ( text:string ) {
|
|
5954
6659
|
templates {
|
|
5955
6660
|
ranger ( "(to_charbuffer " (e 1) ")")
|
|
5956
6661
|
swift3 ( "Array(" (e 1) ".utf8)" )
|
|
5957
|
-
|
|
5958
|
-
|
|
6662
|
+
swift6 ( "Array(" (e 1) ".utf8)" )
|
|
6663
|
+
scala ( (e 1) ".getBytes(\"UTF-8\")")
|
|
6664
|
+
java7 ( (e 1) ".getBytes(java.nio.charset.StandardCharsets.UTF_8)" )
|
|
5959
6665
|
csharp ( "System.Text.Encoding.UTF8.GetBytes(" (e 1) ")" )
|
|
5960
|
-
kotlin ( (e 1 ) ".
|
|
6666
|
+
kotlin ( (e 1 ) ".toByteArray(Charsets.UTF_8)" )
|
|
5961
6667
|
; as_bytes/to_vec, not into_bytes: the source may be a
|
|
5962
6668
|
; borrowed &str, and into_bytes consumes an owned String
|
|
5963
6669
|
rust ( (e 1) ".as_bytes().to_vec()")
|
|
5964
6670
|
cpp ( (e 1) ".c_str()")
|
|
5965
|
-
dart ( (e 1) "
|
|
6671
|
+
dart ( (imp "dart:convert") "utf8.encode(" (e 1) ")" )
|
|
5966
6672
|
php ( (e 1) )
|
|
5967
6673
|
go("[]byte(" (e 1) ")")
|
|
6674
|
+
python ( (e 1) ".encode(\"utf-8\")" )
|
|
6675
|
+
es6 ( "r_cb_enc.encode(" (e 1) ")"
|
|
6676
|
+
(create_polyfill "
|
|
6677
|
+
// A charbuffer is a buffer of BYTES, so it is a Uint8Array here
|
|
6678
|
+
// rather than the string it used to be. One encoder and one decoder for the
|
|
6679
|
+
// process: constructing them per call is most of the cost of a short slice.
|
|
6680
|
+
const r_cb_enc = new TextEncoder();
|
|
6681
|
+
const r_cb_dec = new TextDecoder();
|
|
6682
|
+
")
|
|
6683
|
+
)
|
|
5968
6684
|
* ( (e 1) )
|
|
5969
6685
|
}
|
|
5970
6686
|
}
|
|
@@ -5982,7 +6698,7 @@ static bool r_regex_test_i(string pattern, string s) {
|
|
|
5982
6698
|
templates {
|
|
5983
6699
|
llvm ( "(buffer_alloc " (e 1) ")" )
|
|
5984
6700
|
ranger ( "(buffer_alloc " (e 1) ")" )
|
|
5985
|
-
es6 ( "(function(){
|
|
6701
|
+
es6 ( "(function(b){ return Object.assign(b, { _view: new DataView(b) }); })(new ArrayBuffer(" (e 1) "))" )
|
|
5986
6702
|
go ( "make([]byte, " (e 1) ")" )
|
|
5987
6703
|
rust ( "vec![0u8; " (idx 1) "]" )
|
|
5988
6704
|
cpp ( "std::vector<uint8_t>(" (e 1) ", 0)" (imp "<vector>") (imp "<cstdint>") )
|
|
@@ -6091,7 +6807,7 @@ function r_buf_slice($buf, $start, $end) {
|
|
|
6091
6807
|
buffer_from_string cmdBufferFromString:buffer ( str:string ) {
|
|
6092
6808
|
templates {
|
|
6093
6809
|
ranger ( "(buffer_from_string " (e 1) ")" )
|
|
6094
|
-
es6 ( "(function(s){ var b = new ArrayBuffer(s.length); var v = new Uint8Array(b); for(var i=0;i<s.length;i++)v[i]=s.charCodeAt(i); b
|
|
6810
|
+
es6 ( "(function(s){ var b = new ArrayBuffer(s.length); var v = new Uint8Array(b); for(var i=0;i<s.length;i++)v[i]=s.charCodeAt(i); return Object.assign(b, { _view: new DataView(b) }); })(" (e 1) ")" )
|
|
6095
6811
|
go ( "[]byte(" (e 1) ")" )
|
|
6096
6812
|
rust ( (e 1) ".as_bytes().to_vec()" )
|
|
6097
6813
|
cpp ( "std::vector<uint8_t>(" (e 1) ".begin(), " (e 1) ".end())" )
|
|
@@ -6193,7 +6909,7 @@ std::string r_buffer_to_base64(const std::vector<uint8_t>& data) {
|
|
|
6193
6909
|
templates {
|
|
6194
6910
|
llvm ( "(buffer_write_file " (e 1) " " (e 2) " " (e 3) ")" )
|
|
6195
6911
|
ranger ( "(buffer_write_file " (e 1) " " (e 2) " " (e 3) ")" )
|
|
6196
|
-
es6 ( "require('fs').writeFileSync(" (e 1) "
|
|
6912
|
+
es6 ( "require('fs').writeFileSync(require('path').join(" (e 1) ", " (e 2) "), Buffer.from(" (e 3) "))" )
|
|
6197
6913
|
go ( "os.WriteFile(" (e 1) " + \"/\" + " (e 2) ", " (e 3) ", 0644)" (imp "os") )
|
|
6198
6914
|
rust ( "std::fs::write(format!(\"{}/{}\", " (e 1) ", " (e 2) "), &" (e 3) ").unwrap()" )
|
|
6199
6915
|
cpp ( "r_buffer_write_file(" (e 1) ", " (e 2) ", " (e 3) ")" (imp "<fstream>") (imp "<vector>")
|
|
@@ -6216,7 +6932,7 @@ static void r_buffer_write_file(String path, String filename, byte[] data) {
|
|
|
6216
6932
|
)
|
|
6217
6933
|
python ( "open(" (e 1) " + '/' + " (e 2) ", 'wb').write(" (e 3) ")" )
|
|
6218
6934
|
swift6 ( "try? Data(" (e 3) ").write(to: URL(fileURLWithPath: " (e 1) " + \"/\" + " (e 2) "))" (imp "Foundation") )
|
|
6219
|
-
csharp ( "System.IO.File.WriteAllBytes(" (e 1) " + \"/\" + " (e 2) ", " (e 3) ")" )
|
|
6935
|
+
csharp ( "System.IO.File.WriteAllBytes(" (e 1) " + \"/\" + " (e 2) ", " (e 3) ");" )
|
|
6220
6936
|
kotlin ( "java.io.File(" (e 1) " + \"/\" + " (e 2) ").writeBytes(" (e 3) ")" )
|
|
6221
6937
|
dart ( (imp "dart:io") "File((" (e 1) ") + \"/\" + (" (e 2) ")).writeAsBytesSync(" (e 3) ")" )
|
|
6222
6938
|
php ( "file_put_contents(" (e 1) " . '/' . " (e 2) ", " (e 3) "->d);" )
|
|
@@ -6228,7 +6944,7 @@ static void r_buffer_write_file(String path, String filename, byte[] data) {
|
|
|
6228
6944
|
templates {
|
|
6229
6945
|
llvm ( "(buffer_read_file " (e 1) " " (e 2) ")" )
|
|
6230
6946
|
ranger ( "(buffer_read_file " (e 1) " " (e 2) ")" )
|
|
6231
|
-
es6 ( "(function(){ var b = require('fs').readFileSync(" (e 1) "
|
|
6947
|
+
es6 ( "(function(){ var b = require('fs').readFileSync( require('path').join(" (e 1) ", " (e 2) ") ); var ab = new ArrayBuffer(b.length); var v = new Uint8Array(ab); for(var i=0;i<b.length;i++)v[i]=b[i]; return Object.assign(ab, { _view: new DataView(ab) }); })()" )
|
|
6232
6948
|
go ( "func() []byte { d, _ := os.ReadFile(filepath.Join(" (e 1) ", " (e 2) ")); return d }()" (imp "os") (imp "path/filepath") )
|
|
6233
6949
|
rust ( "std::fs::read(format!(\"{}/{}\", " (e 1) ", " (e 2) ")).unwrap_or_default()" )
|
|
6234
6950
|
cpp ( "r_buffer_read_file(" (e 1) ", " (e 2) ")" (imp "<fstream>") (imp "<vector>") (imp "<iterator>")
|
|
@@ -6271,7 +6987,7 @@ static byte[] r_buffer_read_file(String path, String filename) {
|
|
|
6271
6987
|
java7 ( "System.arraycopy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ");" )
|
|
6272
6988
|
python ( (e 1) "[" (e 2) ":" (e 2) "+" (e 5) "] = " (e 3) "[" (e 4) ":" (e 4) "+" (e 5) "]" )
|
|
6273
6989
|
swift6 ( (e 1) ".replaceSubrange(Int(" (e 2) ")..<Int(" (e 2) "+" (e 5) "), with: " (e 3) "[Int(" (e 4) ")..<Int(" (e 4) "+" (e 5) ")])" )
|
|
6274
|
-
csharp ( "Array.Copy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ")" )
|
|
6990
|
+
csharp ( "Array.Copy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ");" )
|
|
6275
6991
|
kotlin ( "System.arraycopy(" (e 3) ", " (e 4) ", " (e 1) ", " (e 2) ", " (e 5) ")" )
|
|
6276
6992
|
php ( "r_buf_copy(" (e 1) ", " (e 2) ", " (e 3) ", " (e 4) ", " (e 5) ");" )
|
|
6277
6993
|
}
|
|
@@ -6299,7 +7015,7 @@ static byte[] r_buffer_read_file(String path, String filename) {
|
|
|
6299
7015
|
buffer_slice cmdBufferSlice:buffer ( buf:buffer start:int end:int ) {
|
|
6300
7016
|
templates {
|
|
6301
7017
|
ranger ( "(buffer_slice " (e 1) " " (e 2) " " (e 3) ")" )
|
|
6302
|
-
es6 ( "(function(b,s,e){ var slice = b.slice(s,e); slice
|
|
7018
|
+
es6 ( "(function(b,s,e){ var slice = b.slice(s,e); return Object.assign(slice, { _view: new DataView(slice) }); })(" (e 1) "," (e 2) "," (e 3) ")" )
|
|
6303
7019
|
dart ( (e 1) ".sublist(" (e 2) ", " (e 3) ")" )
|
|
6304
7020
|
go ( "append([]byte{}, " (e 1) "[" (e 2) ":" (e 3) "]...)" )
|
|
6305
7021
|
rust ( (e 1) "[" (idx 2) ".." (idx 3) "].to_vec()" )
|
|
@@ -6423,7 +7139,7 @@ static byte[] r_buffer_read_file(String path, String filename) {
|
|
|
6423
7139
|
java7 ( "System.arraycopy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ")" )
|
|
6424
7140
|
python ( (e 1) "[" (e 2) ":" (e 2) "+" (e 5) "] = " (e 3) "[" (e 4) ":" (e 4) "+" (e 5) "]" )
|
|
6425
7141
|
swift6 ( (e 1) ".replaceSubrange(Int(" (e 2) ")..<Int(" (e 2) "+" (e 5) "), with: " (e 3) "[Int(" (e 4) ")..<Int(" (e 4) "+" (e 5) ")])" )
|
|
6426
|
-
csharp ( "Array.Copy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ")" )
|
|
7142
|
+
csharp ( "Array.Copy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ");" )
|
|
6427
7143
|
kotlin ( "System.arraycopy(" (e 3) ", " (e 4) ", " (e 1) ", " (e 2) ", " (e 5) ")" )
|
|
6428
7144
|
}
|
|
6429
7145
|
}
|
|
@@ -6550,7 +7266,7 @@ static byte[] r_buffer_read_file(String path, String filename) {
|
|
|
6550
7266
|
java7 ( "System.arraycopy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ")" )
|
|
6551
7267
|
python ( (e 1) "[" (e 2) ":" (e 2) "+" (e 5) "] = " (e 3) "[" (e 4) ":" (e 4) "+" (e 5) "]" )
|
|
6552
7268
|
swift6 ( (e 1) ".replaceSubrange(Int(" (e 2) ")..<Int(" (e 2) "+" (e 5) "), with: " (e 3) "[Int(" (e 4) ")..<Int(" (e 4) "+" (e 5) ")])" )
|
|
6553
|
-
csharp ( "Array.Copy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ")" )
|
|
7269
|
+
csharp ( "Array.Copy(" (e 3) ", (int)" (e 4) ", " (e 1) ", (int)" (e 2) ", (int)" (e 5) ");" )
|
|
6554
7270
|
kotlin ( "System.arraycopy(" (e 3) ", " (e 4) ", " (e 1) ", " (e 2) ", " (e 5) ")" )
|
|
6555
7271
|
}
|
|
6556
7272
|
}
|
|
@@ -6613,6 +7329,9 @@ static byte[] r_buffer_read_file(String path, String filename) {
|
|
|
6613
7329
|
}
|
|
6614
7330
|
|
|
6615
7331
|
; Length
|
|
7332
|
+
; HOW MANY BYTES. For text that is not ASCII this is more than the
|
|
7333
|
+
; number of characters -- `char_length` is that one. See the block
|
|
7334
|
+
; above the charbuffer overloads.
|
|
6616
7335
|
length cmdLength:int ( buffer:charbuffer ) {
|
|
6617
7336
|
templates {
|
|
6618
7337
|
ranger ( "(length " (e 1) ")")
|
|
@@ -6624,9 +7343,10 @@ static byte[] r_buffer_read_file(String path, String filename) {
|
|
|
6624
7343
|
java7 ( (e 1 ) ".length" )
|
|
6625
7344
|
cpp( "strlen( " (e 1) " )" (imp "<cstring>"))
|
|
6626
7345
|
go ( "int64(len(" (e 1 ) "))")
|
|
6627
|
-
;
|
|
6628
|
-
;
|
|
6629
|
-
;
|
|
7346
|
+
; how many BYTES. A Python charbuffer is `bytes`, so `len`
|
|
7347
|
+
; counts octets, not characters -- the same number every
|
|
7348
|
+
; other arm here answers. The `*` fallback is the JavaScript
|
|
7349
|
+
; `.length` property of a Uint8Array
|
|
6630
7350
|
python ( "len(" (e 1) ")" )
|
|
6631
7351
|
php ( "strlen(" (e 1 ) ")")
|
|
6632
7352
|
* ( (e 1) ".length" )
|
|
@@ -6828,7 +7548,22 @@ func r_last_index_of(_ s: String, _ needle: String) -> Int {
|
|
|
6828
7548
|
kotlin ( (e 1) "[" (e 2) "].code")
|
|
6829
7549
|
dart ( (e 1) ".codeUnitAt(" (e 2) ")" )
|
|
6830
7550
|
scala ( (e 1) "(" (e 2) ")")
|
|
6831
|
-
|
|
7551
|
+
; A Ranger string index is the target's own unit, and on Go
|
|
7552
|
+
; that unit is the UTF-8 byte -- what a Go string is made of,
|
|
7553
|
+
; and the only one it indexes in constant time. It was the
|
|
7554
|
+
; rune, and `[]rune(s)` allocates and copies the WHOLE string
|
|
7555
|
+
; on every read, so a scan was quadratic with a large
|
|
7556
|
+
; constant: 60 000 characters did not finish inside two
|
|
7557
|
+
; minutes where C++ took 5 ms.
|
|
7558
|
+
; It also disagreed with Go's own other string operators.
|
|
7559
|
+
; `indexOf` is strings.Index and answers a BYTE offset, so a
|
|
7560
|
+
; scanner that found a delimiter and sliced at it sliced in
|
|
7561
|
+
; the wrong place as soon as anything non-ASCII stood before
|
|
7562
|
+
; it: for "<a-umlaut>,b" the head came back as "<a-umlaut>,"
|
|
7563
|
+
; and the tail as "" -- the rest of the text, dropped without
|
|
7564
|
+
; a word. `charcode` read []byte(s)[0] all along.
|
|
7565
|
+
; docs/plans/PLAN_STRING_INDEXING.md 2.4.
|
|
7566
|
+
go ( "int64(" (e 1) "[" (e 2) "])")
|
|
6832
7567
|
swift3 ( "Int( ( NSString(string: " (e 1) " ) ).character( at: " (e 2) " ) )")
|
|
6833
7568
|
swift3 ( "Int( String( " (e 1) ".characters[" (e 1) ".index(" (e 1) ".startIndex, offsetBy: " (e 2) ")]))!")
|
|
6834
7569
|
; Also a named helper, and for the same reason: the inline form
|
|
@@ -6927,7 +7662,55 @@ func r_last_index_of(_ s: String, _ needle: String) -> Int {
|
|
|
6927
7662
|
")
|
|
6928
7663
|
)
|
|
6929
7664
|
python ( "ord(" (e 1) "[" (e 2) "])")
|
|
6930
|
-
rust ( (e 1) "
|
|
7665
|
+
rust ( "rg_char_at(&" (e 1) ", " (e 2) ")"
|
|
7666
|
+
(create_polyfill "
|
|
7667
|
+
// A Ranger string index is the TARGET'S OWN unit, and on Rust that unit is
|
|
7668
|
+
// the UTF-8 byte -- what a String is actually made of, and the only one it
|
|
7669
|
+
// indexes in constant time. It used to be the char: strlen counted chars(),
|
|
7670
|
+
// charAt was chars().nth(i) and substring was chars().skip().take(), so the
|
|
7671
|
+
// ordinary `while (i < (strlen s)) { charAt s i }` scan walked the string
|
|
7672
|
+
// once per character and was quadratic -- 120 000 characters took 8.8 s
|
|
7673
|
+
// where C++ took 11 ms. It also disagreed with charcode, which has read
|
|
7674
|
+
// as_bytes()[0] all along.
|
|
7675
|
+
//
|
|
7676
|
+
// Both helpers are TOTAL, because the forms they replace were: an index past
|
|
7677
|
+
// the end answered a zero rather than panicking, and scanners here rely on
|
|
7678
|
+
// reading one past the last character.
|
|
7679
|
+
fn rg_char_at(s: &str, at: i64) -> i64 {
|
|
7680
|
+
let b = s.as_bytes();
|
|
7681
|
+
if at < 0 { return 0; }
|
|
7682
|
+
let i = at as usize;
|
|
7683
|
+
if i >= b.len() { return 0; }
|
|
7684
|
+
b[i] as i64
|
|
7685
|
+
}
|
|
7686
|
+
|
|
7687
|
+
// A byte slice of a String has to be valid UTF-8, and a slice that cuts a
|
|
7688
|
+
// multi byte character is not. Measured over the compiler compiling itself
|
|
7689
|
+
// and the markdown gallery -- 78 012 slices -- not one cut a character:
|
|
7690
|
+
// a scanner slices at a delimiter it found, every delimiter here is ASCII,
|
|
7691
|
+
// and an ASCII byte is always a character boundary in UTF-8. So
|
|
7692
|
+
// from_utf8_lossy is the backstop for what the measurement did not cover,
|
|
7693
|
+
// not the expected path. docs/plans/PLAN_STRING_INDEXING.md 4.1.
|
|
7694
|
+
fn rg_substring(s: &str, from: i64, to: i64) -> String {
|
|
7695
|
+
let b = s.as_bytes();
|
|
7696
|
+
let n = b.len() as i64;
|
|
7697
|
+
let mut a = if from < 0 { 0 } else { from };
|
|
7698
|
+
if a > n { a = n; }
|
|
7699
|
+
let mut e = if to > n { n } else { to };
|
|
7700
|
+
if e < a { e = a; }
|
|
7701
|
+
// A Rust String cannot hold half a character, so a slice that cuts one
|
|
7702
|
+
// has to be rounded to a boundary rather than returned as bytes -- which
|
|
7703
|
+
// is what C++, PHP and Go can do and Rust cannot. The rule is Swift's,
|
|
7704
|
+
// for the same reason (see r_substring): the unit that STARTS a character
|
|
7705
|
+
// carries the whole of it and the units inside it carry nothing, so a
|
|
7706
|
+
// walk that copies one unit at a time still reproduces the text.
|
|
7707
|
+
while a < n && (b[a as usize] & 0xC0) == 0x80 { a += 1; }
|
|
7708
|
+
if e < a { e = a; }
|
|
7709
|
+
while e < n && (b[e as usize] & 0xC0) == 0x80 { e += 1; }
|
|
7710
|
+
String::from_utf8_lossy(&b[a as usize..e as usize]).to_string()
|
|
7711
|
+
}
|
|
7712
|
+
")
|
|
7713
|
+
)
|
|
6931
7714
|
* ( (e 1) ".charCodeAt(" (e 2) " )")
|
|
6932
7715
|
}
|
|
6933
7716
|
}
|
|
@@ -6974,6 +7757,11 @@ std::vector<std::string> r_get_keys_of_map( const M & orig_map ) {
|
|
|
6974
7757
|
}
|
|
6975
7758
|
}
|
|
6976
7759
|
|
|
7760
|
+
; ONE BYTE, 0..255, at that index. Not one character: a character
|
|
7761
|
+
; outside ASCII is two, three or four of these, so this is the
|
|
7762
|
+
; operator to reach for when the subject really is bytes and the
|
|
7763
|
+
; wrong one for walking text. See the block above the charbuffer
|
|
7764
|
+
; overloads.
|
|
6977
7765
|
charAt cmdCharAt:char ( text:charbuffer position:int ) {
|
|
6978
7766
|
templates {
|
|
6979
7767
|
ranger ( "(charAt " (e 1) " " ( e 2 ) ")")
|
|
@@ -6983,14 +7771,18 @@ std::vector<std::string> r_get_keys_of_map( const M & orig_map ) {
|
|
|
6983
7771
|
; a charbuffer is List<int> on Dart: index it, do not call
|
|
6984
7772
|
; codeUnitAt (which is the String overload's entry)
|
|
6985
7773
|
dart ( (e 1) "[" (e 2) "]" )
|
|
6986
|
-
|
|
7774
|
+
; `bytes` on Python: indexing one already gives the int
|
|
7775
|
+
python ( (e 1) "[" (e 2) "]" )
|
|
7776
|
+
; a Uint8Array on JavaScript, so index it rather than falling
|
|
7777
|
+
; through to the String.charCodeAt below
|
|
7778
|
+
es6 ( (e 1) "[" (e 2) "]" )
|
|
6987
7779
|
csharp ( (e 1) "[" (e 2) "]")
|
|
6988
7780
|
php ( "ord(" (e 1) "[" (e 2) "])")
|
|
6989
|
-
|
|
6990
|
-
;
|
|
6991
|
-
|
|
6992
|
-
kotlin ( (e 1) "[" (e 2) "].
|
|
6993
|
-
scala ( (e 1) "(" (e 2) ")")
|
|
7781
|
+
; a byte is SIGNED on the JVM, so & 0xFF is what makes the
|
|
7782
|
+
; answer the 0..255 the operator is declared to return
|
|
7783
|
+
java7 ( "((" (e 1) "[(int)" (e 2) "]) & 0xFF)")
|
|
7784
|
+
kotlin ( "(" (e 1) "[(" (e 2) ").toInt()].toInt() and 0xFF)")
|
|
7785
|
+
scala ( "(" (e 1) "(" (e 2) ".toInt) & 0xFF)")
|
|
6994
7786
|
go ( (e 1) "[" (e 2) "]")
|
|
6995
7787
|
swift3 ( (e 1) "[" (e 2) "]")
|
|
6996
7788
|
; Vec<u8> on Rust, so index the byte; `char` is an integer
|
|
@@ -7024,7 +7816,10 @@ std::vector<std::string> r_get_keys_of_map( const M & orig_map ) {
|
|
|
7024
7816
|
cpp ( '' (e 1) '.substr(' (e 2) ', ' (e 3) ' - ' (e 2) ')' )
|
|
7025
7817
|
csharp ( (e 1) ".Substring(" (e 2) ", " (e 3) " - " (e 2) " )")
|
|
7026
7818
|
php ( "substr(" (e 1) ", " (e 2) ", " (e 3) " - " (e 2) ")")
|
|
7027
|
-
|
|
7819
|
+
; bytes, like strlen and charAt above and like C++ below.
|
|
7820
|
+
; Slicing bytes still round-trips UTF-8 -- the pieces of a
|
|
7821
|
+
; multi byte character concatenate back into the character.
|
|
7822
|
+
go ( (e 1) "[" (e 2) ":" (e 3) "]")
|
|
7028
7823
|
swift3 ( (e 1) "[" (e 1) ".index(" (e 1) ".startIndex, offsetBy:" (e 2) ")..<" (e 1) ".index(" (e 1) ".startIndex, offsetBy:" (e 3) ")]" )
|
|
7029
7824
|
swift6 ( "r_substring(" (e 1) ", " (e 2) ", " (e 3) ")"
|
|
7030
7825
|
(create_polyfill "
|
|
@@ -7118,7 +7913,58 @@ func r_last_index_of(_ s: String, _ needle: String) -> Int {
|
|
|
7118
7913
|
")
|
|
7119
7914
|
)
|
|
7120
7915
|
python ( (e 1) "[" (e 2) ":" (e 3) "]" )
|
|
7121
|
-
|
|
7916
|
+
; rg_substring, the byte slice. The polyfill is the same
|
|
7917
|
+
; text as the one on `charAt` above, so whichever operator a
|
|
7918
|
+
; program uses first writes it and the other is deduped.
|
|
7919
|
+
rust ( "rg_substring(&" (e 1) ", " (e 2) ", " (e 3) ")"
|
|
7920
|
+
(create_polyfill "
|
|
7921
|
+
// A Ranger string index is the TARGET'S OWN unit, and on Rust that unit is
|
|
7922
|
+
// the UTF-8 byte -- what a String is actually made of, and the only one it
|
|
7923
|
+
// indexes in constant time. It used to be the char: strlen counted chars(),
|
|
7924
|
+
// charAt was chars().nth(i) and substring was chars().skip().take(), so the
|
|
7925
|
+
// ordinary `while (i < (strlen s)) { charAt s i }` scan walked the string
|
|
7926
|
+
// once per character and was quadratic -- 120 000 characters took 8.8 s
|
|
7927
|
+
// where C++ took 11 ms. It also disagreed with charcode, which has read
|
|
7928
|
+
// as_bytes()[0] all along.
|
|
7929
|
+
//
|
|
7930
|
+
// Both helpers are TOTAL, because the forms they replace were: an index past
|
|
7931
|
+
// the end answered a zero rather than panicking, and scanners here rely on
|
|
7932
|
+
// reading one past the last character.
|
|
7933
|
+
fn rg_char_at(s: &str, at: i64) -> i64 {
|
|
7934
|
+
let b = s.as_bytes();
|
|
7935
|
+
if at < 0 { return 0; }
|
|
7936
|
+
let i = at as usize;
|
|
7937
|
+
if i >= b.len() { return 0; }
|
|
7938
|
+
b[i] as i64
|
|
7939
|
+
}
|
|
7940
|
+
|
|
7941
|
+
// A byte slice of a String has to be valid UTF-8, and a slice that cuts a
|
|
7942
|
+
// multi byte character is not. Measured over the compiler compiling itself
|
|
7943
|
+
// and the markdown gallery -- 78 012 slices -- not one cut a character:
|
|
7944
|
+
// a scanner slices at a delimiter it found, every delimiter here is ASCII,
|
|
7945
|
+
// and an ASCII byte is always a character boundary in UTF-8. So
|
|
7946
|
+
// from_utf8_lossy is the backstop for what the measurement did not cover,
|
|
7947
|
+
// not the expected path. docs/plans/PLAN_STRING_INDEXING.md 4.1.
|
|
7948
|
+
fn rg_substring(s: &str, from: i64, to: i64) -> String {
|
|
7949
|
+
let b = s.as_bytes();
|
|
7950
|
+
let n = b.len() as i64;
|
|
7951
|
+
let mut a = if from < 0 { 0 } else { from };
|
|
7952
|
+
if a > n { a = n; }
|
|
7953
|
+
let mut e = if to > n { n } else { to };
|
|
7954
|
+
if e < a { e = a; }
|
|
7955
|
+
// A Rust String cannot hold half a character, so a slice that cuts one
|
|
7956
|
+
// has to be rounded to a boundary rather than returned as bytes -- which
|
|
7957
|
+
// is what C++, PHP and Go can do and Rust cannot. The rule is Swift's,
|
|
7958
|
+
// for the same reason (see r_substring): the unit that STARTS a character
|
|
7959
|
+
// carries the whole of it and the units inside it carry nothing, so a
|
|
7960
|
+
// walk that copies one unit at a time still reproduces the text.
|
|
7961
|
+
while a < n && (b[a as usize] & 0xC0) == 0x80 { a += 1; }
|
|
7962
|
+
if e < a { e = a; }
|
|
7963
|
+
while e < n && (b[e as usize] & 0xC0) == 0x80 { e += 1; }
|
|
7964
|
+
String::from_utf8_lossy(&b[a as usize..e as usize]).to_string()
|
|
7965
|
+
}
|
|
7966
|
+
")
|
|
7967
|
+
)
|
|
7122
7968
|
* ( (e 1) ".substring(" (e 2) ", " (e 3) " )")
|
|
7123
7969
|
}
|
|
7124
7970
|
}
|
|
@@ -7311,7 +8157,12 @@ func r_last_index_of(_ s: String, _ needle: String) -> Int {
|
|
|
7311
8157
|
cpp( "((unsigned char)" (e 1) ".at(0))")
|
|
7312
8158
|
dart ( (e 1) ".codeUnitAt(0)" )
|
|
7313
8159
|
php ( "ord(" (e 1) ")")
|
|
7314
|
-
|
|
8160
|
+
; charAt, not getBytes()[0]. A Ranger char is an int on
|
|
8161
|
+
; Java and a string index is a UTF-16 code unit here, so
|
|
8162
|
+
; `charcode` has to answer what `charAt s 0` answers. The byte
|
|
8163
|
+
; form answered neither: a JVM byte is SIGNED, so the first
|
|
8164
|
+
; byte of "<a-umlaut>" came back as -61 where charAt says 228.
|
|
8165
|
+
java7 ( "((int)" (e 1) ".charAt(0))")
|
|
7315
8166
|
swift3 ( "UInt8( ( NSString(string: " (e 1) " ) ).character( at: 0 ) )" (imp "Foundation"))
|
|
7316
8167
|
swift3 ( "UInt8( String( " (e 1) ".characters[" (e 1) ".startIndex]))! ")
|
|
7317
8168
|
swift6 ( "r_char_at(" (e 1) ", 0)"
|
|
@@ -7424,7 +8275,10 @@ func r_last_index_of(_ s: String, _ needle: String) -> Int {
|
|
|
7424
8275
|
templates {
|
|
7425
8276
|
ranger ( "(strfromcode " (e 1) ")")
|
|
7426
8277
|
csharp ( "((char)" (e 1) ").ToString()")
|
|
7427
|
-
|
|
8278
|
+
; the cast is not decoration: a Ranger `char` is a Java
|
|
8279
|
+
; `byte`, and a byte in a char[] initialiser is a narrowing
|
|
8280
|
+
; conversion javac refuses
|
|
8281
|
+
java7 ( "(new String( new char[] {(char)(" (e 1) ") }))")
|
|
7428
8282
|
kotlin ( (e 1) ".toChar().toString()")
|
|
7429
8283
|
swift3 ( "(String( Character( UnicodeScalar(" (e 1) " ) )))")
|
|
7430
8284
|
; A named helper, not an inline expression. UnicodeScalar has
|
|
@@ -7709,32 +8563,10 @@ inline std::string r_double_to_string(double v) {
|
|
|
7709
8563
|
ranger ( "(str2int " (e 1) ")")
|
|
7710
8564
|
cpp ("cpp_str_to_int(" (e 1) ")" (imp "<string>")
|
|
7711
8565
|
|
|
8566
|
+
(imp "<optional>")
|
|
7712
8567
|
(create_polyfill
|
|
7713
|
-
"
|
|
7714
|
-
|
|
7715
|
-
class r_optional_primitive {
|
|
7716
|
-
public:
|
|
7717
|
-
// has_value has to start false: cpp_str_to_int and its siblings leave the
|
|
7718
|
-
// field untouched when the conversion throws, and an indeterminate bool
|
|
7719
|
-
// made a failed str2int read back as a value on the C++ target.
|
|
7720
|
-
bool has_value = false;
|
|
7721
|
-
T value = T();
|
|
7722
|
-
r_optional_primitive<T> & operator=(const r_optional_primitive<T> & rhs) {
|
|
7723
|
-
has_value = rhs.has_value;
|
|
7724
|
-
value = rhs.value;
|
|
7725
|
-
return *this;
|
|
7726
|
-
}
|
|
7727
|
-
r_optional_primitive<T> & operator=(const T a_value) {
|
|
7728
|
-
has_value = true;
|
|
7729
|
-
value = a_value;
|
|
7730
|
-
return *this;
|
|
7731
|
-
}
|
|
7732
|
-
};
|
|
7733
|
-
"
|
|
7734
|
-
)
|
|
7735
|
-
(create_polyfill
|
|
7736
|
-
"r_optional_primitive<int> cpp_str_to_int(std::string s) {
|
|
7737
|
-
r_optional_primitive<int> result;
|
|
8568
|
+
"std::optional<int> cpp_str_to_int(std::string s) {
|
|
8569
|
+
std::optional<int> result;
|
|
7738
8570
|
try {
|
|
7739
8571
|
// Ranger `int` is 64-bit on Go, Rust, Java, Kotlin and Python and 32-bit
|
|
7740
8572
|
// here, so a literal between INT_MAX and INT64_MAX has no C++ int to
|
|
@@ -7744,8 +8576,7 @@ class r_optional_primitive {
|
|
|
7744
8576
|
long long wide = std::stoll(s);
|
|
7745
8577
|
if (wide > 2147483647LL) { wide = 2147483647LL; }
|
|
7746
8578
|
if (wide < -2147483648LL) { wide = -2147483648LL; }
|
|
7747
|
-
result
|
|
7748
|
-
result.has_value = true;
|
|
8579
|
+
result = (int)wide;
|
|
7749
8580
|
} catch (...) {
|
|
7750
8581
|
|
|
7751
8582
|
}
|
|
@@ -7892,32 +8723,10 @@ int? rangerStr2IntPrefix(String s) {
|
|
|
7892
8723
|
templates {
|
|
7893
8724
|
ranger ( "(str2double " (e 1) ")")
|
|
7894
8725
|
cpp ("cpp_str_to_double(" (e 1) ")" (imp "<string>")
|
|
8726
|
+
(imp "<optional>")
|
|
7895
8727
|
(create_polyfill
|
|
7896
|
-
"
|
|
7897
|
-
|
|
7898
|
-
class r_optional_primitive {
|
|
7899
|
-
public:
|
|
7900
|
-
// has_value has to start false: cpp_str_to_int and its siblings leave the
|
|
7901
|
-
// field untouched when the conversion throws, and an indeterminate bool
|
|
7902
|
-
// made a failed str2int read back as a value on the C++ target.
|
|
7903
|
-
bool has_value = false;
|
|
7904
|
-
T value = T();
|
|
7905
|
-
r_optional_primitive<T> & operator=(const r_optional_primitive<T> & rhs) {
|
|
7906
|
-
has_value = rhs.has_value;
|
|
7907
|
-
value = rhs.value;
|
|
7908
|
-
return *this;
|
|
7909
|
-
}
|
|
7910
|
-
r_optional_primitive<T> & operator=(const T a_value) {
|
|
7911
|
-
has_value = true;
|
|
7912
|
-
value = a_value;
|
|
7913
|
-
return *this;
|
|
7914
|
-
}
|
|
7915
|
-
};
|
|
7916
|
-
"
|
|
7917
|
-
)
|
|
7918
|
-
(create_polyfill
|
|
7919
|
-
"r_optional_primitive<double> cpp_str_to_double(std::string s) {
|
|
7920
|
-
r_optional_primitive<double> result;
|
|
8728
|
+
"std::optional<double> cpp_str_to_double(std::string s) {
|
|
8729
|
+
std::optional<double> result;
|
|
7921
8730
|
/* strtod, not stod: glibc's stod throws out_of_range whenever strtod
|
|
7922
8731
|
sets ERANGE, which includes SUBNORMAL results -- parsing 5e-324
|
|
7923
8732
|
(Number.MIN_VALUE) answered nothing at all. strtod still returns the
|
|
@@ -7929,8 +8738,7 @@ class r_optional_primitive {
|
|
|
7929
8738
|
if (end != cs) {
|
|
7930
8739
|
while (*end == 32 || *end == 9 || *end == 10 || *end == 13) { end++; }
|
|
7931
8740
|
if (*end == 0) {
|
|
7932
|
-
result
|
|
7933
|
-
result.has_value = true;
|
|
8741
|
+
result = v;
|
|
7934
8742
|
}
|
|
7935
8743
|
}
|
|
7936
8744
|
return result;
|
|
@@ -7942,7 +8750,7 @@ class r_optional_primitive {
|
|
|
7942
8750
|
"_getDoubleOrNull(" (e 1) " )"
|
|
7943
8751
|
(create_polyfill
|
|
7944
8752
|
"
|
|
7945
|
-
Double _getDoubleOrNull ( String str ) {
|
|
8753
|
+
static Double _getDoubleOrNull ( String str ) {
|
|
7946
8754
|
try {
|
|
7947
8755
|
return (Double.parseDouble(str));
|
|
7948
8756
|
} catch ( NullPointerException e ) {
|
|
@@ -8030,6 +8838,9 @@ def r_str_to_double(s):
|
|
|
8030
8838
|
ranger ( "(join " (e 1) " " (e 2) ")")
|
|
8031
8839
|
java7 ( "joinStrings(" (e 1 ) ", " (e 2) ")"
|
|
8032
8840
|
(imp "java.lang.StringBuilder")
|
|
8841
|
+
; the helper takes an ArrayList, so the file that gets the
|
|
8842
|
+
; helper needs the import even when nothing else in it does
|
|
8843
|
+
(imp "java.util.*")
|
|
8033
8844
|
(create_polyfill "
|
|
8034
8845
|
static String joinStrings(ArrayList<String> list, String delimiter)
|
|
8035
8846
|
{
|
|
@@ -8062,7 +8873,7 @@ std::string join(const T& v, const std::string& delim) {
|
|
|
8062
8873
|
") )
|
|
8063
8874
|
|
|
8064
8875
|
csharp ( "String.Join(" (e 2) ", " (e 1) ")" (imp "System"))
|
|
8065
|
-
go ( "strings.Join(" (e 1) ", " (e 2) ")")
|
|
8876
|
+
go ( "strings.Join(" (e 1) ", " (e 2) ")" (imp "strings"))
|
|
8066
8877
|
scala ( (e 1) ".mkString(" (e 2) ")" )
|
|
8067
8878
|
php ( "implode(" (e 2) ", " (e 1) ")")
|
|
8068
8879
|
swift3 ( (e 1) ".joined(separator:" (e 2) ")")
|
|
@@ -8118,39 +8929,15 @@ std::string join(const T& v, const std::string& delim) {
|
|
|
8118
8929
|
get cmdGet@(optional weak):int ( map:[K:int] key:K ) {
|
|
8119
8930
|
templates {
|
|
8120
8931
|
cpp( "cpp_get_map_int_value(" (e 1) ", " (e 2) ")"
|
|
8121
|
-
(
|
|
8122
|
-
"
|
|
8123
|
-
template <class T>
|
|
8124
|
-
class r_optional_primitive {
|
|
8125
|
-
public:
|
|
8126
|
-
// has_value has to start false: cpp_str_to_int and its siblings leave the
|
|
8127
|
-
// field untouched when the conversion throws, and an indeterminate bool
|
|
8128
|
-
// made a failed str2int read back as a value on the C++ target.
|
|
8129
|
-
bool has_value = false;
|
|
8130
|
-
T value = T();
|
|
8131
|
-
r_optional_primitive<T> & operator=(const r_optional_primitive<T> & rhs) {
|
|
8132
|
-
has_value = rhs.has_value;
|
|
8133
|
-
value = rhs.value;
|
|
8134
|
-
return *this;
|
|
8135
|
-
}
|
|
8136
|
-
r_optional_primitive<T> & operator=(const T a_value) {
|
|
8137
|
-
has_value = true;
|
|
8138
|
-
value = a_value;
|
|
8139
|
-
return *this;
|
|
8140
|
-
}
|
|
8141
|
-
};
|
|
8142
|
-
"
|
|
8143
|
-
)
|
|
8932
|
+
(imp "<optional>")
|
|
8144
8933
|
(macro
|
|
8145
8934
|
("
|
|
8146
8935
|
template<typename M, typename K>
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
result.has_value = false;
|
|
8936
|
+
std::optional<int> cpp_get_map_int_value( const M & m , const K & key) {
|
|
8937
|
+
std::optional<int> result;
|
|
8150
8938
|
auto it = m.find(key);
|
|
8151
8939
|
if (it != m.end()) {
|
|
8152
|
-
result
|
|
8153
|
-
result.has_value = true;
|
|
8940
|
+
result = it->second;
|
|
8154
8941
|
}
|
|
8155
8942
|
return result;
|
|
8156
8943
|
}")
|
|
@@ -8169,39 +8956,15 @@ r_optional_primitive<int> cpp_get_map_int_value( const M & m , const K & key) {
|
|
|
8169
8956
|
get cmdGet@(optional weak):double ( map:[K:double] key:K ) {
|
|
8170
8957
|
templates {
|
|
8171
8958
|
cpp( "cpp_get_map_string_double_value(" (e 1) ", " (e 2) ")"
|
|
8172
|
-
(
|
|
8173
|
-
"
|
|
8174
|
-
template <class T>
|
|
8175
|
-
class r_optional_primitive {
|
|
8176
|
-
public:
|
|
8177
|
-
// has_value has to start false: cpp_str_to_int and its siblings leave the
|
|
8178
|
-
// field untouched when the conversion throws, and an indeterminate bool
|
|
8179
|
-
// made a failed str2int read back as a value on the C++ target.
|
|
8180
|
-
bool has_value = false;
|
|
8181
|
-
T value = T();
|
|
8182
|
-
r_optional_primitive<T> & operator=(const r_optional_primitive<T> & rhs) {
|
|
8183
|
-
has_value = rhs.has_value;
|
|
8184
|
-
value = rhs.value;
|
|
8185
|
-
return *this;
|
|
8186
|
-
}
|
|
8187
|
-
r_optional_primitive<T> & operator=(const T a_value) {
|
|
8188
|
-
has_value = true;
|
|
8189
|
-
value = a_value;
|
|
8190
|
-
return *this;
|
|
8191
|
-
}
|
|
8192
|
-
};
|
|
8193
|
-
"
|
|
8194
|
-
)
|
|
8959
|
+
(imp "<optional>")
|
|
8195
8960
|
(macro
|
|
8196
8961
|
("
|
|
8197
8962
|
template<typename M, typename K>
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
result.has_value = false;
|
|
8963
|
+
std::optional<double> cpp_get_map_string_double_value( const M & m , const K & key) {
|
|
8964
|
+
std::optional<double> result;
|
|
8201
8965
|
auto it = m.find(key);
|
|
8202
8966
|
if (it != m.end()) {
|
|
8203
|
-
result
|
|
8204
|
-
result.has_value = true;
|
|
8967
|
+
result = it->second;
|
|
8205
8968
|
}
|
|
8206
8969
|
return result;
|
|
8207
8970
|
}")
|
|
@@ -8219,13 +8982,29 @@ r_optional_primitive<double> cpp_get_map_string_double_value( const M & m , cons
|
|
|
8219
8982
|
|
|
8220
8983
|
; `bool` and `null` have no common type, so the generic overload's
|
|
8221
8984
|
; conditional does not compile for a map of booleans -- the int and the
|
|
8222
|
-
; double overloads above carry a cast for exactly this reason.
|
|
8223
|
-
;
|
|
8224
|
-
; overload below.
|
|
8985
|
+
; double overloads above carry a cast for exactly this reason. Rust, C#
|
|
8986
|
+
; and C++ have entries here; every other target keeps reaching the
|
|
8987
|
+
; generic overload below.
|
|
8225
8988
|
get cmdGet@(optional weak):boolean ( map:[K:boolean] key:K ) {
|
|
8226
8989
|
templates {
|
|
8227
8990
|
rust ( (e 1) ".get(" (kref 2) ").cloned()" )
|
|
8228
8991
|
csharp ( "(" (e 1) ".ContainsKey(" (e 2) ") ? (bool?)" (e 1) "[" (e 2) "] : null)" )
|
|
8992
|
+
; An optional boolean is a bare bool on C++, so a miss reads
|
|
8993
|
+
; back as false, the value `null?` tests for.
|
|
8994
|
+
cpp ( "r_map_get_bool(" (e 1) ", " (ckey 2) ")"
|
|
8995
|
+
(create_polyfill
|
|
8996
|
+
"
|
|
8997
|
+
template<typename M, typename K>
|
|
8998
|
+
bool r_map_get_bool(const M& m, const K& key) {
|
|
8999
|
+
auto it = m.find(key);
|
|
9000
|
+
if (it != m.end()) {
|
|
9001
|
+
return it->second;
|
|
9002
|
+
}
|
|
9003
|
+
return false;
|
|
9004
|
+
}
|
|
9005
|
+
"
|
|
9006
|
+
)
|
|
9007
|
+
)
|
|
8229
9008
|
}
|
|
8230
9009
|
}
|
|
8231
9010
|
get cmdGet@(optional weak):T ( map:[K:T] key:K ) {
|
|
@@ -8239,31 +9018,16 @@ r_optional_primitive<double> cpp_get_map_string_double_value( const M & m , cons
|
|
|
8239
9018
|
cpp ( "r_map_get_val(" (e 1) ", " (ckey 2) ")"
|
|
8240
9019
|
(create_polyfill
|
|
8241
9020
|
"
|
|
8242
|
-
// Map read that never inserts on miss (unlike std::map::operator[]) and does a
|
|
8243
|
-
// single lookup. Returns a default-constructed value (e.g. null shared_ptr)
|
|
8244
|
-
// when the key is absent.
|
|
8245
|
-
//
|
|
8246
|
-
// A closed family (std::variant) is the one mapped_type with no null state:
|
|
8247
|
-
// every alternative is a live value, so a default-constructed variant reads
|
|
8248
|
-
// back as its FIRST alternative and a miss is indistinguishable from a genuine
|
|
8249
|
-
// value of that case. For those maps the result carries the presence bit in
|
|
8250
|
-
// r_optional_union; it converts back to the bare union, so a non-optional
|
|
8251
|
-
// destination behaves exactly as it did before. Every other mapped_type keeps
|
|
8252
|
-
// the original return type and body.
|
|
8253
|
-
#include <variant>
|
|
8254
|
-
// Defined next to the union typedefs when the program has a closed family. It
|
|
8255
|
-
// is only ever named for a variant-valued map, so a declaration is enough here
|
|
8256
|
-
// and a program with no shape at all still compiles.
|
|
8257
|
-
template <class T> class r_optional_union;
|
|
8258
|
-
template<typename T> struct r_map_result { typedef T type; };
|
|
8259
|
-
template<typename... A> struct r_map_result<std::variant<A...>> {
|
|
8260
|
-
typedef r_optional_union<std::variant<A...>> type;
|
|
8261
|
-
};
|
|
8262
9021
|
template<typename M, typename K>
|
|
8263
|
-
|
|
9022
|
+
std::optional<typename M::mapped_type>
|
|
9023
|
+
r_map_get_val(const M& m, const K& key) {
|
|
8264
9024
|
auto it = m.find(key);
|
|
8265
|
-
|
|
8266
|
-
|
|
9025
|
+
|
|
9026
|
+
if (it != m.end()) {
|
|
9027
|
+
return it->second;
|
|
9028
|
+
}
|
|
9029
|
+
|
|
9030
|
+
return std::nullopt;
|
|
8267
9031
|
}
|
|
8268
9032
|
"
|
|
8269
9033
|
)
|
|
@@ -8792,7 +9556,7 @@ bool r_string_ends_with(const std::string& str, const std::string& suffix) {
|
|
|
8792
9556
|
; change only the first one -- JavaScript, Go, C++ and Python -- and the
|
|
8793
9557
|
; other half changed them all, so the same program gave two answers.
|
|
8794
9558
|
; The compiler itself wants every occurrence: the trigraph escaping of
|
|
8795
|
-
;
|
|
9559
|
+
; RangerCppClassWriter.rgr calls `(replace s "??=" ...)` on a whole
|
|
8796
9560
|
; generated file.
|
|
8797
9561
|
replace _:string (str:string oldStr:string newStr:string) {
|
|
8798
9562
|
templates {
|
|
@@ -8858,7 +9622,14 @@ int r_arr_index_of( std::vector<T> vec, T elem ) {
|
|
|
8858
9622
|
; element -- an Rc is compared by identity, since
|
|
8859
9623
|
; Rc<RefCell<T>> implements PartialEq only when T does
|
|
8860
9624
|
rust ( (custom _) )
|
|
8861
|
-
|
|
9625
|
+
; array_search answers false on a miss, and `false >= 0` holds
|
|
9626
|
+
php ( "r_arr_index_of(" (e 1) ", " (e 2) ")"
|
|
9627
|
+
(create_polyfill "
|
|
9628
|
+
function r_arr_index_of($arr, $item) {
|
|
9629
|
+
$i = array_search($item, $arr, true);
|
|
9630
|
+
return $i === false ? -1 : $i;
|
|
9631
|
+
}
|
|
9632
|
+
"))
|
|
8862
9633
|
csharp ( (e 1) ".IndexOf(" (e 2) ")" )
|
|
8863
9634
|
go ( "r_indexof_arr_" (rawtype 1) "(" (e 1) ", " (e 2) ")"
|
|
8864
9635
|
(macro ("func r_indexof_arr_" (rawtype 1) "( a []" (ptr 1) (rawtype 1) ", item " (ptr 1) (rawtype 1) " ) ( int64 ) { " nl I
|
|
@@ -8956,7 +9727,12 @@ func r_index_of ( arr:" (typeof 1) " , elem: " (typeof 2) ") -> Int { " nl I
|
|
|
8956
9727
|
java7 ( (e 1) ".remove((int)(" (e 2) "));" )
|
|
8957
9728
|
csharp ( (e 1) ".RemoveAt((int)(" (e 2) "));" )
|
|
8958
9729
|
scala ( (e 1) ".remove((" (e 2) ").toInt)" )
|
|
8959
|
-
|
|
9730
|
+
; the index is parenthesised: `as` binds tighter than `-`
|
|
9731
|
+
; in Rust, so `remove(cnt - 1 as usize)` is
|
|
9732
|
+
; `cnt - (1 as usize)` -- i64 minus usize, which is the
|
|
9733
|
+
; only thing standing between this compiler's own Rust
|
|
9734
|
+
; rendering and rustc
|
|
9735
|
+
rust ( (e 1) ".remove((" (e 2) ") as usize);" )
|
|
8960
9736
|
}
|
|
8961
9737
|
}
|
|
8962
9738
|
|
|
@@ -9207,6 +9983,23 @@ func r_index_of ( arr:" (typeof 1) " , elem: " (typeof 2) ") -> Int { " nl I
|
|
|
9207
9983
|
; .toMutableList(): sortedWith answers a read only List, and every
|
|
9208
9984
|
; array in the writer is a MutableList
|
|
9209
9985
|
kotlin ( (e 1) ".sortedWith(Comparator { __a, __b -> (" (e 2) ")(__a, __b).toInt() }).toMutableList()" )
|
|
9986
|
+
; Java 7 has no lambdas and no statement expressions, so the
|
|
9987
|
+
; callback arrives as a LambdaSignature object and the sort
|
|
9988
|
+
; itself is a helper. Collections.sort is in place, and `sort`
|
|
9989
|
+
; leaves its argument alone on every other target, so the
|
|
9990
|
+
; helper sorts a COPY. Without this entry there was no java7
|
|
9991
|
+
; template at all and the operator did not match: the compiler
|
|
9992
|
+
; could not be rendered to Java at all, stopping at
|
|
9993
|
+
; "Could not match argument types for sort" in FlowCollect.
|
|
9994
|
+
java7 ( "r_sort_copy(" (e 1) ", new java.util.Comparator<" (atype 1) ">() { public int compare(" (atype 1) " __a, " (atype 1) " __b) { return (" (e 2) ").run(__a, __b).intValue(); } })" (imp "java.util.*")
|
|
9995
|
+
(create_polyfill "
|
|
9996
|
+
static <T> ArrayList<T> r_sort_copy(ArrayList<T> list, java.util.Comparator<T> cmp) {
|
|
9997
|
+
ArrayList<T> copy = new ArrayList<T>(list);
|
|
9998
|
+
java.util.Collections.sort(copy, cmp);
|
|
9999
|
+
return copy;
|
|
10000
|
+
}
|
|
10001
|
+
")
|
|
10002
|
+
)
|
|
9210
10003
|
; `..sort` is a cascade, so the expression is the sorted COPY --
|
|
9211
10004
|
; `sort` leaves its argument alone on every other target.
|
|
9212
10005
|
dart ( "(" (typeof 1) ".from(" (e 1) ")..sort((__a, __b) => (" (e 2) ")(__a, __b)))" )
|
|
@@ -9214,7 +10007,7 @@ func r_index_of ( arr:" (typeof 1) " , elem: " (typeof 2) ") -> Int { " nl I
|
|
|
9214
10007
|
swift3 ( (e 1) ".sorted(by: { (" (e 2) ")($0, $1) < 0 })" )
|
|
9215
10008
|
swift6 ( (e 1) ".sorted(by: { (" (e 2) ")($0, $1) < 0 })" )
|
|
9216
10009
|
go ( "(func(list " (typeof 1) ") " (typeof 1) " {" nl
|
|
9217
|
-
I "sort.
|
|
10010
|
+
I "sort.SliceStable(" (e 1) ", func(i, j int) bool { " nl
|
|
9218
10011
|
I "sortfn := " (e 2) nl
|
|
9219
10012
|
"sortval := sortfn(" (e 1)"[i], " (e 1)"[j])" nl
|
|
9220
10013
|
"return (sortval < 0)" nl i
|
|
@@ -9239,6 +10032,64 @@ static class RgSort {
|
|
|
9239
10032
|
}
|
|
9240
10033
|
}
|
|
9241
10034
|
|
|
10035
|
+
; `sort` of numbers without a comparison: a new array, ascending, the
|
|
10036
|
+
; argument left alone like the `sort` above
|
|
10037
|
+
sort _:[double] ( array:[double] ) {
|
|
10038
|
+
templates {
|
|
10039
|
+
ranger ( "(sort " (e 1) ")" )
|
|
10040
|
+
es6 ( (e 1) ".slice().sort((__a, __b) => __a - __b)" )
|
|
10041
|
+
python ( "sorted(" (e 1) ")" )
|
|
10042
|
+
php ( "(function($__arr) { sort($__arr); return $__arr; })(" (e 1) ")" )
|
|
10043
|
+
rust ( "{ let mut __v = " (e 1) ".clone(); __v.sort_by(|__a, __b| __a.partial_cmp(__b).unwrap()); __v }" )
|
|
10044
|
+
cpp ( "[&]() { auto __v = " (e 1) "; std::stable_sort(__v.begin(), __v.end()); return __v; }()" (imp "<algorithm>") )
|
|
10045
|
+
kotlin ( (e 1) ".sorted().toMutableList()" )
|
|
10046
|
+
java7 ( "r_sort_natural(" (e 1) ")" (imp "java.util.*")
|
|
10047
|
+
(create_polyfill "
|
|
10048
|
+
static <T extends Comparable<T>> ArrayList<T> r_sort_natural(ArrayList<T> list) {
|
|
10049
|
+
ArrayList<T> copy = new ArrayList<T>(list);
|
|
10050
|
+
java.util.Collections.sort(copy);
|
|
10051
|
+
return copy;
|
|
10052
|
+
}
|
|
10053
|
+
")
|
|
10054
|
+
)
|
|
10055
|
+
dart ( "(" (typeof 1) ".from(" (e 1) ")..sort())" )
|
|
10056
|
+
scala ( (e 1) ".sorted" )
|
|
10057
|
+
swift3 ( (e 1) ".sorted()" )
|
|
10058
|
+
swift6 ( (e 1) ".sorted()" )
|
|
10059
|
+
go ( "func(src " (typeof 1) ") " (typeof 1) " { out := append(" (typeof 1) "{}, src...); sort.SliceStable(out, func(i, j int) bool { return out[i] < out[j] }); return out }(" (e 1) ")" (imp "sort") )
|
|
10060
|
+
csharp ( "System.Linq.Enumerable.ToList(System.Linq.Enumerable.OrderBy(" (e 1) ", __x => __x))" (imp "System.Linq") )
|
|
10061
|
+
}
|
|
10062
|
+
}
|
|
10063
|
+
|
|
10064
|
+
; `sort` of numbers without a comparison: a new array, ascending, the
|
|
10065
|
+
; argument left alone like the `sort` above
|
|
10066
|
+
sort _:[int] ( array:[int] ) {
|
|
10067
|
+
templates {
|
|
10068
|
+
ranger ( "(sort " (e 1) ")" )
|
|
10069
|
+
es6 ( (e 1) ".slice().sort((__a, __b) => __a - __b)" )
|
|
10070
|
+
python ( "sorted(" (e 1) ")" )
|
|
10071
|
+
php ( "(function($__arr) { sort($__arr); return $__arr; })(" (e 1) ")" )
|
|
10072
|
+
rust ( "{ let mut __v = " (e 1) ".clone(); __v.sort_by(|__a, __b| __a.partial_cmp(__b).unwrap()); __v }" )
|
|
10073
|
+
cpp ( "[&]() { auto __v = " (e 1) "; std::stable_sort(__v.begin(), __v.end()); return __v; }()" (imp "<algorithm>") )
|
|
10074
|
+
kotlin ( (e 1) ".sorted().toMutableList()" )
|
|
10075
|
+
java7 ( "r_sort_natural(" (e 1) ")" (imp "java.util.*")
|
|
10076
|
+
(create_polyfill "
|
|
10077
|
+
static <T extends Comparable<T>> ArrayList<T> r_sort_natural(ArrayList<T> list) {
|
|
10078
|
+
ArrayList<T> copy = new ArrayList<T>(list);
|
|
10079
|
+
java.util.Collections.sort(copy);
|
|
10080
|
+
return copy;
|
|
10081
|
+
}
|
|
10082
|
+
")
|
|
10083
|
+
)
|
|
10084
|
+
dart ( "(" (typeof 1) ".from(" (e 1) ")..sort())" )
|
|
10085
|
+
scala ( (e 1) ".sorted" )
|
|
10086
|
+
swift3 ( (e 1) ".sorted()" )
|
|
10087
|
+
swift6 ( (e 1) ".sorted()" )
|
|
10088
|
+
go ( "func(src " (typeof 1) ") " (typeof 1) " { out := append(" (typeof 1) "{}, src...); sort.SliceStable(out, func(i, j int) bool { return out[i] < out[j] }); return out }(" (e 1) ")" (imp "sort") )
|
|
10089
|
+
csharp ( "System.Linq.Enumerable.ToList(System.Linq.Enumerable.OrderBy(" (e 1) ", __x => __x))" (imp "System.Linq") )
|
|
10090
|
+
}
|
|
10091
|
+
}
|
|
10092
|
+
|
|
9242
10093
|
; `reverse` gives a new array and leaves the argument alone -- the es6
|
|
9243
10094
|
; template has always been `.slice().reverse()`. Only es6 had one, so
|
|
9244
10095
|
; the operator did not compile anywhere else.
|
|
@@ -9398,6 +10249,8 @@ static class RgList {
|
|
|
9398
10249
|
php ( nl "echo " (e 1) ";" nl)
|
|
9399
10250
|
python ( nl "print(" (e 1) ", end='')" nl)
|
|
9400
10251
|
csharp ( nl "Console.Write(" (e 1) ");" nl (imp "System"))
|
|
10252
|
+
dart ( nl "stdout.write(" (e 1) ");" nl (imp "dart:io"))
|
|
10253
|
+
scala ( nl "print(" (e 1) ")" nl)
|
|
9401
10254
|
swift3 ( nl "print(" (e 1) ", terminator: \"\")" nl)
|
|
9402
10255
|
swift6 ( nl "print(" (e 1) ", terminator: \"\")" nl)
|
|
9403
10256
|
* ( nl "process.stdout.write(" (e 1) ");" nl)
|
|
@@ -9478,7 +10331,7 @@ static class RgList {
|
|
|
9478
10331
|
|
|
9479
10332
|
; Listen for keyboard input - callback receives key:string
|
|
9480
10333
|
; Creates a global key queue/receiver that poll_keypress can use
|
|
9481
|
-
on_keypress cmdOnKeypress:void (keyvar:string code:block) {
|
|
10334
|
+
on_keypress cmdOnKeypress:void (keyvar@(mutates):string code:block) {
|
|
9482
10335
|
templates {
|
|
9483
10336
|
es6 ( nl
|
|
9484
10337
|
"global.r_key_queue = [];" nl
|
|
@@ -9486,10 +10339,16 @@ static class RgList {
|
|
|
9486
10339
|
"readline.emitKeypressEvents(process.stdin);" nl
|
|
9487
10340
|
"if (process.stdin.isTTY) { process.stdin.setRawMode(true); }" nl
|
|
9488
10341
|
"process.stdin.resume();" nl
|
|
9489
|
-
|
|
9490
|
-
|
|
10342
|
+
; The handler's parameters are PREFIXED. Named `str` and `key`, they
|
|
10343
|
+
; shadowed any Ranger variable of the same name -- and `key` is the
|
|
10344
|
+
; obvious name for a key variable, so `on_keypress key { ... }` gave the
|
|
10345
|
+
; block node's key OBJECT instead of the string, and the assignment
|
|
10346
|
+
; below landed on the parameter rather than on the Ranger local.
|
|
10347
|
+
; ISSUES.md #91.
|
|
10348
|
+
"process.stdin.on('keypress', (__rgr_s, __rgr_key) => {" nl I
|
|
10349
|
+
"if (__rgr_key && __rgr_key.ctrl && __rgr_key.name === 'c') { process.stdout.write('\\x1b[?25h'); process.exit(); }" nl
|
|
9491
10350
|
"var __rgr_k = \"\";" nl
|
|
9492
|
-
"if (
|
|
10351
|
+
"if (__rgr_key && __rgr_key.name) { __rgr_k = __rgr_key.name; } else if (__rgr_s && __rgr_s.length > 0) { __rgr_k = __rgr_s; } else if (__rgr_key && __rgr_key.sequence) { __rgr_k = __rgr_key.sequence; }" nl
|
|
9493
10352
|
"if (__rgr_k !== \"\") { " (e 1) " = __rgr_k; global.r_key_queue.push(__rgr_k); }" nl
|
|
9494
10353
|
(block 2)
|
|
9495
10354
|
i nl "});" nl
|
|
@@ -10203,6 +11062,35 @@ fun r_read_key(): String {
|
|
|
10203
11062
|
}
|
|
10204
11063
|
}
|
|
10205
11064
|
|
|
11065
|
+
; Set the status this program ends with, WITHOUT ending it here.
|
|
11066
|
+
;
|
|
11067
|
+
; `exit` stops the process at once, and on node a stdout that is a pipe
|
|
11068
|
+
; -- `$(rgrc ... 2>&1)`, a log file, CI -- is written asynchronously, so
|
|
11069
|
+
; whatever was printed last is dropped on the floor. That is exactly the
|
|
11070
|
+
; error report the non-zero status is about. So set the code and let the
|
|
11071
|
+
; program end on its own. The targets whose stdout is unbuffered or
|
|
11072
|
+
; flushed at exit have nothing to defer and exit here.
|
|
11073
|
+
set_exit_code cmdSetExitCode:void ( code:int) {
|
|
11074
|
+
templates {
|
|
11075
|
+
llvm ( nl "exit " (e 1) nl)
|
|
11076
|
+
ranger ( nl "set_exit_code " (e 1) nl)
|
|
11077
|
+
cpp ( nl "exit(" (e 1) ");" nl (imp "<cstdlib>"))
|
|
11078
|
+
kotlin ( nl "System.exit(" (e 1) ")" nl )
|
|
11079
|
+
scala ( nl "System.exit(" (e 1) ")" nl )
|
|
11080
|
+
; Narrowed for the same reason as in `exit` below.
|
|
11081
|
+
go ( nl "os.Exit(int(" (e 1) "))" nl (imp "os"))
|
|
11082
|
+
rust ( nl "std::process::exit((" (e 1) ") as i32);" nl )
|
|
11083
|
+
java7 ( nl "System.exit(" (e 1) ");" nl )
|
|
11084
|
+
php ( nl "exit(" (e 1) ");" nl )
|
|
11085
|
+
python ( nl "sys.exit(" (e 1) ")" nl (imp "sys"))
|
|
11086
|
+
csharp ( nl "Environment.ExitCode = " (e 1) ";" nl (imp "System"))
|
|
11087
|
+
dart ( nl "exitCode = " (e 1) ";" nl (imp "dart:io"))
|
|
11088
|
+
swift3 ( nl "exit(Int32(" (e 1) "))" nl (imp "Foundation"))
|
|
11089
|
+
swift6 ( nl "exit(Int32(" (e 1) "))" nl (imp "Foundation"))
|
|
11090
|
+
* ( nl "process.exitCode = " (e 1) ";" nl)
|
|
11091
|
+
}
|
|
11092
|
+
}
|
|
11093
|
+
|
|
10206
11094
|
exit cmdExit:void ( code:int) {
|
|
10207
11095
|
templates {
|
|
10208
11096
|
llvm ( nl "exit " (e 1) nl)
|
|
@@ -10335,9 +11223,29 @@ std::string r_cpp_str_to_uppercase(const std::string& original)
|
|
|
10335
11223
|
}
|
|
10336
11224
|
}
|
|
10337
11225
|
|
|
11226
|
+
; Java: an int, double or boolean is often an Integer / Double /
|
|
11227
|
+
; Boolean object, and `==` between two of them compares references
|
|
11228
|
+
; (Integer caches -128..127 only, so 128 == 128 was false, and two
|
|
11229
|
+
; equal Double fields were never ==). rg_eq compares numbers by value
|
|
11230
|
+
; and everything else by reference, as before.
|
|
10338
11231
|
== cmdEqual:boolean ( left:T right:T ) {
|
|
10339
11232
|
templates {
|
|
10340
11233
|
rust ( (custom _) )
|
|
11234
|
+
java7 ( "rg_eq(" (e 1) ", " (e 2) ")"
|
|
11235
|
+
(create_polyfill "
|
|
11236
|
+
static boolean rg_eq(Object a, Object b) {
|
|
11237
|
+
if (a instanceof Number && b instanceof Number) {
|
|
11238
|
+
if (a instanceof Double || b instanceof Double || a instanceof Float || b instanceof Float) {
|
|
11239
|
+
return ((Number) a).doubleValue() == ((Number) b).doubleValue();
|
|
11240
|
+
}
|
|
11241
|
+
return ((Number) a).longValue() == ((Number) b).longValue();
|
|
11242
|
+
}
|
|
11243
|
+
if (a instanceof Boolean && b instanceof Boolean) {
|
|
11244
|
+
return ((Boolean) a).booleanValue() == ((Boolean) b).booleanValue();
|
|
11245
|
+
}
|
|
11246
|
+
return a == b;
|
|
11247
|
+
}
|
|
11248
|
+
"))
|
|
10341
11249
|
* ( (e 1) " == " (e 2) )
|
|
10342
11250
|
}
|
|
10343
11251
|
}
|
|
@@ -10449,6 +11357,21 @@ std::string r_cpp_str_to_uppercase(const std::string& original)
|
|
|
10449
11357
|
!= cmdNeq:boolean ( left:T right:T ) {
|
|
10450
11358
|
templates {
|
|
10451
11359
|
rust ( (custom _) )
|
|
11360
|
+
java7 ( "!rg_eq(" (e 1) ", " (e 2) ")"
|
|
11361
|
+
(create_polyfill "
|
|
11362
|
+
static boolean rg_eq(Object a, Object b) {
|
|
11363
|
+
if (a instanceof Number && b instanceof Number) {
|
|
11364
|
+
if (a instanceof Double || b instanceof Double || a instanceof Float || b instanceof Float) {
|
|
11365
|
+
return ((Number) a).doubleValue() == ((Number) b).doubleValue();
|
|
11366
|
+
}
|
|
11367
|
+
return ((Number) a).longValue() == ((Number) b).longValue();
|
|
11368
|
+
}
|
|
11369
|
+
if (a instanceof Boolean && b instanceof Boolean) {
|
|
11370
|
+
return ((Boolean) a).booleanValue() == ((Boolean) b).booleanValue();
|
|
11371
|
+
}
|
|
11372
|
+
return a == b;
|
|
11373
|
+
}
|
|
11374
|
+
"))
|
|
10452
11375
|
* ( (e 1) " != " (e 2) )
|
|
10453
11376
|
}
|
|
10454
11377
|
}
|
|
@@ -10499,7 +11422,7 @@ std::string r_cpp_str_to_uppercase(const std::string& original)
|
|
|
10499
11422
|
csharp ( (e 1) " != null && " (e 2) " != null")
|
|
10500
11423
|
|
|
10501
11424
|
php ( "isset("(e 1) ") && isset(" (e 2) ")")
|
|
10502
|
-
java7 ( (e 1) "
|
|
11425
|
+
java7 ( (e 1) " != null && " (e 2) " != null")
|
|
10503
11426
|
rust ( (e 1) ".is_some() && " (e 2) ".is_some()")
|
|
10504
11427
|
swift3 ( (e 1) " != nil && " (e 2) " != nil")
|
|
10505
11428
|
swift6 ( (e 1) " != nil && " (e 2) " != nil")
|
|
@@ -10517,7 +11440,7 @@ std::string r_cpp_str_to_uppercase(const std::string& original)
|
|
|
10517
11440
|
ranger ( "(" (e 1) " && " (e 2) ")" )
|
|
10518
11441
|
php ( (e 1) " && isset(" (e 2) ")")
|
|
10519
11442
|
scala ( (e 1) " && " (e 2) ".isDefined")
|
|
10520
|
-
java7 ( (e 1) " && " (e 2) "
|
|
11443
|
+
java7 ( (e 1) " && " (e 2) " != null")
|
|
10521
11444
|
csharp ( (e 1) " && " (e 2) " != null")
|
|
10522
11445
|
|
|
10523
11446
|
rust ( (e 1) " && " (e 2) ".is_some()")
|
|
@@ -10537,7 +11460,7 @@ std::string r_cpp_str_to_uppercase(const std::string& original)
|
|
|
10537
11460
|
ranger ( "(" (e 1) " && " (e 2) ")" )
|
|
10538
11461
|
php ( "isset("(e 1) ") && " (e 2) )
|
|
10539
11462
|
scala ( ""(e 1) ".isDefined && " (e 2) )
|
|
10540
|
-
java7 ( ""(e 1) "
|
|
11463
|
+
java7 ( ""(e 1) " != null && " (e 2) )
|
|
10541
11464
|
csharp ( ""(e 1) " != null && " (e 2) )
|
|
10542
11465
|
|
|
10543
11466
|
rust ( ""(e 1) ".is_some() && " (e 2) )
|
|
@@ -10725,32 +11648,7 @@ std::string r_cpp_str_to_uppercase(const std::string& original)
|
|
|
10725
11648
|
* ( "false /* sse_is_connected not implemented */" )
|
|
10726
11649
|
}
|
|
10727
11650
|
}
|
|
10728
|
-
|
|
10729
|
-
; HTTP Server Lifecycle Operators
|
|
10730
|
-
; These are special operators - the Go writer will detect @(HttpServer) class
|
|
10731
|
-
; and generate route setup code when start is called on HttpServer
|
|
10732
11651
|
|
|
10733
|
-
; Start HTTP server - wires up all @(GET), @(POST), @(SSE) routes and starts listening
|
|
10734
|
-
; Usage: start server 8080 OR start server (uses default port from annotation)
|
|
10735
|
-
; The Go writer generates http.HandleFunc calls for each annotated method
|
|
10736
|
-
start@(moves@( 1 )) cmdHttpServerStart:void (server:HttpServer port:int) {
|
|
10737
|
-
templates {
|
|
10738
|
-
go ( (custom _) )
|
|
10739
|
-
es6 ( (e 1) ".start(" (e 2) ")" )
|
|
10740
|
-
* ( "/* start HttpServer not implemented */" )
|
|
10741
|
-
}
|
|
10742
|
-
}
|
|
10743
|
-
|
|
10744
|
-
; Stop HTTP server gracefully
|
|
10745
|
-
; Usage: stop server
|
|
10746
|
-
stop@(moves@( 1 )) cmdHttpServerStop:void (server:HttpServer) {
|
|
10747
|
-
templates {
|
|
10748
|
-
go ( (e 1) ".Shutdown(context.Background())" )
|
|
10749
|
-
es6 ( (e 1) ".stop()" )
|
|
10750
|
-
* ( "/* stop HttpServer not implemented */" )
|
|
10751
|
-
}
|
|
10752
|
-
}
|
|
10753
|
-
|
|
10754
11652
|
; Process lifecycle operators (distinct from HttpServer start/stop)
|
|
10755
11653
|
find_process@(moves@( 1 )) cmdFindProcess:RangerProcessBase@(optional) (path:string) {
|
|
10756
11654
|
templates {
|
|
@@ -10762,7 +11660,7 @@ std::string r_cpp_str_to_uppercase(const std::string& original)
|
|
|
10762
11660
|
}
|
|
10763
11661
|
}
|
|
10764
11662
|
|
|
10765
|
-
; proc_send is lowered in
|
|
11663
|
+
; proc_send is lowered in RangerProcessProcSend.rgr (typed handler methods, overload match).
|
|
10766
11664
|
|
|
10767
11665
|
begin_dispatch_turn@(moves@( 1 )) cmdBeginDispatchTurn:void (root:RangerProcessBase) {
|
|
10768
11666
|
templates {
|