diff --git a/.github/actions/setup-ocaml/action.yml b/.github/actions/setup-ocaml/action.yml index d47e60003c5..b9eb3f1ef8e 100644 --- a/.github/actions/setup-ocaml/action.yml +++ b/.github/actions/setup-ocaml/action.yml @@ -82,7 +82,8 @@ runs: run: | dependency_flags_key="${DEPENDENCY_FLAGS//--/}" dependency_flags_key="${dependency_flags_key// /_}" - key="$CACHE_PREFIX-$OS-3.9.0-$COMPILER-$dependency_flags_key-${{ hashFiles('*.opam') }}" + dependency_hash="${{ hashFiles('*.opam', '.github/opam-repository/repo', '.github/opam-repository/packages/**') }}" + key="$CACHE_PREFIX-$OS-3.9.0-$COMPILER-$dependency_flags_key-$dependency_hash" echo "value=${key//,/-}" >> "$GITHUB_OUTPUT" echo "setup-version=3.9.0" >> "$GITHUB_OUTPUT" @@ -104,6 +105,11 @@ runs: uses: ocaml/setup-ocaml@v3.9.0 with: ocaml-compiler: ${{ inputs.compiler }} + # Use the HTTP repository to prevent intermittent CI setup failures: + # the Git-backed default can race with detached Git maintenance while + # OPAM scans it (https://github.com/ocaml/opam/issues/7031). + opam-repositories: | + default: https://opam.ocaml.org opam-pin: false cache: false @@ -125,12 +131,21 @@ runs: env: DEPENDENCY_FLAGS: ${{ inputs.dependency-flags }} run: | + opam repository add rescript-overrides "$GITHUB_WORKSPACE/.github/opam-repository" read -ra dependency_flags <<< "$DEPENDENCY_FLAGS" + if [[ "$RUNNER_OS" == "Windows" ]]; then + export AR=x86_64-w64-mingw32-ar + export RANLIB=x86_64-w64-mingw32-ranlib + export STRIP=x86_64-w64-mingw32-strip + export NM=x86_64-w64-mingw32-nm + export DLLTOOL=x86_64-w64-mingw32-dlltool + export OBJDUMP=x86_64-w64-mingw32-objdump + fi opam install . "${dependency_flags[@]}" - name: Cache OPAM environment # Caches created by pull_request runs are scoped to that PR's merge ref - # and cannot seed other PRs or branches. Only pushes create shared caches. + # and cannot seed other PRs or branches, so only push runs save them. if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'push' uses: actions/cache/save@v6 with: diff --git a/.github/opam-repository/README.md b/.github/opam-repository/README.md new file mode 100644 index 00000000000..35e088bb9a0 --- /dev/null +++ b/.github/opam-repository/README.md @@ -0,0 +1,14 @@ +# ReScript opam overrides + +This repository contains narrowly scoped dependency fixes needed by CI before +they are available from the main opam repository. + +The Luv 0.5.14 override preserves the ARM64 musl compiler's +`-mno-outline-atomics` requirement while building vendored libuv. Without it, +the static executable fails to link because libuv refers to glibc's internal +`__getauxval` symbol. The patch should be contributed upstream and this +override removed once a fixed Luv release is available. + +Luv 0.5.14 also vendors libuv 1.48.0. Evaluating and contributing an update to +a current libuv 1.x release is a separate upstream follow-up; changing the +vendored library is intentionally outside the OCaml rewatch port. diff --git a/.github/opam-repository/packages/luv/luv.0.5.14/files/arm64-musl-outline-atomics.patch b/.github/opam-repository/packages/luv/luv.0.5.14/files/arm64-musl-outline-atomics.patch new file mode 100644 index 00000000000..674f1b37c4c --- /dev/null +++ b/.github/opam-repository/packages/luv/luv.0.5.14/files/arm64-musl-outline-atomics.patch @@ -0,0 +1,20 @@ +--- a/src/c/dune ++++ b/src/c/dune +@@ -82,8 +82,14 @@ + (action (progn + (bash "cp -r vendor/configure/* vendor/libuv/") + (chdir vendor/libuv (progn + (bash +- "sh configure --host `ocamlc -config | awk '/^host:/ {print $NF}'` \ +- 'CC=%{cc}' CFLAGS=-DNDEBUG --silent --enable-silent-rules") ++ "architecture=`ocamlc -config-var architecture` ++ c_compiler=`ocamlc -config-var c_compiler` ++ extra_cflags= ++ case \"$architecture:$c_compiler\" in ++ arm64:*musl*) extra_cflags=-mno-outline-atomics ;; ++ esac ++ sh configure --host `ocamlc -config | awk '/^host:/ {print $NF}'` \ ++ 'CC=%{cc}' CFLAGS=\"-DNDEBUG $extra_cflags\" --silent --enable-silent-rules") + (ignore-outputs (bash + "$([ '%{os_type}' = Unix ] && echo %{make} || echo make) V=0 -j 4 \ + -o aclocal.m4 -o Makefile.in -o configure \ diff --git a/.github/opam-repository/packages/luv/luv.0.5.14/opam b/.github/opam-repository/packages/luv/luv.0.5.14/opam new file mode 100644 index 00000000000..e64c76a6dd5 --- /dev/null +++ b/.github/opam-repository/packages/luv/luv.0.5.14/opam @@ -0,0 +1,42 @@ +opam-version: "2.0" +name: "luv" +version: "0.5.14" +synopsis: "Binding to libuv: cross-platform asynchronous I/O" +description: """\ +Luv is a binding to libuv, the cross-platform C library that does +asynchronous I/O in Node.js and runs its main loop. + +Besides asynchronous I/O, libuv also supports multiprocessing and +multithreading. Multiple event loops can be run in different threads. libuv also +exposes a lot of other functionality, amounting to a full OS API, and an +alternative to the standard module Unix.""" +maintainer: "Anton Bachin " +authors: "Anton Bachin " +license: "MIT" +homepage: "https://github.com/aantron/luv" +doc: "https://aantron.github.io/luv" +bug-reports: "https://github.com/aantron/luv/issues" +depends: [ + "base-unix" {build} + "ctypes" {>= "0.14.0"} + "dune" {>= "2.7.0"} + "ocaml" {>= "4.03.0"} + "alcotest" {with-test & >= "0.8.1"} + "base-unix" {with-test} + "odoc" {with-doc & = "2.4.0"} +] +build: ["dune" "build" "-p" name "-j" jobs] +patches: ["arm64-musl-outline-atomics.patch"] +extra-files: [ + [ + "arm64-musl-outline-atomics.patch" + "sha256=c15c4c4d34c9b545197c5160e19c69a128cc186b65a54e0e9a779c2543528a4f" + ] +] +dev-repo: "git+https://github.com/aantron/luv.git" +url { + src: + "https://github.com/aantron/luv/releases/download/0.5.14/luv-0.5.14.tar.gz" + checksum: + "sha256=8e01b4a50c8876cdd98d8e245c0687c4dc4d883aed161ad9c5ace1fb1fdaae99" +} diff --git a/.github/opam-repository/repo b/.github/opam-repository/repo new file mode 100644 index 00000000000..013b84db617 --- /dev/null +++ b/.github/opam-repository/repo @@ -0,0 +1 @@ +opam-version: "2.0" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e90492a8fde..d5c8f5b5f29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,6 +74,8 @@ jobs: dune-profile: release # Verify that the compiler still builds with the oldest OCaml version we support. + # Steps comparing OCaml and Rust rewatch are skipped on this job; the + # first linux-x64 job runs them. - os: ubuntu-24.04 ocaml_compiler: ocaml-variants.5.0.0+options,ocaml-option-static node-target: linux-x64 @@ -218,8 +220,64 @@ jobs: run: echo "C:\Program Files\Git\bin" >> $GITHUB_PATH shell: bash - - name: Run rewatch tests - run: ./rewatch/tests/suite.sh rewatch/target/release/rescript + - name: Run OCaml rewatch parity tests + if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }} + timeout-minutes: 20 + run: | + bash rewatch-ocaml/tests/check_canonical_test_coverage.sh + bash rewatch-ocaml/tests/check_config_acceptance.sh \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe + bash rewatch-ocaml/tests/check_command_validation.sh \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe + shell: bash + + - name: Run OCaml rewatch interactive output tests + # Terminal rendering depends on the host OS, not the CPU architecture. + # Use the faster ARM runners for one Linux and one macOS check. Windows + # does not provide a reliable native equivalent of the `script` PTY. + if: matrix.node-target == 'linux-arm64' || matrix.node-target == 'darwin-arm64' + timeout-minutes: 15 + run: | + bash rewatch-ocaml/tests/check_interactive_output.sh \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe + shell: bash + + - name: Run OCaml rewatch verbose output tests + if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }} + timeout-minutes: 10 + run: | + bash rewatch-ocaml/tests/check_verbose_output.sh \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \ + packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe + shell: bash + + - name: Run OCaml rewatch unit tests + timeout-minutes: 10 + run: | + opam exec -- dune build tests/rewatch_ounit_tests/rewatch_ounit_tests_main.exe + # Run the executable directly so a stuck test leaves live progress; + # dune otherwise buffers the test output until the action exits. + opam exec -- ./_build/default/tests/rewatch_ounit_tests/rewatch_ounit_tests_main.exe -runner sequential + shell: bash + + - name: Run OCaml rewatch focused integration tests + timeout-minutes: 30 + run: | + sh rewatch-ocaml/tests/run.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe + shell: bash + + - name: Run OCaml rewatch canonical tests + run: ./rewatch/tests/suite.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe + shell: bash + + # The Rust implementation is kept for comparison. One platform runs its + # shared suite; the parity steps exercise it on every platform. + - name: Run Rust rewatch reference tests + if: matrix.node-target == 'linux-arm64' + run: ./rewatch/tests/suite.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe shell: bash - name: Run syntax benchmarks diff --git a/AGENTS.md b/AGENTS.md index 1ee7b86c96a..a0f09dcad76 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,8 +25,8 @@ The Makefile’s targets build on each other in this order: 1. `yarn-install` runs automatically for targets that need JavaScript tooling (lib, playground, tests, formatting, etc.). 2. `build` (default target) builds the toolchain binaries (all copied into `packages/@rescript//bin`): - - `compiler` builds the dune executables (`bsc`, `rescript-*`, `ounit_tests`, etc.). - - `rewatch` builds the Rust-based ReScript build system and CLI. + - `compiler` builds the dune executables (`bsc`, `rescript-*`, `ounit_tests`, etc.), including the OCaml build system and CLI (`rescript`). + - `rewatch` builds the Rust implementation of the build system (`rescript-rust`). 3. `lib` uses those toolchain outputs to build the runtime sources. 4. Test targets (`make test`, `make test-syntax`, etc.) reuse everything above. @@ -34,7 +34,9 @@ The Makefile’s targets build on each other in this order: Before changing a subsystem, read its local agent instructions and area guide. For compiler changes, read [compiler/AGENTS.md](compiler/AGENTS.md). For build -system changes, read [rewatch/AGENTS.md](rewatch/AGENTS.md). These apply even +system changes, read [rewatch-ocaml/AGENTS.md](rewatch-ocaml/AGENTS.md) for the +OCaml implementation and [rewatch/AGENTS.md](rewatch/AGENTS.md) for the Rust +one. These apply even when the task starts at the repository root. Changes spanning areas need the relevant guidance from each. @@ -45,7 +47,8 @@ relevant guidance from each. - [`compiler/core/README.md`](compiler/core/README.md) for Lambda optimization and JavaScript generation - [`analysis/README.md`](analysis/README.md) for editor analysis -- [`rewatch/README.md`](rewatch/README.md) for the build system +- [`rewatch-ocaml/README.md`](rewatch-ocaml/README.md) and + [`rewatch/README.md`](rewatch/README.md) for the build system - [`tools/README.md`](tools/README.md) for `rescript-tools` ## Coding guidelines diff --git a/Makefile b/Makefile index c15c49dcaeb..110dff344ce 100644 --- a/Makefile +++ b/Makefile @@ -79,6 +79,8 @@ $(YARN_INSTALL_STAMP): $(YARN_INSTALL_SOURCES) REWATCH_SOURCES = $(shell find rewatch/src -name '*.rs') rewatch/Cargo.toml rewatch/Cargo.lock RESCRIPT_EXE = $(BIN_DIR)/rescript.exe +RESCRIPT_RUST_EXE := $(BIN_DIR)/rescript-rust.exe +PACKAGED_RUST_EXE := $(RESCRIPT_RUST_EXE) ifdef CI REWATCH_PROFILE := release REWATCH_CARGO_FLAGS := --release @@ -88,22 +90,22 @@ else endif REWATCH_TARGET := rewatch/target/$(REWATCH_PROFILE)/rescript$(PLATFORM_EXE_EXT) -rewatch: $(RESCRIPT_EXE) +rewatch: $(PACKAGED_RUST_EXE) -$(RESCRIPT_EXE): $(REWATCH_TARGET) +$(PACKAGED_RUST_EXE): $(REWATCH_TARGET) $(call COPY_EXE,$<,$@) $(REWATCH_TARGET): $(REWATCH_SOURCES) cargo build --manifest-path rewatch/Cargo.toml $(REWATCH_CARGO_FLAGS) clean-rewatch: - cargo clean --manifest-path rewatch/Cargo.toml && rm -rf rewatch/target && rm -f $(RESCRIPT_EXE) + cargo clean --manifest-path rewatch/Cargo.toml && rm -rf rewatch/target && rm -f $(PACKAGED_RUST_EXE) # Compiler -COMPILER_SOURCE_DIRS := compiler tests analysis tools -COMPILER_SOURCES = $(shell find $(COMPILER_SOURCE_DIRS) -type f \( -name '*.ml' -o -name '*.mli' -o -name '*.dune' -o -name dune -o -name dune-project \)) -COMPILER_BIN_NAMES := bsc rescript-editor-analysis rescript-tools +COMPILER_SOURCE_DIRS := compiler tests analysis tools rewatch-ocaml +COMPILER_SOURCES = $(shell find $(COMPILER_SOURCE_DIRS) -type f \( -name '*.ml' -o -name '*.mli' -o -name '*.c' -o -name '*.h' -o -name '*.dune' -o -name dune -o -name dune-project \)) +COMPILER_BIN_NAMES := bsc rescript-editor-analysis rescript-tools rescript COMPILER_EXES := $(addsuffix .exe,$(addprefix $(BIN_DIR)/,$(COMPILER_BIN_NAMES))) compiler: $(COMPILER_EXES) @@ -279,9 +281,13 @@ COVERAGE_TEST_ENV := BISECT_FILE=$(COVERAGE_BISECT_PREFIX) BISECT_SILENT=YES .PHONY: coverage-build coverage-build: | $(YARN_INSTALL_STAMP) dune build --instrument-with bisect_ppx - @$(foreach bin,$(COMPILER_BIN_NAMES), \ + @$(foreach bin,$(filter-out rescript,$(COMPILER_BIN_NAMES)), \ cp $(DUNE_BIN_DIR)/$(bin)$(PLATFORM_EXE_EXT) $(BIN_DIR)/$(bin).exe && \ chmod 755 $(BIN_DIR)/$(bin).exe;) +ifneq ($(OS),Windows_NT) + cp _build/default/rewatch-ocaml/rescript_ocaml.exe $(RESCRIPT_EXE) + chmod 755 $(RESCRIPT_EXE) +endif .PHONY: coverage-prepare coverage-prepare: clean-coverage coverage-build diff --git a/biome.json b/biome.json index 94358cad64f..09994b663ab 100644 --- a/biome.json +++ b/biome.json @@ -64,6 +64,7 @@ "!**/tests/tests/**/src", "!**/tests/tools_tests/**/src", "!**/rewatch", + "!**/rewatch-ocaml", "!**/lib/es6", "!**/lib/js", "!**/lib/bs", diff --git a/changes/ocaml-rewatch-strict-config.breaking.md b/changes/ocaml-rewatch-strict-config.breaking.md new file mode 100644 index 00000000000..4a1ae5c8b8e --- /dev/null +++ b/changes/ocaml-rewatch-strict-config.breaking.md @@ -0,0 +1 @@ +- The OCaml build system rejects duplicate keys in `rescript.json` maps, a `namespace-entry` without a namespace, and a value after `--no-timing`. https://github.com/rescript-lang/rescript/pull/8780 diff --git a/changes/ocaml-rewatch.feature.md b/changes/ocaml-rewatch.feature.md new file mode 100644 index 00000000000..62fbd68f5c9 --- /dev/null +++ b/changes/ocaml-rewatch.feature.md @@ -0,0 +1 @@ +- `rescript` now runs a build system rewritten in OCaml; the Rust implementation remains available as `rescript-rust`. https://github.com/rescript-lang/rescript/pull/8780 diff --git a/cli/common/bins.cjs b/cli/common/bins.cjs index a99de4b02ab..41f478e09db 100644 --- a/cli/common/bins.cjs +++ b/cli/common/bins.cjs @@ -46,6 +46,7 @@ exports.rescript_editor_analysis_exe = path.join( ); exports.rescript_tools_exe = path.join(binDir, "rescript-tools.exe"); exports.rescript_exe = path.join(binDir, "rescript.exe"); +exports.rescript_rust_exe = path.join(binDir, "rescript-rust.exe"); function checkNodeVersionSupported() { if ( diff --git a/cli/common/bins.js b/cli/common/bins.js index 10a97c2a13a..6a375fc9284 100644 --- a/cli/common/bins.js +++ b/cli/common/bins.js @@ -7,5 +7,6 @@ export { bsc_exe, rescript_editor_analysis_exe, rescript_exe, + rescript_rust_exe, rescript_tools_exe, } from "./bins.cjs"; diff --git a/cli/common/runBuildSystem.js b/cli/common/runBuildSystem.js new file mode 100644 index 00000000000..09ce5ae8427 --- /dev/null +++ b/cli/common/runBuildSystem.js @@ -0,0 +1,72 @@ +// @ts-check + +import * as child_process from "node:child_process"; +import { runtimePath } from "./runtime.js"; + +/** @type {Record} */ +const signalToNumber = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1, SIGQUIT: 3 }; + +/** + * Run a build-system executable with the package runtime and forward terminal + * signals so watch mode can clean up before the Node launcher exits. + * + * @param {string} executable + */ +export function runBuildSystem(executable) { + const child = child_process.spawn(executable, process.argv.slice(2), { + stdio: "inherit", + env: { ...process.env, RESCRIPT_RUNTIME: runtimePath }, + }); + + let forwardedSignal = false; + /** @param {NodeJS.Signals} signal */ + const handleSignal = signal => { + if (forwardedSignal) return; + forwardedSignal = true; + // Ctrl+C is delivered to every process attached to the Windows console. + // child.kill("SIGINT") uses TerminateProcess there and can kill the build + // system before its console handler releases locks and owned descendants. + if (process.platform === "win32" && signal === "SIGINT") return; + try { + if (child.exitCode === null && child.signalCode == null) { + child.kill(signal); + } + } catch { + // Signal forwarding is best effort if the child exited concurrently. + } + }; + + process.on("SIGINT", handleSignal); + process.on("SIGTERM", handleSignal); + process.on("SIGHUP", handleSignal); + process.on("SIGQUIT", handleSignal); + + process.on("exit", () => { + if (child.exitCode === null && child.signalCode == null) { + try { + child.kill("SIGTERM"); + } catch { + // The child may already have exited. + } + } + }); + + child.on("exit", (code, signal) => { + process.removeListener("SIGINT", handleSignal); + process.removeListener("SIGTERM", handleSignal); + process.removeListener("SIGHUP", handleSignal); + process.removeListener("SIGQUIT", handleSignal); + + if (signal) { + const number = signalToNumber[signal]; + process.exit(typeof number === "number" ? 128 + number : 1); + } else { + process.exit(typeof code === "number" ? code : 0); + } + }); + + child.on("error", error => { + console.error(error?.message ?? String(error)); + process.exit(1); + }); +} diff --git a/cli/rescript-rust.js b/cli/rescript-rust.js new file mode 100755 index 00000000000..af48395a16f --- /dev/null +++ b/cli/rescript-rust.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +// @ts-check + +import { rescript_rust_exe } from "./common/bins.js"; +import { runBuildSystem } from "./common/runBuildSystem.js"; + +runBuildSystem(rescript_rust_exe); diff --git a/cli/rescript.js b/cli/rescript.js index 236e1847e82..49eb73c852f 100755 --- a/cli/rescript.js +++ b/cli/rescript.js @@ -2,92 +2,7 @@ // @ts-check -import * as child_process from "node:child_process"; import { rescript_exe } from "./common/bins.js"; -import { runtimePath } from "./common/runtime.js"; +import { runBuildSystem } from "./common/runBuildSystem.js"; -const args = process.argv.slice(2); - -// We intentionally use spawn (async) instead of execFileSync (sync) here. -// Rationale: -// - execFileSync blocks Node's event loop, so Ctrl+C (SIGINT) causes Node to -// exit immediately without giving us a chance to forward the signal to the -// child and wait for its cleanup. In watch mode, the Rust watcher prints -// "Exiting..." on SIGINT and performs cleanup; with execFileSync that output -// may appear after the shell prompt and sometimes requires an extra keypress. -// - spawn lets us install signal handlers, forward them to the child, and then -// exit the parent with the correct status only after the child has exited. -const child = child_process.spawn(rescript_exe, args, { - stdio: "inherit", - env: { ...process.env, RESCRIPT_RUNTIME: runtimePath }, -}); - -// Map POSIX signal names to conventional exit status numbers so we can -// reproduce the usual 128 + signal behavior when exiting due to a signal. -/** @type {Record} */ -const signalToNumber = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1, SIGQUIT: 3 }; - -let forwardedSignal = false; -/** - * @param {NodeJS.Signals} signal - */ -const handleSignal = signal => { - // Intercept the signal in the parent, forward it to the child, and let the - // child perform its own cleanup. This ensures ordered shutdown in watch mode. - // Guard against double-forwarding since terminals or OSes can deliver - // multiple signals (e.g., repeated Ctrl+C). - // Prevent Node from exiting immediately; forward to child first - if (forwardedSignal) return; - forwardedSignal = true; - try { - if (child.exitCode === null && child.signalCode == null) { - child.kill(signal); - } - } catch { - // best effort - } -}; - -process.on("SIGINT", handleSignal); -process.on("SIGTERM", handleSignal); -process.on("SIGHUP", handleSignal); -process.on("SIGQUIT", handleSignal); - -// Cross-platform note: -// - On Unix, Ctrl+C sends SIGINT to the process group; we also explicitly -// forward it to the child to be robust. -// - On Windows, Node maps kill('SIGINT'/'SIGTERM') to console control events; -// the Rust watcher (via the ctrlc crate) handles these and exits cleanly. - -// Ensure no orphaned process if parent exits unexpectedly -process.on("exit", () => { - if (child.exitCode === null && child.signalCode == null) { - try { - child.kill("SIGTERM"); - } catch { - // ignore - } - } -}); - -child.on("exit", (code, signal) => { - process.removeListener("SIGINT", handleSignal); - process.removeListener("SIGTERM", handleSignal); - process.removeListener("SIGHUP", handleSignal); - process.removeListener("SIGQUIT", handleSignal); - - // If the child exited due to a signal, emulate the conventional exit status - // (128 + signalNumber). Otherwise, pass through the child's numeric exit code. - if (signal) { - const n = signalToNumber[signal]; - process.exit(typeof n === "number" ? 128 + n : 1); - } else { - process.exit(typeof code === "number" ? code : 0); - } -}); - -// Surface spawn errors (e.g., executable not found) and exit with failure. -child.on("error", err => { - console.error(err?.message ?? String(err)); - process.exit(1); -}); +runBuildSystem(rescript_exe); diff --git a/compiler/sync/dune b/compiler/sync/dune index e11fdfacaae..c8f334b877e 100644 --- a/compiler/sync/dune +++ b/compiler/sync/dune @@ -7,10 +7,10 @@ ; cause no timestamp churn downstream. ; ; One rule per platform; %{system}/%{architecture} come from `ocamlc -config` -; (note: x64 is "amd64" there). Windows copies without stripping, matching -; the historical packaging step. The browser profile is excluded because it -; builds a playground-flavoured compiler that must never overwrite the -; native binaries. +; (note: x64 is "amd64" there). Every package receives the OCaml build system +; as rescript.exe; Cargo separately promotes the Rust reference as +; rescript-rust.exe. The browser profile is excluded because it builds a +; playground-flavoured compiler that must never overwrite the native binaries. (rule (enabled_if @@ -18,11 +18,16 @@ (<> %{profile} browser) (= %{system} macosx) (= %{architecture} arm64))) - (targets bsc.exe rescript-editor-analysis.exe rescript-tools.exe) + (targets + bsc.exe + rescript-editor-analysis.exe + rescript-tools.exe + rescript.exe) (deps ../bsc/rescript_compiler_main.exe ../../analysis/bin/main.exe - ../../tools/bin/main.exe) + ../../tools/bin/main.exe + ../../rewatch-ocaml/rescript_ocaml.exe) (mode (promote (until-clean) @@ -31,7 +36,8 @@ (progn (run strip -o bsc.exe ../bsc/rescript_compiler_main.exe) (run strip -o rescript-editor-analysis.exe ../../analysis/bin/main.exe) - (run strip -o rescript-tools.exe ../../tools/bin/main.exe)))) + (run strip -o rescript-tools.exe ../../tools/bin/main.exe) + (run strip -o rescript.exe ../../rewatch-ocaml/rescript_ocaml.exe)))) (rule (enabled_if @@ -39,11 +45,16 @@ (<> %{profile} browser) (= %{system} macosx) (= %{architecture} amd64))) - (targets bsc.exe rescript-editor-analysis.exe rescript-tools.exe) + (targets + bsc.exe + rescript-editor-analysis.exe + rescript-tools.exe + rescript.exe) (deps ../bsc/rescript_compiler_main.exe ../../analysis/bin/main.exe - ../../tools/bin/main.exe) + ../../tools/bin/main.exe + ../../rewatch-ocaml/rescript_ocaml.exe) (mode (promote (until-clean) @@ -52,7 +63,8 @@ (progn (run strip -o bsc.exe ../bsc/rescript_compiler_main.exe) (run strip -o rescript-editor-analysis.exe ../../analysis/bin/main.exe) - (run strip -o rescript-tools.exe ../../tools/bin/main.exe)))) + (run strip -o rescript-tools.exe ../../tools/bin/main.exe) + (run strip -o rescript.exe ../../rewatch-ocaml/rescript_ocaml.exe)))) (rule (enabled_if @@ -60,11 +72,16 @@ (<> %{profile} browser) (= %{system} linux) (= %{architecture} arm64))) - (targets bsc.exe rescript-editor-analysis.exe rescript-tools.exe) + (targets + bsc.exe + rescript-editor-analysis.exe + rescript-tools.exe + rescript.exe) (deps ../bsc/rescript_compiler_main.exe ../../analysis/bin/main.exe - ../../tools/bin/main.exe) + ../../tools/bin/main.exe + ../../rewatch-ocaml/rescript_ocaml.exe) (mode (promote (until-clean) @@ -73,7 +90,8 @@ (progn (run strip -o bsc.exe ../bsc/rescript_compiler_main.exe) (run strip -o rescript-editor-analysis.exe ../../analysis/bin/main.exe) - (run strip -o rescript-tools.exe ../../tools/bin/main.exe)))) + (run strip -o rescript-tools.exe ../../tools/bin/main.exe) + (run strip -o rescript.exe ../../rewatch-ocaml/rescript_ocaml.exe)))) (rule (enabled_if @@ -81,11 +99,16 @@ (<> %{profile} browser) (= %{system} linux) (= %{architecture} amd64))) - (targets bsc.exe rescript-editor-analysis.exe rescript-tools.exe) + (targets + bsc.exe + rescript-editor-analysis.exe + rescript-tools.exe + rescript.exe) (deps ../bsc/rescript_compiler_main.exe ../../analysis/bin/main.exe - ../../tools/bin/main.exe) + ../../tools/bin/main.exe + ../../rewatch-ocaml/rescript_ocaml.exe) (mode (promote (until-clean) @@ -94,7 +117,8 @@ (progn (run strip -o bsc.exe ../bsc/rescript_compiler_main.exe) (run strip -o rescript-editor-analysis.exe ../../analysis/bin/main.exe) - (run strip -o rescript-tools.exe ../../tools/bin/main.exe)))) + (run strip -o rescript-tools.exe ../../tools/bin/main.exe) + (run strip -o rescript.exe ../../rewatch-ocaml/rescript_ocaml.exe)))) (rule (enabled_if @@ -102,11 +126,16 @@ (<> %{profile} browser) (= %{system} mingw64) (= %{architecture} amd64))) - (targets bsc.exe rescript-editor-analysis.exe rescript-tools.exe) + (targets + bsc.exe + rescript-editor-analysis.exe + rescript-tools.exe + rescript.exe) (deps ../bsc/rescript_compiler_main.exe ../../analysis/bin/main.exe - ../../tools/bin/main.exe) + ../../tools/bin/main.exe + ../../rewatch-ocaml/rescript_ocaml.exe) (mode (promote (until-clean) @@ -115,4 +144,5 @@ (progn (copy ../bsc/rescript_compiler_main.exe bsc.exe) (copy ../../analysis/bin/main.exe rescript-editor-analysis.exe) - (copy ../../tools/bin/main.exe rescript-tools.exe)))) + (copy ../../tools/bin/main.exe rescript-tools.exe) + (copy ../../rewatch-ocaml/rescript_ocaml.exe rescript.exe)))) diff --git a/dune b/dune index e9bf1898332..526e18fbc01 100644 --- a/dune +++ b/dune @@ -1,4 +1,4 @@ -(dirs compiler tests analysis tools) +(dirs compiler tests analysis tools rewatch-ocaml) ; All warnings are enabled, except: ; - 4 (fragile-match): wildcard cases are used deliberately. diff --git a/dune-project b/dune-project index 3638e482acb..77999e85a4d 100644 --- a/dune-project +++ b/dune-project @@ -30,6 +30,14 @@ (and :with-test (= 0.29.0))) (yojson (= 3.0.0)) + (spawn + (= v0.17.0)) + (cmdliner + (= 2.1.1)) + (luv + (= 0.5.14)) + (re + (= 1.14.0)) (ounit2 (and :with-test (= 2.2.7))) (odoc :with-doc) diff --git a/package.json b/package.json index 60aafcdb87a..5ce0580037b 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "bin": { "bsc": "cli/bsc.js", "rescript": "cli/rescript.js", + "rescript-rust": "cli/rescript-rust.js", "rescript-tools": "cli/rescript-tools.js" }, "scripts": { diff --git a/packages/@rescript/belt/.gitignore b/packages/@rescript/belt/.gitignore index 4673ed827b1..97db98ea625 100644 --- a/packages/@rescript/belt/.gitignore +++ b/packages/@rescript/belt/.gitignore @@ -11,3 +11,5 @@ src/*.js src/*.mjs src/*.cjs lib/**/*.res.js +lib/es6 +lib/js diff --git a/packages/@rescript/belt/lib/es6/src/Belt.mjs b/packages/@rescript/belt/lib/es6/src/Belt.mjs deleted file mode 100644 index 46fc28ba537..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt.mjs +++ /dev/null @@ -1,57 +0,0 @@ - - - -let Id; - -let $$Array; - -let SortArray; - -let MutableQueue; - -let MutableStack; - -let List; - -let Range; - -let $$Set; - -let $$Map; - -let MutableSet; - -let MutableMap; - -let HashSet; - -let HashMap; - -let Option; - -let Result; - -let Int; - -let Float; - -export { - Id, - $$Array, - SortArray, - MutableQueue, - MutableStack, - List, - Range, - $$Set, - $$Map, - MutableSet, - MutableMap, - HashSet, - HashMap, - Option, - Result, - Int, - Float, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Array.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Array.mjs deleted file mode 100644 index bfc5abcc70d..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Array.mjs +++ /dev/null @@ -1,713 +0,0 @@ - - -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function get(arr, i) { - if (i >= 0 && i < arr.length) { - return Primitive_option.some(arr[i]); - } -} - -function getOrThrow(arr, i) { - if (!(i >= 0 && i < arr.length)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_Array.res", - 27, - 2 - ], - Error: new Error() - }; - } - return arr[i]; -} - -function set(arr, i, v) { - if (i >= 0 && i < arr.length) { - arr[i] = v; - return true; - } else { - return false; - } -} - -function setOrThrow(arr, i, v) { - if (!(i >= 0 && i < arr.length)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_Array.res", - 42, - 2 - ], - Error: new Error() - }; - } - arr[i] = v; -} - -function swapUnsafe(xs, i, j) { - let tmp = xs[i]; - xs[i] = xs[j]; - xs[j] = tmp; -} - -function shuffleInPlace(xs) { - let len = xs.length; - let random_int = (min, max) => Math.floor(Math.random() * (max - min | 0)) + min | 0; - for (let i = 0; i < len; ++i) { - swapUnsafe(xs, i, random_int(i, len)); - } -} - -function shuffle(xs) { - let result = xs.slice(0); - shuffleInPlace(result); - return result; -} - -function reverseInPlace(xs) { - let len = xs.length; - let ofs = 0; - for (let i = 0, i_finish = len / 2 | 0; i < i_finish; ++i) { - swapUnsafe(xs, ofs + i | 0, ((ofs + len | 0) - i | 0) - 1 | 0); - } -} - -function reverse(xs) { - let len = xs.length; - let result = new Array(len); - for (let i = 0; i < len; ++i) { - result[i] = xs[(len - 1 | 0) - i | 0]; - } - return result; -} - -function make(l, f) { - if (l <= 0) { - return []; - } - let res = new Array(l); - for (let i = 0; i < l; ++i) { - res[i] = f; - } - return res; -} - -function makeBy(l, f) { - if (l <= 0) { - return []; - } - let res = new Array(l); - for (let i = 0; i < l; ++i) { - res[i] = f(i); - } - return res; -} - -function makeByAndShuffle(l, f) { - let u = makeBy(l, f); - shuffleInPlace(u); - return u; -} - -function range(start, finish) { - let cut = finish - start | 0; - if (cut < 0) { - return []; - } - let arr = new Array(cut + 1 | 0); - for (let i = 0; i <= cut; ++i) { - arr[i] = start + i | 0; - } - return arr; -} - -function rangeBy(start, finish, step) { - let cut = finish - start | 0; - if (cut < 0 || step <= 0) { - return []; - } - let nb = (cut / step | 0) + 1 | 0; - let arr = new Array(nb); - let cur = start; - for (let i = 0; i < nb; ++i) { - arr[i] = cur; - cur = cur + step | 0; - } - return arr; -} - -function zip(xs, ys) { - let lenx = xs.length; - let leny = ys.length; - let len = Primitive_int.min(lenx, leny); - let s = new Array(len); - for (let i = 0; i < len; ++i) { - s[i] = [ - xs[i], - ys[i] - ]; - } - return s; -} - -function zipBy(xs, ys, f) { - let lenx = xs.length; - let leny = ys.length; - let len = Primitive_int.min(lenx, leny); - let s = new Array(len); - for (let i = 0; i < len; ++i) { - s[i] = f(xs[i], ys[i]); - } - return s; -} - -function concat(a1, a2) { - let l1 = a1.length; - let l2 = a2.length; - let a1a2 = new Array(l1 + l2 | 0); - for (let i = 0; i < l1; ++i) { - a1a2[i] = a1[i]; - } - for (let i$1 = 0; i$1 < l2; ++i$1) { - a1a2[l1 + i$1 | 0] = a2[i$1]; - } - return a1a2; -} - -function concatMany(arrs) { - let lenArrs = arrs.length; - let totalLen = 0; - for (let i = 0; i < lenArrs; ++i) { - totalLen = totalLen + arrs[i].length | 0; - } - let result = new Array(totalLen); - totalLen = 0; - for (let j = 0; j < lenArrs; ++j) { - let cur = arrs[j]; - for (let k = 0, k_finish = cur.length; k < k_finish; ++k) { - result[totalLen] = cur[k]; - totalLen = totalLen + 1 | 0; - } - } - return result; -} - -function slice(a, offset, len) { - if (len <= 0) { - return []; - } - let lena = a.length; - let ofs = offset < 0 ? Primitive_int.max(lena + offset | 0, 0) : offset; - let hasLen = lena - ofs | 0; - let copyLength = Primitive_int.min(hasLen, len); - if (copyLength <= 0) { - return []; - } - let result = new Array(copyLength); - for (let i = 0; i < copyLength; ++i) { - result[i] = a[ofs + i | 0]; - } - return result; -} - -function sliceToEnd(a, offset) { - let lena = a.length; - let ofs = offset < 0 ? Primitive_int.max(lena + offset | 0, 0) : offset; - let len = lena > ofs ? lena - ofs | 0 : 0; - let result = new Array(len); - for (let i = 0; i < len; ++i) { - result[i] = a[ofs + i | 0]; - } - return result; -} - -function fill(a, offset, len, v) { - if (len <= 0) { - return; - } - let lena = a.length; - let ofs = offset < 0 ? Primitive_int.max(lena + offset | 0, 0) : offset; - let hasLen = lena - ofs | 0; - let fillLength = Primitive_int.min(hasLen, len); - if (fillLength <= 0) { - return; - } - for (let i = ofs, i_finish = ofs + fillLength | 0; i < i_finish; ++i) { - a[i] = v; - } -} - -function blitUnsafe(a1, srcofs1, a2, srcofs2, blitLength) { - if (srcofs2 <= srcofs1) { - for (let j = 0; j < blitLength; ++j) { - a2[j + srcofs2 | 0] = a1[j + srcofs1 | 0]; - } - return; - } - for (let j$1 = blitLength - 1 | 0; j$1 >= 0; --j$1) { - a2[j$1 + srcofs2 | 0] = a1[j$1 + srcofs1 | 0]; - } -} - -function blit(a1, ofs1, a2, ofs2, len) { - let lena1 = a1.length; - let lena2 = a2.length; - let srcofs1 = ofs1 < 0 ? Primitive_int.max(lena1 + ofs1 | 0, 0) : ofs1; - let srcofs2 = ofs2 < 0 ? Primitive_int.max(lena2 + ofs2 | 0, 0) : ofs2; - let blitLength = Primitive_int.min(len, Primitive_int.min(lena1 - srcofs1 | 0, lena2 - srcofs2 | 0)); - if (srcofs2 <= srcofs1) { - for (let j = 0; j < blitLength; ++j) { - a2[j + srcofs2 | 0] = a1[j + srcofs1 | 0]; - } - return; - } - for (let j$1 = blitLength - 1 | 0; j$1 >= 0; --j$1) { - a2[j$1 + srcofs2 | 0] = a1[j$1 + srcofs1 | 0]; - } -} - -function forEach(a, f) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(a[i]); - } -} - -function map(a, f) { - let l = a.length; - let r = new Array(l); - for (let i = 0; i < l; ++i) { - r[i] = f(a[i]); - } - return r; -} - -function flatMap(a, f) { - return concatMany(map(a, f)); -} - -function getBy(a, p) { - let l = a.length; - let i = 0; - let r; - while (r === undefined && i < l) { - let v = a[i]; - if (p(v)) { - r = Primitive_option.some(v); - } - i = i + 1 | 0; - }; - return r; -} - -function getIndexBy(a, p) { - let l = a.length; - let i = 0; - let r; - while (r === undefined && i < l) { - let v = a[i]; - if (p(v)) { - r = i; - } - i = i + 1 | 0; - }; - return r; -} - -function keep(a, f) { - let l = a.length; - let r = new Array(l); - let j = 0; - for (let i = 0; i < l; ++i) { - let v = a[i]; - if (f(v)) { - r[j] = v; - j = j + 1 | 0; - } - } - r.length = j; - return r; -} - -function keepWithIndex(a, f) { - let l = a.length; - let r = new Array(l); - let j = 0; - for (let i = 0; i < l; ++i) { - let v = a[i]; - if (f(v, i)) { - r[j] = v; - j = j + 1 | 0; - } - } - r.length = j; - return r; -} - -function keepMap(a, f) { - let l = a.length; - let r = new Array(l); - let j = 0; - for (let i = 0; i < l; ++i) { - let v = a[i]; - let v$1 = f(v); - if (v$1 !== undefined) { - r[j] = Primitive_option.valFromOption(v$1); - j = j + 1 | 0; - } - } - r.length = j; - return r; -} - -function forEachWithIndex(a, f) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(i, a[i]); - } -} - -function mapWithIndex(a, f) { - let l = a.length; - let r = new Array(l); - for (let i = 0; i < l; ++i) { - r[i] = f(i, a[i]); - } - return r; -} - -function reduce(a, x, f) { - let r = x; - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - r = f(r, a[i]); - } - return r; -} - -function reduceReverse(a, x, f) { - let r = x; - for (let i = a.length - 1 | 0; i >= 0; --i) { - r = f(r, a[i]); - } - return r; -} - -function reduceReverse2(a, b, x, f) { - let r = x; - let len = Primitive_int.min(a.length, b.length); - for (let i = len - 1 | 0; i >= 0; --i) { - r = f(r, a[i], b[i]); - } - return r; -} - -function reduceWithIndex(a, x, f) { - let r = x; - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - r = f(r, a[i], i); - } - return r; -} - -function every(arr, b) { - let len = arr.length; - let _i = 0; - while (true) { - let i = _i; - if (i === len) { - return true; - } - if (!b(arr[i])) { - return false; - } - _i = i + 1 | 0; - continue; - }; -} - -function some(arr, b) { - let len = arr.length; - let _i = 0; - while (true) { - let i = _i; - if (i === len) { - return false; - } - if (b(arr[i])) { - return true; - } - _i = i + 1 | 0; - continue; - }; -} - -function everyAux2(arr1, arr2, _i, b, len) { - while (true) { - let i = _i; - if (i === len) { - return true; - } - if (!b(arr1[i], arr2[i])) { - return false; - } - _i = i + 1 | 0; - continue; - }; -} - -function every2(a, b, p) { - return everyAux2(a, b, 0, p, Primitive_int.min(a.length, b.length)); -} - -function some2(a, b, p) { - let _i = 0; - let len = Primitive_int.min(a.length, b.length); - while (true) { - let i = _i; - if (i === len) { - return false; - } - if (p(a[i], b[i])) { - return true; - } - _i = i + 1 | 0; - continue; - }; -} - -function eq(a, b, p) { - let lena = a.length; - let lenb = b.length; - if (lena === lenb) { - return everyAux2(a, b, 0, p, lena); - } else { - return false; - } -} - -function cmp(a, b, p) { - let lena = a.length; - let lenb = b.length; - if (lena > lenb) { - return 1; - } else if (lena < lenb) { - return -1; - } else { - let _i = 0; - while (true) { - let i = _i; - if (i === lena) { - return 0; - } - let c = p(a[i], b[i]); - if (c !== 0) { - return c; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function partition(a, f) { - let l = a.length; - let i = 0; - let j = 0; - let a1 = new Array(l); - let a2 = new Array(l); - for (let ii = 0; ii < l; ++ii) { - let v = a[ii]; - if (f(v)) { - a1[i] = v; - i = i + 1 | 0; - } else { - a2[j] = v; - j = j + 1 | 0; - } - } - a1.length = i; - a2.length = j; - return [ - a1, - a2 - ]; -} - -function unzip(a) { - let l = a.length; - let a1 = new Array(l); - let a2 = new Array(l); - for (let i = 0; i < l; ++i) { - let match = a[i]; - a1[i] = match[0]; - a2[i] = match[1]; - } - return [ - a1, - a2 - ]; -} - -function joinWith(a, sep, toString) { - let l = a.length; - if (l === 0) { - return ""; - } - let lastIndex = l - 1 | 0; - let _i = 0; - let _res = ""; - while (true) { - let res = _res; - let i = _i; - if (i === lastIndex) { - return res + toString(a[i]); - } - _res = res + (toString(a[i]) + sep); - _i = i + 1 | 0; - continue; - }; -} - -function init(n, f) { - let v = new Array(n); - for (let i = 0; i < n; ++i) { - v[i] = f(i); - } - return v; -} - -let getExn = getOrThrow; - -let setExn = setOrThrow; - -let makeByU = makeBy; - -let makeByAndShuffleU = makeByAndShuffle; - -let zipByU = zipBy; - -let forEachU = forEach; - -let mapU = map; - -let flatMapU = flatMap; - -let getByU = getBy; - -let getIndexByU = getIndexBy; - -let keepU = keep; - -let keepWithIndexU = keepWithIndex; - -let keepMapU = keepMap; - -let forEachWithIndexU = forEachWithIndex; - -let mapWithIndexU = mapWithIndex; - -let partitionU = partition; - -let reduceU = reduce; - -let reduceReverseU = reduceReverse; - -let reduceReverse2U = reduceReverse2; - -let reduceWithIndexU = reduceWithIndex; - -let joinWithU = joinWith; - -let someU = some; - -let everyU = every; - -let every2U = every2; - -let some2U = some2; - -let cmpU = cmp; - -let eqU = eq; - -let initU = init; - -export { - get, - getExn, - getOrThrow, - set, - setExn, - setOrThrow, - shuffleInPlace, - shuffle, - reverseInPlace, - reverse, - make, - range, - rangeBy, - makeByU, - makeBy, - makeByAndShuffleU, - makeByAndShuffle, - zip, - zipByU, - zipBy, - unzip, - concat, - concatMany, - slice, - sliceToEnd, - fill, - blit, - blitUnsafe, - forEachU, - forEach, - mapU, - map, - flatMapU, - flatMap, - getByU, - getBy, - getIndexByU, - getIndexBy, - keepU, - keep, - keepWithIndexU, - keepWithIndex, - keepMapU, - keepMap, - forEachWithIndexU, - forEachWithIndex, - mapWithIndexU, - mapWithIndex, - partitionU, - partition, - reduceU, - reduce, - reduceReverseU, - reduceReverse, - reduceReverse2U, - reduceReverse2, - reduceWithIndexU, - reduceWithIndex, - joinWithU, - joinWith, - someU, - some, - everyU, - every, - every2U, - every2, - some2U, - some2, - cmpU, - cmp, - eqU, - eq, - initU, - init, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Float.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Float.mjs deleted file mode 100644 index 80c12e96f16..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Float.mjs +++ /dev/null @@ -1,16 +0,0 @@ - - - -function fromString(i) { - let i$1 = parseFloat(i); - if (isNaN(i$1)) { - return; - } else { - return i$1; - } -} - -export { - fromString, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_HashMap.mjs b/packages/@rescript/belt/lib/es6/src/Belt_HashMap.mjs deleted file mode 100644 index c45922bb7a7..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_HashMap.mjs +++ /dev/null @@ -1,276 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalBuckets from "./Belt_internalBuckets.mjs"; -import * as Belt_internalBucketsType from "./Belt_internalBucketsType.mjs"; - -function size(h) { - return h.size; -} - -function copyBucketReHash(hash, h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = hash(old_bucket.key) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function replaceInBucket(eq, key, info, _cell) { - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - cell.value = info; - return false; - } - let cell$1 = cell.next; - if (cell$1 === undefined) { - return true; - } - _cell = cell$1; - continue; - }; -} - -function set0(h, key, value, eq, hash) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = hash(key) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - if (replaceInBucket(eq, key, value, l)) { - h_buckets[i] = { - key: key, - value: value, - next: l - }; - h.size = h.size + 1 | 0; - } - } else { - h_buckets[i] = { - key: key, - value: value, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucketReHash(hash, h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function set(h, key, value) { - set0(h, key, value, h.eq, h.hash); -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = h.hash(key) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[i]; - if (bucket === undefined) { - return; - } - let eq = h.eq; - if (eq(bucket.key, key)) { - h_buckets[i] = bucket.next; - h.size = h.size - 1 | 0; - return; - } else { - let _prec = bucket; - let _bucket = bucket.next; - while (true) { - let bucket$1 = _bucket; - let prec = _prec; - if (bucket$1 === undefined) { - return; - } - let cell_next = bucket$1.next; - if (eq(bucket$1.key, key)) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - _bucket = cell_next; - _prec = bucket$1; - continue; - }; - } -} - -function get(h, key) { - let h_buckets = h.buckets; - let nid = h.hash(key) & (h_buckets.length - 1 | 0); - let cell1 = h_buckets[nid]; - if (cell1 === undefined) { - return; - } - let eq = h.eq; - if (eq(key, cell1.key)) { - return Primitive_option.some(cell1.value); - } - let cell2 = cell1.next; - if (cell2 === undefined) { - return; - } - if (eq(key, cell2.key)) { - return Primitive_option.some(cell2.value); - } - let cell3 = cell2.next; - if (cell3 !== undefined) { - if (eq(key, cell3.key)) { - return Primitive_option.some(cell3.value); - } else { - let _buckets = cell3.next; - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - if (eq(key, buckets.key)) { - return Primitive_option.some(buckets.value); - } - _buckets = buckets.next; - continue; - }; - } - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = h.hash(key) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - let eq = h.eq; - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize, id) { - return Belt_internalBucketsType.make(id.hash, id.eq, hintSize); -} - -function fromArray(arr, id) { - let hash = id.hash; - let eq = id.eq; - let len = arr.length; - let v = Belt_internalBucketsType.make(hash, eq, len); - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set0(v, match[0], match[1], eq, hash); - } - return v; -} - -function mergeMany(h, arr) { - let hash = h.hash; - let eq = h.eq; - let len = arr.length; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set0(h, match[0], match[1], eq, hash); - } -} - -let Int; - -let $$String; - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalBuckets.copy; - -let forEachU = Belt_internalBuckets.forEach; - -let forEach = Belt_internalBuckets.forEach; - -let reduceU = Belt_internalBuckets.reduce; - -let reduce = Belt_internalBuckets.reduce; - -let keepMapInPlaceU = Belt_internalBuckets.keepMapInPlace; - -let keepMapInPlace = Belt_internalBuckets.keepMapInPlace; - -let toArray = Belt_internalBuckets.toArray; - -let keysToArray = Belt_internalBuckets.keysToArray; - -let valuesToArray = Belt_internalBuckets.valuesToArray; - -let getBucketHistogram = Belt_internalBuckets.getBucketHistogram; - -let logStats = Belt_internalBuckets.logStats; - -export { - Int, - $$String, - make, - clear, - isEmpty, - set, - copy, - get, - has, - remove, - forEachU, - forEach, - reduceU, - reduce, - keepMapInPlaceU, - keepMapInPlace, - size, - toArray, - keysToArray, - valuesToArray, - fromArray, - mergeMany, - getBucketHistogram, - logStats, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_HashMapInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_HashMapInt.mjs deleted file mode 100644 index 28fd20910a6..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_HashMapInt.mjs +++ /dev/null @@ -1,259 +0,0 @@ - - -import * as Primitive_hash from "@rescript/runtime/lib/es6/Primitive_hash.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalBuckets from "./Belt_internalBuckets.mjs"; -import * as Belt_internalBucketsType from "./Belt_internalBucketsType.mjs"; - -function copyBucketReHash(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function replaceInBucket(key, info, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - cell.value = info; - return false; - } - let cell$1 = cell.next; - if (cell$1 === undefined) { - return true; - } - _cell = cell$1; - continue; - }; -} - -function set(h, key, value) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - if (replaceInBucket(key, value, l)) { - h_buckets[i] = { - key: key, - value: value, - next: l - }; - h.size = h.size + 1 | 0; - } - } else { - h_buckets[i] = { - key: key, - value: value, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucketReHash(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[i]; - if (bucket !== undefined) { - if (bucket.key === key) { - h_buckets[i] = bucket.next; - h.size = h.size - 1 | 0; - return; - } else { - let _prec = bucket; - let _buckets = bucket.next; - while (true) { - let buckets = _buckets; - let prec = _prec; - if (buckets === undefined) { - return; - } - let cell_next = buckets.next; - if (buckets.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - _buckets = cell_next; - _prec = buckets; - continue; - }; - } - } -} - -function get(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let cell1 = h_buckets[nid]; - if (cell1 === undefined) { - return; - } - if (key === cell1.key) { - return Primitive_option.some(cell1.value); - } - let cell2 = cell1.next; - if (cell2 === undefined) { - return; - } - if (key === cell2.key) { - return Primitive_option.some(cell2.value); - } - let cell3 = cell2.next; - if (cell3 !== undefined) { - if (key === cell3.key) { - return Primitive_option.some(cell3.value); - } else { - let _buckets = cell3.next; - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - if (key === buckets.key) { - return Primitive_option.some(buckets.value); - } - _buckets = buckets.next; - continue; - }; - } - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(v, match[0], match[1]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(h, match[0], match[1]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalBuckets.copy; - -let forEachU = Belt_internalBuckets.forEach; - -let forEach = Belt_internalBuckets.forEach; - -let reduceU = Belt_internalBuckets.reduce; - -let reduce = Belt_internalBuckets.reduce; - -let keepMapInPlaceU = Belt_internalBuckets.keepMapInPlace; - -let keepMapInPlace = Belt_internalBuckets.keepMapInPlace; - -let toArray = Belt_internalBuckets.toArray; - -let keysToArray = Belt_internalBuckets.keysToArray; - -let valuesToArray = Belt_internalBuckets.valuesToArray; - -let getBucketHistogram = Belt_internalBuckets.getBucketHistogram; - -let logStats = Belt_internalBuckets.logStats; - -export { - make, - clear, - isEmpty, - set, - copy, - get, - has, - remove, - forEachU, - forEach, - reduceU, - reduce, - keepMapInPlaceU, - keepMapInPlace, - size, - toArray, - keysToArray, - valuesToArray, - fromArray, - mergeMany, - getBucketHistogram, - logStats, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_HashMapString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_HashMapString.mjs deleted file mode 100644 index 19a9d71371f..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_HashMapString.mjs +++ /dev/null @@ -1,259 +0,0 @@ - - -import * as Primitive_hash from "@rescript/runtime/lib/es6/Primitive_hash.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalBuckets from "./Belt_internalBuckets.mjs"; -import * as Belt_internalBucketsType from "./Belt_internalBucketsType.mjs"; - -function copyBucketReHash(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function replaceInBucket(key, info, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - cell.value = info; - return false; - } - let cell$1 = cell.next; - if (cell$1 === undefined) { - return true; - } - _cell = cell$1; - continue; - }; -} - -function set(h, key, value) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - if (replaceInBucket(key, value, l)) { - h_buckets[i] = { - key: key, - value: value, - next: l - }; - h.size = h.size + 1 | 0; - } - } else { - h_buckets[i] = { - key: key, - value: value, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucketReHash(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[i]; - if (bucket !== undefined) { - if (bucket.key === key) { - h_buckets[i] = bucket.next; - h.size = h.size - 1 | 0; - return; - } else { - let _prec = bucket; - let _buckets = bucket.next; - while (true) { - let buckets = _buckets; - let prec = _prec; - if (buckets === undefined) { - return; - } - let cell_next = buckets.next; - if (buckets.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - _buckets = cell_next; - _prec = buckets; - continue; - }; - } - } -} - -function get(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let cell1 = h_buckets[nid]; - if (cell1 === undefined) { - return; - } - if (key === cell1.key) { - return Primitive_option.some(cell1.value); - } - let cell2 = cell1.next; - if (cell2 === undefined) { - return; - } - if (key === cell2.key) { - return Primitive_option.some(cell2.value); - } - let cell3 = cell2.next; - if (cell3 !== undefined) { - if (key === cell3.key) { - return Primitive_option.some(cell3.value); - } else { - let _buckets = cell3.next; - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - if (key === buckets.key) { - return Primitive_option.some(buckets.value); - } - _buckets = buckets.next; - continue; - }; - } - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(v, match[0], match[1]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(h, match[0], match[1]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalBuckets.copy; - -let forEachU = Belt_internalBuckets.forEach; - -let forEach = Belt_internalBuckets.forEach; - -let reduceU = Belt_internalBuckets.reduce; - -let reduce = Belt_internalBuckets.reduce; - -let keepMapInPlaceU = Belt_internalBuckets.keepMapInPlace; - -let keepMapInPlace = Belt_internalBuckets.keepMapInPlace; - -let toArray = Belt_internalBuckets.toArray; - -let keysToArray = Belt_internalBuckets.keysToArray; - -let valuesToArray = Belt_internalBuckets.valuesToArray; - -let getBucketHistogram = Belt_internalBuckets.getBucketHistogram; - -let logStats = Belt_internalBuckets.logStats; - -export { - make, - clear, - isEmpty, - set, - copy, - get, - has, - remove, - forEachU, - forEach, - reduceU, - reduce, - keepMapInPlaceU, - keepMapInPlace, - size, - toArray, - keysToArray, - valuesToArray, - fromArray, - mergeMany, - getBucketHistogram, - logStats, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_HashSet.mjs b/packages/@rescript/belt/lib/es6/src/Belt_HashSet.mjs deleted file mode 100644 index 089fc362ceb..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_HashSet.mjs +++ /dev/null @@ -1,220 +0,0 @@ - - -import * as Belt_internalSetBuckets from "./Belt_internalSetBuckets.mjs"; -import * as Belt_internalBucketsType from "./Belt_internalBucketsType.mjs"; - -function copyBucket(hash, h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = hash(old_bucket.key) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function remove(h, key) { - let eq = h.eq; - let h_buckets = h.buckets; - let i = h.hash(key) & (h_buckets.length - 1 | 0); - let l = h_buckets[i]; - if (l === undefined) { - return; - } - let next_cell = l.next; - if (eq(l.key, key)) { - h.size = h.size - 1 | 0; - h_buckets[i] = next_cell; - return; - } else if (next_cell !== undefined) { - let _prec = l; - let _cell = next_cell; - while (true) { - let cell = _cell; - let prec = _prec; - let cell_next = cell.next; - if (eq(cell.key, key)) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - if (cell_next === undefined) { - return; - } - _cell = cell_next; - _prec = cell; - continue; - }; - } else { - return; - } -} - -function addBucket(h, key, _cell, eq) { - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - return; - } - let n = cell.next; - if (n !== undefined) { - _cell = n; - continue; - } - h.size = h.size + 1 | 0; - cell.next = { - key: key, - next: undefined - }; - return; - }; -} - -function add0(h, key, hash, eq) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = hash(key) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - addBucket(h, key, l, eq); - } else { - h.size = h.size + 1 | 0; - h_buckets[i] = { - key: key, - next: undefined - }; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucket(hash, h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function add(h, key) { - add0(h, key, h.hash, h.eq); -} - -function has(h, key) { - let eq = h.eq; - let h_buckets = h.buckets; - let nid = h.hash(key) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize, id) { - return Belt_internalBucketsType.make(id.hash, id.eq, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr, id) { - let eq = id.eq; - let hash = id.hash; - let len = arr.length; - let v = Belt_internalBucketsType.make(hash, eq, len); - for (let i = 0; i < len; ++i) { - add0(v, arr[i], hash, eq); - } - return v; -} - -function mergeMany(h, arr) { - let eq = h.eq; - let hash = h.hash; - let len = arr.length; - for (let i = 0; i < len; ++i) { - add0(h, arr[i], hash, eq); - } -} - -let Int; - -let $$String; - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalSetBuckets.copy; - -let forEachU = Belt_internalSetBuckets.forEach; - -let forEach = Belt_internalSetBuckets.forEach; - -let reduceU = Belt_internalSetBuckets.reduce; - -let reduce = Belt_internalSetBuckets.reduce; - -let logStats = Belt_internalSetBuckets.logStats; - -let toArray = Belt_internalSetBuckets.toArray; - -let getBucketHistogram = Belt_internalSetBuckets.getBucketHistogram; - -export { - Int, - $$String, - make, - clear, - isEmpty, - add, - copy, - has, - remove, - forEachU, - forEach, - reduceU, - reduce, - size, - logStats, - toArray, - fromArray, - mergeMany, - getBucketHistogram, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_HashSetInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_HashSetInt.mjs deleted file mode 100644 index 79494aff019..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_HashSetInt.mjs +++ /dev/null @@ -1,205 +0,0 @@ - - -import * as Primitive_hash from "@rescript/runtime/lib/es6/Primitive_hash.mjs"; -import * as Belt_internalSetBuckets from "./Belt_internalSetBuckets.mjs"; -import * as Belt_internalBucketsType from "./Belt_internalBucketsType.mjs"; - -function copyBucket(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let l = h_buckets[i]; - if (l === undefined) { - return; - } - let next_cell = l.next; - if (l.key === key) { - h.size = h.size - 1 | 0; - h_buckets[i] = next_cell; - return; - } else if (next_cell !== undefined) { - let _prec = l; - let _cell = next_cell; - while (true) { - let cell = _cell; - let prec = _prec; - let cell_next = cell.next; - if (cell.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - if (cell_next === undefined) { - return; - } - _cell = cell_next; - _prec = cell; - continue; - }; - } else { - return; - } -} - -function addBucket(h, key, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - return; - } - let n = cell.next; - if (n !== undefined) { - _cell = n; - continue; - } - h.size = h.size + 1 | 0; - cell.next = { - key: key, - next: undefined - }; - return; - }; -} - -function add(h, key) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - addBucket(h, key, l); - } else { - h_buckets[i] = { - key: key, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucket(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - add(v, arr[i]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - add(h, arr[i]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalSetBuckets.copy; - -let forEachU = Belt_internalSetBuckets.forEach; - -let forEach = Belt_internalSetBuckets.forEach; - -let reduceU = Belt_internalSetBuckets.reduce; - -let reduce = Belt_internalSetBuckets.reduce; - -let logStats = Belt_internalSetBuckets.logStats; - -let toArray = Belt_internalSetBuckets.toArray; - -let getBucketHistogram = Belt_internalSetBuckets.getBucketHistogram; - -export { - make, - clear, - isEmpty, - add, - copy, - has, - remove, - forEachU, - forEach, - reduceU, - reduce, - size, - logStats, - toArray, - fromArray, - mergeMany, - getBucketHistogram, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_HashSetString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_HashSetString.mjs deleted file mode 100644 index d06ccf8445e..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_HashSetString.mjs +++ /dev/null @@ -1,205 +0,0 @@ - - -import * as Primitive_hash from "@rescript/runtime/lib/es6/Primitive_hash.mjs"; -import * as Belt_internalSetBuckets from "./Belt_internalSetBuckets.mjs"; -import * as Belt_internalBucketsType from "./Belt_internalBucketsType.mjs"; - -function copyBucket(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let l = h_buckets[i]; - if (l === undefined) { - return; - } - let next_cell = l.next; - if (l.key === key) { - h.size = h.size - 1 | 0; - h_buckets[i] = next_cell; - return; - } else if (next_cell !== undefined) { - let _prec = l; - let _cell = next_cell; - while (true) { - let cell = _cell; - let prec = _prec; - let cell_next = cell.next; - if (cell.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - if (cell_next === undefined) { - return; - } - _cell = cell_next; - _prec = cell; - continue; - }; - } else { - return; - } -} - -function addBucket(h, key, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - return; - } - let n = cell.next; - if (n !== undefined) { - _cell = n; - continue; - } - h.size = h.size + 1 | 0; - cell.next = { - key: key, - next: undefined - }; - return; - }; -} - -function add(h, key) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - addBucket(h, key, l); - } else { - h_buckets[i] = { - key: key, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucket(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - add(v, arr[i]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - add(h, arr[i]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalSetBuckets.copy; - -let forEachU = Belt_internalSetBuckets.forEach; - -let forEach = Belt_internalSetBuckets.forEach; - -let reduceU = Belt_internalSetBuckets.reduce; - -let reduce = Belt_internalSetBuckets.reduce; - -let logStats = Belt_internalSetBuckets.logStats; - -let toArray = Belt_internalSetBuckets.toArray; - -let getBucketHistogram = Belt_internalSetBuckets.getBucketHistogram; - -export { - make, - clear, - isEmpty, - add, - copy, - has, - remove, - forEachU, - forEach, - reduceU, - reduce, - size, - logStats, - toArray, - fromArray, - mergeMany, - getBucketHistogram, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Id.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Id.mjs deleted file mode 100644 index 2b6ffd16752..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Id.mjs +++ /dev/null @@ -1,43 +0,0 @@ - - - -function MakeComparable(M) { - return M; -} - -function comparable(cmp) { - return { - cmp: cmp - }; -} - -function MakeHashable(M) { - return M; -} - -function hashable(hash, eq) { - return { - hash: hash, - eq: eq - }; -} - -let MakeComparableU = MakeComparable; - -let comparableU = comparable; - -let MakeHashableU = MakeHashable; - -let hashableU = hashable; - -export { - MakeComparableU, - MakeComparable, - comparableU, - comparable, - MakeHashableU, - MakeHashable, - hashableU, - hashable, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Int.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Int.mjs deleted file mode 100644 index 500142b3b49..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Int.mjs +++ /dev/null @@ -1,16 +0,0 @@ - - - -function fromString(i) { - let i$1 = parseInt(i, 10); - if (isNaN(i$1)) { - return; - } else { - return i$1; - } -} - -export { - fromString, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_List.mjs b/packages/@rescript/belt/lib/es6/src/Belt_List.mjs deleted file mode 100644 index 6d264e4b28a..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_List.mjs +++ /dev/null @@ -1,1315 +0,0 @@ - - -import * as Belt_Array from "./Belt_Array.mjs"; -import * as Belt_SortArray from "./Belt_SortArray.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function head(x) { - if (x !== 0) { - return Primitive_option.some(x.hd); - } -} - -function headOrThrow(x) { - if (x !== 0) { - return x.hd; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function tail(x) { - if (x !== 0) { - return x.tl; - } -} - -function tailOrThrow(x) { - if (x !== 0) { - return x.tl; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function add(xs, x) { - return {hd: x, tl: xs}; -} - -function get(x, n) { - if (n < 0) { - return; - } else { - let _x = x; - let _n = n; - while (true) { - let n$1 = _n; - let x$1 = _x; - if (x$1 === 0) { - return; - } - if (n$1 === 0) { - return Primitive_option.some(x$1.hd); - } - _n = n$1 - 1 | 0; - _x = x$1.tl; - continue; - }; - } -} - -function getOrThrow(x, n) { - if (n < 0) { - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - } - let _x = x; - let _n = n; - while (true) { - let n$1 = _n; - let x$1 = _x; - if (x$1 !== 0) { - if (n$1 === 0) { - return x$1.hd; - } - _n = n$1 - 1 | 0; - _x = x$1.tl; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function partitionAux(p, _cell, _precX, _precY) { - while (true) { - let precY = _precY; - let precX = _precX; - let cell = _cell; - if (cell === 0) { - return; - } - let t = cell.tl; - let h = cell.hd; - let next = {hd: h, tl: /* [] */0}; - if (p(h)) { - precX.tl = next; - _precX = next; - _cell = t; - continue; - } - precY.tl = next; - _precY = next; - _cell = t; - continue; - }; -} - -function splitAux(_cell, _precX, _precY) { - while (true) { - let precY = _precY; - let precX = _precX; - let cell = _cell; - if (cell === 0) { - return; - } - let match = cell.hd; - let nextA = {hd: match[0], tl: /* [] */0}; - let nextB = {hd: match[1], tl: /* [] */0}; - precX.tl = nextA; - precY.tl = nextB; - _precY = nextB; - _precX = nextA; - _cell = cell.tl; - continue; - }; -} - -function copyAuxCont(_cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return prec; - } - let next = {hd: cellX.hd, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = cellX.tl; - continue; - }; -} - -function copyAuxWitFilter(f, _cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let t = cellX.tl; - let h = cellX.hd; - if (f(h)) { - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - } - _cellX = t; - continue; - }; -} - -function copyAuxWithFilterIndex(f, _cellX, _prec, _i) { - while (true) { - let i = _i; - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let t = cellX.tl; - let h = cellX.hd; - if (f(h, i)) { - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _i = i + 1 | 0; - _prec = next; - _cellX = t; - continue; - } - _i = i + 1 | 0; - _cellX = t; - continue; - }; -} - -function copyAuxWitFilterMap(f, _cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let t = cellX.tl; - let h = f(cellX.hd); - if (h !== undefined) { - let next = {hd: Primitive_option.valFromOption(h), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - } - _cellX = t; - continue; - }; -} - -function removeAssocAuxWithMap(_cellX, x, _prec, f) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return false; - } - let t = cellX.tl; - let h = cellX.hd; - if (f(h[0], x)) { - prec.tl = t; - return true; - } - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - }; -} - -function setAssocAuxWithMap(_cellX, x, k, _prec, eq) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return false; - } - let t = cellX.tl; - let h = cellX.hd; - if (eq(h[0], x)) { - prec.tl = {hd: [ - x, - k - ], tl: t}; - return true; - } - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - }; -} - -function copyAuxWithMap(_cellX, _prec, f) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let next = {hd: f(cellX.hd), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = cellX.tl; - continue; - }; -} - -function zipAux(_cellX, _cellY, _prec) { - while (true) { - let prec = _prec; - let cellY = _cellY; - let cellX = _cellX; - if (cellX === 0) { - return; - } - if (cellY === 0) { - return; - } - let next = {hd: [ - cellX.hd, - cellY.hd - ], tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellY = cellY.tl; - _cellX = cellX.tl; - continue; - }; -} - -function copyAuxWithMap2(f, _cellX, _cellY, _prec) { - while (true) { - let prec = _prec; - let cellY = _cellY; - let cellX = _cellX; - if (cellX === 0) { - return; - } - if (cellY === 0) { - return; - } - let next = {hd: f(cellX.hd, cellY.hd), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellY = cellY.tl; - _cellX = cellX.tl; - continue; - }; -} - -function copyAuxWithMapI(f, _i, _cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - let i = _i; - if (cellX === 0) { - return; - } - let next = {hd: f(i, cellX.hd), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = cellX.tl; - _i = i + 1 | 0; - continue; - }; -} - -function takeAux(_n, _cell, _prec) { - while (true) { - let prec = _prec; - let cell = _cell; - let n = _n; - if (n === 0) { - return true; - } - if (cell === 0) { - return false; - } - let cell$1 = {hd: cell.hd, tl: /* [] */0}; - prec.tl = cell$1; - _prec = cell$1; - _cell = cell.tl; - _n = n - 1 | 0; - continue; - }; -} - -function splitAtAux(_n, _cell, _prec) { - while (true) { - let prec = _prec; - let cell = _cell; - let n = _n; - if (n === 0) { - return cell; - } - if (cell === 0) { - return; - } - let cell$1 = {hd: cell.hd, tl: /* [] */0}; - prec.tl = cell$1; - _prec = cell$1; - _cell = cell.tl; - _n = n - 1 | 0; - continue; - }; -} - -function take(lst, n) { - if (n < 0) { - return; - } - if (n === 0) { - return /* [] */0; - } - if (lst === 0) { - return; - } - let cell = {hd: lst.hd, tl: /* [] */0}; - let has = takeAux(n - 1 | 0, lst.tl, cell); - if (has) { - return cell; - } -} - -function drop(lst, n) { - if (n < 0) { - return; - } else { - let _l = lst; - let _n = n; - while (true) { - let n$1 = _n; - let l = _l; - if (n$1 === 0) { - return l; - } - if (l === 0) { - return; - } - _n = n$1 - 1 | 0; - _l = l.tl; - continue; - }; - } -} - -function splitAt(lst, n) { - if (n < 0) { - return; - } - if (n === 0) { - return [ - /* [] */0, - lst - ]; - } - if (lst === 0) { - return; - } - let cell = {hd: lst.hd, tl: /* [] */0}; - let rest = splitAtAux(n - 1 | 0, lst.tl, cell); - if (rest !== undefined) { - return [ - cell, - rest - ]; - } -} - -function concat(xs, ys) { - if (xs === 0) { - return ys; - } - let cell = {hd: xs.hd, tl: /* [] */0}; - copyAuxCont(xs.tl, cell).tl = ys; - return cell; -} - -function map(xs, f) { - if (xs === 0) { - return /* [] */0; - } - let cell = {hd: f(xs.hd), tl: /* [] */0}; - copyAuxWithMap(xs.tl, cell, f); - return cell; -} - -function zipBy(l1, l2, f) { - if (l1 === 0) { - return /* [] */0; - } - if (l2 === 0) { - return /* [] */0; - } - let cell = {hd: f(l1.hd, l2.hd), tl: /* [] */0}; - copyAuxWithMap2(f, l1.tl, l2.tl, cell); - return cell; -} - -function mapWithIndex(xs, f) { - if (xs === 0) { - return /* [] */0; - } - let cell = {hd: f(0, xs.hd), tl: /* [] */0}; - copyAuxWithMapI(f, 1, xs.tl, cell); - return cell; -} - -function makeBy(n, f) { - if (n <= 0) { - return /* [] */0; - } - let headX = {hd: f(0), tl: /* [] */0}; - let cur = headX; - let i = 1; - while (i < n) { - let v = {hd: f(i), tl: /* [] */0}; - cur.tl = v; - cur = v; - i = i + 1 | 0; - }; - return headX; -} - -function make(n, v) { - if (n <= 0) { - return /* [] */0; - } - let headX = {hd: v, tl: /* [] */0}; - let cur = headX; - let i = 1; - while (i < n) { - let v$1 = {hd: v, tl: /* [] */0}; - cur.tl = v$1; - cur = v$1; - i = i + 1 | 0; - }; - return headX; -} - -function length(xs) { - let _x = xs; - let _acc = 0; - while (true) { - let acc = _acc; - let x = _x; - if (x === 0) { - return acc; - } - _acc = acc + 1 | 0; - _x = x.tl; - continue; - }; -} - -function fillAux(arr, _i, _x) { - while (true) { - let x = _x; - let i = _i; - if (x === 0) { - return; - } - arr[i] = x.hd; - _x = x.tl; - _i = i + 1 | 0; - continue; - }; -} - -function fromArray(a) { - let _i = a.length - 1 | 0; - let _res = /* [] */0; - while (true) { - let res = _res; - let i = _i; - if (i < 0) { - return res; - } - _res = {hd: a[i], tl: res}; - _i = i - 1 | 0; - continue; - }; -} - -function toArray(x) { - let len = length(x); - let arr = new Array(len); - fillAux(arr, 0, x); - return arr; -} - -function shuffle(xs) { - let v = toArray(xs); - Belt_Array.shuffleInPlace(v); - return fromArray(v); -} - -function reverseConcat(_l1, _l2) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return l2; - } - _l2 = {hd: l1.hd, tl: l2}; - _l1 = l1.tl; - continue; - }; -} - -function reverse(l) { - return reverseConcat(l, /* [] */0); -} - -function flattenAux(_prec, _xs) { - while (true) { - let xs = _xs; - let prec = _prec; - if (xs !== 0) { - _xs = xs.tl; - _prec = copyAuxCont(xs.hd, prec); - continue; - } - prec.tl = /* [] */0; - return; - }; -} - -function flatten(_xs) { - while (true) { - let xs = _xs; - if (xs === 0) { - return /* [] */0; - } - let match = xs.hd; - if (match !== 0) { - let cell = {hd: match.hd, tl: /* [] */0}; - flattenAux(copyAuxCont(match.tl, cell), xs.tl); - return cell; - } - _xs = xs.tl; - continue; - }; -} - -function concatMany(xs) { - let len = xs.length; - if (len === 1) { - return xs[0]; - } - if (len === 0) { - return /* [] */0; - } - let len$1 = xs.length; - let v = xs[len$1 - 1 | 0]; - for (let i = len$1 - 2 | 0; i >= 0; --i) { - v = concat(xs[i], v); - } - return v; -} - -function mapReverse(l, f) { - let _accu = /* [] */0; - let _xs = l; - while (true) { - let xs = _xs; - let accu = _accu; - if (xs === 0) { - return accu; - } - _xs = xs.tl; - _accu = {hd: f(xs.hd), tl: accu}; - continue; - }; -} - -function forEach(_xs, f) { - while (true) { - let xs = _xs; - if (xs === 0) { - return; - } - f(xs.hd); - _xs = xs.tl; - continue; - }; -} - -function forEachWithIndex(l, f) { - let _xs = l; - let _i = 0; - while (true) { - let i = _i; - let xs = _xs; - if (xs === 0) { - return; - } - f(i, xs.hd); - _i = i + 1 | 0; - _xs = xs.tl; - continue; - }; -} - -function reduce(_l, _accu, f) { - while (true) { - let accu = _accu; - let l = _l; - if (l === 0) { - return accu; - } - _accu = f(accu, l.hd); - _l = l.tl; - continue; - }; -} - -function reduceReverseUnsafe(l, accu, f) { - if (l !== 0) { - return f(reduceReverseUnsafe(l.tl, accu, f), l.hd); - } else { - return accu; - } -} - -function reduceReverse(l, acc, f) { - let len = length(l); - if (len < 1000) { - return reduceReverseUnsafe(l, acc, f); - } else { - return Belt_Array.reduceReverse(toArray(l), acc, f); - } -} - -function reduceWithIndex(l, acc, f) { - let _l = l; - let _acc = acc; - let _i = 0; - while (true) { - let i = _i; - let acc$1 = _acc; - let l$1 = _l; - if (l$1 === 0) { - return acc$1; - } - _i = i + 1 | 0; - _acc = f(acc$1, l$1.hd, i); - _l = l$1.tl; - continue; - }; -} - -function mapReverse2(l1, l2, f) { - let _l1 = l1; - let _l2 = l2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1$1 = _l1; - if (l1$1 === 0) { - return accu; - } - if (l2$1 === 0) { - return accu; - } - _accu = {hd: f(l1$1.hd, l2$1.hd), tl: accu}; - _l2 = l2$1.tl; - _l1 = l1$1.tl; - continue; - }; -} - -function forEach2(_l1, _l2, f) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return; - } - if (l2 === 0) { - return; - } - f(l1.hd, l2.hd); - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function reduce2(_l1, _l2, _accu, f) { - while (true) { - let accu = _accu; - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return accu; - } - if (l2 === 0) { - return accu; - } - _accu = f(accu, l1.hd, l2.hd); - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function reduceReverse2Unsafe(l1, l2, accu, f) { - if (l1 !== 0 && l2 !== 0) { - return f(reduceReverse2Unsafe(l1.tl, l2.tl, accu, f), l1.hd, l2.hd); - } else { - return accu; - } -} - -function reduceReverse2(l1, l2, acc, f) { - let len = length(l1); - if (len < 1000) { - return reduceReverse2Unsafe(l1, l2, acc, f); - } else { - return Belt_Array.reduceReverse2(toArray(l1), toArray(l2), acc, f); - } -} - -function every(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return true; - } - if (!p(xs.hd)) { - return false; - } - _xs = xs.tl; - continue; - }; -} - -function some(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return false; - } - if (p(xs.hd)) { - return true; - } - _xs = xs.tl; - continue; - }; -} - -function every2(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return true; - } - if (l2 === 0) { - return true; - } - if (!p(l1.hd, l2.hd)) { - return false; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function cmpByLength(_l1, _l2) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - if (l2 !== 0) { - return -1; - } else { - return 0; - } - } - if (l2 === 0) { - return 1; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function cmp(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - if (l2 !== 0) { - return -1; - } else { - return 0; - } - } - if (l2 === 0) { - return 1; - } - let c = p(l1.hd, l2.hd); - if (c !== 0) { - return c; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function eq(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return l2 === 0; - } - if (l2 === 0) { - return false; - } - if (!p(l1.hd, l2.hd)) { - return false; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function some2(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return false; - } - if (l2 === 0) { - return false; - } - if (p(l1.hd, l2.hd)) { - return true; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function has(_xs, x, eq) { - while (true) { - let xs = _xs; - if (xs === 0) { - return false; - } - if (eq(xs.hd, x)) { - return true; - } - _xs = xs.tl; - continue; - }; -} - -function getAssoc(_xs, x, eq) { - while (true) { - let xs = _xs; - if (xs === 0) { - return; - } - let match = xs.hd; - if (eq(match[0], x)) { - return Primitive_option.some(match[1]); - } - _xs = xs.tl; - continue; - }; -} - -function hasAssoc(_xs, x, eq) { - while (true) { - let xs = _xs; - if (xs === 0) { - return false; - } - if (eq(xs.hd[0], x)) { - return true; - } - _xs = xs.tl; - continue; - }; -} - -function removeAssoc(xs, x, eq) { - if (xs === 0) { - return /* [] */0; - } - let l = xs.tl; - let pair = xs.hd; - if (eq(pair[0], x)) { - return l; - } - let cell = {hd: pair, tl: /* [] */0}; - let removed = removeAssocAuxWithMap(l, x, cell, eq); - if (removed) { - return cell; - } else { - return xs; - } -} - -function setAssoc(xs, x, k, eq) { - if (xs === 0) { - return {hd: [ - x, - k - ], tl: /* [] */0}; - } - let l = xs.tl; - let pair = xs.hd; - if (eq(pair[0], x)) { - return {hd: [ - x, - k - ], tl: l}; - } - let cell = {hd: pair, tl: /* [] */0}; - let replaced = setAssocAuxWithMap(l, x, k, cell, eq); - if (replaced) { - return cell; - } else { - return {hd: [ - x, - k - ], tl: xs}; - } -} - -function sort(xs, cmp) { - let arr = toArray(xs); - Belt_SortArray.stableSortInPlaceBy(arr, cmp); - return fromArray(arr); -} - -function getBy(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return; - } - let x = xs.hd; - if (p(x)) { - return Primitive_option.some(x); - } - _xs = xs.tl; - continue; - }; -} - -function keep(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return /* [] */0; - } - let t = xs.tl; - let h = xs.hd; - if (p(h)) { - let cell = {hd: h, tl: /* [] */0}; - copyAuxWitFilter(p, t, cell); - return cell; - } - _xs = t; - continue; - }; -} - -function keepWithIndex(xs, p) { - let _xs = xs; - let _i = 0; - while (true) { - let i = _i; - let xs$1 = _xs; - if (xs$1 === 0) { - return /* [] */0; - } - let t = xs$1.tl; - let h = xs$1.hd; - if (p(h, i)) { - let cell = {hd: h, tl: /* [] */0}; - copyAuxWithFilterIndex(p, t, cell, i + 1 | 0); - return cell; - } - _i = i + 1 | 0; - _xs = t; - continue; - }; -} - -function keepMap(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return /* [] */0; - } - let t = xs.tl; - let h = p(xs.hd); - if (h !== undefined) { - let cell = {hd: Primitive_option.valFromOption(h), tl: /* [] */0}; - copyAuxWitFilterMap(p, t, cell); - return cell; - } - _xs = t; - continue; - }; -} - -function partition(l, p) { - if (l === 0) { - return [ - /* [] */0, - /* [] */0 - ]; - } - let h = l.hd; - let nextX = {hd: h, tl: /* [] */0}; - let nextY = {hd: h, tl: /* [] */0}; - let b = p(h); - partitionAux(p, l.tl, nextX, nextY); - if (b) { - return [ - nextX, - nextY.tl - ]; - } else { - return [ - nextX.tl, - nextY - ]; - } -} - -function unzip(xs) { - if (xs === 0) { - return [ - /* [] */0, - /* [] */0 - ]; - } - let match = xs.hd; - let cellX = {hd: match[0], tl: /* [] */0}; - let cellY = {hd: match[1], tl: /* [] */0}; - splitAux(xs.tl, cellX, cellY); - return [ - cellX, - cellY - ]; -} - -function zip(l1, l2) { - if (l1 === 0) { - return /* [] */0; - } - if (l2 === 0) { - return /* [] */0; - } - let cell = {hd: [ - l1.hd, - l2.hd - ], tl: /* [] */0}; - zipAux(l1.tl, l2.tl, cell); - return cell; -} - -let size = length; - -let headExn = headOrThrow; - -let tailExn = tailOrThrow; - -let getExn = getOrThrow; - -let makeByU = makeBy; - -let mapU = map; - -let zipByU = zipBy; - -let mapWithIndexU = mapWithIndex; - -let mapReverseU = mapReverse; - -let forEachU = forEach; - -let forEachWithIndexU = forEachWithIndex; - -let reduceU = reduce; - -let reduceWithIndexU = reduceWithIndex; - -let reduceReverseU = reduceReverse; - -let mapReverse2U = mapReverse2; - -let forEach2U = forEach2; - -let reduce2U = reduce2; - -let reduceReverse2U = reduceReverse2; - -let everyU = every; - -let someU = some; - -let every2U = every2; - -let some2U = some2; - -let cmpU = cmp; - -let eqU = eq; - -let hasU = has; - -let getByU = getBy; - -let keepU = keep; - -let filter = keep; - -let keepWithIndexU = keepWithIndex; - -let filterWithIndex = keepWithIndex; - -let keepMapU = keepMap; - -let partitionU = partition; - -let getAssocU = getAssoc; - -let hasAssocU = hasAssoc; - -let removeAssocU = removeAssoc; - -let setAssocU = setAssoc; - -let sortU = sort; - -export { - length, - size, - head, - headExn, - headOrThrow, - tail, - tailExn, - tailOrThrow, - add, - get, - getExn, - getOrThrow, - make, - makeByU, - makeBy, - shuffle, - drop, - take, - splitAt, - concat, - concatMany, - reverseConcat, - flatten, - mapU, - map, - zip, - zipByU, - zipBy, - mapWithIndexU, - mapWithIndex, - fromArray, - toArray, - reverse, - mapReverseU, - mapReverse, - forEachU, - forEach, - forEachWithIndexU, - forEachWithIndex, - reduceU, - reduce, - reduceWithIndexU, - reduceWithIndex, - reduceReverseU, - reduceReverse, - mapReverse2U, - mapReverse2, - forEach2U, - forEach2, - reduce2U, - reduce2, - reduceReverse2U, - reduceReverse2, - everyU, - every, - someU, - some, - every2U, - every2, - some2U, - some2, - cmpByLength, - cmpU, - cmp, - eqU, - eq, - hasU, - has, - getByU, - getBy, - keepU, - keep, - filter, - keepWithIndexU, - keepWithIndex, - filterWithIndex, - keepMapU, - keepMap, - partitionU, - partition, - unzip, - getAssocU, - getAssoc, - hasAssocU, - hasAssoc, - removeAssocU, - removeAssoc, - setAssocU, - setAssoc, - sortU, - sort, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Map.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Map.mjs deleted file mode 100644 index 037146cdf67..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Map.mjs +++ /dev/null @@ -1,327 +0,0 @@ - - -import * as Belt_MapDict from "./Belt_MapDict.mjs"; - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_MapDict.fromArray(data, cmp) - }; -} - -function remove(m, x) { - let odata = m.data; - let cmp = m.cmp; - let newData = Belt_MapDict.remove(odata, x, cmp); - if (newData === odata) { - return m; - } else { - return { - cmp: cmp, - data: newData - }; - } -} - -function removeMany(m, x) { - let cmp = m.cmp; - let newData = Belt_MapDict.removeMany(m.data, x, cmp); - return { - cmp: cmp, - data: newData - }; -} - -function set(m, key, d) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_MapDict.set(m.data, key, d, cmp) - }; -} - -function mergeMany(m, e) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_MapDict.mergeMany(m.data, e, cmp) - }; -} - -function update(m, key, f) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_MapDict.update(m.data, key, f, cmp) - }; -} - -function split(m, x) { - let cmp = m.cmp; - let match = Belt_MapDict.split(m.data, x, cmp); - let match$1 = match[0]; - return [ - [ - { - cmp: cmp, - data: match$1[0] - }, - { - cmp: cmp, - data: match$1[1] - } - ], - match[1] - ]; -} - -function merge(s1, s2, f) { - let cmp = s1.cmp; - return { - cmp: cmp, - data: Belt_MapDict.merge(s1.data, s2.data, f, cmp) - }; -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function isEmpty(map) { - return Belt_MapDict.isEmpty(map.data); -} - -function findFirstBy(m, f) { - return Belt_MapDict.findFirstBy(m.data, f); -} - -function forEach(m, f) { - Belt_MapDict.forEach(m.data, f); -} - -function reduce(m, acc, f) { - return Belt_MapDict.reduce(m.data, acc, f); -} - -function every(m, f) { - return Belt_MapDict.every(m.data, f); -} - -function some(m, f) { - return Belt_MapDict.some(m.data, f); -} - -function keep(m, f) { - return { - cmp: m.cmp, - data: Belt_MapDict.keep(m.data, f) - }; -} - -function partition(m, p) { - let cmp = m.cmp; - let match = Belt_MapDict.partition(m.data, p); - return [ - { - cmp: cmp, - data: match[0] - }, - { - cmp: cmp, - data: match[1] - } - ]; -} - -function map(m, f) { - return { - cmp: m.cmp, - data: Belt_MapDict.map(m.data, f) - }; -} - -function mapWithKey(m, f) { - return { - cmp: m.cmp, - data: Belt_MapDict.mapWithKey(m.data, f) - }; -} - -function size(map) { - return Belt_MapDict.size(map.data); -} - -function toList(map) { - return Belt_MapDict.toList(map.data); -} - -function toArray(m) { - return Belt_MapDict.toArray(m.data); -} - -function keysToArray(m) { - return Belt_MapDict.keysToArray(m.data); -} - -function valuesToArray(m) { - return Belt_MapDict.valuesToArray(m.data); -} - -function minKey(m) { - return Belt_MapDict.minKey(m.data); -} - -function maxKey(m) { - return Belt_MapDict.maxKey(m.data); -} - -function minimum(m) { - return Belt_MapDict.minimum(m.data); -} - -function maximum(m) { - return Belt_MapDict.maximum(m.data); -} - -function get(map, x) { - return Belt_MapDict.get(map.data, x, map.cmp); -} - -function getWithDefault(map, x, def) { - return Belt_MapDict.getWithDefault(map.data, x, def, map.cmp); -} - -function getOrThrow(map, x) { - return Belt_MapDict.getOrThrow(map.data, x, map.cmp); -} - -function has(map, x) { - return Belt_MapDict.has(map.data, x, map.cmp); -} - -function checkInvariantInternal(m) { - Belt_MapDict.checkInvariantInternal(m.data); -} - -function eq(m1, m2, veq) { - return Belt_MapDict.eq(m1.data, m2.data, m1.cmp, veq); -} - -function cmp(m1, m2, vcmp) { - return Belt_MapDict.cmp(m1.data, m2.data, m1.cmp, vcmp); -} - -function getData(m) { - return m.data; -} - -function getId(m) { - let cmp = m.cmp; - return { - cmp: cmp - }; -} - -function packIdData(id, data) { - return { - cmp: id.cmp, - data: data - }; -} - -let Int; - -let $$String; - -let Dict; - -let cmpU = cmp; - -let eqU = eq; - -let findFirstByU = findFirstBy; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mergeU = merge; - -let keepU = keep; - -let partitionU = partition; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -export { - Int, - $$String, - Dict, - make, - isEmpty, - has, - cmpU, - cmp, - eqU, - eq, - findFirstByU, - findFirstBy, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - size, - toArray, - toList, - fromArray, - keysToArray, - valuesToArray, - minKey, - maxKey, - minimum, - maximum, - get, - getWithDefault, - getExn, - getOrThrow, - remove, - removeMany, - set, - updateU, - update, - mergeMany, - mergeU, - merge, - keepU, - keep, - partitionU, - partition, - split, - mapU, - map, - mapWithKeyU, - mapWithKey, - getData, - getId, - packIdData, - checkInvariantInternal, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MapDict.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MapDict.mjs deleted file mode 100644 index 5a226ffb174..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MapDict.mjs +++ /dev/null @@ -1,394 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; - -function set(t, newK, newD, cmp) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(newK, newD); - } - let k = t.k; - let c = cmp(newK, k); - if (c === 0) { - return Belt_internalAVLtree.updateValue(t, newD); - } - let l = t.l; - let r = t.r; - let v = t.v; - if (c < 0) { - return Belt_internalAVLtree.bal(set(l, newK, newD, cmp), k, v, r); - } else { - return Belt_internalAVLtree.bal(l, k, v, set(r, newK, newD, cmp)); - } -} - -function update(t, newK, f, cmp) { - if (t !== undefined) { - let k = t.k; - let c = cmp(newK, k); - if (c === 0) { - let newD = f(Primitive_option.some(t.v)); - if (newD !== undefined) { - return Belt_internalAVLtree.updateValue(t, Primitive_option.valFromOption(newD)); - } - let l = t.l; - let r = t.r; - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - let l$1 = t.l; - let r$2 = t.r; - let v = t.v; - if (c < 0) { - let ll = update(l$1, newK, f, cmp); - if (l$1 === ll) { - return t; - } else { - return Belt_internalAVLtree.bal(ll, k, v, r$2); - } - } - let rr = update(r$2, newK, f, cmp); - if (r$2 === rr) { - return t; - } else { - return Belt_internalAVLtree.bal(l$1, k, v, rr); - } - } - let newD$1 = f(undefined); - if (newD$1 !== undefined) { - return Belt_internalAVLtree.singleton(newK, Primitive_option.valFromOption(newD$1)); - } else { - return t; - } -} - -function removeAux0(n, x, cmp) { - let v = n.k; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - if (c < 0) { - if (l === undefined) { - return n; - } - let ll = removeAux0(l, x, cmp); - if (ll === l) { - return n; - } else { - return Belt_internalAVLtree.bal(ll, v, n.v, r); - } - } - if (r === undefined) { - return n; - } - let rr = removeAux0(r, x, cmp); - if (rr === r) { - return n; - } else { - return Belt_internalAVLtree.bal(l, v, n.v, rr); - } -} - -function remove(n, x, cmp) { - if (n !== undefined) { - return removeAux0(n, x, cmp); - } -} - -function mergeMany(h, arr, cmp) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - v = set(v, match[0], match[1], cmp); - } - return v; -} - -function splitAuxPivot(n, x, pres, cmp) { - let v = n.k; - let d = n.v; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - pres.contents = Primitive_option.some(d); - return [ - l, - r - ]; - } - if (c < 0) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(l, x, pres, cmp); - return [ - match[0], - Belt_internalAVLtree.join(match[1], v, d, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(r, x, pres, cmp); - return [ - Belt_internalAVLtree.join(l, v, d, match$1[0]), - match$1[1] - ]; -} - -function split(n, x, cmp) { - if (n === undefined) { - return [ - [ - undefined, - undefined - ], - undefined - ]; - } - let pres = { - contents: undefined - }; - let v = splitAuxPivot(n, x, pres, cmp); - return [ - v, - pres.contents - ]; -} - -function merge(s1, s2, f, cmp) { - if (s1 === undefined) { - if (s2 !== undefined) { - return Belt_internalAVLtree.keepMap(s2, (k, v) => f(k, undefined, Primitive_option.some(v))); - } else { - return; - } - } - if (s2 === undefined) { - return Belt_internalAVLtree.keepMap(s1, (k, v) => f(k, Primitive_option.some(v), undefined)); - } - if (s1.h >= s2.h) { - let v1 = s1.k; - let d1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let d2 = { - contents: undefined - }; - let match = splitAuxPivot(s2, v1, d2, cmp); - let d2$1 = d2.contents; - let newLeft = merge(l1, match[0], f, cmp); - let newD = f(v1, Primitive_option.some(d1), d2$1); - let newRight = merge(r1, match[1], f, cmp); - return Belt_internalAVLtree.concatOrJoin(newLeft, v1, newD, newRight); - } - let v2 = s2.k; - let d2$2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let d1$1 = { - contents: undefined - }; - let match$1 = splitAuxPivot(s1, v2, d1$1, cmp); - let d1$2 = d1$1.contents; - let newLeft$1 = merge(match$1[0], l2, f, cmp); - let newD$1 = f(v2, d1$2, Primitive_option.some(d2$2)); - let newRight$1 = merge(match$1[1], r2, f, cmp); - return Belt_internalAVLtree.concatOrJoin(newLeft$1, v2, newD$1, newRight$1); -} - -function removeMany(t, keys, cmp) { - let len = keys.length; - if (t !== undefined) { - let _t = t; - let _i = 0; - while (true) { - let i = _i; - let t$1 = _t; - if (i >= len) { - return t$1; - } - let ele = keys[i]; - let u = removeAux0(t$1, ele, cmp); - if (u === undefined) { - return u; - } - _i = i + 1 | 0; - _t = u; - continue; - }; - } -} - -let empty; - -let isEmpty = Belt_internalAVLtree.isEmpty; - -let has = Belt_internalAVLtree.has; - -let cmpU = Belt_internalAVLtree.cmp; - -let cmp = Belt_internalAVLtree.cmp; - -let eqU = Belt_internalAVLtree.eq; - -let eq = Belt_internalAVLtree.eq; - -let findFirstByU = Belt_internalAVLtree.findFirstBy; - -let findFirstBy = Belt_internalAVLtree.findFirstBy; - -let forEachU = Belt_internalAVLtree.forEach; - -let forEach = Belt_internalAVLtree.forEach; - -let reduceU = Belt_internalAVLtree.reduce; - -let reduce = Belt_internalAVLtree.reduce; - -let everyU = Belt_internalAVLtree.every; - -let every = Belt_internalAVLtree.every; - -let someU = Belt_internalAVLtree.some; - -let some = Belt_internalAVLtree.some; - -let size = Belt_internalAVLtree.size; - -let toList = Belt_internalAVLtree.toList; - -let toArray = Belt_internalAVLtree.toArray; - -let fromArray = Belt_internalAVLtree.fromArray; - -let keysToArray = Belt_internalAVLtree.keysToArray; - -let valuesToArray = Belt_internalAVLtree.valuesToArray; - -let minKey = Belt_internalAVLtree.minKey; - -let maxKey = Belt_internalAVLtree.maxKey; - -let minimum = Belt_internalAVLtree.minimum; - -let maximum = Belt_internalAVLtree.maximum; - -let get = Belt_internalAVLtree.get; - -let getWithDefault = Belt_internalAVLtree.getWithDefault; - -let getExn = Belt_internalAVLtree.getOrThrow; - -let getOrThrow = Belt_internalAVLtree.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLtree.checkInvariantInternal; - -let updateU = update; - -let mergeU = merge; - -let keepU = Belt_internalAVLtree.keepShared; - -let keep = Belt_internalAVLtree.keepShared; - -let partitionU = Belt_internalAVLtree.partitionShared; - -let partition = Belt_internalAVLtree.partitionShared; - -let mapU = Belt_internalAVLtree.map; - -let map = Belt_internalAVLtree.map; - -let mapWithKeyU = Belt_internalAVLtree.mapWithKey; - -let mapWithKey = Belt_internalAVLtree.mapWithKey; - -export { - empty, - isEmpty, - has, - cmpU, - cmp, - eqU, - eq, - findFirstByU, - findFirstBy, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - size, - toList, - toArray, - fromArray, - keysToArray, - valuesToArray, - minKey, - maxKey, - minimum, - maximum, - get, - getWithDefault, - getExn, - getOrThrow, - checkInvariantInternal, - remove, - removeMany, - set, - updateU, - update, - mergeU, - merge, - mergeMany, - keepU, - keep, - partitionU, - partition, - split, - mapU, - map, - mapWithKeyU, - mapWithKey, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MapInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MapInt.mjs deleted file mode 100644 index d0e96b75908..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MapInt.mjs +++ /dev/null @@ -1,290 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalMapInt from "./Belt_internalMapInt.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; - -function set(t, newK, newD) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(newK, newD); - } - let k = t.k; - if (newK === k) { - return Belt_internalAVLtree.updateValue(t, newD); - } - let v = t.v; - if (newK < k) { - return Belt_internalAVLtree.bal(set(t.l, newK, newD), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, set(t.r, newK, newD)); - } -} - -function update(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (x === k) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - return Belt_internalAVLtree.updateValue(t, Primitive_option.valFromOption(data)); - } - let l = t.l; - let r = t.r; - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - let v = t.v; - let l$1 = t.l; - let r$2 = t.r; - if (x < k) { - let ll = update(l$1, x, f); - if (l$1 === ll) { - return t; - } else { - return Belt_internalAVLtree.bal(ll, k, v, r$2); - } - } - let rr = update(r$2, x, f); - if (r$2 === rr) { - return t; - } else { - return Belt_internalAVLtree.bal(l$1, k, v, rr); - } - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function removeAux(n, x) { - let v = n.k; - let l = n.l; - let r = n.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - if (x < v) { - if (l === undefined) { - return n; - } - let ll = removeAux(l, x); - if (ll === l) { - return n; - } else { - return Belt_internalAVLtree.bal(ll, v, n.v, r); - } - } - if (r === undefined) { - return n; - } - let rr = removeAux(r, x); - return Belt_internalAVLtree.bal(l, v, n.v, rr); -} - -function remove(n, x) { - if (n !== undefined) { - return removeAux(n, x); - } -} - -function removeMany(t, keys) { - let len = keys.length; - if (t !== undefined) { - let _t = t; - let _i = 0; - while (true) { - let i = _i; - let t$1 = _t; - if (i >= len) { - return t$1; - } - let ele = keys[i]; - let u = removeAux(t$1, ele); - if (u === undefined) { - return u; - } - _i = i + 1 | 0; - _t = u; - continue; - }; - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - v = set(v, match[0], match[1]); - } - return v; -} - -let empty; - -let isEmpty = Belt_internalAVLtree.isEmpty; - -let has = Belt_internalMapInt.has; - -let cmpU = Belt_internalMapInt.cmp; - -let cmp = Belt_internalMapInt.cmp; - -let eqU = Belt_internalMapInt.eq; - -let eq = Belt_internalMapInt.eq; - -let findFirstByU = Belt_internalAVLtree.findFirstBy; - -let findFirstBy = Belt_internalAVLtree.findFirstBy; - -let forEachU = Belt_internalAVLtree.forEach; - -let forEach = Belt_internalAVLtree.forEach; - -let reduceU = Belt_internalAVLtree.reduce; - -let reduce = Belt_internalAVLtree.reduce; - -let everyU = Belt_internalAVLtree.every; - -let every = Belt_internalAVLtree.every; - -let someU = Belt_internalAVLtree.some; - -let some = Belt_internalAVLtree.some; - -let size = Belt_internalAVLtree.size; - -let toList = Belt_internalAVLtree.toList; - -let toArray = Belt_internalAVLtree.toArray; - -let fromArray = Belt_internalMapInt.fromArray; - -let keysToArray = Belt_internalAVLtree.keysToArray; - -let valuesToArray = Belt_internalAVLtree.valuesToArray; - -let minKey = Belt_internalAVLtree.minKey; - -let maxKey = Belt_internalAVLtree.maxKey; - -let minimum = Belt_internalAVLtree.minimum; - -let maximum = Belt_internalAVLtree.maximum; - -let get = Belt_internalMapInt.get; - -let getWithDefault = Belt_internalMapInt.getWithDefault; - -let getExn = Belt_internalMapInt.getOrThrow; - -let getOrThrow = Belt_internalMapInt.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLtree.checkInvariantInternal; - -let updateU = update; - -let mergeU = Belt_internalMapInt.merge; - -let merge = Belt_internalMapInt.merge; - -let keepU = Belt_internalAVLtree.keepShared; - -let keep = Belt_internalAVLtree.keepShared; - -let partitionU = Belt_internalAVLtree.partitionShared; - -let partition = Belt_internalAVLtree.partitionShared; - -let split = Belt_internalMapInt.split; - -let mapU = Belt_internalAVLtree.map; - -let map = Belt_internalAVLtree.map; - -let mapWithKeyU = Belt_internalAVLtree.mapWithKey; - -let mapWithKey = Belt_internalAVLtree.mapWithKey; - -export { - empty, - isEmpty, - has, - cmpU, - cmp, - eqU, - eq, - findFirstByU, - findFirstBy, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - size, - toList, - toArray, - fromArray, - keysToArray, - valuesToArray, - minKey, - maxKey, - minimum, - maximum, - get, - getWithDefault, - getExn, - getOrThrow, - checkInvariantInternal, - remove, - removeMany, - set, - updateU, - update, - mergeU, - merge, - mergeMany, - keepU, - keep, - partitionU, - partition, - split, - mapU, - map, - mapWithKeyU, - mapWithKey, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MapString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MapString.mjs deleted file mode 100644 index a80f7eb6efa..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MapString.mjs +++ /dev/null @@ -1,290 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; -import * as Belt_internalMapString from "./Belt_internalMapString.mjs"; - -function set(t, newK, newD) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(newK, newD); - } - let k = t.k; - if (newK === k) { - return Belt_internalAVLtree.updateValue(t, newD); - } - let v = t.v; - if (newK < k) { - return Belt_internalAVLtree.bal(set(t.l, newK, newD), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, set(t.r, newK, newD)); - } -} - -function update(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (x === k) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - return Belt_internalAVLtree.updateValue(t, Primitive_option.valFromOption(data)); - } - let l = t.l; - let r = t.r; - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - let v = t.v; - let l$1 = t.l; - let r$2 = t.r; - if (x < k) { - let ll = update(l$1, x, f); - if (l$1 === ll) { - return t; - } else { - return Belt_internalAVLtree.bal(ll, k, v, r$2); - } - } - let rr = update(r$2, x, f); - if (r$2 === rr) { - return t; - } else { - return Belt_internalAVLtree.bal(l$1, k, v, rr); - } - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function removeAux(n, x) { - let v = n.k; - let l = n.l; - let r = n.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - if (x < v) { - if (l === undefined) { - return n; - } - let ll = removeAux(l, x); - if (ll === l) { - return n; - } else { - return Belt_internalAVLtree.bal(ll, v, n.v, r); - } - } - if (r === undefined) { - return n; - } - let rr = removeAux(r, x); - return Belt_internalAVLtree.bal(l, v, n.v, rr); -} - -function remove(n, x) { - if (n !== undefined) { - return removeAux(n, x); - } -} - -function removeMany(t, keys) { - let len = keys.length; - if (t !== undefined) { - let _t = t; - let _i = 0; - while (true) { - let i = _i; - let t$1 = _t; - if (i >= len) { - return t$1; - } - let ele = keys[i]; - let u = removeAux(t$1, ele); - if (u === undefined) { - return u; - } - _i = i + 1 | 0; - _t = u; - continue; - }; - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - v = set(v, match[0], match[1]); - } - return v; -} - -let empty; - -let isEmpty = Belt_internalAVLtree.isEmpty; - -let has = Belt_internalMapString.has; - -let cmpU = Belt_internalMapString.cmp; - -let cmp = Belt_internalMapString.cmp; - -let eqU = Belt_internalMapString.eq; - -let eq = Belt_internalMapString.eq; - -let findFirstByU = Belt_internalAVLtree.findFirstBy; - -let findFirstBy = Belt_internalAVLtree.findFirstBy; - -let forEachU = Belt_internalAVLtree.forEach; - -let forEach = Belt_internalAVLtree.forEach; - -let reduceU = Belt_internalAVLtree.reduce; - -let reduce = Belt_internalAVLtree.reduce; - -let everyU = Belt_internalAVLtree.every; - -let every = Belt_internalAVLtree.every; - -let someU = Belt_internalAVLtree.some; - -let some = Belt_internalAVLtree.some; - -let size = Belt_internalAVLtree.size; - -let toList = Belt_internalAVLtree.toList; - -let toArray = Belt_internalAVLtree.toArray; - -let fromArray = Belt_internalMapString.fromArray; - -let keysToArray = Belt_internalAVLtree.keysToArray; - -let valuesToArray = Belt_internalAVLtree.valuesToArray; - -let minKey = Belt_internalAVLtree.minKey; - -let maxKey = Belt_internalAVLtree.maxKey; - -let minimum = Belt_internalAVLtree.minimum; - -let maximum = Belt_internalAVLtree.maximum; - -let get = Belt_internalMapString.get; - -let getWithDefault = Belt_internalMapString.getWithDefault; - -let getExn = Belt_internalMapString.getOrThrow; - -let getOrThrow = Belt_internalMapString.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLtree.checkInvariantInternal; - -let updateU = update; - -let mergeU = Belt_internalMapString.merge; - -let merge = Belt_internalMapString.merge; - -let keepU = Belt_internalAVLtree.keepShared; - -let keep = Belt_internalAVLtree.keepShared; - -let partitionU = Belt_internalAVLtree.partitionShared; - -let partition = Belt_internalAVLtree.partitionShared; - -let split = Belt_internalMapString.split; - -let mapU = Belt_internalAVLtree.map; - -let map = Belt_internalAVLtree.map; - -let mapWithKeyU = Belt_internalAVLtree.mapWithKey; - -let mapWithKey = Belt_internalAVLtree.mapWithKey; - -export { - empty, - isEmpty, - has, - cmpU, - cmp, - eqU, - eq, - findFirstByU, - findFirstBy, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - size, - toList, - toArray, - fromArray, - keysToArray, - valuesToArray, - minKey, - maxKey, - minimum, - maximum, - get, - getWithDefault, - getExn, - getOrThrow, - checkInvariantInternal, - remove, - removeMany, - set, - updateU, - update, - mergeU, - merge, - mergeMany, - keepU, - keep, - partitionU, - partition, - split, - mapU, - map, - mapWithKeyU, - mapWithKey, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableMap.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableMap.mjs deleted file mode 100644 index 1946813b92c..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableMap.mjs +++ /dev/null @@ -1,349 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; - -function removeMutateAux(nt, x, cmp) { - let k = nt.k; - let c = cmp(x, k); - if (c === 0) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLtree.balMutate(nt); - } else { - return l; - } - } else if (r !== undefined) { - return r; - } else { - return l; - } - } - if (c < 0) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeMutateAux(l$1, x, cmp); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeMutateAux(r$1, x, cmp); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, k) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = removeMutateAux(oldRoot, k, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeArrayMutateAux(_t, xs, _i, len, cmp) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = removeMutateAux(t, ele, cmp); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - let newRoot = removeArrayMutateAux(oldRoot, xs, 0, len, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function updateDone(t, x, f, cmp) { - if (t !== undefined) { - let k = t.k; - let c = cmp(x, k); - if (c === 0) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - t.v = Primitive_option.valFromOption(data); - return t; - } - let l = t.l; - let r = t.r; - if (l !== undefined) { - if (r !== undefined) { - t.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(t, r); - return Belt_internalAVLtree.balMutate(t); - } else { - return l; - } - } else if (r !== undefined) { - return r; - } else { - return l; - } - } - if (c < 0) { - t.l = updateDone(t.l, x, f, cmp); - } else { - t.r = updateDone(t.r, x, f, cmp); - } - return Belt_internalAVLtree.balMutate(t); - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function update(t, x, f) { - let oldRoot = t.data; - let newRoot = updateDone(oldRoot, x, f, t.cmp); - if (newRoot !== oldRoot) { - t.data = newRoot; - return; - } -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function clear(m) { - m.data = undefined; -} - -function isEmpty(d) { - let x = d.data; - return x === undefined; -} - -function minKey(m) { - return Belt_internalAVLtree.minKey(m.data); -} - -function maxKey(m) { - return Belt_internalAVLtree.maxKey(m.data); -} - -function minimum(m) { - return Belt_internalAVLtree.minimum(m.data); -} - -function maximum(m) { - return Belt_internalAVLtree.maximum(m.data); -} - -function forEach(d, f) { - Belt_internalAVLtree.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLtree.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLtree.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLtree.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLtree.size(d.data); -} - -function toList(d) { - return Belt_internalAVLtree.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLtree.toArray(d.data); -} - -function keysToArray(d) { - return Belt_internalAVLtree.keysToArray(d.data); -} - -function valuesToArray(d) { - return Belt_internalAVLtree.valuesToArray(d.data); -} - -function checkInvariantInternal(d) { - Belt_internalAVLtree.checkInvariantInternal(d.data); -} - -function cmp(m1, m2, cmp$1) { - return Belt_internalAVLtree.cmp(m1.data, m2.data, m1.cmp, cmp$1); -} - -function eq(m1, m2, cmp) { - return Belt_internalAVLtree.eq(m1.data, m2.data, m1.cmp, cmp); -} - -function map(m, f) { - return { - cmp: m.cmp, - data: Belt_internalAVLtree.map(m.data, f) - }; -} - -function mapWithKey(m, f) { - return { - cmp: m.cmp, - data: Belt_internalAVLtree.mapWithKey(m.data, f) - }; -} - -function get(m, x) { - return Belt_internalAVLtree.get(m.data, x, m.cmp); -} - -function getWithDefault(m, x, def) { - return Belt_internalAVLtree.getWithDefault(m.data, x, def, m.cmp); -} - -function getOrThrow(m, x) { - return Belt_internalAVLtree.getOrThrow(m.data, x, m.cmp); -} - -function has(m, x) { - return Belt_internalAVLtree.has(m.data, x, m.cmp); -} - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_internalAVLtree.fromArray(data, cmp) - }; -} - -function set(m, e, v) { - let oldRoot = m.data; - let newRoot = Belt_internalAVLtree.updateMutate(oldRoot, e, v, m.cmp); - if (newRoot !== oldRoot) { - m.data = newRoot; - return; - } -} - -function mergeManyAux(t, xs, cmp) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - let match = xs[i]; - v = Belt_internalAVLtree.updateMutate(v, match[0], match[1], cmp); - } - return v; -} - -function mergeMany(d, xs) { - let oldRoot = d.data; - let newRoot = mergeManyAux(oldRoot, xs, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -let Int; - -let $$String; - -let cmpU = cmp; - -let eqU = eq; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -export { - Int, - $$String, - make, - clear, - isEmpty, - has, - cmpU, - cmp, - eqU, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - size, - toList, - toArray, - fromArray, - keysToArray, - valuesToArray, - minKey, - maxKey, - minimum, - maximum, - get, - getWithDefault, - getExn, - getOrThrow, - checkInvariantInternal, - remove, - removeMany, - set, - updateU, - update, - mergeMany, - mapU, - map, - mapWithKeyU, - mapWithKey, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableMapInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableMapInt.mjs deleted file mode 100644 index a45deb1acc0..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableMapInt.mjs +++ /dev/null @@ -1,317 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalMapInt from "./Belt_internalMapInt.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; - -function make() { - return { - data: undefined - }; -} - -function isEmpty(m) { - let x = m.data; - return x === undefined; -} - -function clear(m) { - m.data = undefined; -} - -function minKey(m) { - return Belt_internalAVLtree.minKey(m.data); -} - -function maxKey(m) { - return Belt_internalAVLtree.maxKey(m.data); -} - -function minimum(m) { - return Belt_internalAVLtree.minimum(m.data); -} - -function maximum(m) { - return Belt_internalAVLtree.maximum(m.data); -} - -function set(m, k, v) { - let old_data = m.data; - let v$1 = Belt_internalMapInt.addMutate(old_data, k, v); - if (v$1 !== old_data) { - m.data = v$1; - return; - } -} - -function forEach(d, f) { - Belt_internalAVLtree.forEach(d.data, f); -} - -function map(d, f) { - return { - data: Belt_internalAVLtree.map(d.data, f) - }; -} - -function mapWithKey(d, f) { - return { - data: Belt_internalAVLtree.mapWithKey(d.data, f) - }; -} - -function reduce(d, acc, f) { - return Belt_internalAVLtree.reduce(d.data, acc, f); -} - -function every(d, f) { - return Belt_internalAVLtree.every(d.data, f); -} - -function some(d, f) { - return Belt_internalAVLtree.some(d.data, f); -} - -function size(d) { - return Belt_internalAVLtree.size(d.data); -} - -function toList(d) { - return Belt_internalAVLtree.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLtree.toArray(d.data); -} - -function keysToArray(d) { - return Belt_internalAVLtree.keysToArray(d.data); -} - -function valuesToArray(d) { - return Belt_internalAVLtree.valuesToArray(d.data); -} - -function checkInvariantInternal(d) { - Belt_internalAVLtree.checkInvariantInternal(d.data); -} - -function has(d, v) { - return Belt_internalMapInt.has(d.data, v); -} - -function removeMutateAux(nt, x) { - let k = nt.k; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLtree.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeMutateAux(l$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeMutateAux(r$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = removeMutateAux(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function updateDone(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (k === x) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - t.v = Primitive_option.valFromOption(data); - return t; - } - let l = t.l; - let r = t.r; - if (l !== undefined) { - if (r !== undefined) { - t.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(t, r); - return Belt_internalAVLtree.balMutate(t); - } else { - return l; - } - } else { - return r; - } - } - let l$1 = t.l; - let r$1 = t.r; - if (x < k) { - let ll = updateDone(l$1, x, f); - t.l = ll; - } else { - t.r = updateDone(r$1, x, f); - } - return Belt_internalAVLtree.balMutate(t); - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function update(t, x, f) { - let oldRoot = t.data; - let newRoot = updateDone(oldRoot, x, f); - if (newRoot !== oldRoot) { - t.data = newRoot; - return; - } -} - -function removeArrayMutateAux(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = removeMutateAux(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - let newRoot = removeArrayMutateAux(oldRoot, xs, 0, len); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function fromArray(xs) { - return { - data: Belt_internalMapInt.fromArray(xs) - }; -} - -function cmp(d0, d1, f) { - return Belt_internalMapInt.cmp(d0.data, d1.data, f); -} - -function eq(d0, d1, f) { - return Belt_internalMapInt.eq(d0.data, d1.data, f); -} - -function get(d, x) { - return Belt_internalMapInt.get(d.data, x); -} - -function getWithDefault(d, x, def) { - return Belt_internalMapInt.getWithDefault(d.data, x, def); -} - -function getOrThrow(d, x) { - return Belt_internalMapInt.getOrThrow(d.data, x); -} - -let cmpU = cmp; - -let eqU = eq; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -export { - make, - clear, - isEmpty, - has, - cmpU, - cmp, - eqU, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - size, - toList, - toArray, - fromArray, - keysToArray, - valuesToArray, - minKey, - maxKey, - minimum, - maximum, - get, - getWithDefault, - getExn, - getOrThrow, - checkInvariantInternal, - remove, - removeMany, - set, - updateU, - update, - mapU, - map, - mapWithKeyU, - mapWithKey, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableMapString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableMapString.mjs deleted file mode 100644 index 7e4683ebadf..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableMapString.mjs +++ /dev/null @@ -1,317 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; -import * as Belt_internalMapString from "./Belt_internalMapString.mjs"; - -function make() { - return { - data: undefined - }; -} - -function isEmpty(m) { - let x = m.data; - return x === undefined; -} - -function clear(m) { - m.data = undefined; -} - -function minKey(m) { - return Belt_internalAVLtree.minKey(m.data); -} - -function maxKey(m) { - return Belt_internalAVLtree.maxKey(m.data); -} - -function minimum(m) { - return Belt_internalAVLtree.minimum(m.data); -} - -function maximum(m) { - return Belt_internalAVLtree.maximum(m.data); -} - -function set(m, k, v) { - let old_data = m.data; - let v$1 = Belt_internalMapString.addMutate(old_data, k, v); - if (v$1 !== old_data) { - m.data = v$1; - return; - } -} - -function forEach(d, f) { - Belt_internalAVLtree.forEach(d.data, f); -} - -function map(d, f) { - return { - data: Belt_internalAVLtree.map(d.data, f) - }; -} - -function mapWithKey(d, f) { - return { - data: Belt_internalAVLtree.mapWithKey(d.data, f) - }; -} - -function reduce(d, acc, f) { - return Belt_internalAVLtree.reduce(d.data, acc, f); -} - -function every(d, f) { - return Belt_internalAVLtree.every(d.data, f); -} - -function some(d, f) { - return Belt_internalAVLtree.some(d.data, f); -} - -function size(d) { - return Belt_internalAVLtree.size(d.data); -} - -function toList(d) { - return Belt_internalAVLtree.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLtree.toArray(d.data); -} - -function keysToArray(d) { - return Belt_internalAVLtree.keysToArray(d.data); -} - -function valuesToArray(d) { - return Belt_internalAVLtree.valuesToArray(d.data); -} - -function checkInvariantInternal(d) { - Belt_internalAVLtree.checkInvariantInternal(d.data); -} - -function has(d, v) { - return Belt_internalMapString.has(d.data, v); -} - -function removeMutateAux(nt, x) { - let k = nt.k; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLtree.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeMutateAux(l$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeMutateAux(r$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = removeMutateAux(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function updateDone(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (k === x) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - t.v = Primitive_option.valFromOption(data); - return t; - } - let l = t.l; - let r = t.r; - if (l !== undefined) { - if (r !== undefined) { - t.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(t, r); - return Belt_internalAVLtree.balMutate(t); - } else { - return l; - } - } else { - return r; - } - } - let l$1 = t.l; - let r$1 = t.r; - if (x < k) { - let ll = updateDone(l$1, x, f); - t.l = ll; - } else { - t.r = updateDone(r$1, x, f); - } - return Belt_internalAVLtree.balMutate(t); - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function update(t, x, f) { - let oldRoot = t.data; - let newRoot = updateDone(oldRoot, x, f); - if (newRoot !== oldRoot) { - t.data = newRoot; - return; - } -} - -function removeArrayMutateAux(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = removeMutateAux(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - let newRoot = removeArrayMutateAux(oldRoot, xs, 0, len); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function fromArray(xs) { - return { - data: Belt_internalMapString.fromArray(xs) - }; -} - -function cmp(d0, d1, f) { - return Belt_internalMapString.cmp(d0.data, d1.data, f); -} - -function eq(d0, d1, f) { - return Belt_internalMapString.eq(d0.data, d1.data, f); -} - -function get(d, x) { - return Belt_internalMapString.get(d.data, x); -} - -function getWithDefault(d, x, def) { - return Belt_internalMapString.getWithDefault(d.data, x, def); -} - -function getOrThrow(d, x) { - return Belt_internalMapString.getOrThrow(d.data, x); -} - -let cmpU = cmp; - -let eqU = eq; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -export { - make, - clear, - isEmpty, - has, - cmpU, - cmp, - eqU, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - size, - toList, - toArray, - fromArray, - keysToArray, - valuesToArray, - minKey, - maxKey, - minimum, - maximum, - get, - getWithDefault, - getExn, - getOrThrow, - checkInvariantInternal, - remove, - removeMany, - set, - updateU, - update, - mapU, - map, - mapWithKeyU, - mapWithKey, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableQueue.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableQueue.mjs deleted file mode 100644 index d31e683f522..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableQueue.mjs +++ /dev/null @@ -1,271 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function make() { - return { - length: 0, - first: undefined, - last: undefined - }; -} - -function clear(q) { - q.length = 0; - q.first = undefined; - q.last = undefined; -} - -function add(q, x) { - let cell = { - content: x, - next: undefined - }; - let last = q.last; - if (last !== undefined) { - q.length = q.length + 1 | 0; - last.next = cell; - q.last = cell; - } else { - q.length = 1; - q.first = cell; - q.last = cell; - } -} - -function peek(q) { - let v = q.first; - if (v !== undefined) { - return Primitive_option.some(v.content); - } -} - -function peekOrThrow(q) { - let v = q.first; - if (v !== undefined) { - return v.content; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function pop(q) { - let x = q.first; - if (x === undefined) { - return; - } - let next = x.next; - if (next === undefined) { - clear(q); - return Primitive_option.some(x.content); - } else { - q.length = q.length - 1 | 0; - q.first = next; - return Primitive_option.some(x.content); - } -} - -function popOrThrow(q) { - let x = q.first; - if (x !== undefined) { - let next = x.next; - if (next === undefined) { - clear(q); - return x.content; - } else { - q.length = q.length - 1 | 0; - q.first = next; - return x.content; - } - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function copy(q) { - let qRes = { - length: q.length, - first: undefined, - last: undefined - }; - let _prev; - let _cell = q.first; - while (true) { - let cell = _cell; - let prev = _prev; - if (cell !== undefined) { - let content = cell.content; - let res = { - content: content, - next: undefined - }; - if (prev !== undefined) { - prev.next = res; - } else { - qRes.first = res; - } - _cell = cell.next; - _prev = res; - continue; - } - qRes.last = prev; - return qRes; - }; -} - -function map(q, f) { - let qRes = { - length: q.length, - first: undefined, - last: undefined - }; - let _prev; - let _cell = q.first; - while (true) { - let cell = _cell; - let prev = _prev; - if (cell !== undefined) { - let content = f(cell.content); - let res = { - content: content, - next: undefined - }; - if (prev !== undefined) { - prev.next = res; - } else { - qRes.first = res; - } - _cell = cell.next; - _prev = res; - continue; - } - qRes.last = prev; - return qRes; - }; -} - -function isEmpty(q) { - return q.length === 0; -} - -function size(q) { - return q.length; -} - -function forEach(q, f) { - let _cell = q.first; - while (true) { - let cell = _cell; - if (cell === undefined) { - return; - } - f(cell.content); - _cell = cell.next; - continue; - }; -} - -function reduce(q, accu, f) { - let _accu = accu; - let _cell = q.first; - while (true) { - let cell = _cell; - let accu$1 = _accu; - if (cell === undefined) { - return accu$1; - } - let accu$2 = f(accu$1, cell.content); - _cell = cell.next; - _accu = accu$2; - continue; - }; -} - -function transfer(q1, q2) { - if (q1.length <= 0) { - return; - } - let l = q2.last; - if (l !== undefined) { - q2.length = q2.length + q1.length | 0; - l.next = q1.first; - q2.last = q1.last; - return clear(q1); - } else { - q2.length = q1.length; - q2.first = q1.first; - q2.last = q1.last; - return clear(q1); - } -} - -function fillAux(_i, arr, _cell) { - while (true) { - let cell = _cell; - let i = _i; - if (cell === undefined) { - return; - } - arr[i] = cell.content; - _cell = cell.next; - _i = i + 1 | 0; - continue; - }; -} - -function toArray(x) { - let v = new Array(x.length); - fillAux(0, v, x.first); - return v; -} - -function fromArray(arr) { - let q = { - length: 0, - first: undefined, - last: undefined - }; - for (let i = 0, i_finish = arr.length; i < i_finish; ++i) { - add(q, arr[i]); - } - return q; -} - -let peekExn = peekOrThrow; - -let popExn = popOrThrow; - -let mapU = map; - -let forEachU = forEach; - -let reduceU = reduce; - -export { - make, - clear, - isEmpty, - fromArray, - add, - peek, - peekExn, - peekOrThrow, - pop, - popExn, - popOrThrow, - copy, - size, - mapU, - map, - forEachU, - forEach, - reduceU, - reduce, - transfer, - toArray, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableSet.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableSet.mjs deleted file mode 100644 index 157629c2fa0..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableSet.mjs +++ /dev/null @@ -1,512 +0,0 @@ - - -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Belt_SortArray from "./Belt_SortArray.mjs"; -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; - -function remove0(nt, x, cmp) { - let k = nt.v; - let c = cmp(x, k); - if (c === 0) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (c < 0) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = remove0(l$1, x, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = remove0(r$1, x, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = remove0(oldRoot, v, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeMany0(_t, xs, _i, len, cmp) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = remove0(t, ele, cmp); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - d.data = removeMany0(oldRoot, xs, 0, len, d.cmp); -} - -function removeCheck0(nt, x, removed, cmp) { - let k = nt.v; - let c = cmp(x, k); - if (c === 0) { - removed.contents = true; - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (c < 0) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeCheck0(l$1, x, removed, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeCheck0(r$1, x, removed, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function removeCheck(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return false; - } - let removed = { - contents: false - }; - let newRoot = removeCheck0(oldRoot, v, removed, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - } - return removed.contents; -} - -function addCheck0(t, x, added, cmp) { - if (t !== undefined) { - let k = t.v; - let c = cmp(x, k); - if (c === 0) { - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = addCheck0(l, x, added, cmp); - t.l = ll; - } else { - t.r = addCheck0(r, x, added, cmp); - } - return Belt_internalAVLset.balMutate(t); - } - added.contents = true; - return Belt_internalAVLset.singleton(x); -} - -function addCheck(m, e) { - let oldRoot = m.data; - let added = { - contents: false - }; - let newRoot = addCheck0(oldRoot, e, added, m.cmp); - if (newRoot !== oldRoot) { - m.data = newRoot; - } - return added.contents; -} - -function add(m, e) { - let oldRoot = m.data; - let newRoot = Belt_internalAVLset.addMutate(m.cmp, oldRoot, e); - if (newRoot !== oldRoot) { - m.data = newRoot; - return; - } -} - -function addArrayMutate(t, xs, cmp) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - v = Belt_internalAVLset.addMutate(cmp, v, xs[i]); - } - return v; -} - -function mergeMany(d, xs) { - d.data = addArrayMutate(d.data, xs, d.cmp); -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function isEmpty(d) { - let n = d.data; - return n === undefined; -} - -function minimum(d) { - return Belt_internalAVLset.minimum(d.data); -} - -function maximum(d) { - return Belt_internalAVLset.maximum(d.data); -} - -function forEach(d, f) { - Belt_internalAVLset.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLset.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLset.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLset.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLset.size(d.data); -} - -function toList(d) { - return Belt_internalAVLset.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLset.toArray(d.data); -} - -function fromSortedArrayUnsafe(xs, id) { - return { - cmp: id.cmp, - data: Belt_internalAVLset.fromSortedArrayUnsafe(xs) - }; -} - -function checkInvariantInternal(d) { - Belt_internalAVLset.checkInvariantInternal(d.data); -} - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_internalAVLset.fromArray(data, cmp) - }; -} - -function cmp(d0, d1) { - return Belt_internalAVLset.cmp(d0.data, d1.data, d0.cmp); -} - -function eq(d0, d1) { - return Belt_internalAVLset.eq(d0.data, d1.data, d0.cmp); -} - -function get(d, x) { - return Belt_internalAVLset.get(d.data, x, d.cmp); -} - -function getOrThrow(d, x) { - return Belt_internalAVLset.getOrThrow(d.data, x, d.cmp); -} - -function split(d, key) { - let arr = Belt_internalAVLset.toArray(d.data); - let cmp = d.cmp; - let i = Belt_SortArray.binarySearchBy(arr, key, cmp); - let len = arr.length; - if (i >= 0) { - return [ - [ - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, i) - }, - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, i + 1 | 0, (len - i | 0) - 1 | 0) - } - ], - true - ]; - } - let next = (-i | 0) - 1 | 0; - return [ - [ - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, next) - }, - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, next, len - next | 0) - } - ], - false - ]; -} - -function keep(d, p) { - return { - cmp: d.cmp, - data: Belt_internalAVLset.keepCopy(d.data, p) - }; -} - -function partition(d, p) { - let cmp = d.cmp; - let match = Belt_internalAVLset.partitionCopy(d.data, p); - return [ - { - cmp: cmp, - data: match[0] - }, - { - cmp: cmp, - data: match[1] - } - ]; -} - -function subset(a, b) { - return Belt_internalAVLset.subset(a.data, b.data, a.cmp); -} - -function intersect(a, b) { - let cmp = a.cmp; - let match = a.data; - let match$1 = b.data; - if (match === undefined) { - return { - cmp: cmp, - data: undefined - }; - } - if (match$1 === undefined) { - return { - cmp: cmp, - data: undefined - }; - } - let sizea = Belt_internalAVLset.lengthNode(match); - let sizeb = Belt_internalAVLset.lengthNode(match$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(match, 0, tmp); - Belt_internalAVLset.fillArray(match$1, sizea, tmp); - if (cmp(tmp[sizea - 1 | 0], tmp[sizea]) < 0 || cmp(tmp[totalSize - 1 | 0], tmp[0]) < 0) { - return { - cmp: cmp, - data: undefined - }; - } - let tmp2 = new Array(Primitive_int.min(sizea, sizeb)); - let k = Belt_SortArray.intersect(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0, cmp); - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function diff(a, b) { - let cmp = a.cmp; - let dataa = a.data; - let match = b.data; - if (dataa === undefined) { - return { - cmp: cmp, - data: undefined - }; - } - if (match === undefined) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(dataa) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa); - let sizeb = Belt_internalAVLset.lengthNode(match); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa, 0, tmp); - Belt_internalAVLset.fillArray(match, sizea, tmp); - if (cmp(tmp[sizea - 1 | 0], tmp[sizea]) < 0 || cmp(tmp[totalSize - 1 | 0], tmp[0]) < 0) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(dataa) - }; - } - let tmp2 = new Array(sizea); - let k = Belt_SortArray.diff(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0, cmp); - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function union(a, b) { - let cmp = a.cmp; - let dataa = a.data; - let datab = b.data; - if (dataa === undefined) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(datab) - }; - } - if (datab === undefined) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(dataa) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa); - let sizeb = Belt_internalAVLset.lengthNode(datab); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa, 0, tmp); - Belt_internalAVLset.fillArray(datab, sizea, tmp); - if (cmp(tmp[sizea - 1 | 0], tmp[sizea]) < 0) { - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp, 0, totalSize) - }; - } - let tmp2 = new Array(totalSize); - let k = Belt_SortArray.union(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0, cmp); - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function has(d, x) { - return Belt_internalAVLset.has(d.data, x, d.cmp); -} - -function copy(d) { - return { - cmp: d.cmp, - data: Belt_internalAVLset.copy(d.data) - }; -} - -let Int; - -let $$String; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -export { - Int, - $$String, - make, - fromArray, - fromSortedArrayUnsafe, - copy, - isEmpty, - has, - add, - addCheck, - mergeMany, - remove, - removeCheck, - removeMany, - union, - intersect, - diff, - subset, - cmp, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - keepU, - keep, - partitionU, - partition, - size, - toList, - toArray, - minimum, - maximum, - get, - getExn, - getOrThrow, - split, - checkInvariantInternal, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableSetInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableSetInt.mjs deleted file mode 100644 index 569e1aa5f09..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableSetInt.mjs +++ /dev/null @@ -1,475 +0,0 @@ - - -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Belt_SortArrayInt from "./Belt_SortArrayInt.mjs"; -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; -import * as Belt_internalSetInt from "./Belt_internalSetInt.mjs"; - -function remove0(nt, x) { - let k = nt.v; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = remove0(l$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = remove0(r$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = remove0(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeMany0(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = remove0(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - d.data = removeMany0(oldRoot, xs, 0, len); -} - -function removeCheck0(nt, x, removed) { - let k = nt.v; - if (x === k) { - removed.contents = true; - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeCheck0(l$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeCheck0(r$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function removeCheck(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return false; - } - let removed = { - contents: false - }; - let newRoot = removeCheck0(oldRoot, v, removed); - if (newRoot !== oldRoot) { - d.data = newRoot; - } - return removed.contents; -} - -function addCheck0(t, x, added) { - if (t !== undefined) { - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addCheck0(l, x, added); - t.l = ll; - } else { - t.r = addCheck0(r, x, added); - } - return Belt_internalAVLset.balMutate(t); - } - added.contents = true; - return Belt_internalAVLset.singleton(x); -} - -function addCheck(m, e) { - let oldRoot = m.data; - let added = { - contents: false - }; - let newRoot = addCheck0(oldRoot, e, added); - if (newRoot !== oldRoot) { - m.data = newRoot; - } - return added.contents; -} - -function add(d, k) { - let oldRoot = d.data; - let v = Belt_internalSetInt.addMutate(oldRoot, k); - if (v !== oldRoot) { - d.data = v; - return; - } -} - -function addArrayMutate(t, xs) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - v = Belt_internalSetInt.addMutate(v, xs[i]); - } - return v; -} - -function mergeMany(d, arr) { - d.data = addArrayMutate(d.data, arr); -} - -function make() { - return { - data: undefined - }; -} - -function isEmpty(d) { - let n = d.data; - return n === undefined; -} - -function minimum(d) { - return Belt_internalAVLset.minimum(d.data); -} - -function maximum(d) { - return Belt_internalAVLset.maximum(d.data); -} - -function forEach(d, f) { - Belt_internalAVLset.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLset.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLset.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLset.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLset.size(d.data); -} - -function toList(d) { - return Belt_internalAVLset.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLset.toArray(d.data); -} - -function fromSortedArrayUnsafe(xs) { - return { - data: Belt_internalAVLset.fromSortedArrayUnsafe(xs) - }; -} - -function checkInvariantInternal(d) { - Belt_internalAVLset.checkInvariantInternal(d.data); -} - -function fromArray(xs) { - return { - data: Belt_internalSetInt.fromArray(xs) - }; -} - -function cmp(d0, d1) { - return Belt_internalSetInt.cmp(d0.data, d1.data); -} - -function eq(d0, d1) { - return Belt_internalSetInt.eq(d0.data, d1.data); -} - -function get(d, x) { - return Belt_internalSetInt.get(d.data, x); -} - -function getOrThrow(d, x) { - return Belt_internalSetInt.getOrThrow(d.data, x); -} - -function split(d, key) { - let arr = Belt_internalAVLset.toArray(d.data); - let i = Belt_SortArrayInt.binarySearch(arr, key); - let len = arr.length; - if (i >= 0) { - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, i) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, i + 1 | 0, (len - i | 0) - 1 | 0) - } - ], - true - ]; - } - let next = (-i | 0) - 1 | 0; - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, next) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, next, len - next | 0) - } - ], - false - ]; -} - -function keep(d, p) { - return { - data: Belt_internalAVLset.keepCopy(d.data, p) - }; -} - -function partition(d, p) { - let match = Belt_internalAVLset.partitionCopy(d.data, p); - return [ - { - data: match[0] - }, - { - data: match[1] - } - ]; -} - -function subset(a, b) { - return Belt_internalSetInt.subset(a.data, b.data); -} - -function intersect(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: undefined - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: undefined - }; - } - let tmp2 = new Array(Primitive_int.min(sizea, sizeb)); - let k = Belt_SortArrayInt.intersect(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function diff(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let tmp2 = new Array(sizea); - let k = Belt_SortArrayInt.diff(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function union(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: Belt_internalAVLset.copy(datab$1) - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea]) { - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp, 0, totalSize) - }; - } - let tmp2 = new Array(totalSize); - let k = Belt_SortArrayInt.union(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function has(d, x) { - return Belt_internalSetInt.has(d.data, x); -} - -function copy(d) { - return { - data: Belt_internalAVLset.copy(d.data) - }; -} - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -export { - make, - fromArray, - fromSortedArrayUnsafe, - copy, - isEmpty, - has, - add, - addCheck, - mergeMany, - remove, - removeCheck, - removeMany, - union, - intersect, - diff, - subset, - cmp, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - keepU, - keep, - partitionU, - partition, - size, - toList, - toArray, - minimum, - maximum, - get, - getExn, - getOrThrow, - split, - checkInvariantInternal, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableSetString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableSetString.mjs deleted file mode 100644 index 202698b5850..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableSetString.mjs +++ /dev/null @@ -1,475 +0,0 @@ - - -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; -import * as Belt_SortArrayString from "./Belt_SortArrayString.mjs"; -import * as Belt_internalSetString from "./Belt_internalSetString.mjs"; - -function remove0(nt, x) { - let k = nt.v; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = remove0(l$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = remove0(r$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = remove0(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeMany0(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = remove0(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - d.data = removeMany0(oldRoot, xs, 0, len); -} - -function removeCheck0(nt, x, removed) { - let k = nt.v; - if (x === k) { - removed.contents = true; - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeCheck0(l$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeCheck0(r$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function removeCheck(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return false; - } - let removed = { - contents: false - }; - let newRoot = removeCheck0(oldRoot, v, removed); - if (newRoot !== oldRoot) { - d.data = newRoot; - } - return removed.contents; -} - -function addCheck0(t, x, added) { - if (t !== undefined) { - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addCheck0(l, x, added); - t.l = ll; - } else { - t.r = addCheck0(r, x, added); - } - return Belt_internalAVLset.balMutate(t); - } - added.contents = true; - return Belt_internalAVLset.singleton(x); -} - -function addCheck(m, e) { - let oldRoot = m.data; - let added = { - contents: false - }; - let newRoot = addCheck0(oldRoot, e, added); - if (newRoot !== oldRoot) { - m.data = newRoot; - } - return added.contents; -} - -function add(d, k) { - let oldRoot = d.data; - let v = Belt_internalSetString.addMutate(oldRoot, k); - if (v !== oldRoot) { - d.data = v; - return; - } -} - -function addArrayMutate(t, xs) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - v = Belt_internalSetString.addMutate(v, xs[i]); - } - return v; -} - -function mergeMany(d, arr) { - d.data = addArrayMutate(d.data, arr); -} - -function make() { - return { - data: undefined - }; -} - -function isEmpty(d) { - let n = d.data; - return n === undefined; -} - -function minimum(d) { - return Belt_internalAVLset.minimum(d.data); -} - -function maximum(d) { - return Belt_internalAVLset.maximum(d.data); -} - -function forEach(d, f) { - Belt_internalAVLset.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLset.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLset.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLset.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLset.size(d.data); -} - -function toList(d) { - return Belt_internalAVLset.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLset.toArray(d.data); -} - -function fromSortedArrayUnsafe(xs) { - return { - data: Belt_internalAVLset.fromSortedArrayUnsafe(xs) - }; -} - -function checkInvariantInternal(d) { - Belt_internalAVLset.checkInvariantInternal(d.data); -} - -function fromArray(xs) { - return { - data: Belt_internalSetString.fromArray(xs) - }; -} - -function cmp(d0, d1) { - return Belt_internalSetString.cmp(d0.data, d1.data); -} - -function eq(d0, d1) { - return Belt_internalSetString.eq(d0.data, d1.data); -} - -function get(d, x) { - return Belt_internalSetString.get(d.data, x); -} - -function getOrThrow(d, x) { - return Belt_internalSetString.getOrThrow(d.data, x); -} - -function split(d, key) { - let arr = Belt_internalAVLset.toArray(d.data); - let i = Belt_SortArrayString.binarySearch(arr, key); - let len = arr.length; - if (i >= 0) { - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, i) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, i + 1 | 0, (len - i | 0) - 1 | 0) - } - ], - true - ]; - } - let next = (-i | 0) - 1 | 0; - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, next) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, next, len - next | 0) - } - ], - false - ]; -} - -function keep(d, p) { - return { - data: Belt_internalAVLset.keepCopy(d.data, p) - }; -} - -function partition(d, p) { - let match = Belt_internalAVLset.partitionCopy(d.data, p); - return [ - { - data: match[0] - }, - { - data: match[1] - } - ]; -} - -function subset(a, b) { - return Belt_internalSetString.subset(a.data, b.data); -} - -function intersect(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: undefined - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: undefined - }; - } - let tmp2 = new Array(Primitive_int.min(sizea, sizeb)); - let k = Belt_SortArrayString.intersect(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function diff(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let tmp2 = new Array(sizea); - let k = Belt_SortArrayString.diff(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function union(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: Belt_internalAVLset.copy(datab$1) - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea]) { - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp, 0, totalSize) - }; - } - let tmp2 = new Array(totalSize); - let k = Belt_SortArrayString.union(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function has(d, x) { - return Belt_internalSetString.has(d.data, x); -} - -function copy(d) { - return { - data: Belt_internalAVLset.copy(d.data) - }; -} - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -export { - make, - fromArray, - fromSortedArrayUnsafe, - copy, - isEmpty, - has, - add, - addCheck, - mergeMany, - remove, - removeCheck, - removeMany, - union, - intersect, - diff, - subset, - cmp, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - keepU, - keep, - partitionU, - partition, - size, - toList, - toArray, - minimum, - maximum, - get, - getExn, - getOrThrow, - split, - checkInvariantInternal, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_MutableStack.mjs b/packages/@rescript/belt/lib/es6/src/Belt_MutableStack.mjs deleted file mode 100644 index 44aa615c1b0..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_MutableStack.mjs +++ /dev/null @@ -1,124 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function make() { - return { - root: undefined - }; -} - -function clear(s) { - s.root = undefined; -} - -function copy(s) { - return { - root: s.root - }; -} - -function push(s, x) { - s.root = { - head: x, - tail: s.root - }; -} - -function top(s) { - let x = s.root; - if (x !== undefined) { - return Primitive_option.some(x.head); - } -} - -function isEmpty(s) { - return s.root === undefined; -} - -function pop(s) { - let x = s.root; - if (x !== undefined) { - s.root = x.tail; - return Primitive_option.some(x.head); - } -} - -function popOrThrow(s) { - let x = s.root; - if (x !== undefined) { - s.root = x.tail; - return x.head; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function size(s) { - let x = s.root; - if (x !== undefined) { - let _x = x; - let _acc = 0; - while (true) { - let acc = _acc; - let x$1 = _x; - let x$2 = x$1.tail; - if (x$2 === undefined) { - return acc + 1 | 0; - } - _acc = acc + 1 | 0; - _x = x$2; - continue; - }; - } else { - return 0; - } -} - -function forEach(s, f) { - let _s = s.root; - while (true) { - let s$1 = _s; - if (s$1 === undefined) { - return; - } - f(s$1.head); - _s = s$1.tail; - continue; - }; -} - -function dynamicPopIter(s, f) { - while (true) { - let match = s.root; - if (match === undefined) { - return; - } - s.root = match.tail; - f(match.head); - continue; - }; -} - -let forEachU = forEach; - -let dynamicPopIterU = dynamicPopIter; - -export { - make, - clear, - copy, - push, - pop, - popOrThrow, - top, - isEmpty, - size, - forEachU, - forEach, - dynamicPopIterU, - dynamicPopIter, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Option.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Option.mjs deleted file mode 100644 index 7b28bdb38a1..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Option.mjs +++ /dev/null @@ -1,135 +0,0 @@ - - -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function keep(opt, p) { - if (opt !== undefined && p(Primitive_option.valFromOption(opt))) { - return opt; - } -} - -function forEach(opt, f) { - if (opt !== undefined) { - return f(Primitive_option.valFromOption(opt)); - } -} - -function getOrThrow(x) { - if (x !== undefined) { - return Primitive_option.valFromOption(x); - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function mapWithDefault(opt, $$default, f) { - if (opt !== undefined) { - return f(Primitive_option.valFromOption(opt)); - } else { - return $$default; - } -} - -function map(opt, f) { - if (opt !== undefined) { - return Primitive_option.some(f(Primitive_option.valFromOption(opt))); - } -} - -function flatMap(opt, f) { - if (opt !== undefined) { - return f(Primitive_option.valFromOption(opt)); - } -} - -function getWithDefault(opt, $$default) { - if (opt !== undefined) { - return Primitive_option.valFromOption(opt); - } else { - return $$default; - } -} - -function orElse(opt, other) { - if (opt !== undefined) { - return opt; - } else { - return other; - } -} - -function isSome(x) { - return x !== undefined; -} - -function isNone(x) { - return x === undefined; -} - -function eq(a, b, f) { - if (a !== undefined) { - if (b !== undefined) { - return f(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); - } else { - return false; - } - } else { - return b === undefined; - } -} - -function cmp(a, b, f) { - if (a !== undefined) { - if (b !== undefined) { - return f(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); - } else { - return 1; - } - } else if (b !== undefined) { - return -1; - } else { - return 0; - } -} - -let keepU = keep; - -let forEachU = forEach; - -let getExn = getOrThrow; - -let mapWithDefaultU = mapWithDefault; - -let mapU = map; - -let flatMapU = flatMap; - -let eqU = eq; - -let cmpU = cmp; - -export { - keepU, - keep, - forEachU, - forEach, - getExn, - getOrThrow, - mapWithDefaultU, - mapWithDefault, - mapU, - map, - flatMapU, - flatMap, - getWithDefault, - orElse, - isSome, - isNone, - eqU, - eq, - cmpU, - cmp, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Range.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Range.mjs deleted file mode 100644 index 1cc6096cb9f..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Range.mjs +++ /dev/null @@ -1,98 +0,0 @@ - - - -function forEach(s, f, action) { - for (let i = s; i <= f; ++i) { - action(i); - } -} - -function every(_s, f, p) { - while (true) { - let s = _s; - if (s > f) { - return true; - } - if (!p(s)) { - return false; - } - _s = s + 1 | 0; - continue; - }; -} - -function everyBy(s, f, step, p) { - if (step > 0) { - let _s = s; - while (true) { - let s$1 = _s; - if (s$1 > f) { - return true; - } - if (!p(s$1)) { - return false; - } - _s = s$1 + step | 0; - continue; - }; - } else { - return true; - } -} - -function some(_s, f, p) { - while (true) { - let s = _s; - if (s > f) { - return false; - } - if (p(s)) { - return true; - } - _s = s + 1 | 0; - continue; - }; -} - -function someBy(s, f, step, p) { - if (step > 0) { - let _s = s; - while (true) { - let s$1 = _s; - if (s$1 > f) { - return false; - } - if (p(s$1)) { - return true; - } - _s = s$1 + step | 0; - continue; - }; - } else { - return false; - } -} - -let forEachU = forEach; - -let everyU = every; - -let everyByU = everyBy; - -let someU = some; - -let someByU = someBy; - -export { - forEachU, - forEach, - everyU, - every, - everyByU, - everyBy, - someU, - some, - someByU, - someBy, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Result.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Result.mjs deleted file mode 100644 index b8c9739a817..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Result.mjs +++ /dev/null @@ -1,118 +0,0 @@ - - - -function getOrThrow(x) { - if (x.TAG === "Ok") { - return x._0; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function mapWithDefault(opt, $$default, f) { - if (opt.TAG === "Ok") { - return f(opt._0); - } else { - return $$default; - } -} - -function map(opt, f) { - if (opt.TAG === "Ok") { - return { - TAG: "Ok", - _0: f(opt._0) - }; - } else { - return { - TAG: "Error", - _0: opt._0 - }; - } -} - -function flatMap(opt, f) { - if (opt.TAG === "Ok") { - return f(opt._0); - } else { - return { - TAG: "Error", - _0: opt._0 - }; - } -} - -function getWithDefault(opt, $$default) { - if (opt.TAG === "Ok") { - return opt._0; - } else { - return $$default; - } -} - -function isOk(x) { - return x.TAG === "Ok"; -} - -function isError(x) { - return x.TAG !== "Ok"; -} - -function eq(a, b, f) { - if (a.TAG === "Ok") { - if (b.TAG === "Ok") { - return f(a._0, b._0); - } else { - return false; - } - } else { - return b.TAG !== "Ok"; - } -} - -function cmp(a, b, f) { - if (a.TAG === "Ok") { - if (b.TAG === "Ok") { - return f(a._0, b._0); - } else { - return 1; - } - } else if (b.TAG === "Ok") { - return -1; - } else { - return 0; - } -} - -let getExn = getOrThrow; - -let mapWithDefaultU = mapWithDefault; - -let mapU = map; - -let flatMapU = flatMap; - -let eqU = eq; - -let cmpU = cmp; - -export { - getExn, - getOrThrow, - mapWithDefaultU, - mapWithDefault, - mapU, - map, - flatMapU, - flatMap, - getWithDefault, - isOk, - isError, - eqU, - eq, - cmpU, - cmp, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_Set.mjs b/packages/@rescript/belt/lib/es6/src/Belt_Set.mjs deleted file mode 100644 index 891ea58887a..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_Set.mjs +++ /dev/null @@ -1,289 +0,0 @@ - - -import * as Belt_SetDict from "./Belt_SetDict.mjs"; - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_SetDict.fromArray(data, cmp) - }; -} - -function remove(m, e) { - let data = m.data; - let cmp = m.cmp; - let newData = Belt_SetDict.remove(data, e, cmp); - if (newData === data) { - return m; - } else { - return { - cmp: cmp, - data: newData - }; - } -} - -function add(m, e) { - let data = m.data; - let cmp = m.cmp; - let newData = Belt_SetDict.add(data, e, cmp); - if (newData === data) { - return m; - } else { - return { - cmp: cmp, - data: newData - }; - } -} - -function mergeMany(m, e) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.mergeMany(m.data, e, cmp) - }; -} - -function removeMany(m, e) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.removeMany(m.data, e, cmp) - }; -} - -function union(m, n) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.union(m.data, n.data, cmp) - }; -} - -function intersect(m, n) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.intersect(m.data, n.data, cmp) - }; -} - -function diff(m, n) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.diff(m.data, n.data, cmp) - }; -} - -function subset(m, n) { - let cmp = m.cmp; - return Belt_SetDict.subset(m.data, n.data, cmp); -} - -function split(m, e) { - let cmp = m.cmp; - let match = Belt_SetDict.split(m.data, e, cmp); - let match$1 = match[0]; - return [ - [ - { - cmp: cmp, - data: match$1[0] - }, - { - cmp: cmp, - data: match$1[1] - } - ], - match[1] - ]; -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function isEmpty(m) { - return Belt_SetDict.isEmpty(m.data); -} - -function cmp(m, n) { - let cmp$1 = m.cmp; - return Belt_SetDict.cmp(m.data, n.data, cmp$1); -} - -function eq(m, n) { - return Belt_SetDict.eq(m.data, n.data, m.cmp); -} - -function forEach(m, f) { - Belt_SetDict.forEach(m.data, f); -} - -function reduce(m, acc, f) { - return Belt_SetDict.reduce(m.data, acc, f); -} - -function every(m, f) { - return Belt_SetDict.every(m.data, f); -} - -function some(m, f) { - return Belt_SetDict.some(m.data, f); -} - -function keep(m, f) { - return { - cmp: m.cmp, - data: Belt_SetDict.keep(m.data, f) - }; -} - -function partition(m, f) { - let match = Belt_SetDict.partition(m.data, f); - let cmp = m.cmp; - return [ - { - cmp: cmp, - data: match[0] - }, - { - cmp: cmp, - data: match[1] - } - ]; -} - -function size(m) { - return Belt_SetDict.size(m.data); -} - -function toList(m) { - return Belt_SetDict.toList(m.data); -} - -function toArray(m) { - return Belt_SetDict.toArray(m.data); -} - -function minimum(m) { - return Belt_SetDict.minimum(m.data); -} - -function maximum(m) { - return Belt_SetDict.maximum(m.data); -} - -function get(m, e) { - return Belt_SetDict.get(m.data, e, m.cmp); -} - -function getOrThrow(m, e) { - return Belt_SetDict.getOrThrow(m.data, e, m.cmp); -} - -function has(m, e) { - return Belt_SetDict.has(m.data, e, m.cmp); -} - -function fromSortedArrayUnsafe(xs, id) { - return { - cmp: id.cmp, - data: Belt_SetDict.fromSortedArrayUnsafe(xs) - }; -} - -function getData(m) { - return m.data; -} - -function getId(m) { - let cmp = m.cmp; - return { - cmp: cmp - }; -} - -function packIdData(id, data) { - return { - cmp: id.cmp, - data: data - }; -} - -function checkInvariantInternal(d) { - Belt_SetDict.checkInvariantInternal(d.data); -} - -let Int; - -let $$String; - -let Dict; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -export { - Int, - $$String, - Dict, - make, - fromArray, - fromSortedArrayUnsafe, - isEmpty, - has, - add, - mergeMany, - remove, - removeMany, - union, - intersect, - diff, - subset, - cmp, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - keepU, - keep, - partitionU, - partition, - size, - toArray, - toList, - minimum, - maximum, - get, - getExn, - getOrThrow, - split, - checkInvariantInternal, - getData, - getId, - packIdData, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_SetDict.mjs b/packages/@rescript/belt/lib/es6/src/Belt_SetDict.mjs deleted file mode 100644 index 538d266f6a0..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_SetDict.mjs +++ /dev/null @@ -1,356 +0,0 @@ - - -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; - -function add(t, x, cmp) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let k = t.v; - let c = cmp(x, k); - if (c === 0) { - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = add(l, x, cmp); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, k, r); - } - } - let rr = add(r, x, cmp); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, k, rr); - } -} - -function remove(t, x, cmp) { - if (t === undefined) { - return t; - } - let v = t.v; - let l = t.l; - let r = t.r; - let c = cmp(x, v); - if (c === 0) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let v$1 = { - contents: r.v - }; - let r$1 = Belt_internalAVLset.removeMinAuxWithRef(r, v$1); - return Belt_internalAVLset.bal(l, v$1.contents, r$1); - } - if (c < 0) { - let ll = remove(l, x, cmp); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = remove(r, x, cmp); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function mergeMany(h, arr, cmp) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = add(v, key, cmp); - } - return v; -} - -function removeMany(h, arr, cmp) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = remove(v, key, cmp); - } - return v; -} - -function splitAuxNoPivot(cmp, n, x) { - let v = n.v; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - return [ - l, - r - ]; - } - if (c < 0) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxNoPivot(cmp, l, x); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxNoPivot(cmp, r, x); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function splitAuxPivot(cmp, n, x, pres) { - let v = n.v; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - pres.contents = true; - return [ - l, - r - ]; - } - if (c < 0) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(cmp, l, x, pres); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(cmp, r, x, pres); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function split(t, x, cmp) { - if (t === undefined) { - return [ - [ - undefined, - undefined - ], - false - ]; - } - let pres = { - contents: false - }; - let v = splitAuxPivot(cmp, t, x, pres); - return [ - v, - pres.contents - ]; -} - -function union(s1, s2, cmp) { - if (s1 === undefined) { - return s2; - } - if (s2 === undefined) { - return s1; - } - let h1 = s1.h; - let h2 = s2.h; - if (h1 >= h2) { - if (h2 === 1) { - return add(s1, s2.v, cmp); - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = splitAuxNoPivot(cmp, s2, v1); - return Belt_internalAVLset.joinShared(union(l1, match[0], cmp), v1, union(r1, match[1], cmp)); - } - if (h1 === 1) { - return add(s2, s1.v, cmp); - } - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = splitAuxNoPivot(cmp, s1, v2); - return Belt_internalAVLset.joinShared(union(match$1[0], l2, cmp), v2, union(match$1[1], r2, cmp)); -} - -function intersect(s1, s2, cmp) { - if (s1 === undefined) { - return; - } - if (s2 === undefined) { - return; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(cmp, s2, v1, pres); - let ll = intersect(l1, match[0], cmp); - let rr = intersect(r1, match[1], cmp); - if (pres.contents) { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } else { - return Belt_internalAVLset.concatShared(ll, rr); - } -} - -function diff(s1, s2, cmp) { - if (s1 === undefined) { - return s1; - } - if (s2 === undefined) { - return s1; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(cmp, s2, v1, pres); - let ll = diff(l1, match[0], cmp); - let rr = diff(r1, match[1], cmp); - if (pres.contents) { - return Belt_internalAVLset.concatShared(ll, rr); - } else { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } -} - -let empty; - -let fromArray = Belt_internalAVLset.fromArray; - -let fromSortedArrayUnsafe = Belt_internalAVLset.fromSortedArrayUnsafe; - -let isEmpty = Belt_internalAVLset.isEmpty; - -let has = Belt_internalAVLset.has; - -let subset = Belt_internalAVLset.subset; - -let cmp = Belt_internalAVLset.cmp; - -let eq = Belt_internalAVLset.eq; - -let forEachU = Belt_internalAVLset.forEach; - -let forEach = Belt_internalAVLset.forEach; - -let reduceU = Belt_internalAVLset.reduce; - -let reduce = Belt_internalAVLset.reduce; - -let everyU = Belt_internalAVLset.every; - -let every = Belt_internalAVLset.every; - -let someU = Belt_internalAVLset.some; - -let some = Belt_internalAVLset.some; - -let keepU = Belt_internalAVLset.keepShared; - -let keep = Belt_internalAVLset.keepShared; - -let partitionU = Belt_internalAVLset.partitionShared; - -let partition = Belt_internalAVLset.partitionShared; - -let size = Belt_internalAVLset.size; - -let toList = Belt_internalAVLset.toList; - -let toArray = Belt_internalAVLset.toArray; - -let minimum = Belt_internalAVLset.minimum; - -let maximum = Belt_internalAVLset.maximum; - -let get = Belt_internalAVLset.get; - -let getExn = Belt_internalAVLset.getOrThrow; - -let getOrThrow = Belt_internalAVLset.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLset.checkInvariantInternal; - -export { - empty, - fromArray, - fromSortedArrayUnsafe, - isEmpty, - has, - add, - mergeMany, - remove, - removeMany, - union, - intersect, - diff, - subset, - cmp, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - keepU, - keep, - partitionU, - partition, - size, - toList, - toArray, - minimum, - maximum, - get, - getExn, - getOrThrow, - split, - checkInvariantInternal, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_SetInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_SetInt.mjs deleted file mode 100644 index 81b93fc7ded..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_SetInt.mjs +++ /dev/null @@ -1,353 +0,0 @@ - - -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; -import * as Belt_internalSetInt from "./Belt_internalSetInt.mjs"; - -function add(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let v = t.v; - if (x === v) { - return t; - } - let l = t.l; - let r = t.r; - if (x < v) { - let ll = add(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = add(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = add(v, key); - } - return v; -} - -function remove(t, x) { - if (t === undefined) { - return t; - } - let v = t.v; - let l = t.l; - let r = t.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let v$1 = { - contents: r.v - }; - let r$1 = Belt_internalAVLset.removeMinAuxWithRef(r, v$1); - return Belt_internalAVLset.bal(l, v$1.contents, r$1); - } - if (x < v) { - let ll = remove(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = remove(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function removeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = remove(v, key); - } - return v; -} - -function splitAuxNoPivot(n, x) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxNoPivot(l, x); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxNoPivot(r, x); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function splitAuxPivot(n, x, pres) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - pres.contents = true; - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(l, x, pres); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(r, x, pres); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function split(t, x) { - if (t === undefined) { - return [ - [ - undefined, - undefined - ], - false - ]; - } - let pres = { - contents: false - }; - let v = splitAuxPivot(t, x, pres); - return [ - v, - pres.contents - ]; -} - -function union(s1, s2) { - if (s1 === undefined) { - return s2; - } - if (s2 === undefined) { - return s1; - } - let h1 = s1.h; - let h2 = s2.h; - if (h1 >= h2) { - if (h2 === 1) { - return add(s1, s2.v); - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = splitAuxNoPivot(s2, v1); - return Belt_internalAVLset.joinShared(union(l1, match[0]), v1, union(r1, match[1])); - } - if (h1 === 1) { - return add(s2, s1.v); - } - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = splitAuxNoPivot(s1, v2); - return Belt_internalAVLset.joinShared(union(match$1[0], l2), v2, union(match$1[1], r2)); -} - -function intersect(s1, s2) { - if (s1 === undefined) { - return; - } - if (s2 === undefined) { - return; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = intersect(l1, match[0]); - let rr = intersect(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } else { - return Belt_internalAVLset.concatShared(ll, rr); - } -} - -function diff(s1, s2) { - if (s1 === undefined) { - return s1; - } - if (s2 === undefined) { - return s1; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = diff(l1, match[0]); - let rr = diff(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.concatShared(ll, rr); - } else { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } -} - -let empty; - -let fromArray = Belt_internalSetInt.fromArray; - -let fromSortedArrayUnsafe = Belt_internalAVLset.fromSortedArrayUnsafe; - -let isEmpty = Belt_internalAVLset.isEmpty; - -let has = Belt_internalSetInt.has; - -let subset = Belt_internalSetInt.subset; - -let cmp = Belt_internalSetInt.cmp; - -let eq = Belt_internalSetInt.eq; - -let forEachU = Belt_internalAVLset.forEach; - -let forEach = Belt_internalAVLset.forEach; - -let reduceU = Belt_internalAVLset.reduce; - -let reduce = Belt_internalAVLset.reduce; - -let everyU = Belt_internalAVLset.every; - -let every = Belt_internalAVLset.every; - -let someU = Belt_internalAVLset.some; - -let some = Belt_internalAVLset.some; - -let keepU = Belt_internalAVLset.keepShared; - -let keep = Belt_internalAVLset.keepShared; - -let partitionU = Belt_internalAVLset.partitionShared; - -let partition = Belt_internalAVLset.partitionShared; - -let size = Belt_internalAVLset.size; - -let toList = Belt_internalAVLset.toList; - -let toArray = Belt_internalAVLset.toArray; - -let minimum = Belt_internalAVLset.minimum; - -let maximum = Belt_internalAVLset.maximum; - -let get = Belt_internalSetInt.get; - -let getExn = Belt_internalSetInt.getOrThrow; - -let getOrThrow = Belt_internalSetInt.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLset.checkInvariantInternal; - -export { - empty, - fromArray, - fromSortedArrayUnsafe, - isEmpty, - has, - add, - mergeMany, - remove, - removeMany, - union, - intersect, - diff, - subset, - cmp, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - keepU, - keep, - partitionU, - partition, - size, - toList, - toArray, - minimum, - maximum, - get, - getExn, - getOrThrow, - split, - checkInvariantInternal, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_SetString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_SetString.mjs deleted file mode 100644 index e2f2982d4ad..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_SetString.mjs +++ /dev/null @@ -1,353 +0,0 @@ - - -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; -import * as Belt_internalSetString from "./Belt_internalSetString.mjs"; - -function add(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let v = t.v; - if (x === v) { - return t; - } - let l = t.l; - let r = t.r; - if (x < v) { - let ll = add(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = add(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = add(v, key); - } - return v; -} - -function remove(t, x) { - if (t === undefined) { - return t; - } - let v = t.v; - let l = t.l; - let r = t.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let v$1 = { - contents: r.v - }; - let r$1 = Belt_internalAVLset.removeMinAuxWithRef(r, v$1); - return Belt_internalAVLset.bal(l, v$1.contents, r$1); - } - if (x < v) { - let ll = remove(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = remove(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function removeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = remove(v, key); - } - return v; -} - -function splitAuxNoPivot(n, x) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxNoPivot(l, x); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxNoPivot(r, x); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function splitAuxPivot(n, x, pres) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - pres.contents = true; - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(l, x, pres); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(r, x, pres); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function split(t, x) { - if (t === undefined) { - return [ - [ - undefined, - undefined - ], - false - ]; - } - let pres = { - contents: false - }; - let v = splitAuxPivot(t, x, pres); - return [ - v, - pres.contents - ]; -} - -function union(s1, s2) { - if (s1 === undefined) { - return s2; - } - if (s2 === undefined) { - return s1; - } - let h1 = s1.h; - let h2 = s2.h; - if (h1 >= h2) { - if (h2 === 1) { - return add(s1, s2.v); - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = splitAuxNoPivot(s2, v1); - return Belt_internalAVLset.joinShared(union(l1, match[0]), v1, union(r1, match[1])); - } - if (h1 === 1) { - return add(s2, s1.v); - } - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = splitAuxNoPivot(s1, v2); - return Belt_internalAVLset.joinShared(union(match$1[0], l2), v2, union(match$1[1], r2)); -} - -function intersect(s1, s2) { - if (s1 === undefined) { - return; - } - if (s2 === undefined) { - return; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = intersect(l1, match[0]); - let rr = intersect(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } else { - return Belt_internalAVLset.concatShared(ll, rr); - } -} - -function diff(s1, s2) { - if (s1 === undefined) { - return s1; - } - if (s2 === undefined) { - return s1; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = diff(l1, match[0]); - let rr = diff(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.concatShared(ll, rr); - } else { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } -} - -let empty; - -let fromArray = Belt_internalSetString.fromArray; - -let fromSortedArrayUnsafe = Belt_internalAVLset.fromSortedArrayUnsafe; - -let isEmpty = Belt_internalAVLset.isEmpty; - -let has = Belt_internalSetString.has; - -let subset = Belt_internalSetString.subset; - -let cmp = Belt_internalSetString.cmp; - -let eq = Belt_internalSetString.eq; - -let forEachU = Belt_internalAVLset.forEach; - -let forEach = Belt_internalAVLset.forEach; - -let reduceU = Belt_internalAVLset.reduce; - -let reduce = Belt_internalAVLset.reduce; - -let everyU = Belt_internalAVLset.every; - -let every = Belt_internalAVLset.every; - -let someU = Belt_internalAVLset.some; - -let some = Belt_internalAVLset.some; - -let keepU = Belt_internalAVLset.keepShared; - -let keep = Belt_internalAVLset.keepShared; - -let partitionU = Belt_internalAVLset.partitionShared; - -let partition = Belt_internalAVLset.partitionShared; - -let size = Belt_internalAVLset.size; - -let toList = Belt_internalAVLset.toList; - -let toArray = Belt_internalAVLset.toArray; - -let minimum = Belt_internalAVLset.minimum; - -let maximum = Belt_internalAVLset.maximum; - -let get = Belt_internalSetString.get; - -let getExn = Belt_internalSetString.getOrThrow; - -let getOrThrow = Belt_internalSetString.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLset.checkInvariantInternal; - -export { - empty, - fromArray, - fromSortedArrayUnsafe, - isEmpty, - has, - add, - mergeMany, - remove, - removeMany, - union, - intersect, - diff, - subset, - cmp, - eq, - forEachU, - forEach, - reduceU, - reduce, - everyU, - every, - someU, - some, - keepU, - keep, - partitionU, - partition, - size, - toList, - toArray, - minimum, - maximum, - get, - getExn, - getOrThrow, - split, - checkInvariantInternal, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_SortArray.mjs b/packages/@rescript/belt/lib/es6/src/Belt_SortArray.mjs deleted file mode 100644 index e3b19cab4ef..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_SortArray.mjs +++ /dev/null @@ -1,410 +0,0 @@ - - -import * as Belt_Array from "./Belt_Array.mjs"; - -function sortedLengthAuxMore(xs, _prec, _acc, len, lt) { - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (!lt(v, prec)) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; -} - -function strictlySortedLength(xs, lt) { - let len = xs.length; - if (len === 0 || len === 1) { - return len; - } - let x0 = xs[0]; - let x1 = xs[1]; - if (lt(x0, x1)) { - let _prec = x1; - let _acc = 2; - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (!lt(prec, v)) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; - } else if (lt(x1, x0)) { - return -sortedLengthAuxMore(xs, x1, 2, len, lt) | 0; - } else { - return 1; - } -} - -function isSorted(a, cmp) { - let len = a.length; - if (len === 0) { - return true; - } else { - let _i = 0; - let last_bound = len - 1 | 0; - while (true) { - let i = _i; - if (i === last_bound) { - return true; - } - if (cmp(a[i], a[i + 1 | 0]) > 0) { - return false; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function merge(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (cmp(s1, s2) <= 0) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return Belt_Array.blitUnsafe(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - dst[d] = s2; - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return Belt_Array.blitUnsafe(src, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = src2[i2$1]; - _i2 = i2$1; - continue; - }; -} - -function union(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - let c = cmp(s1, s2); - if (c < 0) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - let d$1 = d + 1 | 0; - if (i1$1 < src1r) { - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - Belt_Array.blitUnsafe(src2, i2, dst, d$1, src2r - i2 | 0); - return (d$1 + src2r | 0) - i2 | 0; - } - if (c === 0) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$2 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - Belt_Array.blitUnsafe(src2, i2$1, dst, d$2, src2r - i2$1 | 0); - return (d$2 + src2r | 0) - i2$1 | 0; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d$2, src1r - i1$2 | 0); - return (d$2 + src1r | 0) - i1$2 | 0; - } - } - _d = d$2; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - dst[d] = s2; - let i2$2 = i2 + 1 | 0; - let d$3 = d + 1 | 0; - if (i2$2 < src2r) { - _d = d$3; - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d$3, src1r - i1 | 0); - return (d$3 + src1r | 0) - i1 | 0; - }; -} - -function intersect(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - let c = cmp(s1, s2); - if (c < 0) { - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d; - } - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (c === 0) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$1 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - return d$1; - } - _d = d$1; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 >= src2r) { - return d; - } - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - }; -} - -function diff(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - let c = cmp(s1, s2); - if (c < 0) { - dst[d] = s1; - let d$1 = d + 1 | 0; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d$1; - } - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (c === 0) { - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - return d; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d, src1r - i1$2 | 0); - return (d + src1r | 0) - i1$2 | 0; - } - } - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 < src2r) { - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d, src1r - i1 | 0); - return (d + src1r | 0) - i1 | 0; - }; -} - -function insertionSort(src, srcofs, dst, dstofs, len, cmp) { - for (let i = 0; i < len; ++i) { - let e = src[srcofs + i | 0]; - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && cmp(dst[j], e) > 0) { - dst[j + 1 | 0] = dst[j]; - j = j - 1 | 0; - }; - dst[j + 1 | 0] = e; - } -} - -function sortTo(src, srcofs, dst, dstofs, len, cmp) { - if (len <= 5) { - return insertionSort(src, srcofs, dst, dstofs, len, cmp); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortTo(src, srcofs + l1 | 0, dst, dstofs + l1 | 0, l2, cmp); - sortTo(src, srcofs, src, srcofs + l2 | 0, l1, cmp); - merge(src, srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs, cmp); -} - -function stableSortInPlaceBy(a, cmp) { - let l = a.length; - if (l <= 5) { - return insertionSort(a, 0, a, 0, l, cmp); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let t = new Array(l2); - sortTo(a, l1, t, 0, l2, cmp); - sortTo(a, 0, a, l2, l1, cmp); - merge(a, l2, l1, t, 0, l2, a, 0, cmp); -} - -function stableSortBy(a, cmp) { - let b = a.slice(0); - stableSortInPlaceBy(b, cmp); - return b; -} - -function binarySearchBy(sorted, key, cmp) { - let len = sorted.length; - if (len === 0) { - return -1; - } - let lo = sorted[0]; - let c = cmp(key, lo); - if (c < 0) { - return -1; - } - let hi = sorted[len - 1 | 0]; - let c2 = cmp(key, hi); - if (c2 > 0) { - return -(len + 1 | 0) | 0; - } else { - let _lo = 0; - let _hi = len - 1 | 0; - while (true) { - let hi$1 = _hi; - let lo$1 = _lo; - let mid = (lo$1 + hi$1 | 0) / 2 | 0; - let midVal = sorted[mid]; - let c$1 = cmp(key, midVal); - if (c$1 === 0) { - return mid; - } - if (c$1 < 0) { - if (hi$1 === mid) { - if (cmp(sorted[lo$1], key) === 0) { - return lo$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _hi = mid; - continue; - } - if (lo$1 === mid) { - if (cmp(sorted[hi$1], key) === 0) { - return hi$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _lo = mid; - continue; - }; - } -} - -let Int; - -let $$String; - -let strictlySortedLengthU = strictlySortedLength; - -let isSortedU = isSorted; - -let stableSortInPlaceByU = stableSortInPlaceBy; - -let stableSortByU = stableSortBy; - -let binarySearchByU = binarySearchBy; - -let unionU = union; - -let intersectU = intersect; - -let diffU = diff; - -export { - Int, - $$String, - strictlySortedLengthU, - strictlySortedLength, - isSortedU, - isSorted, - stableSortInPlaceByU, - stableSortInPlaceBy, - stableSortByU, - stableSortBy, - binarySearchByU, - binarySearchBy, - unionU, - union, - intersectU, - intersect, - diffU, - diff, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_SortArrayInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_SortArrayInt.mjs deleted file mode 100644 index 61a0042a667..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_SortArrayInt.mjs +++ /dev/null @@ -1,374 +0,0 @@ - - -import * as Belt_Array from "./Belt_Array.mjs"; - -function sortedLengthAuxMore(xs, _prec, _acc, len) { - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec <= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; -} - -function strictlySortedLength(xs) { - let len = xs.length; - if (len === 0 || len === 1) { - return len; - } - let x0 = xs[0]; - let x1 = xs[1]; - if (x0 < x1) { - let _prec = x1; - let _acc = 2; - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec >= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; - } else if (x0 > x1) { - return -sortedLengthAuxMore(xs, x1, 2, len) | 0; - } else { - return 1; - } -} - -function isSorted(a) { - let len = a.length; - if (len === 0) { - return true; - } else { - let _i = 0; - let last_bound = len - 1 | 0; - while (true) { - let i = _i; - if (i === last_bound) { - return true; - } - if (a[i] > a[i + 1 | 0]) { - return false; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function merge(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 <= s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return Belt_Array.blitUnsafe(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - dst[d] = s2; - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return Belt_Array.blitUnsafe(src, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = src2[i2$1]; - _i2 = i2$1; - continue; - }; -} - -function union(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - let d$1 = d + 1 | 0; - if (i1$1 < src1r) { - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - Belt_Array.blitUnsafe(src2, i2, dst, d$1, src2r - i2 | 0); - return (d$1 + src2r | 0) - i2 | 0; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$2 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - Belt_Array.blitUnsafe(src2, i2$1, dst, d$2, src2r - i2$1 | 0); - return (d$2 + src2r | 0) - i2$1 | 0; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d$2, src1r - i1$2 | 0); - return (d$2 + src1r | 0) - i1$2 | 0; - } - } - _d = d$2; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - dst[d] = s2; - let i2$2 = i2 + 1 | 0; - let d$3 = d + 1 | 0; - if (i2$2 < src2r) { - _d = d$3; - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d$3, src1r - i1 | 0); - return (d$3 + src1r | 0) - i1 | 0; - }; -} - -function intersect(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d; - } - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$1 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - return d$1; - } - _d = d$1; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 >= src2r) { - return d; - } - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - }; -} - -function diff(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let d$1 = d + 1 | 0; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d$1; - } - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - return d; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d, src1r - i1$2 | 0); - return (d + src1r | 0) - i1$2 | 0; - } - } - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 < src2r) { - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d, src1r - i1 | 0); - return (d + src1r | 0) - i1 | 0; - }; -} - -function insertionSort(src, srcofs, dst, dstofs, len) { - for (let i = 0; i < len; ++i) { - let e = src[srcofs + i | 0]; - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && dst[j] > e) { - dst[j + 1 | 0] = dst[j]; - j = j - 1 | 0; - }; - dst[j + 1 | 0] = e; - } -} - -function sortTo(src, srcofs, dst, dstofs, len) { - if (len <= 5) { - return insertionSort(src, srcofs, dst, dstofs, len); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortTo(src, srcofs + l1 | 0, dst, dstofs + l1 | 0, l2); - sortTo(src, srcofs, src, srcofs + l2 | 0, l1); - merge(src, srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs); -} - -function stableSortInPlace(a) { - let l = a.length; - if (l <= 5) { - return insertionSort(a, 0, a, 0, l); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let t = new Array(l2); - sortTo(a, l1, t, 0, l2); - sortTo(a, 0, a, l2, l1); - merge(a, l2, l1, t, 0, l2, a, 0); -} - -function stableSort(a) { - let b = a.slice(0); - stableSortInPlace(b); - return b; -} - -function binarySearch(sorted, key) { - let len = sorted.length; - if (len === 0) { - return -1; - } - let lo = sorted[0]; - if (key < lo) { - return -1; - } - let hi = sorted[len - 1 | 0]; - if (key > hi) { - return -(len + 1 | 0) | 0; - } else { - let _lo = 0; - let _hi = len - 1 | 0; - while (true) { - let hi$1 = _hi; - let lo$1 = _lo; - let mid = (lo$1 + hi$1 | 0) / 2 | 0; - let midVal = sorted[mid]; - if (key === midVal) { - return mid; - } - if (key < midVal) { - if (hi$1 === mid) { - if (sorted[lo$1] === key) { - return lo$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _hi = mid; - continue; - } - if (lo$1 === mid) { - if (sorted[hi$1] === key) { - return hi$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _lo = mid; - continue; - }; - } -} - -export { - strictlySortedLength, - isSorted, - stableSortInPlace, - stableSort, - binarySearch, - union, - intersect, - diff, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_SortArrayString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_SortArrayString.mjs deleted file mode 100644 index 61a0042a667..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_SortArrayString.mjs +++ /dev/null @@ -1,374 +0,0 @@ - - -import * as Belt_Array from "./Belt_Array.mjs"; - -function sortedLengthAuxMore(xs, _prec, _acc, len) { - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec <= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; -} - -function strictlySortedLength(xs) { - let len = xs.length; - if (len === 0 || len === 1) { - return len; - } - let x0 = xs[0]; - let x1 = xs[1]; - if (x0 < x1) { - let _prec = x1; - let _acc = 2; - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec >= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; - } else if (x0 > x1) { - return -sortedLengthAuxMore(xs, x1, 2, len) | 0; - } else { - return 1; - } -} - -function isSorted(a) { - let len = a.length; - if (len === 0) { - return true; - } else { - let _i = 0; - let last_bound = len - 1 | 0; - while (true) { - let i = _i; - if (i === last_bound) { - return true; - } - if (a[i] > a[i + 1 | 0]) { - return false; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function merge(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 <= s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return Belt_Array.blitUnsafe(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - dst[d] = s2; - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return Belt_Array.blitUnsafe(src, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = src2[i2$1]; - _i2 = i2$1; - continue; - }; -} - -function union(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - let d$1 = d + 1 | 0; - if (i1$1 < src1r) { - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - Belt_Array.blitUnsafe(src2, i2, dst, d$1, src2r - i2 | 0); - return (d$1 + src2r | 0) - i2 | 0; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$2 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - Belt_Array.blitUnsafe(src2, i2$1, dst, d$2, src2r - i2$1 | 0); - return (d$2 + src2r | 0) - i2$1 | 0; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d$2, src1r - i1$2 | 0); - return (d$2 + src1r | 0) - i1$2 | 0; - } - } - _d = d$2; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - dst[d] = s2; - let i2$2 = i2 + 1 | 0; - let d$3 = d + 1 | 0; - if (i2$2 < src2r) { - _d = d$3; - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d$3, src1r - i1 | 0); - return (d$3 + src1r | 0) - i1 | 0; - }; -} - -function intersect(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d; - } - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$1 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - return d$1; - } - _d = d$1; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 >= src2r) { - return d; - } - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - }; -} - -function diff(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let d$1 = d + 1 | 0; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d$1; - } - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - return d; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d, src1r - i1$2 | 0); - return (d + src1r | 0) - i1$2 | 0; - } - } - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 < src2r) { - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d, src1r - i1 | 0); - return (d + src1r | 0) - i1 | 0; - }; -} - -function insertionSort(src, srcofs, dst, dstofs, len) { - for (let i = 0; i < len; ++i) { - let e = src[srcofs + i | 0]; - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && dst[j] > e) { - dst[j + 1 | 0] = dst[j]; - j = j - 1 | 0; - }; - dst[j + 1 | 0] = e; - } -} - -function sortTo(src, srcofs, dst, dstofs, len) { - if (len <= 5) { - return insertionSort(src, srcofs, dst, dstofs, len); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortTo(src, srcofs + l1 | 0, dst, dstofs + l1 | 0, l2); - sortTo(src, srcofs, src, srcofs + l2 | 0, l1); - merge(src, srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs); -} - -function stableSortInPlace(a) { - let l = a.length; - if (l <= 5) { - return insertionSort(a, 0, a, 0, l); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let t = new Array(l2); - sortTo(a, l1, t, 0, l2); - sortTo(a, 0, a, l2, l1); - merge(a, l2, l1, t, 0, l2, a, 0); -} - -function stableSort(a) { - let b = a.slice(0); - stableSortInPlace(b); - return b; -} - -function binarySearch(sorted, key) { - let len = sorted.length; - if (len === 0) { - return -1; - } - let lo = sorted[0]; - if (key < lo) { - return -1; - } - let hi = sorted[len - 1 | 0]; - if (key > hi) { - return -(len + 1 | 0) | 0; - } else { - let _lo = 0; - let _hi = len - 1 | 0; - while (true) { - let hi$1 = _hi; - let lo$1 = _lo; - let mid = (lo$1 + hi$1 | 0) / 2 | 0; - let midVal = sorted[mid]; - if (key === midVal) { - return mid; - } - if (key < midVal) { - if (hi$1 === mid) { - if (sorted[lo$1] === key) { - return lo$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _hi = mid; - continue; - } - if (lo$1 === mid) { - if (sorted[hi$1] === key) { - return hi$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _lo = mid; - continue; - }; - } -} - -export { - strictlySortedLength, - isSorted, - stableSortInPlace, - stableSort, - binarySearch, - union, - intersect, - diff, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalAVLset.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalAVLset.mjs deleted file mode 100644 index af11c9527df..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalAVLset.mjs +++ /dev/null @@ -1,845 +0,0 @@ - - -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Belt_SortArray from "./Belt_SortArray.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function copy(n) { - if (n !== undefined) { - return { - v: n.v, - h: n.h, - l: copy(n.l), - r: copy(n.r) - }; - } else { - return n; - } -} - -function create(l, v, r) { - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - return { - v: v, - h: ( - hl >= hr ? hl : hr - ) + 1 | 0, - l: l, - r: r - }; -} - -function singleton(x) { - return { - v: x, - h: 1, - l: undefined, - r: undefined - }; -} - -function heightGe(l, r) { - if (r !== undefined) { - if (l !== undefined) { - return l.h >= r.h; - } else { - return false; - } - } else { - return true; - } -} - -function bal(l, v, r) { - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - if (hl > (hr + 2 | 0)) { - let ll = l.l; - let lr = l.r; - if (heightGe(ll, lr)) { - return create(ll, l.v, create(lr, v, r)); - } else { - return create(create(ll, l.v, lr.l), lr.v, create(lr.r, v, r)); - } - } - if (hr <= (hl + 2 | 0)) { - return { - v: v, - h: ( - hl >= hr ? hl : hr - ) + 1 | 0, - l: l, - r: r - }; - } - let rl = r.l; - let rr = r.r; - if (heightGe(rr, rl)) { - return create(create(l, v, rl), r.v, rr); - } else { - return create(create(l, v, rl.l), rl.v, create(rl.r, r.v, rr)); - } -} - -function min0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.l; - if (n$1 === undefined) { - return n.v; - } - _n = n$1; - continue; - }; -} - -function minimum(n) { - if (n !== undefined) { - return Primitive_option.some(min0Aux(n)); - } -} - -function max0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.r; - if (n$1 === undefined) { - return n.v; - } - _n = n$1; - continue; - }; -} - -function maximum(n) { - if (n !== undefined) { - return Primitive_option.some(max0Aux(n)); - } -} - -function removeMinAuxWithRef(n, v) { - let ln = n.l; - if (ln !== undefined) { - return bal(removeMinAuxWithRef(ln, v), n.v, n.r); - } else { - v.contents = n.v; - return n.r; - } -} - -function isEmpty(n) { - return n === undefined; -} - -function stackAllLeft(_v, _s) { - while (true) { - let s = _s; - let v = _v; - if (v === undefined) { - return s; - } - _s = {hd: v, tl: s}; - _v = v.l; - continue; - }; -} - -function forEach(_n, f) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - forEach(n.l, f); - f(n.v); - _n = n.r; - continue; - }; -} - -function reduce(_s, _accu, f) { - while (true) { - let accu = _accu; - let s = _s; - if (s === undefined) { - return accu; - } - _accu = f(reduce(s.l, accu, f), s.v); - _s = s.r; - continue; - }; -} - -function every(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return true; - } - if (!p(n.v)) { - return false; - } - if (!every(n.l, p)) { - return false; - } - _n = n.r; - continue; - }; -} - -function some(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - if (p(n.v)) { - return true; - } - if (some(n.l, p)) { - return true; - } - _n = n.r; - continue; - }; -} - -function addMinElement(n, v) { - if (n !== undefined) { - return bal(addMinElement(n.l, v), n.v, n.r); - } else { - return singleton(v); - } -} - -function addMaxElement(n, v) { - if (n !== undefined) { - return bal(n.l, n.v, addMaxElement(n.r, v)); - } else { - return singleton(v); - } -} - -function joinShared(ln, v, rn) { - if (ln === undefined) { - return addMinElement(rn, v); - } - if (rn === undefined) { - return addMaxElement(ln, v); - } - let lh = ln.h; - let rh = rn.h; - if (lh > (rh + 2 | 0)) { - return bal(ln.l, ln.v, joinShared(ln.r, v, rn)); - } else if (rh > (lh + 2 | 0)) { - return bal(joinShared(ln, v, rn.l), rn.v, rn.r); - } else { - return create(ln, v, rn); - } -} - -function concatShared(t1, t2) { - if (t1 === undefined) { - return t2; - } - if (t2 === undefined) { - return t1; - } - let v = { - contents: t2.v - }; - let t2r = removeMinAuxWithRef(t2, v); - return joinShared(t1, v.contents, t2r); -} - -function partitionShared(n, p) { - if (n === undefined) { - return [ - undefined, - undefined - ]; - } - let value = n.v; - let match = partitionShared(n.l, p); - let lf = match[1]; - let lt = match[0]; - let pv = p(value); - let match$1 = partitionShared(n.r, p); - let rf = match$1[1]; - let rt = match$1[0]; - if (pv) { - return [ - joinShared(lt, value, rt), - concatShared(lf, rf) - ]; - } else { - return [ - concatShared(lt, rt), - joinShared(lf, value, rf) - ]; - } -} - -function lengthNode(n) { - let l = n.l; - let r = n.r; - let sizeL = l !== undefined ? lengthNode(l) : 0; - let sizeR = r !== undefined ? lengthNode(r) : 0; - return (1 + sizeL | 0) + sizeR | 0; -} - -function size(n) { - if (n !== undefined) { - return lengthNode(n); - } else { - return 0; - } -} - -function toListAux(_n, _accu) { - while (true) { - let accu = _accu; - let n = _n; - if (n === undefined) { - return accu; - } - _accu = {hd: n.v, tl: toListAux(n.r, accu)}; - _n = n.l; - continue; - }; -} - -function toList(s) { - return toListAux(s, /* [] */0); -} - -function checkInvariantInternal(_v) { - while (true) { - let v = _v; - if (v === undefined) { - return; - } - let l = v.l; - let r = v.r; - let diff = ( - l !== undefined ? l.h : 0 - ) - ( - r !== undefined ? r.h : 0 - ) | 0; - if (!(diff <= 2 && diff >= -2)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_internalAVLset.res", - 280, - 4 - ], - Error: new Error() - }; - } - checkInvariantInternal(l); - _v = r; - continue; - }; -} - -function fillArray(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let v = n.v; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArray(l, i, arr) : i; - arr[next] = v; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function fillArrayWithPartition(_n, cursor, arr, p) { - while (true) { - let n = _n; - let v = n.v; - let l = n.l; - let r = n.r; - if (l !== undefined) { - fillArrayWithPartition(l, cursor, arr, p); - } - if (p(v)) { - let c = cursor.forward; - arr[c] = v; - cursor.forward = c + 1 | 0; - } else { - let c$1 = cursor.backward; - arr[c$1] = v; - cursor.backward = c$1 - 1 | 0; - } - if (r === undefined) { - return; - } - _n = r; - continue; - }; -} - -function fillArrayWithFilter(_n, _i, arr, p) { - while (true) { - let i = _i; - let n = _n; - let v = n.v; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArrayWithFilter(l, i, arr, p) : i; - let rnext = p(v) ? (arr[next] = v, next + 1 | 0) : next; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function toArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArray(n, 0, v); - return v; -} - -function fromSortedArrayRevAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - return singleton(arr[off]); - case 2 : - let x0 = arr[off]; - let x1 = arr[off - 1 | 0]; - return { - v: x1, - h: 2, - l: singleton(x0), - r: undefined - }; - case 3 : - let x0$1 = arr[off]; - let x1$1 = arr[off - 1 | 0]; - let x2 = arr[off - 2 | 0]; - return { - v: x1$1, - h: 2, - l: singleton(x0$1), - r: singleton(x2) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayRevAux(arr, off, nl); - let mid = arr[off - nl | 0]; - let right = fromSortedArrayRevAux(arr, (off - nl | 0) - 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, mid, right); - } -} - -function fromSortedArrayAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - return singleton(arr[off]); - case 2 : - let x0 = arr[off]; - let x1 = arr[off + 1 | 0]; - return { - v: x1, - h: 2, - l: singleton(x0), - r: undefined - }; - case 3 : - let x0$1 = arr[off]; - let x1$1 = arr[off + 1 | 0]; - let x2 = arr[off + 2 | 0]; - return { - v: x1$1, - h: 2, - l: singleton(x0$1), - r: singleton(x2) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayAux(arr, off, nl); - let mid = arr[off + nl | 0]; - let right = fromSortedArrayAux(arr, (off + nl | 0) + 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, mid, right); - } -} - -function fromSortedArrayUnsafe(arr) { - return fromSortedArrayAux(arr, 0, arr.length); -} - -function keepShared(n, p) { - if (n === undefined) { - return; - } - let v = n.v; - let l = n.l; - let r = n.r; - let newL = keepShared(l, p); - let pv = p(v); - let newR = keepShared(r, p); - if (pv) { - if (l === newL && r === newR) { - return n; - } else { - return joinShared(newL, v, newR); - } - } else { - return concatShared(newL, newR); - } -} - -function keepCopy(n, p) { - if (n === undefined) { - return; - } - let size = lengthNode(n); - let v = new Array(size); - let last = fillArrayWithFilter(n, 0, v, p); - return fromSortedArrayAux(v, 0, last); -} - -function partitionCopy(n, p) { - if (n === undefined) { - return [ - undefined, - undefined - ]; - } - let size = lengthNode(n); - let v = new Array(size); - let backward = size - 1 | 0; - let cursor = { - forward: 0, - backward: backward - }; - fillArrayWithPartition(n, cursor, v, p); - let forwardLen = cursor.forward; - return [ - fromSortedArrayAux(v, 0, forwardLen), - fromSortedArrayRevAux(v, backward, size - forwardLen | 0) - ]; -} - -function has(_t, x, cmp) { - while (true) { - let t = _t; - if (t === undefined) { - return false; - } - let v = t.v; - let c = cmp(x, v); - if (c === 0) { - return true; - } - _t = c < 0 ? t.l : t.r; - continue; - }; -} - -function cmp(s1, s2, cmp$1) { - let len1 = size(s1); - let len2 = size(s2); - if (len1 === len2) { - let _e1 = stackAllLeft(s1, /* [] */0); - let _e2 = stackAllLeft(s2, /* [] */0); - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = cmp$1(h1.v, h2.v); - if (c !== 0) { - return c; - } - _e2 = stackAllLeft(h2.r, e2.tl); - _e1 = stackAllLeft(h1.r, e1.tl); - continue; - }; - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2, c) { - return cmp(s1, s2, c) === 0; -} - -function subset(_s1, _s2, cmp) { - while (true) { - let s2 = _s2; - let s1 = _s1; - if (s1 === undefined) { - return true; - } - if (s2 === undefined) { - return false; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let c = cmp(v1, v2); - if (c === 0) { - if (!subset(l1, l2, cmp)) { - return false; - } - _s2 = r2; - _s1 = r1; - continue; - } - if (c < 0) { - if (!subset(create(l1, v1, undefined), l2, cmp)) { - return false; - } - _s1 = r1; - continue; - } - if (!subset(create(undefined, v1, r1), r2, cmp)) { - return false; - } - _s1 = l1; - continue; - }; -} - -function get(_n, x, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.v; - let c = cmp(x, v); - if (c === 0) { - return Primitive_option.some(v); - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x, cmp) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.v; - let c = cmp(x, v); - if (c === 0) { - return v; - } - _n = c < 0 ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function rotateWithLeftChild(k2) { - let k1 = k2.l; - k2.l = k1.r; - k1.r = k2; - let n = k2.l; - let hlk2 = n !== undefined ? n.h : 0; - let n$1 = k2.r; - let hrk2 = n$1 !== undefined ? n$1.h : 0; - k2.h = Primitive_int.max(hlk2, hrk2) + 1 | 0; - let n$2 = k1.l; - let hlk1 = n$2 !== undefined ? n$2.h : 0; - let hk2 = k2.h; - k1.h = Primitive_int.max(hlk1, hk2) + 1 | 0; - return k1; -} - -function rotateWithRightChild(k1) { - let k2 = k1.r; - k1.r = k2.l; - k2.l = k1; - let n = k1.l; - let hlk1 = n !== undefined ? n.h : 0; - let n$1 = k1.r; - let hrk1 = n$1 !== undefined ? n$1.h : 0; - k1.h = Primitive_int.max(hlk1, hrk1) + 1 | 0; - let n$2 = k2.r; - let hrk2 = n$2 !== undefined ? n$2.h : 0; - let hk1 = k1.h; - k2.h = Primitive_int.max(hrk2, hk1) + 1 | 0; - return k2; -} - -function doubleWithLeftChild(k3) { - let k3l = k3.l; - let v = rotateWithRightChild(k3l); - k3.l = v; - return rotateWithLeftChild(k3); -} - -function doubleWithRightChild(k2) { - let k2r = k2.r; - let v = rotateWithLeftChild(k2r); - k2.r = v; - return rotateWithRightChild(k2); -} - -function heightUpdateMutate(t) { - let n = t.l; - let hlt = n !== undefined ? n.h : 0; - let n$1 = t.r; - let hrt = n$1 !== undefined ? n$1.h : 0; - t.h = Primitive_int.max(hlt, hrt) + 1 | 0; - return t; -} - -function balMutate(nt) { - let l = nt.l; - let r = nt.r; - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - if (hl > (2 + hr | 0)) { - let ll = l.l; - let lr = l.r; - if (heightGe(ll, lr)) { - return heightUpdateMutate(rotateWithLeftChild(nt)); - } else { - return heightUpdateMutate(doubleWithLeftChild(nt)); - } - } - if (hr > (2 + hl | 0)) { - let rl = r.l; - let rr = r.r; - if (heightGe(rr, rl)) { - return heightUpdateMutate(rotateWithRightChild(nt)); - } else { - return heightUpdateMutate(doubleWithRightChild(nt)); - } - } - nt.h = Primitive_int.max(hl, hr) + 1 | 0; - return nt; -} - -function addMutate(cmp, t, x) { - if (t === undefined) { - return singleton(x); - } - let k = t.v; - let c = cmp(x, k); - if (c === 0) { - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = addMutate(cmp, l, x); - t.l = ll; - } else { - t.r = addMutate(cmp, r, x); - } - return balMutate(t); -} - -function fromArray(xs, cmp) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (x, y) => cmp(x, y) < 0); - let result; - if (next >= 0) { - result = fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - result = addMutate(cmp, result, xs[i]); - } - return result; -} - -function removeMinAuxWithRootMutate(nt, n) { - let ln = n.l; - let rn = n.r; - if (ln !== undefined) { - n.l = removeMinAuxWithRootMutate(nt, ln); - return balMutate(n); - } else { - nt.v = n.v; - return rn; - } -} - -export { - copy, - create, - bal, - singleton, - minimum, - maximum, - removeMinAuxWithRef, - isEmpty, - stackAllLeft, - forEach, - reduce, - every, - some, - joinShared, - concatShared, - keepShared, - keepCopy, - partitionShared, - partitionCopy, - lengthNode, - size, - toList, - checkInvariantInternal, - fillArray, - toArray, - fromSortedArrayAux, - fromSortedArrayRevAux, - fromSortedArrayUnsafe, - has, - cmp, - eq, - subset, - get, - getOrThrow, - fromArray, - addMutate, - balMutate, - removeMinAuxWithRootMutate, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalAVLtree.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalAVLtree.mjs deleted file mode 100644 index c44ed4b3761..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalAVLtree.mjs +++ /dev/null @@ -1,1012 +0,0 @@ - - -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Belt_SortArray from "./Belt_SortArray.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function treeHeight(n) { - if (n !== undefined) { - return n.h; - } else { - return 0; - } -} - -function copy(n) { - if (n !== undefined) { - return { - k: n.k, - v: n.v, - h: n.h, - l: copy(n.l), - r: copy(n.r) - }; - } else { - return n; - } -} - -function create(l, x, d, r) { - let hl = treeHeight(l); - let hr = treeHeight(r); - return { - k: x, - v: d, - h: hl >= hr ? hl + 1 | 0 : hr + 1 | 0, - l: l, - r: r - }; -} - -function singleton(x, d) { - return { - k: x, - v: d, - h: 1, - l: undefined, - r: undefined - }; -} - -function heightGe(l, r) { - if (r !== undefined) { - if (l !== undefined) { - return l.h >= r.h; - } else { - return false; - } - } else { - return true; - } -} - -function updateValue(n, newValue) { - if (n.v === newValue) { - return n; - } else { - return { - k: n.k, - v: newValue, - h: n.h, - l: n.l, - r: n.r - }; - } -} - -function bal(l, x, d, r) { - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - if (hl > (hr + 2 | 0)) { - let ll = l.l; - let lr = l.r; - if (treeHeight(ll) >= treeHeight(lr)) { - return create(ll, l.k, l.v, create(lr, x, d, r)); - } else { - return create(create(ll, l.k, l.v, lr.l), lr.k, lr.v, create(lr.r, x, d, r)); - } - } - if (hr <= (hl + 2 | 0)) { - return { - k: x, - v: d, - h: hl >= hr ? hl + 1 | 0 : hr + 1 | 0, - l: l, - r: r - }; - } - let rl = r.l; - let rr = r.r; - if (treeHeight(rr) >= treeHeight(rl)) { - return create(create(l, x, d, rl), r.k, r.v, rr); - } else { - return create(create(l, x, d, rl.l), rl.k, rl.v, create(rl.r, r.k, r.v, rr)); - } -} - -function minKey0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.l; - if (n$1 === undefined) { - return n.k; - } - _n = n$1; - continue; - }; -} - -function minKey(n) { - if (n !== undefined) { - return Primitive_option.some(minKey0Aux(n)); - } -} - -function maxKey0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.r; - if (n$1 === undefined) { - return n.k; - } - _n = n$1; - continue; - }; -} - -function maxKey(n) { - if (n !== undefined) { - return Primitive_option.some(maxKey0Aux(n)); - } -} - -function minKV0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.l; - if (n$1 === undefined) { - return [ - n.k, - n.v - ]; - } - _n = n$1; - continue; - }; -} - -function minimum(n) { - if (n !== undefined) { - return minKV0Aux(n); - } -} - -function maxKV0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.r; - if (n$1 === undefined) { - return [ - n.k, - n.v - ]; - } - _n = n$1; - continue; - }; -} - -function maximum(n) { - if (n !== undefined) { - return maxKV0Aux(n); - } -} - -function removeMinAuxWithRef(n, kr, vr) { - let ln = n.l; - if (ln !== undefined) { - return bal(removeMinAuxWithRef(ln, kr, vr), n.k, n.v, n.r); - } else { - kr.contents = n.k; - vr.contents = n.v; - return n.r; - } -} - -function isEmpty(x) { - return x === undefined; -} - -function stackAllLeft(_v, _s) { - while (true) { - let s = _s; - let v = _v; - if (v === undefined) { - return s; - } - _s = {hd: v, tl: s}; - _v = v.l; - continue; - }; -} - -function findFirstBy(n, p) { - if (n === undefined) { - return; - } - let left = findFirstBy(n.l, p); - if (left !== undefined) { - return left; - } - let v = n.k; - let d = n.v; - let pvd = p(v, d); - if (pvd) { - return [ - v, - d - ]; - } - let right = findFirstBy(n.r, p); - if (right !== undefined) { - return right; - } -} - -function forEach(_n, f) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - forEach(n.l, f); - f(n.k, n.v); - _n = n.r; - continue; - }; -} - -function map(n, f) { - if (n === undefined) { - return; - } - let newLeft = map(n.l, f); - let newD = f(n.v); - let newRight = map(n.r, f); - return { - k: n.k, - v: newD, - h: n.h, - l: newLeft, - r: newRight - }; -} - -function mapWithKey(n, f) { - if (n === undefined) { - return; - } - let key = n.k; - let newLeft = mapWithKey(n.l, f); - let newD = f(key, n.v); - let newRight = mapWithKey(n.r, f); - return { - k: key, - v: newD, - h: n.h, - l: newLeft, - r: newRight - }; -} - -function reduce(_m, _accu, f) { - while (true) { - let accu = _accu; - let m = _m; - if (m === undefined) { - return accu; - } - let v = m.k; - let d = m.v; - let l = m.l; - let r = m.r; - _accu = f(reduce(l, accu, f), v, d); - _m = r; - continue; - }; -} - -function every(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return true; - } - if (!p(n.k, n.v)) { - return false; - } - if (!every(n.l, p)) { - return false; - } - _n = n.r; - continue; - }; -} - -function some(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - if (p(n.k, n.v)) { - return true; - } - if (some(n.l, p)) { - return true; - } - _n = n.r; - continue; - }; -} - -function addMinElement(n, k, v) { - if (n !== undefined) { - return bal(addMinElement(n.l, k, v), n.k, n.v, n.r); - } else { - return singleton(k, v); - } -} - -function addMaxElement(n, k, v) { - if (n !== undefined) { - return bal(n.l, n.k, n.v, addMaxElement(n.r, k, v)); - } else { - return singleton(k, v); - } -} - -function join(ln, v, d, rn) { - if (ln === undefined) { - return addMinElement(rn, v, d); - } - if (rn === undefined) { - return addMaxElement(ln, v, d); - } - let lv = ln.k; - let ld = ln.v; - let lh = ln.h; - let ll = ln.l; - let lr = ln.r; - let rv = rn.k; - let rd = rn.v; - let rh = rn.h; - let rl = rn.l; - let rr = rn.r; - if (lh > (rh + 2 | 0)) { - return bal(ll, lv, ld, join(lr, v, d, rn)); - } else if (rh > (lh + 2 | 0)) { - return bal(join(ln, v, d, rl), rv, rd, rr); - } else { - return create(ln, v, d, rn); - } -} - -function concat(t1, t2) { - if (t1 === undefined) { - return t2; - } - if (t2 === undefined) { - return t1; - } - let kr = { - contents: t2.k - }; - let vr = { - contents: t2.v - }; - let t2r = removeMinAuxWithRef(t2, kr, vr); - return join(t1, kr.contents, vr.contents, t2r); -} - -function concatOrJoin(t1, v, d, t2) { - if (d !== undefined) { - return join(t1, v, Primitive_option.valFromOption(d), t2); - } else { - return concat(t1, t2); - } -} - -function keepShared(n, p) { - if (n === undefined) { - return; - } - let v = n.k; - let d = n.v; - let newLeft = keepShared(n.l, p); - let pvd = p(v, d); - let newRight = keepShared(n.r, p); - if (pvd) { - return join(newLeft, v, d, newRight); - } else { - return concat(newLeft, newRight); - } -} - -function keepMap(n, p) { - if (n === undefined) { - return; - } - let v = n.k; - let d = n.v; - let newLeft = keepMap(n.l, p); - let pvd = p(v, d); - let newRight = keepMap(n.r, p); - if (pvd !== undefined) { - return join(newLeft, v, Primitive_option.valFromOption(pvd), newRight); - } else { - return concat(newLeft, newRight); - } -} - -function partitionShared(n, p) { - if (n === undefined) { - return [ - undefined, - undefined - ]; - } - let key = n.k; - let value = n.v; - let match = partitionShared(n.l, p); - let lf = match[1]; - let lt = match[0]; - let pvd = p(key, value); - let match$1 = partitionShared(n.r, p); - let rf = match$1[1]; - let rt = match$1[0]; - if (pvd) { - return [ - join(lt, key, value, rt), - concat(lf, rf) - ]; - } else { - return [ - concat(lt, rt), - join(lf, key, value, rf) - ]; - } -} - -function lengthNode(n) { - let l = n.l; - let r = n.r; - let sizeL = l !== undefined ? lengthNode(l) : 0; - let sizeR = r !== undefined ? lengthNode(r) : 0; - return (1 + sizeL | 0) + sizeR | 0; -} - -function size(n) { - if (n !== undefined) { - return lengthNode(n); - } else { - return 0; - } -} - -function toListAux(_n, _accu) { - while (true) { - let accu = _accu; - let n = _n; - if (n === undefined) { - return accu; - } - let k = n.k; - let v = n.v; - let l = n.l; - let r = n.r; - _accu = {hd: [ - k, - v - ], tl: toListAux(r, accu)}; - _n = l; - continue; - }; -} - -function toList(s) { - return toListAux(s, /* [] */0); -} - -function checkInvariantInternal(_v) { - while (true) { - let v = _v; - if (v === undefined) { - return; - } - let l = v.l; - let r = v.r; - let diff = treeHeight(l) - treeHeight(r) | 0; - if (!(diff <= 2 && diff >= -2)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_internalAVLtree.res", - 408, - 4 - ], - Error: new Error() - }; - } - checkInvariantInternal(l); - _v = r; - continue; - }; -} - -function fillArrayKey(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let v = n.k; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArrayKey(l, i, arr) : i; - arr[next] = v; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function fillArrayValue(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArrayValue(l, i, arr) : i; - arr[next] = n.v; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function fillArray(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let l = n.l; - let v = n.k; - let r = n.r; - let next = l !== undefined ? fillArray(l, i, arr) : i; - arr[next] = [ - v, - n.v - ]; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function toArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArray(n, 0, v); - return v; -} - -function keysToArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArrayKey(n, 0, v); - return v; -} - -function valuesToArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArrayValue(n, 0, v); - return v; -} - -function fromSortedArrayRevAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - let match = arr[off]; - return singleton(match[0], match[1]); - case 2 : - let match_0 = arr[off]; - let match_1 = arr[off - 1 | 0]; - let match$1 = match_1; - let match$2 = match_0; - return { - k: match$1[0], - v: match$1[1], - h: 2, - l: singleton(match$2[0], match$2[1]), - r: undefined - }; - case 3 : - let match_0$1 = arr[off]; - let match_1$1 = arr[off - 1 | 0]; - let match_2 = arr[off - 2 | 0]; - let match$3 = match_2; - let match$4 = match_1$1; - let match$5 = match_0$1; - return { - k: match$4[0], - v: match$4[1], - h: 2, - l: singleton(match$5[0], match$5[1]), - r: singleton(match$3[0], match$3[1]) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayRevAux(arr, off, nl); - let match$6 = arr[off - nl | 0]; - let right = fromSortedArrayRevAux(arr, (off - nl | 0) - 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, match$6[0], match$6[1], right); - } -} - -function fromSortedArrayAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - let match = arr[off]; - return singleton(match[0], match[1]); - case 2 : - let match_0 = arr[off]; - let match_1 = arr[off + 1 | 0]; - let match$1 = match_1; - let match$2 = match_0; - return { - k: match$1[0], - v: match$1[1], - h: 2, - l: singleton(match$2[0], match$2[1]), - r: undefined - }; - case 3 : - let match_0$1 = arr[off]; - let match_1$1 = arr[off + 1 | 0]; - let match_2 = arr[off + 2 | 0]; - let match$3 = match_2; - let match$4 = match_1$1; - let match$5 = match_0$1; - return { - k: match$4[0], - v: match$4[1], - h: 2, - l: singleton(match$5[0], match$5[1]), - r: singleton(match$3[0], match$3[1]) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayAux(arr, off, nl); - let match$6 = arr[off + nl | 0]; - let right = fromSortedArrayAux(arr, (off + nl | 0) + 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, match$6[0], match$6[1], right); - } -} - -function fromSortedArrayUnsafe(arr) { - return fromSortedArrayAux(arr, 0, arr.length); -} - -function cmp(s1, s2, kcmp, vcmp) { - let len1 = size(s1); - let len2 = size(s2); - if (len1 === len2) { - let _e1 = stackAllLeft(s1, /* [] */0); - let _e2 = stackAllLeft(s2, /* [] */0); - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = kcmp(h1.k, h2.k); - if (c !== 0) { - return c; - } - let cx = vcmp(h1.v, h2.v); - if (cx !== 0) { - return cx; - } - _e2 = stackAllLeft(h2.r, e2.tl); - _e1 = stackAllLeft(h1.r, e1.tl); - continue; - }; - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2, kcmp, veq) { - let len1 = size(s1); - let len2 = size(s2); - if (len1 === len2) { - let _e1 = stackAllLeft(s1, /* [] */0); - let _e2 = stackAllLeft(s2, /* [] */0); - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return true; - } - if (e2 === 0) { - return true; - } - let h2 = e2.hd; - let h1 = e1.hd; - if (!(kcmp(h1.k, h2.k) === 0 && veq(h1.v, h2.v))) { - return false; - } - _e2 = stackAllLeft(h2.r, e2.tl); - _e1 = stackAllLeft(h1.r, e1.tl); - continue; - }; - } else { - return false; - } -} - -function get(_n, x, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return Primitive_option.some(n.v); - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x, cmp) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return n.v; - } - _n = c < 0 ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function getWithDefault(_n, x, def, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return def; - } - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return n.v; - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function has(_n, x, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return true; - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function rotateWithLeftChild(k2) { - let k1 = k2.l; - k2.l = k1.r; - k1.r = k2; - let hlk2 = treeHeight(k2.l); - let hrk2 = treeHeight(k2.r); - k2.h = Primitive_int.max(hlk2, hrk2) + 1 | 0; - let hlk1 = treeHeight(k1.l); - let hk2 = k2.h; - k1.h = Primitive_int.max(hlk1, hk2) + 1 | 0; - return k1; -} - -function rotateWithRightChild(k1) { - let k2 = k1.r; - k1.r = k2.l; - k2.l = k1; - let hlk1 = treeHeight(k1.l); - let hrk1 = treeHeight(k1.r); - k1.h = Primitive_int.max(hlk1, hrk1) + 1 | 0; - let hrk2 = treeHeight(k2.r); - let hk1 = k1.h; - k2.h = Primitive_int.max(hrk2, hk1) + 1 | 0; - return k2; -} - -function doubleWithLeftChild(k3) { - let x = k3.l; - let v = rotateWithRightChild(x); - k3.l = v; - return rotateWithLeftChild(k3); -} - -function doubleWithRightChild(k2) { - let x = k2.r; - let v = rotateWithLeftChild(x); - k2.r = v; - return rotateWithRightChild(k2); -} - -function heightUpdateMutate(t) { - let hlt = treeHeight(t.l); - let hrt = treeHeight(t.r); - t.h = Primitive_int.max(hlt, hrt) + 1 | 0; - return t; -} - -function balMutate(nt) { - let l = nt.l; - let r = nt.r; - let hl = treeHeight(l); - let hr = treeHeight(r); - if (hl > (2 + hr | 0)) { - let ll = l.l; - let lr = l.r; - if (heightGe(ll, lr)) { - return heightUpdateMutate(rotateWithLeftChild(nt)); - } else { - return heightUpdateMutate(doubleWithLeftChild(nt)); - } - } - if (hr > (2 + hl | 0)) { - let rl = r.l; - let rr = r.r; - if (heightGe(rr, rl)) { - return heightUpdateMutate(rotateWithRightChild(nt)); - } else { - return heightUpdateMutate(doubleWithRightChild(nt)); - } - } - nt.h = Primitive_int.max(hl, hr) + 1 | 0; - return nt; -} - -function updateMutate(t, x, data, cmp) { - if (t === undefined) { - return singleton(x, data); - } - let k = t.k; - let c = cmp(x, k); - if (c === 0) { - t.v = data; - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = updateMutate(l, x, data, cmp); - t.l = ll; - } else { - t.r = updateMutate(r, x, data, cmp); - } - return balMutate(t); -} - -function fromArray(xs, cmp) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (param, param$1) => cmp(param[0], param$1[0]) < 0); - let result; - if (next >= 0) { - result = fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - let match = xs[i]; - result = updateMutate(result, match[0], match[1], cmp); - } - return result; -} - -function removeMinAuxWithRootMutate(nt, n) { - let rn = n.r; - let ln = n.l; - if (ln !== undefined) { - n.l = removeMinAuxWithRootMutate(nt, ln); - return balMutate(n); - } else { - nt.k = n.k; - nt.v = n.v; - return rn; - } -} - -export { - copy, - create, - bal, - singleton, - updateValue, - minKey, - maxKey, - minimum, - maximum, - removeMinAuxWithRef, - isEmpty, - stackAllLeft, - findFirstBy, - forEach, - map, - mapWithKey, - reduce, - every, - some, - join, - concat, - concatOrJoin, - keepShared, - keepMap, - partitionShared, - lengthNode, - size, - toList, - checkInvariantInternal, - fillArray, - toArray, - keysToArray, - valuesToArray, - fromSortedArrayAux, - fromSortedArrayRevAux, - fromSortedArrayUnsafe, - cmp, - eq, - get, - getWithDefault, - getOrThrow, - has, - fromArray, - updateMutate, - balMutate, - removeMinAuxWithRootMutate, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalBuckets.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalBuckets.mjs deleted file mode 100644 index 9ed766f6fba..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalBuckets.mjs +++ /dev/null @@ -1,258 +0,0 @@ - - -import * as Belt_Array from "./Belt_Array.mjs"; -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; - -function copyAuxCont(_c, _prec) { - while (true) { - let prec = _prec; - let c = _c; - if (c === undefined) { - return; - } - let ncopy = { - key: c.key, - value: c.value, - next: undefined - }; - prec.next = ncopy; - _prec = ncopy; - _c = c.next; - continue; - }; -} - -function copyBucket(c) { - if (c === undefined) { - return c; - } - let head = { - key: c.key, - value: c.value, - next: undefined - }; - copyAuxCont(c.next, head); - return head; -} - -function copyBuckets(buckets) { - let len = buckets.length; - let newBuckets = new Array(len); - for (let i = 0; i < len; ++i) { - newBuckets[i] = copyBucket(buckets[i]); - } - return newBuckets; -} - -function copy(x) { - return { - size: x.size, - buckets: copyBuckets(x.buckets), - hash: x.hash, - eq: x.eq - }; -} - -function bucketLength(_accu, _buckets) { - while (true) { - let buckets = _buckets; - let accu = _accu; - if (buckets === undefined) { - return accu; - } - _buckets = buckets.next; - _accu = accu + 1 | 0; - continue; - }; -} - -function do_bucket_iter(f, _buckets) { - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - f(buckets.key, buckets.value); - _buckets = buckets.next; - continue; - }; -} - -function forEach(h, f) { - let d = h.buckets; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - do_bucket_iter(f, d[i]); - } -} - -function do_bucket_fold(f, _b, _accu) { - while (true) { - let accu = _accu; - let b = _b; - if (b === undefined) { - return accu; - } - _accu = f(accu, b.key, b.value); - _b = b.next; - continue; - }; -} - -function reduce(h, init, f) { - let d = h.buckets; - let accu = init; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - accu = do_bucket_fold(f, d[i], accu); - } - return accu; -} - -function getMaxBucketLength(h) { - return Belt_Array.reduce(h.buckets, 0, (m, b) => { - let len = bucketLength(0, b); - return Primitive_int.max(m, len); - }); -} - -function getBucketHistogram(h) { - let mbl = getMaxBucketLength(h); - let histo = Belt_Array.makeBy(mbl + 1 | 0, param => 0); - Belt_Array.forEach(h.buckets, b => { - let l = bucketLength(0, b); - histo[l] = histo[l] + 1 | 0; - }); - return histo; -} - -function logStats(h) { - let histogram = getBucketHistogram(h); - console.log({ - bindings: h.size, - buckets: h.buckets.length, - histogram: histogram - }); -} - -function filterMapInplaceBucket(f, h, i, _prec, _cell) { - while (true) { - let cell = _cell; - let prec = _prec; - let n = cell.next; - let data = f(cell.key, cell.value); - if (data !== undefined) { - if (prec !== undefined) { - cell.next = cell; - } else { - h.buckets[i] = cell; - } - cell.value = Primitive_option.valFromOption(data); - if (n === undefined) { - cell.next = n; - return; - } - _cell = n; - _prec = cell; - continue; - } - h.size = h.size - 1 | 0; - if (n === undefined) { - if (prec !== undefined) { - prec.next = n; - } else { - h.buckets[i] = prec; - } - return; - } - _cell = n; - continue; - }; -} - -function keepMapInPlace(h, f) { - let h_buckets = h.buckets; - for (let i = 0, i_finish = h_buckets.length; i < i_finish; ++i) { - let v = h_buckets[i]; - if (v !== undefined) { - filterMapInplaceBucket(f, h, i, undefined, v); - } - } -} - -function fillArray(_i, arr, _cell) { - while (true) { - let cell = _cell; - let i = _i; - arr[i] = [ - cell.key, - cell.value - ]; - let v = cell.next; - if (v === undefined) { - return i + 1 | 0; - } - _cell = v; - _i = i + 1 | 0; - continue; - }; -} - -function fillArrayMap(_i, arr, _cell, f) { - while (true) { - let cell = _cell; - let i = _i; - arr[i] = f(cell); - let v = cell.next; - if (v === undefined) { - return i + 1 | 0; - } - _cell = v; - _i = i + 1 | 0; - continue; - }; -} - -function linear(h, f) { - let d = h.buckets; - let current = 0; - let arr = new Array(h.size); - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - let cell = d[i]; - if (cell !== undefined) { - current = fillArrayMap(current, arr, cell, f); - } - } - return arr; -} - -function keysToArray(h) { - return linear(h, x => x.key); -} - -function valuesToArray(h) { - return linear(h, x => x.value); -} - -function toArray(h) { - return linear(h, x => [ - x.key, - x.value - ]); -} - -let C; - -export { - C, - copy, - forEach, - reduce, - logStats, - keepMapInPlace, - fillArray, - keysToArray, - valuesToArray, - toArray, - getBucketHistogram, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalBucketsType.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalBucketsType.mjs deleted file mode 100644 index d2101f53bfd..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalBucketsType.mjs +++ /dev/null @@ -1,49 +0,0 @@ - - - -function power_2_above(_x, n) { - while (true) { - let x = _x; - if (x >= n) { - return x; - } - if ((x << 1) < x) { - return x; - } - _x = (x << 1); - continue; - }; -} - -function make(hash, eq, hintSize) { - let s = power_2_above(16, hintSize); - return { - size: 0, - buckets: new Array(s), - hash: hash, - eq: eq - }; -} - -function clear(h) { - h.size = 0; - let h_buckets = h.buckets; - let len = h_buckets.length; - for (let i = 0; i < len; ++i) { - h_buckets[i] = undefined; - } -} - -function isEmpty(h) { - return h.size === 0; -} - -let emptyOpt; - -export { - emptyOpt, - make, - clear, - isEmpty, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalMapInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalMapInt.mjs deleted file mode 100644 index 7e8a5653f9f..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalMapInt.mjs +++ /dev/null @@ -1,330 +0,0 @@ - - -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; -import * as Belt_SortArray from "./Belt_SortArray.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; - -function add(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - return Belt_internalAVLtree.updateValue(t, data); - } - let v = t.v; - if (x < k) { - return Belt_internalAVLtree.bal(add(t.l, x, data), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, add(t.r, x, data)); - } -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.k; - if (x === v) { - return Primitive_option.some(n.v); - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function getWithDefault(_n, x, def) { - while (true) { - let n = _n; - if (n === undefined) { - return def; - } - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function has(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - let v = n.k; - if (x === v) { - return true; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function remove(n, x) { - if (n === undefined) { - return n; - } - let v = n.k; - let l = n.l; - let r = n.r; - if (x !== v) { - if (x < v) { - return Belt_internalAVLtree.bal(remove(l, x), v, n.v, r); - } else { - return Belt_internalAVLtree.bal(l, v, n.v, remove(r, x)); - } - } - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); -} - -function splitAux(x, n) { - let v = n.k; - let d = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - Primitive_option.some(d), - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - undefined, - n - ]; - } - let match = splitAux(x, l); - return [ - match[0], - match[1], - Belt_internalAVLtree.join(match[2], v, d, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined, - undefined - ]; - } - let match$1 = splitAux(x, r); - return [ - Belt_internalAVLtree.join(l, v, d, match$1[0]), - match$1[1], - match$1[2] - ]; -} - -function split(x, n) { - if (n !== undefined) { - return splitAux(x, n); - } else { - return [ - undefined, - undefined, - undefined - ]; - } -} - -function merge(s1, s2, f) { - if (s1 !== undefined) { - if (s1.h >= ( - s2 !== undefined ? s2.h : 0 - )) { - let v1 = s1.k; - let d1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = split(v1, s2); - return Belt_internalAVLtree.concatOrJoin(merge(l1, match[0], f), v1, f(v1, Primitive_option.some(d1), match[1]), merge(r1, match[2], f)); - } - } else if (s2 === undefined) { - return; - } - let v2 = s2.k; - let d2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = split(v2, s1); - return Belt_internalAVLtree.concatOrJoin(merge(match$1[0], l2, f), v2, f(v2, match$1[1], Primitive_option.some(d2)), merge(match$1[2], r2, f)); -} - -function compareAux(_e1, _e2, vcmp) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = Primitive_int.compare(h1.k, h2.k); - if (c !== 0) { - return c; - } - let cx = vcmp(h1.v, h2.v); - if (cx !== 0) { - return cx; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2, cmp$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), cmp$1); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eqAux(_e1, _e2, eq) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return true; - } - if (e2 === 0) { - return true; - } - let h2 = e2.hd; - let h1 = e1.hd; - if (!(h1.k === h2.k && eq(h1.v, h2.v))) { - return false; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function eq(s1, s2, eq$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return eqAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), eq$1); - } else { - return false; - } -} - -function addMutate(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - t.k = x; - t.v = data; - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addMutate(l, x, data); - t.l = ll; - } else { - t.r = addMutate(r, x, data); - } - return Belt_internalAVLtree.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (param, param$1) => param[0] < param$1[0]); - let result; - if (next >= 0) { - result = Belt_internalAVLtree.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLtree.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - let match = xs[i]; - result = addMutate(result, match[0], match[1]); - } - return result; -} - -let N; - -let A; - -let S; - -export { - N, - A, - S, - add, - get, - getOrThrow, - getWithDefault, - has, - remove, - splitAux, - split, - merge, - compareAux, - cmp, - eqAux, - eq, - addMutate, - fromArray, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalMapString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalMapString.mjs deleted file mode 100644 index f8772ce7914..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalMapString.mjs +++ /dev/null @@ -1,330 +0,0 @@ - - -import * as Belt_SortArray from "./Belt_SortArray.mjs"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs"; -import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.mjs"; -import * as Belt_internalAVLtree from "./Belt_internalAVLtree.mjs"; - -function add(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - return Belt_internalAVLtree.updateValue(t, data); - } - let v = t.v; - if (x < k) { - return Belt_internalAVLtree.bal(add(t.l, x, data), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, add(t.r, x, data)); - } -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.k; - if (x === v) { - return Primitive_option.some(n.v); - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function getWithDefault(_n, x, def) { - while (true) { - let n = _n; - if (n === undefined) { - return def; - } - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function has(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - let v = n.k; - if (x === v) { - return true; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function remove(n, x) { - if (n === undefined) { - return n; - } - let v = n.k; - let l = n.l; - let r = n.r; - if (x !== v) { - if (x < v) { - return Belt_internalAVLtree.bal(remove(l, x), v, n.v, r); - } else { - return Belt_internalAVLtree.bal(l, v, n.v, remove(r, x)); - } - } - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); -} - -function splitAux(x, n) { - let v = n.k; - let d = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - Primitive_option.some(d), - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - undefined, - n - ]; - } - let match = splitAux(x, l); - return [ - match[0], - match[1], - Belt_internalAVLtree.join(match[2], v, d, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined, - undefined - ]; - } - let match$1 = splitAux(x, r); - return [ - Belt_internalAVLtree.join(l, v, d, match$1[0]), - match$1[1], - match$1[2] - ]; -} - -function split(x, n) { - if (n !== undefined) { - return splitAux(x, n); - } else { - return [ - undefined, - undefined, - undefined - ]; - } -} - -function merge(s1, s2, f) { - if (s1 !== undefined) { - if (s1.h >= ( - s2 !== undefined ? s2.h : 0 - )) { - let v1 = s1.k; - let d1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = split(v1, s2); - return Belt_internalAVLtree.concatOrJoin(merge(l1, match[0], f), v1, f(v1, Primitive_option.some(d1), match[1]), merge(r1, match[2], f)); - } - } else if (s2 === undefined) { - return; - } - let v2 = s2.k; - let d2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = split(v2, s1); - return Belt_internalAVLtree.concatOrJoin(merge(match$1[0], l2, f), v2, f(v2, match$1[1], Primitive_option.some(d2)), merge(match$1[2], r2, f)); -} - -function compareAux(_e1, _e2, vcmp) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = Primitive_string.compare(h1.k, h2.k); - if (c !== 0) { - return c; - } - let cx = vcmp(h1.v, h2.v); - if (cx !== 0) { - return cx; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2, cmp$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), cmp$1); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eqAux(_e1, _e2, eq) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return true; - } - if (e2 === 0) { - return true; - } - let h2 = e2.hd; - let h1 = e1.hd; - if (!(h1.k === h2.k && eq(h1.v, h2.v))) { - return false; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function eq(s1, s2, eq$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return eqAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), eq$1); - } else { - return false; - } -} - -function addMutate(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - t.k = x; - t.v = data; - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addMutate(l, x, data); - t.l = ll; - } else { - t.r = addMutate(r, x, data); - } - return Belt_internalAVLtree.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (param, param$1) => param[0] < param$1[0]); - let result; - if (next >= 0) { - result = Belt_internalAVLtree.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLtree.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - let match = xs[i]; - result = addMutate(result, match[0], match[1]); - } - return result; -} - -let N; - -let A; - -let S; - -export { - N, - A, - S, - add, - get, - getOrThrow, - getWithDefault, - has, - remove, - splitAux, - split, - merge, - compareAux, - cmp, - eqAux, - eq, - addMutate, - fromArray, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalSetBuckets.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalSetBuckets.mjs deleted file mode 100644 index 9d060ba5e26..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalSetBuckets.mjs +++ /dev/null @@ -1,174 +0,0 @@ - - -import * as Belt_Array from "./Belt_Array.mjs"; -import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.mjs"; - -function copyAuxCont(_c, _prec) { - while (true) { - let prec = _prec; - let c = _c; - if (c === undefined) { - return; - } - let ncopy = { - key: c.key, - next: undefined - }; - prec.next = ncopy; - _prec = ncopy; - _c = c.next; - continue; - }; -} - -function copyBucket(c) { - if (c === undefined) { - return c; - } - let head = { - key: c.key, - next: undefined - }; - copyAuxCont(c.next, head); - return head; -} - -function copyBuckets(buckets) { - let len = buckets.length; - let newBuckets = new Array(len); - for (let i = 0; i < len; ++i) { - newBuckets[i] = copyBucket(buckets[i]); - } - return newBuckets; -} - -function copy(x) { - return { - size: x.size, - buckets: copyBuckets(x.buckets), - hash: x.hash, - eq: x.eq - }; -} - -function bucketLength(_accu, _buckets) { - while (true) { - let buckets = _buckets; - let accu = _accu; - if (buckets === undefined) { - return accu; - } - _buckets = buckets.next; - _accu = accu + 1 | 0; - continue; - }; -} - -function doBucketIter(f, _buckets) { - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - f(buckets.key); - _buckets = buckets.next; - continue; - }; -} - -function forEach(h, f) { - let d = h.buckets; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - doBucketIter(f, d[i]); - } -} - -function fillArray(_i, arr, _cell) { - while (true) { - let cell = _cell; - let i = _i; - arr[i] = cell.key; - let v = cell.next; - if (v === undefined) { - return i + 1 | 0; - } - _cell = v; - _i = i + 1 | 0; - continue; - }; -} - -function toArray(h) { - let d = h.buckets; - let current = 0; - let arr = new Array(h.size); - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - let cell = d[i]; - if (cell !== undefined) { - current = fillArray(current, arr, cell); - } - } - return arr; -} - -function doBucketFold(f, _b, _accu) { - while (true) { - let accu = _accu; - let b = _b; - if (b === undefined) { - return accu; - } - _accu = f(accu, b.key); - _b = b.next; - continue; - }; -} - -function reduce(h, init, f) { - let d = h.buckets; - let accu = init; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - accu = doBucketFold(f, d[i], accu); - } - return accu; -} - -function getMaxBucketLength(h) { - return Belt_Array.reduce(h.buckets, 0, (m, b) => { - let len = bucketLength(0, b); - return Primitive_int.max(m, len); - }); -} - -function getBucketHistogram(h) { - let mbl = getMaxBucketLength(h); - let histo = Belt_Array.makeBy(mbl + 1 | 0, param => 0); - Belt_Array.forEach(h.buckets, b => { - let l = bucketLength(0, b); - histo[l] = histo[l] + 1 | 0; - }); - return histo; -} - -function logStats(h) { - let histogram = getBucketHistogram(h); - console.log({ - bindings: h.size, - buckets: h.buckets.length, - histogram: histogram - }); -} - -let C; - -export { - C, - copy, - forEach, - fillArray, - toArray, - reduce, - logStats, - getBucketHistogram, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalSetInt.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalSetInt.mjs deleted file mode 100644 index ccaeefcde89..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalSetInt.mjs +++ /dev/null @@ -1,193 +0,0 @@ - - -import * as Belt_SortArrayInt from "./Belt_SortArrayInt.mjs"; -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; - -function has(_t, x) { - while (true) { - let t = _t; - if (t === undefined) { - return false; - } - let v = t.v; - if (x === v) { - return true; - } - _t = x < v ? t.l : t.r; - continue; - }; -} - -function compareAux(_e1, _e2) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let k1 = h1.v; - let k2 = h2.v; - if (k1 !== k2) { - if (k1 < k2) { - return -1; - } else { - return 1; - } - } - _e2 = Belt_internalAVLset.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLset.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2) { - let len1 = Belt_internalAVLset.size(s1); - let len2 = Belt_internalAVLset.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLset.stackAllLeft(s1, /* [] */0), Belt_internalAVLset.stackAllLeft(s2, /* [] */0)); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2) { - return cmp(s1, s2) === 0; -} - -function subset(_s1, _s2) { - while (true) { - let s2 = _s2; - let s1 = _s1; - if (s1 === undefined) { - return true; - } - if (s2 === undefined) { - return false; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - if (v1 === v2) { - if (!subset(l1, l2)) { - return false; - } - _s2 = r2; - _s1 = r1; - continue; - } - if (v1 < v2) { - if (!subset(Belt_internalAVLset.create(l1, v1, undefined), l2)) { - return false; - } - _s1 = r1; - continue; - } - if (!subset(Belt_internalAVLset.create(undefined, v1, r1), r2)) { - return false; - } - _s1 = l1; - continue; - }; -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function addMutate(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - t.l = addMutate(l, x); - } else { - t.r = addMutate(r, x); - } - return Belt_internalAVLset.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArrayInt.strictlySortedLength(xs); - let result; - if (next >= 0) { - result = Belt_internalAVLset.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLset.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - result = addMutate(result, xs[i]); - } - return result; -} - -let S; - -let N; - -let A; - -export { - S, - N, - A, - has, - compareAux, - cmp, - eq, - subset, - get, - getOrThrow, - addMutate, - fromArray, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/es6/src/Belt_internalSetString.mjs b/packages/@rescript/belt/lib/es6/src/Belt_internalSetString.mjs deleted file mode 100644 index d0173f633db..00000000000 --- a/packages/@rescript/belt/lib/es6/src/Belt_internalSetString.mjs +++ /dev/null @@ -1,193 +0,0 @@ - - -import * as Belt_internalAVLset from "./Belt_internalAVLset.mjs"; -import * as Belt_SortArrayString from "./Belt_SortArrayString.mjs"; - -function has(_t, x) { - while (true) { - let t = _t; - if (t === undefined) { - return false; - } - let v = t.v; - if (x === v) { - return true; - } - _t = x < v ? t.l : t.r; - continue; - }; -} - -function compareAux(_e1, _e2) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let k1 = h1.v; - let k2 = h2.v; - if (k1 !== k2) { - if (k1 < k2) { - return -1; - } else { - return 1; - } - } - _e2 = Belt_internalAVLset.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLset.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2) { - let len1 = Belt_internalAVLset.size(s1); - let len2 = Belt_internalAVLset.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLset.stackAllLeft(s1, /* [] */0), Belt_internalAVLset.stackAllLeft(s2, /* [] */0)); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2) { - return cmp(s1, s2) === 0; -} - -function subset(_s1, _s2) { - while (true) { - let s2 = _s2; - let s1 = _s1; - if (s1 === undefined) { - return true; - } - if (s2 === undefined) { - return false; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - if (v1 === v2) { - if (!subset(l1, l2)) { - return false; - } - _s2 = r2; - _s1 = r1; - continue; - } - if (v1 < v2) { - if (!subset(Belt_internalAVLset.create(l1, v1, undefined), l2)) { - return false; - } - _s1 = r1; - continue; - } - if (!subset(Belt_internalAVLset.create(undefined, v1, r1), r2)) { - return false; - } - _s1 = l1; - continue; - }; -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function addMutate(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - t.l = addMutate(l, x); - } else { - t.r = addMutate(r, x); - } - return Belt_internalAVLset.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArrayString.strictlySortedLength(xs); - let result; - if (next >= 0) { - result = Belt_internalAVLset.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLset.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - result = addMutate(result, xs[i]); - } - return result; -} - -let S; - -let N; - -let A; - -export { - S, - N, - A, - has, - compareAux, - cmp, - eq, - subset, - get, - getOrThrow, - addMutate, - fromArray, -} -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt.cjs b/packages/@rescript/belt/lib/js/src/Belt.cjs deleted file mode 100644 index 78d1d8521a8..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt.cjs +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - - -let Id; - -let $$Array; - -let SortArray; - -let MutableQueue; - -let MutableStack; - -let List; - -let Range; - -let $$Set; - -let $$Map; - -let MutableSet; - -let MutableMap; - -let HashSet; - -let HashMap; - -let Option; - -let Result; - -let Int; - -let Float; - -exports.Id = Id; -exports.$$Array = $$Array; -exports.SortArray = SortArray; -exports.MutableQueue = MutableQueue; -exports.MutableStack = MutableStack; -exports.List = List; -exports.Range = Range; -exports.$$Set = $$Set; -exports.$$Map = $$Map; -exports.MutableSet = MutableSet; -exports.MutableMap = MutableMap; -exports.HashSet = HashSet; -exports.HashMap = HashMap; -exports.Option = Option; -exports.Result = Result; -exports.Int = Int; -exports.Float = Float; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Array.cjs b/packages/@rescript/belt/lib/js/src/Belt_Array.cjs deleted file mode 100644 index e922e627206..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Array.cjs +++ /dev/null @@ -1,711 +0,0 @@ -'use strict'; - -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function get(arr, i) { - if (i >= 0 && i < arr.length) { - return Primitive_option.some(arr[i]); - } -} - -function getOrThrow(arr, i) { - if (!(i >= 0 && i < arr.length)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_Array.res", - 27, - 2 - ], - Error: new Error() - }; - } - return arr[i]; -} - -function set(arr, i, v) { - if (i >= 0 && i < arr.length) { - arr[i] = v; - return true; - } else { - return false; - } -} - -function setOrThrow(arr, i, v) { - if (!(i >= 0 && i < arr.length)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_Array.res", - 42, - 2 - ], - Error: new Error() - }; - } - arr[i] = v; -} - -function swapUnsafe(xs, i, j) { - let tmp = xs[i]; - xs[i] = xs[j]; - xs[j] = tmp; -} - -function shuffleInPlace(xs) { - let len = xs.length; - let random_int = (min, max) => Math.floor(Math.random() * (max - min | 0)) + min | 0; - for (let i = 0; i < len; ++i) { - swapUnsafe(xs, i, random_int(i, len)); - } -} - -function shuffle(xs) { - let result = xs.slice(0); - shuffleInPlace(result); - return result; -} - -function reverseInPlace(xs) { - let len = xs.length; - let ofs = 0; - for (let i = 0, i_finish = len / 2 | 0; i < i_finish; ++i) { - swapUnsafe(xs, ofs + i | 0, ((ofs + len | 0) - i | 0) - 1 | 0); - } -} - -function reverse(xs) { - let len = xs.length; - let result = new Array(len); - for (let i = 0; i < len; ++i) { - result[i] = xs[(len - 1 | 0) - i | 0]; - } - return result; -} - -function make(l, f) { - if (l <= 0) { - return []; - } - let res = new Array(l); - for (let i = 0; i < l; ++i) { - res[i] = f; - } - return res; -} - -function makeBy(l, f) { - if (l <= 0) { - return []; - } - let res = new Array(l); - for (let i = 0; i < l; ++i) { - res[i] = f(i); - } - return res; -} - -function makeByAndShuffle(l, f) { - let u = makeBy(l, f); - shuffleInPlace(u); - return u; -} - -function range(start, finish) { - let cut = finish - start | 0; - if (cut < 0) { - return []; - } - let arr = new Array(cut + 1 | 0); - for (let i = 0; i <= cut; ++i) { - arr[i] = start + i | 0; - } - return arr; -} - -function rangeBy(start, finish, step) { - let cut = finish - start | 0; - if (cut < 0 || step <= 0) { - return []; - } - let nb = (cut / step | 0) + 1 | 0; - let arr = new Array(nb); - let cur = start; - for (let i = 0; i < nb; ++i) { - arr[i] = cur; - cur = cur + step | 0; - } - return arr; -} - -function zip(xs, ys) { - let lenx = xs.length; - let leny = ys.length; - let len = Primitive_int.min(lenx, leny); - let s = new Array(len); - for (let i = 0; i < len; ++i) { - s[i] = [ - xs[i], - ys[i] - ]; - } - return s; -} - -function zipBy(xs, ys, f) { - let lenx = xs.length; - let leny = ys.length; - let len = Primitive_int.min(lenx, leny); - let s = new Array(len); - for (let i = 0; i < len; ++i) { - s[i] = f(xs[i], ys[i]); - } - return s; -} - -function concat(a1, a2) { - let l1 = a1.length; - let l2 = a2.length; - let a1a2 = new Array(l1 + l2 | 0); - for (let i = 0; i < l1; ++i) { - a1a2[i] = a1[i]; - } - for (let i$1 = 0; i$1 < l2; ++i$1) { - a1a2[l1 + i$1 | 0] = a2[i$1]; - } - return a1a2; -} - -function concatMany(arrs) { - let lenArrs = arrs.length; - let totalLen = 0; - for (let i = 0; i < lenArrs; ++i) { - totalLen = totalLen + arrs[i].length | 0; - } - let result = new Array(totalLen); - totalLen = 0; - for (let j = 0; j < lenArrs; ++j) { - let cur = arrs[j]; - for (let k = 0, k_finish = cur.length; k < k_finish; ++k) { - result[totalLen] = cur[k]; - totalLen = totalLen + 1 | 0; - } - } - return result; -} - -function slice(a, offset, len) { - if (len <= 0) { - return []; - } - let lena = a.length; - let ofs = offset < 0 ? Primitive_int.max(lena + offset | 0, 0) : offset; - let hasLen = lena - ofs | 0; - let copyLength = Primitive_int.min(hasLen, len); - if (copyLength <= 0) { - return []; - } - let result = new Array(copyLength); - for (let i = 0; i < copyLength; ++i) { - result[i] = a[ofs + i | 0]; - } - return result; -} - -function sliceToEnd(a, offset) { - let lena = a.length; - let ofs = offset < 0 ? Primitive_int.max(lena + offset | 0, 0) : offset; - let len = lena > ofs ? lena - ofs | 0 : 0; - let result = new Array(len); - for (let i = 0; i < len; ++i) { - result[i] = a[ofs + i | 0]; - } - return result; -} - -function fill(a, offset, len, v) { - if (len <= 0) { - return; - } - let lena = a.length; - let ofs = offset < 0 ? Primitive_int.max(lena + offset | 0, 0) : offset; - let hasLen = lena - ofs | 0; - let fillLength = Primitive_int.min(hasLen, len); - if (fillLength <= 0) { - return; - } - for (let i = ofs, i_finish = ofs + fillLength | 0; i < i_finish; ++i) { - a[i] = v; - } -} - -function blitUnsafe(a1, srcofs1, a2, srcofs2, blitLength) { - if (srcofs2 <= srcofs1) { - for (let j = 0; j < blitLength; ++j) { - a2[j + srcofs2 | 0] = a1[j + srcofs1 | 0]; - } - return; - } - for (let j$1 = blitLength - 1 | 0; j$1 >= 0; --j$1) { - a2[j$1 + srcofs2 | 0] = a1[j$1 + srcofs1 | 0]; - } -} - -function blit(a1, ofs1, a2, ofs2, len) { - let lena1 = a1.length; - let lena2 = a2.length; - let srcofs1 = ofs1 < 0 ? Primitive_int.max(lena1 + ofs1 | 0, 0) : ofs1; - let srcofs2 = ofs2 < 0 ? Primitive_int.max(lena2 + ofs2 | 0, 0) : ofs2; - let blitLength = Primitive_int.min(len, Primitive_int.min(lena1 - srcofs1 | 0, lena2 - srcofs2 | 0)); - if (srcofs2 <= srcofs1) { - for (let j = 0; j < blitLength; ++j) { - a2[j + srcofs2 | 0] = a1[j + srcofs1 | 0]; - } - return; - } - for (let j$1 = blitLength - 1 | 0; j$1 >= 0; --j$1) { - a2[j$1 + srcofs2 | 0] = a1[j$1 + srcofs1 | 0]; - } -} - -function forEach(a, f) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(a[i]); - } -} - -function map(a, f) { - let l = a.length; - let r = new Array(l); - for (let i = 0; i < l; ++i) { - r[i] = f(a[i]); - } - return r; -} - -function flatMap(a, f) { - return concatMany(map(a, f)); -} - -function getBy(a, p) { - let l = a.length; - let i = 0; - let r; - while (r === undefined && i < l) { - let v = a[i]; - if (p(v)) { - r = Primitive_option.some(v); - } - i = i + 1 | 0; - }; - return r; -} - -function getIndexBy(a, p) { - let l = a.length; - let i = 0; - let r; - while (r === undefined && i < l) { - let v = a[i]; - if (p(v)) { - r = i; - } - i = i + 1 | 0; - }; - return r; -} - -function keep(a, f) { - let l = a.length; - let r = new Array(l); - let j = 0; - for (let i = 0; i < l; ++i) { - let v = a[i]; - if (f(v)) { - r[j] = v; - j = j + 1 | 0; - } - } - r.length = j; - return r; -} - -function keepWithIndex(a, f) { - let l = a.length; - let r = new Array(l); - let j = 0; - for (let i = 0; i < l; ++i) { - let v = a[i]; - if (f(v, i)) { - r[j] = v; - j = j + 1 | 0; - } - } - r.length = j; - return r; -} - -function keepMap(a, f) { - let l = a.length; - let r = new Array(l); - let j = 0; - for (let i = 0; i < l; ++i) { - let v = a[i]; - let v$1 = f(v); - if (v$1 !== undefined) { - r[j] = Primitive_option.valFromOption(v$1); - j = j + 1 | 0; - } - } - r.length = j; - return r; -} - -function forEachWithIndex(a, f) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(i, a[i]); - } -} - -function mapWithIndex(a, f) { - let l = a.length; - let r = new Array(l); - for (let i = 0; i < l; ++i) { - r[i] = f(i, a[i]); - } - return r; -} - -function reduce(a, x, f) { - let r = x; - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - r = f(r, a[i]); - } - return r; -} - -function reduceReverse(a, x, f) { - let r = x; - for (let i = a.length - 1 | 0; i >= 0; --i) { - r = f(r, a[i]); - } - return r; -} - -function reduceReverse2(a, b, x, f) { - let r = x; - let len = Primitive_int.min(a.length, b.length); - for (let i = len - 1 | 0; i >= 0; --i) { - r = f(r, a[i], b[i]); - } - return r; -} - -function reduceWithIndex(a, x, f) { - let r = x; - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - r = f(r, a[i], i); - } - return r; -} - -function every(arr, b) { - let len = arr.length; - let _i = 0; - while (true) { - let i = _i; - if (i === len) { - return true; - } - if (!b(arr[i])) { - return false; - } - _i = i + 1 | 0; - continue; - }; -} - -function some(arr, b) { - let len = arr.length; - let _i = 0; - while (true) { - let i = _i; - if (i === len) { - return false; - } - if (b(arr[i])) { - return true; - } - _i = i + 1 | 0; - continue; - }; -} - -function everyAux2(arr1, arr2, _i, b, len) { - while (true) { - let i = _i; - if (i === len) { - return true; - } - if (!b(arr1[i], arr2[i])) { - return false; - } - _i = i + 1 | 0; - continue; - }; -} - -function every2(a, b, p) { - return everyAux2(a, b, 0, p, Primitive_int.min(a.length, b.length)); -} - -function some2(a, b, p) { - let _i = 0; - let len = Primitive_int.min(a.length, b.length); - while (true) { - let i = _i; - if (i === len) { - return false; - } - if (p(a[i], b[i])) { - return true; - } - _i = i + 1 | 0; - continue; - }; -} - -function eq(a, b, p) { - let lena = a.length; - let lenb = b.length; - if (lena === lenb) { - return everyAux2(a, b, 0, p, lena); - } else { - return false; - } -} - -function cmp(a, b, p) { - let lena = a.length; - let lenb = b.length; - if (lena > lenb) { - return 1; - } else if (lena < lenb) { - return -1; - } else { - let _i = 0; - while (true) { - let i = _i; - if (i === lena) { - return 0; - } - let c = p(a[i], b[i]); - if (c !== 0) { - return c; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function partition(a, f) { - let l = a.length; - let i = 0; - let j = 0; - let a1 = new Array(l); - let a2 = new Array(l); - for (let ii = 0; ii < l; ++ii) { - let v = a[ii]; - if (f(v)) { - a1[i] = v; - i = i + 1 | 0; - } else { - a2[j] = v; - j = j + 1 | 0; - } - } - a1.length = i; - a2.length = j; - return [ - a1, - a2 - ]; -} - -function unzip(a) { - let l = a.length; - let a1 = new Array(l); - let a2 = new Array(l); - for (let i = 0; i < l; ++i) { - let match = a[i]; - a1[i] = match[0]; - a2[i] = match[1]; - } - return [ - a1, - a2 - ]; -} - -function joinWith(a, sep, toString) { - let l = a.length; - if (l === 0) { - return ""; - } - let lastIndex = l - 1 | 0; - let _i = 0; - let _res = ""; - while (true) { - let res = _res; - let i = _i; - if (i === lastIndex) { - return res + toString(a[i]); - } - _res = res + (toString(a[i]) + sep); - _i = i + 1 | 0; - continue; - }; -} - -function init(n, f) { - let v = new Array(n); - for (let i = 0; i < n; ++i) { - v[i] = f(i); - } - return v; -} - -let getExn = getOrThrow; - -let setExn = setOrThrow; - -let makeByU = makeBy; - -let makeByAndShuffleU = makeByAndShuffle; - -let zipByU = zipBy; - -let forEachU = forEach; - -let mapU = map; - -let flatMapU = flatMap; - -let getByU = getBy; - -let getIndexByU = getIndexBy; - -let keepU = keep; - -let keepWithIndexU = keepWithIndex; - -let keepMapU = keepMap; - -let forEachWithIndexU = forEachWithIndex; - -let mapWithIndexU = mapWithIndex; - -let partitionU = partition; - -let reduceU = reduce; - -let reduceReverseU = reduceReverse; - -let reduceReverse2U = reduceReverse2; - -let reduceWithIndexU = reduceWithIndex; - -let joinWithU = joinWith; - -let someU = some; - -let everyU = every; - -let every2U = every2; - -let some2U = some2; - -let cmpU = cmp; - -let eqU = eq; - -let initU = init; - -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.set = set; -exports.setExn = setExn; -exports.setOrThrow = setOrThrow; -exports.shuffleInPlace = shuffleInPlace; -exports.shuffle = shuffle; -exports.reverseInPlace = reverseInPlace; -exports.reverse = reverse; -exports.make = make; -exports.range = range; -exports.rangeBy = rangeBy; -exports.makeByU = makeByU; -exports.makeBy = makeBy; -exports.makeByAndShuffleU = makeByAndShuffleU; -exports.makeByAndShuffle = makeByAndShuffle; -exports.zip = zip; -exports.zipByU = zipByU; -exports.zipBy = zipBy; -exports.unzip = unzip; -exports.concat = concat; -exports.concatMany = concatMany; -exports.slice = slice; -exports.sliceToEnd = sliceToEnd; -exports.fill = fill; -exports.blit = blit; -exports.blitUnsafe = blitUnsafe; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.mapU = mapU; -exports.map = map; -exports.flatMapU = flatMapU; -exports.flatMap = flatMap; -exports.getByU = getByU; -exports.getBy = getBy; -exports.getIndexByU = getIndexByU; -exports.getIndexBy = getIndexBy; -exports.keepU = keepU; -exports.keep = keep; -exports.keepWithIndexU = keepWithIndexU; -exports.keepWithIndex = keepWithIndex; -exports.keepMapU = keepMapU; -exports.keepMap = keepMap; -exports.forEachWithIndexU = forEachWithIndexU; -exports.forEachWithIndex = forEachWithIndex; -exports.mapWithIndexU = mapWithIndexU; -exports.mapWithIndex = mapWithIndex; -exports.partitionU = partitionU; -exports.partition = partition; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.reduceReverseU = reduceReverseU; -exports.reduceReverse = reduceReverse; -exports.reduceReverse2U = reduceReverse2U; -exports.reduceReverse2 = reduceReverse2; -exports.reduceWithIndexU = reduceWithIndexU; -exports.reduceWithIndex = reduceWithIndex; -exports.joinWithU = joinWithU; -exports.joinWith = joinWith; -exports.someU = someU; -exports.some = some; -exports.everyU = everyU; -exports.every = every; -exports.every2U = every2U; -exports.every2 = every2; -exports.some2U = some2U; -exports.some2 = some2; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.initU = initU; -exports.init = init; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Float.cjs b/packages/@rescript/belt/lib/js/src/Belt_Float.cjs deleted file mode 100644 index 4859867af11..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Float.cjs +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - - -function fromString(i) { - let i$1 = parseFloat(i); - if (isNaN(i$1)) { - return; - } else { - return i$1; - } -} - -exports.fromString = fromString; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_HashMap.cjs b/packages/@rescript/belt/lib/js/src/Belt_HashMap.cjs deleted file mode 100644 index 15e97e99393..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_HashMap.cjs +++ /dev/null @@ -1,274 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalBuckets = require("./Belt_internalBuckets.cjs"); -let Belt_internalBucketsType = require("./Belt_internalBucketsType.cjs"); - -function size(h) { - return h.size; -} - -function copyBucketReHash(hash, h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = hash(old_bucket.key) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function replaceInBucket(eq, key, info, _cell) { - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - cell.value = info; - return false; - } - let cell$1 = cell.next; - if (cell$1 === undefined) { - return true; - } - _cell = cell$1; - continue; - }; -} - -function set0(h, key, value, eq, hash) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = hash(key) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - if (replaceInBucket(eq, key, value, l)) { - h_buckets[i] = { - key: key, - value: value, - next: l - }; - h.size = h.size + 1 | 0; - } - } else { - h_buckets[i] = { - key: key, - value: value, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucketReHash(hash, h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function set(h, key, value) { - set0(h, key, value, h.eq, h.hash); -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = h.hash(key) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[i]; - if (bucket === undefined) { - return; - } - let eq = h.eq; - if (eq(bucket.key, key)) { - h_buckets[i] = bucket.next; - h.size = h.size - 1 | 0; - return; - } else { - let _prec = bucket; - let _bucket = bucket.next; - while (true) { - let bucket$1 = _bucket; - let prec = _prec; - if (bucket$1 === undefined) { - return; - } - let cell_next = bucket$1.next; - if (eq(bucket$1.key, key)) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - _bucket = cell_next; - _prec = bucket$1; - continue; - }; - } -} - -function get(h, key) { - let h_buckets = h.buckets; - let nid = h.hash(key) & (h_buckets.length - 1 | 0); - let cell1 = h_buckets[nid]; - if (cell1 === undefined) { - return; - } - let eq = h.eq; - if (eq(key, cell1.key)) { - return Primitive_option.some(cell1.value); - } - let cell2 = cell1.next; - if (cell2 === undefined) { - return; - } - if (eq(key, cell2.key)) { - return Primitive_option.some(cell2.value); - } - let cell3 = cell2.next; - if (cell3 !== undefined) { - if (eq(key, cell3.key)) { - return Primitive_option.some(cell3.value); - } else { - let _buckets = cell3.next; - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - if (eq(key, buckets.key)) { - return Primitive_option.some(buckets.value); - } - _buckets = buckets.next; - continue; - }; - } - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = h.hash(key) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - let eq = h.eq; - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize, id) { - return Belt_internalBucketsType.make(id.hash, id.eq, hintSize); -} - -function fromArray(arr, id) { - let hash = id.hash; - let eq = id.eq; - let len = arr.length; - let v = Belt_internalBucketsType.make(hash, eq, len); - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set0(v, match[0], match[1], eq, hash); - } - return v; -} - -function mergeMany(h, arr) { - let hash = h.hash; - let eq = h.eq; - let len = arr.length; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set0(h, match[0], match[1], eq, hash); - } -} - -let Int; - -let $$String; - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalBuckets.copy; - -let forEachU = Belt_internalBuckets.forEach; - -let forEach = Belt_internalBuckets.forEach; - -let reduceU = Belt_internalBuckets.reduce; - -let reduce = Belt_internalBuckets.reduce; - -let keepMapInPlaceU = Belt_internalBuckets.keepMapInPlace; - -let keepMapInPlace = Belt_internalBuckets.keepMapInPlace; - -let toArray = Belt_internalBuckets.toArray; - -let keysToArray = Belt_internalBuckets.keysToArray; - -let valuesToArray = Belt_internalBuckets.valuesToArray; - -let getBucketHistogram = Belt_internalBuckets.getBucketHistogram; - -let logStats = Belt_internalBuckets.logStats; - -exports.Int = Int; -exports.$$String = $$String; -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.set = set; -exports.copy = copy; -exports.get = get; -exports.has = has; -exports.remove = remove; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.keepMapInPlaceU = keepMapInPlaceU; -exports.keepMapInPlace = keepMapInPlace; -exports.size = size; -exports.toArray = toArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.fromArray = fromArray; -exports.mergeMany = mergeMany; -exports.getBucketHistogram = getBucketHistogram; -exports.logStats = logStats; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_HashMapInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_HashMapInt.cjs deleted file mode 100644 index 8bea56463a1..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_HashMapInt.cjs +++ /dev/null @@ -1,257 +0,0 @@ -'use strict'; - -let Primitive_hash = require("@rescript/runtime/lib/js/Primitive_hash.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalBuckets = require("./Belt_internalBuckets.cjs"); -let Belt_internalBucketsType = require("./Belt_internalBucketsType.cjs"); - -function copyBucketReHash(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function replaceInBucket(key, info, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - cell.value = info; - return false; - } - let cell$1 = cell.next; - if (cell$1 === undefined) { - return true; - } - _cell = cell$1; - continue; - }; -} - -function set(h, key, value) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - if (replaceInBucket(key, value, l)) { - h_buckets[i] = { - key: key, - value: value, - next: l - }; - h.size = h.size + 1 | 0; - } - } else { - h_buckets[i] = { - key: key, - value: value, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucketReHash(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[i]; - if (bucket !== undefined) { - if (bucket.key === key) { - h_buckets[i] = bucket.next; - h.size = h.size - 1 | 0; - return; - } else { - let _prec = bucket; - let _buckets = bucket.next; - while (true) { - let buckets = _buckets; - let prec = _prec; - if (buckets === undefined) { - return; - } - let cell_next = buckets.next; - if (buckets.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - _buckets = cell_next; - _prec = buckets; - continue; - }; - } - } -} - -function get(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let cell1 = h_buckets[nid]; - if (cell1 === undefined) { - return; - } - if (key === cell1.key) { - return Primitive_option.some(cell1.value); - } - let cell2 = cell1.next; - if (cell2 === undefined) { - return; - } - if (key === cell2.key) { - return Primitive_option.some(cell2.value); - } - let cell3 = cell2.next; - if (cell3 !== undefined) { - if (key === cell3.key) { - return Primitive_option.some(cell3.value); - } else { - let _buckets = cell3.next; - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - if (key === buckets.key) { - return Primitive_option.some(buckets.value); - } - _buckets = buckets.next; - continue; - }; - } - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(v, match[0], match[1]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(h, match[0], match[1]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalBuckets.copy; - -let forEachU = Belt_internalBuckets.forEach; - -let forEach = Belt_internalBuckets.forEach; - -let reduceU = Belt_internalBuckets.reduce; - -let reduce = Belt_internalBuckets.reduce; - -let keepMapInPlaceU = Belt_internalBuckets.keepMapInPlace; - -let keepMapInPlace = Belt_internalBuckets.keepMapInPlace; - -let toArray = Belt_internalBuckets.toArray; - -let keysToArray = Belt_internalBuckets.keysToArray; - -let valuesToArray = Belt_internalBuckets.valuesToArray; - -let getBucketHistogram = Belt_internalBuckets.getBucketHistogram; - -let logStats = Belt_internalBuckets.logStats; - -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.set = set; -exports.copy = copy; -exports.get = get; -exports.has = has; -exports.remove = remove; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.keepMapInPlaceU = keepMapInPlaceU; -exports.keepMapInPlace = keepMapInPlace; -exports.size = size; -exports.toArray = toArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.fromArray = fromArray; -exports.mergeMany = mergeMany; -exports.getBucketHistogram = getBucketHistogram; -exports.logStats = logStats; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_HashMapString.cjs b/packages/@rescript/belt/lib/js/src/Belt_HashMapString.cjs deleted file mode 100644 index 89e80544db3..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_HashMapString.cjs +++ /dev/null @@ -1,257 +0,0 @@ -'use strict'; - -let Primitive_hash = require("@rescript/runtime/lib/js/Primitive_hash.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalBuckets = require("./Belt_internalBuckets.cjs"); -let Belt_internalBucketsType = require("./Belt_internalBucketsType.cjs"); - -function copyBucketReHash(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function replaceInBucket(key, info, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - cell.value = info; - return false; - } - let cell$1 = cell.next; - if (cell$1 === undefined) { - return true; - } - _cell = cell$1; - continue; - }; -} - -function set(h, key, value) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - if (replaceInBucket(key, value, l)) { - h_buckets[i] = { - key: key, - value: value, - next: l - }; - h.size = h.size + 1 | 0; - } - } else { - h_buckets[i] = { - key: key, - value: value, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucketReHash(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[i]; - if (bucket !== undefined) { - if (bucket.key === key) { - h_buckets[i] = bucket.next; - h.size = h.size - 1 | 0; - return; - } else { - let _prec = bucket; - let _buckets = bucket.next; - while (true) { - let buckets = _buckets; - let prec = _prec; - if (buckets === undefined) { - return; - } - let cell_next = buckets.next; - if (buckets.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - _buckets = cell_next; - _prec = buckets; - continue; - }; - } - } -} - -function get(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let cell1 = h_buckets[nid]; - if (cell1 === undefined) { - return; - } - if (key === cell1.key) { - return Primitive_option.some(cell1.value); - } - let cell2 = cell1.next; - if (cell2 === undefined) { - return; - } - if (key === cell2.key) { - return Primitive_option.some(cell2.value); - } - let cell3 = cell2.next; - if (cell3 !== undefined) { - if (key === cell3.key) { - return Primitive_option.some(cell3.value); - } else { - let _buckets = cell3.next; - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - if (key === buckets.key) { - return Primitive_option.some(buckets.value); - } - _buckets = buckets.next; - continue; - }; - } - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(v, match[0], match[1]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - set(h, match[0], match[1]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalBuckets.copy; - -let forEachU = Belt_internalBuckets.forEach; - -let forEach = Belt_internalBuckets.forEach; - -let reduceU = Belt_internalBuckets.reduce; - -let reduce = Belt_internalBuckets.reduce; - -let keepMapInPlaceU = Belt_internalBuckets.keepMapInPlace; - -let keepMapInPlace = Belt_internalBuckets.keepMapInPlace; - -let toArray = Belt_internalBuckets.toArray; - -let keysToArray = Belt_internalBuckets.keysToArray; - -let valuesToArray = Belt_internalBuckets.valuesToArray; - -let getBucketHistogram = Belt_internalBuckets.getBucketHistogram; - -let logStats = Belt_internalBuckets.logStats; - -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.set = set; -exports.copy = copy; -exports.get = get; -exports.has = has; -exports.remove = remove; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.keepMapInPlaceU = keepMapInPlaceU; -exports.keepMapInPlace = keepMapInPlace; -exports.size = size; -exports.toArray = toArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.fromArray = fromArray; -exports.mergeMany = mergeMany; -exports.getBucketHistogram = getBucketHistogram; -exports.logStats = logStats; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_HashSet.cjs b/packages/@rescript/belt/lib/js/src/Belt_HashSet.cjs deleted file mode 100644 index 618c2b44326..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_HashSet.cjs +++ /dev/null @@ -1,218 +0,0 @@ -'use strict'; - -let Belt_internalSetBuckets = require("./Belt_internalSetBuckets.cjs"); -let Belt_internalBucketsType = require("./Belt_internalBucketsType.cjs"); - -function copyBucket(hash, h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = hash(old_bucket.key) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function remove(h, key) { - let eq = h.eq; - let h_buckets = h.buckets; - let i = h.hash(key) & (h_buckets.length - 1 | 0); - let l = h_buckets[i]; - if (l === undefined) { - return; - } - let next_cell = l.next; - if (eq(l.key, key)) { - h.size = h.size - 1 | 0; - h_buckets[i] = next_cell; - return; - } else if (next_cell !== undefined) { - let _prec = l; - let _cell = next_cell; - while (true) { - let cell = _cell; - let prec = _prec; - let cell_next = cell.next; - if (eq(cell.key, key)) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - if (cell_next === undefined) { - return; - } - _cell = cell_next; - _prec = cell; - continue; - }; - } else { - return; - } -} - -function addBucket(h, key, _cell, eq) { - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - return; - } - let n = cell.next; - if (n !== undefined) { - _cell = n; - continue; - } - h.size = h.size + 1 | 0; - cell.next = { - key: key, - next: undefined - }; - return; - }; -} - -function add0(h, key, hash, eq) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = hash(key) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - addBucket(h, key, l, eq); - } else { - h.size = h.size + 1 | 0; - h_buckets[i] = { - key: key, - next: undefined - }; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucket(hash, h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function add(h, key) { - add0(h, key, h.hash, h.eq); -} - -function has(h, key) { - let eq = h.eq; - let h_buckets = h.buckets; - let nid = h.hash(key) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (eq(cell.key, key)) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize, id) { - return Belt_internalBucketsType.make(id.hash, id.eq, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr, id) { - let eq = id.eq; - let hash = id.hash; - let len = arr.length; - let v = Belt_internalBucketsType.make(hash, eq, len); - for (let i = 0; i < len; ++i) { - add0(v, arr[i], hash, eq); - } - return v; -} - -function mergeMany(h, arr) { - let eq = h.eq; - let hash = h.hash; - let len = arr.length; - for (let i = 0; i < len; ++i) { - add0(h, arr[i], hash, eq); - } -} - -let Int; - -let $$String; - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalSetBuckets.copy; - -let forEachU = Belt_internalSetBuckets.forEach; - -let forEach = Belt_internalSetBuckets.forEach; - -let reduceU = Belt_internalSetBuckets.reduce; - -let reduce = Belt_internalSetBuckets.reduce; - -let logStats = Belt_internalSetBuckets.logStats; - -let toArray = Belt_internalSetBuckets.toArray; - -let getBucketHistogram = Belt_internalSetBuckets.getBucketHistogram; - -exports.Int = Int; -exports.$$String = $$String; -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.add = add; -exports.copy = copy; -exports.has = has; -exports.remove = remove; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.size = size; -exports.logStats = logStats; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.mergeMany = mergeMany; -exports.getBucketHistogram = getBucketHistogram; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_HashSetInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_HashSetInt.cjs deleted file mode 100644 index 01dd05804a4..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_HashSetInt.cjs +++ /dev/null @@ -1,203 +0,0 @@ -'use strict'; - -let Primitive_hash = require("@rescript/runtime/lib/js/Primitive_hash.cjs"); -let Belt_internalSetBuckets = require("./Belt_internalSetBuckets.cjs"); -let Belt_internalBucketsType = require("./Belt_internalBucketsType.cjs"); - -function copyBucket(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let l = h_buckets[i]; - if (l === undefined) { - return; - } - let next_cell = l.next; - if (l.key === key) { - h.size = h.size - 1 | 0; - h_buckets[i] = next_cell; - return; - } else if (next_cell !== undefined) { - let _prec = l; - let _cell = next_cell; - while (true) { - let cell = _cell; - let prec = _prec; - let cell_next = cell.next; - if (cell.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - if (cell_next === undefined) { - return; - } - _cell = cell_next; - _prec = cell; - continue; - }; - } else { - return; - } -} - -function addBucket(h, key, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - return; - } - let n = cell.next; - if (n !== undefined) { - _cell = n; - continue; - } - h.size = h.size + 1 | 0; - cell.next = { - key: key, - next: undefined - }; - return; - }; -} - -function add(h, key) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - addBucket(h, key, l); - } else { - h_buckets[i] = { - key: key, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucket(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_int(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - add(v, arr[i]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - add(h, arr[i]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalSetBuckets.copy; - -let forEachU = Belt_internalSetBuckets.forEach; - -let forEach = Belt_internalSetBuckets.forEach; - -let reduceU = Belt_internalSetBuckets.reduce; - -let reduce = Belt_internalSetBuckets.reduce; - -let logStats = Belt_internalSetBuckets.logStats; - -let toArray = Belt_internalSetBuckets.toArray; - -let getBucketHistogram = Belt_internalSetBuckets.getBucketHistogram; - -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.add = add; -exports.copy = copy; -exports.has = has; -exports.remove = remove; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.size = size; -exports.logStats = logStats; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.mergeMany = mergeMany; -exports.getBucketHistogram = getBucketHistogram; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_HashSetString.cjs b/packages/@rescript/belt/lib/js/src/Belt_HashSetString.cjs deleted file mode 100644 index 9299a94e43c..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_HashSetString.cjs +++ /dev/null @@ -1,203 +0,0 @@ -'use strict'; - -let Primitive_hash = require("@rescript/runtime/lib/js/Primitive_hash.cjs"); -let Belt_internalSetBuckets = require("./Belt_internalSetBuckets.cjs"); -let Belt_internalBucketsType = require("./Belt_internalBucketsType.cjs"); - -function copyBucket(h_buckets, ndata_tail, _old_bucket) { - while (true) { - let old_bucket = _old_bucket; - if (old_bucket === undefined) { - return; - } - let nidx = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, old_bucket.key)) & (h_buckets.length - 1 | 0); - let tail = ndata_tail[nidx]; - if (tail !== undefined) { - tail.next = old_bucket; - } else { - h_buckets[nidx] = old_bucket; - } - ndata_tail[nidx] = old_bucket; - _old_bucket = old_bucket.next; - continue; - }; -} - -function remove(h, key) { - let h_buckets = h.buckets; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let l = h_buckets[i]; - if (l === undefined) { - return; - } - let next_cell = l.next; - if (l.key === key) { - h.size = h.size - 1 | 0; - h_buckets[i] = next_cell; - return; - } else if (next_cell !== undefined) { - let _prec = l; - let _cell = next_cell; - while (true) { - let cell = _cell; - let prec = _prec; - let cell_next = cell.next; - if (cell.key === key) { - prec.next = cell_next; - h.size = h.size - 1 | 0; - return; - } - if (cell_next === undefined) { - return; - } - _cell = cell_next; - _prec = cell; - continue; - }; - } else { - return; - } -} - -function addBucket(h, key, _cell) { - while (true) { - let cell = _cell; - if (cell.key === key) { - return; - } - let n = cell.next; - if (n !== undefined) { - _cell = n; - continue; - } - h.size = h.size + 1 | 0; - cell.next = { - key: key, - next: undefined - }; - return; - }; -} - -function add(h, key) { - let h_buckets = h.buckets; - let buckets_len = h_buckets.length; - let i = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (buckets_len - 1 | 0); - let l = h_buckets[i]; - if (l !== undefined) { - addBucket(h, key, l); - } else { - h_buckets[i] = { - key: key, - next: undefined - }; - h.size = h.size + 1 | 0; - } - if (h.size > (buckets_len << 1)) { - let odata = h.buckets; - let osize = odata.length; - let nsize = (osize << 1); - if (nsize < osize) { - return; - } - let h_buckets$1 = new Array(nsize); - let ndata_tail = new Array(nsize); - h.buckets = h_buckets$1; - for (let i$1 = 0; i$1 < osize; ++i$1) { - copyBucket(h_buckets$1, ndata_tail, odata[i$1]); - } - for (let i$2 = 0; i$2 < nsize; ++i$2) { - let tail = ndata_tail[i$2]; - if (tail !== undefined) { - tail.next = undefined; - } - } - return; - } -} - -function has(h, key) { - let h_buckets = h.buckets; - let nid = Primitive_hash.hash_final_mix(Primitive_hash.hash_mix_string(0, key)) & (h_buckets.length - 1 | 0); - let bucket = h_buckets[nid]; - if (bucket !== undefined) { - let _cell = bucket; - while (true) { - let cell = _cell; - if (cell.key === key) { - return true; - } - let nextCell = cell.next; - if (nextCell === undefined) { - return false; - } - _cell = nextCell; - continue; - }; - } else { - return false; - } -} - -function make(hintSize) { - return Belt_internalBucketsType.make(undefined, undefined, hintSize); -} - -function size(h) { - return h.size; -} - -function fromArray(arr) { - let len = arr.length; - let v = Belt_internalBucketsType.make(undefined, undefined, len); - for (let i = 0; i < len; ++i) { - add(v, arr[i]); - } - return v; -} - -function mergeMany(h, arr) { - let len = arr.length; - for (let i = 0; i < len; ++i) { - add(h, arr[i]); - } -} - -let clear = Belt_internalBucketsType.clear; - -let isEmpty = Belt_internalBucketsType.isEmpty; - -let copy = Belt_internalSetBuckets.copy; - -let forEachU = Belt_internalSetBuckets.forEach; - -let forEach = Belt_internalSetBuckets.forEach; - -let reduceU = Belt_internalSetBuckets.reduce; - -let reduce = Belt_internalSetBuckets.reduce; - -let logStats = Belt_internalSetBuckets.logStats; - -let toArray = Belt_internalSetBuckets.toArray; - -let getBucketHistogram = Belt_internalSetBuckets.getBucketHistogram; - -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.add = add; -exports.copy = copy; -exports.has = has; -exports.remove = remove; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.size = size; -exports.logStats = logStats; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.mergeMany = mergeMany; -exports.getBucketHistogram = getBucketHistogram; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Id.cjs b/packages/@rescript/belt/lib/js/src/Belt_Id.cjs deleted file mode 100644 index 6ea31d35cdd..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Id.cjs +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - - -function MakeComparable(M) { - return M; -} - -function comparable(cmp) { - return { - cmp: cmp - }; -} - -function MakeHashable(M) { - return M; -} - -function hashable(hash, eq) { - return { - hash: hash, - eq: eq - }; -} - -let MakeComparableU = MakeComparable; - -let comparableU = comparable; - -let MakeHashableU = MakeHashable; - -let hashableU = hashable; - -exports.MakeComparableU = MakeComparableU; -exports.MakeComparable = MakeComparable; -exports.comparableU = comparableU; -exports.comparable = comparable; -exports.MakeHashableU = MakeHashableU; -exports.MakeHashable = MakeHashable; -exports.hashableU = hashableU; -exports.hashable = hashable; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Int.cjs b/packages/@rescript/belt/lib/js/src/Belt_Int.cjs deleted file mode 100644 index f90c0798b42..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Int.cjs +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - - -function fromString(i) { - let i$1 = parseInt(i, 10); - if (isNaN(i$1)) { - return; - } else { - return i$1; - } -} - -exports.fromString = fromString; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_List.cjs b/packages/@rescript/belt/lib/js/src/Belt_List.cjs deleted file mode 100644 index 1a761f40137..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_List.cjs +++ /dev/null @@ -1,1313 +0,0 @@ -'use strict'; - -let Belt_Array = require("./Belt_Array.cjs"); -let Belt_SortArray = require("./Belt_SortArray.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function head(x) { - if (x !== 0) { - return Primitive_option.some(x.hd); - } -} - -function headOrThrow(x) { - if (x !== 0) { - return x.hd; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function tail(x) { - if (x !== 0) { - return x.tl; - } -} - -function tailOrThrow(x) { - if (x !== 0) { - return x.tl; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function add(xs, x) { - return {hd: x, tl: xs}; -} - -function get(x, n) { - if (n < 0) { - return; - } else { - let _x = x; - let _n = n; - while (true) { - let n$1 = _n; - let x$1 = _x; - if (x$1 === 0) { - return; - } - if (n$1 === 0) { - return Primitive_option.some(x$1.hd); - } - _n = n$1 - 1 | 0; - _x = x$1.tl; - continue; - }; - } -} - -function getOrThrow(x, n) { - if (n < 0) { - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - } - let _x = x; - let _n = n; - while (true) { - let n$1 = _n; - let x$1 = _x; - if (x$1 !== 0) { - if (n$1 === 0) { - return x$1.hd; - } - _n = n$1 - 1 | 0; - _x = x$1.tl; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function partitionAux(p, _cell, _precX, _precY) { - while (true) { - let precY = _precY; - let precX = _precX; - let cell = _cell; - if (cell === 0) { - return; - } - let t = cell.tl; - let h = cell.hd; - let next = {hd: h, tl: /* [] */0}; - if (p(h)) { - precX.tl = next; - _precX = next; - _cell = t; - continue; - } - precY.tl = next; - _precY = next; - _cell = t; - continue; - }; -} - -function splitAux(_cell, _precX, _precY) { - while (true) { - let precY = _precY; - let precX = _precX; - let cell = _cell; - if (cell === 0) { - return; - } - let match = cell.hd; - let nextA = {hd: match[0], tl: /* [] */0}; - let nextB = {hd: match[1], tl: /* [] */0}; - precX.tl = nextA; - precY.tl = nextB; - _precY = nextB; - _precX = nextA; - _cell = cell.tl; - continue; - }; -} - -function copyAuxCont(_cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return prec; - } - let next = {hd: cellX.hd, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = cellX.tl; - continue; - }; -} - -function copyAuxWitFilter(f, _cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let t = cellX.tl; - let h = cellX.hd; - if (f(h)) { - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - } - _cellX = t; - continue; - }; -} - -function copyAuxWithFilterIndex(f, _cellX, _prec, _i) { - while (true) { - let i = _i; - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let t = cellX.tl; - let h = cellX.hd; - if (f(h, i)) { - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _i = i + 1 | 0; - _prec = next; - _cellX = t; - continue; - } - _i = i + 1 | 0; - _cellX = t; - continue; - }; -} - -function copyAuxWitFilterMap(f, _cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let t = cellX.tl; - let h = f(cellX.hd); - if (h !== undefined) { - let next = {hd: Primitive_option.valFromOption(h), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - } - _cellX = t; - continue; - }; -} - -function removeAssocAuxWithMap(_cellX, x, _prec, f) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return false; - } - let t = cellX.tl; - let h = cellX.hd; - if (f(h[0], x)) { - prec.tl = t; - return true; - } - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - }; -} - -function setAssocAuxWithMap(_cellX, x, k, _prec, eq) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return false; - } - let t = cellX.tl; - let h = cellX.hd; - if (eq(h[0], x)) { - prec.tl = {hd: [ - x, - k - ], tl: t}; - return true; - } - let next = {hd: h, tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = t; - continue; - }; -} - -function copyAuxWithMap(_cellX, _prec, f) { - while (true) { - let prec = _prec; - let cellX = _cellX; - if (cellX === 0) { - return; - } - let next = {hd: f(cellX.hd), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = cellX.tl; - continue; - }; -} - -function zipAux(_cellX, _cellY, _prec) { - while (true) { - let prec = _prec; - let cellY = _cellY; - let cellX = _cellX; - if (cellX === 0) { - return; - } - if (cellY === 0) { - return; - } - let next = {hd: [ - cellX.hd, - cellY.hd - ], tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellY = cellY.tl; - _cellX = cellX.tl; - continue; - }; -} - -function copyAuxWithMap2(f, _cellX, _cellY, _prec) { - while (true) { - let prec = _prec; - let cellY = _cellY; - let cellX = _cellX; - if (cellX === 0) { - return; - } - if (cellY === 0) { - return; - } - let next = {hd: f(cellX.hd, cellY.hd), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellY = cellY.tl; - _cellX = cellX.tl; - continue; - }; -} - -function copyAuxWithMapI(f, _i, _cellX, _prec) { - while (true) { - let prec = _prec; - let cellX = _cellX; - let i = _i; - if (cellX === 0) { - return; - } - let next = {hd: f(i, cellX.hd), tl: /* [] */0}; - prec.tl = next; - _prec = next; - _cellX = cellX.tl; - _i = i + 1 | 0; - continue; - }; -} - -function takeAux(_n, _cell, _prec) { - while (true) { - let prec = _prec; - let cell = _cell; - let n = _n; - if (n === 0) { - return true; - } - if (cell === 0) { - return false; - } - let cell$1 = {hd: cell.hd, tl: /* [] */0}; - prec.tl = cell$1; - _prec = cell$1; - _cell = cell.tl; - _n = n - 1 | 0; - continue; - }; -} - -function splitAtAux(_n, _cell, _prec) { - while (true) { - let prec = _prec; - let cell = _cell; - let n = _n; - if (n === 0) { - return cell; - } - if (cell === 0) { - return; - } - let cell$1 = {hd: cell.hd, tl: /* [] */0}; - prec.tl = cell$1; - _prec = cell$1; - _cell = cell.tl; - _n = n - 1 | 0; - continue; - }; -} - -function take(lst, n) { - if (n < 0) { - return; - } - if (n === 0) { - return /* [] */0; - } - if (lst === 0) { - return; - } - let cell = {hd: lst.hd, tl: /* [] */0}; - let has = takeAux(n - 1 | 0, lst.tl, cell); - if (has) { - return cell; - } -} - -function drop(lst, n) { - if (n < 0) { - return; - } else { - let _l = lst; - let _n = n; - while (true) { - let n$1 = _n; - let l = _l; - if (n$1 === 0) { - return l; - } - if (l === 0) { - return; - } - _n = n$1 - 1 | 0; - _l = l.tl; - continue; - }; - } -} - -function splitAt(lst, n) { - if (n < 0) { - return; - } - if (n === 0) { - return [ - /* [] */0, - lst - ]; - } - if (lst === 0) { - return; - } - let cell = {hd: lst.hd, tl: /* [] */0}; - let rest = splitAtAux(n - 1 | 0, lst.tl, cell); - if (rest !== undefined) { - return [ - cell, - rest - ]; - } -} - -function concat(xs, ys) { - if (xs === 0) { - return ys; - } - let cell = {hd: xs.hd, tl: /* [] */0}; - copyAuxCont(xs.tl, cell).tl = ys; - return cell; -} - -function map(xs, f) { - if (xs === 0) { - return /* [] */0; - } - let cell = {hd: f(xs.hd), tl: /* [] */0}; - copyAuxWithMap(xs.tl, cell, f); - return cell; -} - -function zipBy(l1, l2, f) { - if (l1 === 0) { - return /* [] */0; - } - if (l2 === 0) { - return /* [] */0; - } - let cell = {hd: f(l1.hd, l2.hd), tl: /* [] */0}; - copyAuxWithMap2(f, l1.tl, l2.tl, cell); - return cell; -} - -function mapWithIndex(xs, f) { - if (xs === 0) { - return /* [] */0; - } - let cell = {hd: f(0, xs.hd), tl: /* [] */0}; - copyAuxWithMapI(f, 1, xs.tl, cell); - return cell; -} - -function makeBy(n, f) { - if (n <= 0) { - return /* [] */0; - } - let headX = {hd: f(0), tl: /* [] */0}; - let cur = headX; - let i = 1; - while (i < n) { - let v = {hd: f(i), tl: /* [] */0}; - cur.tl = v; - cur = v; - i = i + 1 | 0; - }; - return headX; -} - -function make(n, v) { - if (n <= 0) { - return /* [] */0; - } - let headX = {hd: v, tl: /* [] */0}; - let cur = headX; - let i = 1; - while (i < n) { - let v$1 = {hd: v, tl: /* [] */0}; - cur.tl = v$1; - cur = v$1; - i = i + 1 | 0; - }; - return headX; -} - -function length(xs) { - let _x = xs; - let _acc = 0; - while (true) { - let acc = _acc; - let x = _x; - if (x === 0) { - return acc; - } - _acc = acc + 1 | 0; - _x = x.tl; - continue; - }; -} - -function fillAux(arr, _i, _x) { - while (true) { - let x = _x; - let i = _i; - if (x === 0) { - return; - } - arr[i] = x.hd; - _x = x.tl; - _i = i + 1 | 0; - continue; - }; -} - -function fromArray(a) { - let _i = a.length - 1 | 0; - let _res = /* [] */0; - while (true) { - let res = _res; - let i = _i; - if (i < 0) { - return res; - } - _res = {hd: a[i], tl: res}; - _i = i - 1 | 0; - continue; - }; -} - -function toArray(x) { - let len = length(x); - let arr = new Array(len); - fillAux(arr, 0, x); - return arr; -} - -function shuffle(xs) { - let v = toArray(xs); - Belt_Array.shuffleInPlace(v); - return fromArray(v); -} - -function reverseConcat(_l1, _l2) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return l2; - } - _l2 = {hd: l1.hd, tl: l2}; - _l1 = l1.tl; - continue; - }; -} - -function reverse(l) { - return reverseConcat(l, /* [] */0); -} - -function flattenAux(_prec, _xs) { - while (true) { - let xs = _xs; - let prec = _prec; - if (xs !== 0) { - _xs = xs.tl; - _prec = copyAuxCont(xs.hd, prec); - continue; - } - prec.tl = /* [] */0; - return; - }; -} - -function flatten(_xs) { - while (true) { - let xs = _xs; - if (xs === 0) { - return /* [] */0; - } - let match = xs.hd; - if (match !== 0) { - let cell = {hd: match.hd, tl: /* [] */0}; - flattenAux(copyAuxCont(match.tl, cell), xs.tl); - return cell; - } - _xs = xs.tl; - continue; - }; -} - -function concatMany(xs) { - let len = xs.length; - if (len === 1) { - return xs[0]; - } - if (len === 0) { - return /* [] */0; - } - let len$1 = xs.length; - let v = xs[len$1 - 1 | 0]; - for (let i = len$1 - 2 | 0; i >= 0; --i) { - v = concat(xs[i], v); - } - return v; -} - -function mapReverse(l, f) { - let _accu = /* [] */0; - let _xs = l; - while (true) { - let xs = _xs; - let accu = _accu; - if (xs === 0) { - return accu; - } - _xs = xs.tl; - _accu = {hd: f(xs.hd), tl: accu}; - continue; - }; -} - -function forEach(_xs, f) { - while (true) { - let xs = _xs; - if (xs === 0) { - return; - } - f(xs.hd); - _xs = xs.tl; - continue; - }; -} - -function forEachWithIndex(l, f) { - let _xs = l; - let _i = 0; - while (true) { - let i = _i; - let xs = _xs; - if (xs === 0) { - return; - } - f(i, xs.hd); - _i = i + 1 | 0; - _xs = xs.tl; - continue; - }; -} - -function reduce(_l, _accu, f) { - while (true) { - let accu = _accu; - let l = _l; - if (l === 0) { - return accu; - } - _accu = f(accu, l.hd); - _l = l.tl; - continue; - }; -} - -function reduceReverseUnsafe(l, accu, f) { - if (l !== 0) { - return f(reduceReverseUnsafe(l.tl, accu, f), l.hd); - } else { - return accu; - } -} - -function reduceReverse(l, acc, f) { - let len = length(l); - if (len < 1000) { - return reduceReverseUnsafe(l, acc, f); - } else { - return Belt_Array.reduceReverse(toArray(l), acc, f); - } -} - -function reduceWithIndex(l, acc, f) { - let _l = l; - let _acc = acc; - let _i = 0; - while (true) { - let i = _i; - let acc$1 = _acc; - let l$1 = _l; - if (l$1 === 0) { - return acc$1; - } - _i = i + 1 | 0; - _acc = f(acc$1, l$1.hd, i); - _l = l$1.tl; - continue; - }; -} - -function mapReverse2(l1, l2, f) { - let _l1 = l1; - let _l2 = l2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1$1 = _l1; - if (l1$1 === 0) { - return accu; - } - if (l2$1 === 0) { - return accu; - } - _accu = {hd: f(l1$1.hd, l2$1.hd), tl: accu}; - _l2 = l2$1.tl; - _l1 = l1$1.tl; - continue; - }; -} - -function forEach2(_l1, _l2, f) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return; - } - if (l2 === 0) { - return; - } - f(l1.hd, l2.hd); - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function reduce2(_l1, _l2, _accu, f) { - while (true) { - let accu = _accu; - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return accu; - } - if (l2 === 0) { - return accu; - } - _accu = f(accu, l1.hd, l2.hd); - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function reduceReverse2Unsafe(l1, l2, accu, f) { - if (l1 !== 0 && l2 !== 0) { - return f(reduceReverse2Unsafe(l1.tl, l2.tl, accu, f), l1.hd, l2.hd); - } else { - return accu; - } -} - -function reduceReverse2(l1, l2, acc, f) { - let len = length(l1); - if (len < 1000) { - return reduceReverse2Unsafe(l1, l2, acc, f); - } else { - return Belt_Array.reduceReverse2(toArray(l1), toArray(l2), acc, f); - } -} - -function every(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return true; - } - if (!p(xs.hd)) { - return false; - } - _xs = xs.tl; - continue; - }; -} - -function some(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return false; - } - if (p(xs.hd)) { - return true; - } - _xs = xs.tl; - continue; - }; -} - -function every2(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return true; - } - if (l2 === 0) { - return true; - } - if (!p(l1.hd, l2.hd)) { - return false; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function cmpByLength(_l1, _l2) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - if (l2 !== 0) { - return -1; - } else { - return 0; - } - } - if (l2 === 0) { - return 1; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function cmp(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - if (l2 !== 0) { - return -1; - } else { - return 0; - } - } - if (l2 === 0) { - return 1; - } - let c = p(l1.hd, l2.hd); - if (c !== 0) { - return c; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function eq(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return l2 === 0; - } - if (l2 === 0) { - return false; - } - if (!p(l1.hd, l2.hd)) { - return false; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function some2(_l1, _l2, p) { - while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1 === 0) { - return false; - } - if (l2 === 0) { - return false; - } - if (p(l1.hd, l2.hd)) { - return true; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - }; -} - -function has(_xs, x, eq) { - while (true) { - let xs = _xs; - if (xs === 0) { - return false; - } - if (eq(xs.hd, x)) { - return true; - } - _xs = xs.tl; - continue; - }; -} - -function getAssoc(_xs, x, eq) { - while (true) { - let xs = _xs; - if (xs === 0) { - return; - } - let match = xs.hd; - if (eq(match[0], x)) { - return Primitive_option.some(match[1]); - } - _xs = xs.tl; - continue; - }; -} - -function hasAssoc(_xs, x, eq) { - while (true) { - let xs = _xs; - if (xs === 0) { - return false; - } - if (eq(xs.hd[0], x)) { - return true; - } - _xs = xs.tl; - continue; - }; -} - -function removeAssoc(xs, x, eq) { - if (xs === 0) { - return /* [] */0; - } - let l = xs.tl; - let pair = xs.hd; - if (eq(pair[0], x)) { - return l; - } - let cell = {hd: pair, tl: /* [] */0}; - let removed = removeAssocAuxWithMap(l, x, cell, eq); - if (removed) { - return cell; - } else { - return xs; - } -} - -function setAssoc(xs, x, k, eq) { - if (xs === 0) { - return {hd: [ - x, - k - ], tl: /* [] */0}; - } - let l = xs.tl; - let pair = xs.hd; - if (eq(pair[0], x)) { - return {hd: [ - x, - k - ], tl: l}; - } - let cell = {hd: pair, tl: /* [] */0}; - let replaced = setAssocAuxWithMap(l, x, k, cell, eq); - if (replaced) { - return cell; - } else { - return {hd: [ - x, - k - ], tl: xs}; - } -} - -function sort(xs, cmp) { - let arr = toArray(xs); - Belt_SortArray.stableSortInPlaceBy(arr, cmp); - return fromArray(arr); -} - -function getBy(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return; - } - let x = xs.hd; - if (p(x)) { - return Primitive_option.some(x); - } - _xs = xs.tl; - continue; - }; -} - -function keep(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return /* [] */0; - } - let t = xs.tl; - let h = xs.hd; - if (p(h)) { - let cell = {hd: h, tl: /* [] */0}; - copyAuxWitFilter(p, t, cell); - return cell; - } - _xs = t; - continue; - }; -} - -function keepWithIndex(xs, p) { - let _xs = xs; - let _i = 0; - while (true) { - let i = _i; - let xs$1 = _xs; - if (xs$1 === 0) { - return /* [] */0; - } - let t = xs$1.tl; - let h = xs$1.hd; - if (p(h, i)) { - let cell = {hd: h, tl: /* [] */0}; - copyAuxWithFilterIndex(p, t, cell, i + 1 | 0); - return cell; - } - _i = i + 1 | 0; - _xs = t; - continue; - }; -} - -function keepMap(_xs, p) { - while (true) { - let xs = _xs; - if (xs === 0) { - return /* [] */0; - } - let t = xs.tl; - let h = p(xs.hd); - if (h !== undefined) { - let cell = {hd: Primitive_option.valFromOption(h), tl: /* [] */0}; - copyAuxWitFilterMap(p, t, cell); - return cell; - } - _xs = t; - continue; - }; -} - -function partition(l, p) { - if (l === 0) { - return [ - /* [] */0, - /* [] */0 - ]; - } - let h = l.hd; - let nextX = {hd: h, tl: /* [] */0}; - let nextY = {hd: h, tl: /* [] */0}; - let b = p(h); - partitionAux(p, l.tl, nextX, nextY); - if (b) { - return [ - nextX, - nextY.tl - ]; - } else { - return [ - nextX.tl, - nextY - ]; - } -} - -function unzip(xs) { - if (xs === 0) { - return [ - /* [] */0, - /* [] */0 - ]; - } - let match = xs.hd; - let cellX = {hd: match[0], tl: /* [] */0}; - let cellY = {hd: match[1], tl: /* [] */0}; - splitAux(xs.tl, cellX, cellY); - return [ - cellX, - cellY - ]; -} - -function zip(l1, l2) { - if (l1 === 0) { - return /* [] */0; - } - if (l2 === 0) { - return /* [] */0; - } - let cell = {hd: [ - l1.hd, - l2.hd - ], tl: /* [] */0}; - zipAux(l1.tl, l2.tl, cell); - return cell; -} - -let size = length; - -let headExn = headOrThrow; - -let tailExn = tailOrThrow; - -let getExn = getOrThrow; - -let makeByU = makeBy; - -let mapU = map; - -let zipByU = zipBy; - -let mapWithIndexU = mapWithIndex; - -let mapReverseU = mapReverse; - -let forEachU = forEach; - -let forEachWithIndexU = forEachWithIndex; - -let reduceU = reduce; - -let reduceWithIndexU = reduceWithIndex; - -let reduceReverseU = reduceReverse; - -let mapReverse2U = mapReverse2; - -let forEach2U = forEach2; - -let reduce2U = reduce2; - -let reduceReverse2U = reduceReverse2; - -let everyU = every; - -let someU = some; - -let every2U = every2; - -let some2U = some2; - -let cmpU = cmp; - -let eqU = eq; - -let hasU = has; - -let getByU = getBy; - -let keepU = keep; - -let filter = keep; - -let keepWithIndexU = keepWithIndex; - -let filterWithIndex = keepWithIndex; - -let keepMapU = keepMap; - -let partitionU = partition; - -let getAssocU = getAssoc; - -let hasAssocU = hasAssoc; - -let removeAssocU = removeAssoc; - -let setAssocU = setAssoc; - -let sortU = sort; - -exports.length = length; -exports.size = size; -exports.head = head; -exports.headExn = headExn; -exports.headOrThrow = headOrThrow; -exports.tail = tail; -exports.tailExn = tailExn; -exports.tailOrThrow = tailOrThrow; -exports.add = add; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.make = make; -exports.makeByU = makeByU; -exports.makeBy = makeBy; -exports.shuffle = shuffle; -exports.drop = drop; -exports.take = take; -exports.splitAt = splitAt; -exports.concat = concat; -exports.concatMany = concatMany; -exports.reverseConcat = reverseConcat; -exports.flatten = flatten; -exports.mapU = mapU; -exports.map = map; -exports.zip = zip; -exports.zipByU = zipByU; -exports.zipBy = zipBy; -exports.mapWithIndexU = mapWithIndexU; -exports.mapWithIndex = mapWithIndex; -exports.fromArray = fromArray; -exports.toArray = toArray; -exports.reverse = reverse; -exports.mapReverseU = mapReverseU; -exports.mapReverse = mapReverse; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.forEachWithIndexU = forEachWithIndexU; -exports.forEachWithIndex = forEachWithIndex; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.reduceWithIndexU = reduceWithIndexU; -exports.reduceWithIndex = reduceWithIndex; -exports.reduceReverseU = reduceReverseU; -exports.reduceReverse = reduceReverse; -exports.mapReverse2U = mapReverse2U; -exports.mapReverse2 = mapReverse2; -exports.forEach2U = forEach2U; -exports.forEach2 = forEach2; -exports.reduce2U = reduce2U; -exports.reduce2 = reduce2; -exports.reduceReverse2U = reduceReverse2U; -exports.reduceReverse2 = reduceReverse2; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.every2U = every2U; -exports.every2 = every2; -exports.some2U = some2U; -exports.some2 = some2; -exports.cmpByLength = cmpByLength; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.hasU = hasU; -exports.has = has; -exports.getByU = getByU; -exports.getBy = getBy; -exports.keepU = keepU; -exports.keep = keep; -exports.filter = filter; -exports.keepWithIndexU = keepWithIndexU; -exports.keepWithIndex = keepWithIndex; -exports.filterWithIndex = filterWithIndex; -exports.keepMapU = keepMapU; -exports.keepMap = keepMap; -exports.partitionU = partitionU; -exports.partition = partition; -exports.unzip = unzip; -exports.getAssocU = getAssocU; -exports.getAssoc = getAssoc; -exports.hasAssocU = hasAssocU; -exports.hasAssoc = hasAssoc; -exports.removeAssocU = removeAssocU; -exports.removeAssoc = removeAssoc; -exports.setAssocU = setAssocU; -exports.setAssoc = setAssoc; -exports.sortU = sortU; -exports.sort = sort; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Map.cjs b/packages/@rescript/belt/lib/js/src/Belt_Map.cjs deleted file mode 100644 index 5221fd8c74d..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Map.cjs +++ /dev/null @@ -1,325 +0,0 @@ -'use strict'; - -let Belt_MapDict = require("./Belt_MapDict.cjs"); - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_MapDict.fromArray(data, cmp) - }; -} - -function remove(m, x) { - let odata = m.data; - let cmp = m.cmp; - let newData = Belt_MapDict.remove(odata, x, cmp); - if (newData === odata) { - return m; - } else { - return { - cmp: cmp, - data: newData - }; - } -} - -function removeMany(m, x) { - let cmp = m.cmp; - let newData = Belt_MapDict.removeMany(m.data, x, cmp); - return { - cmp: cmp, - data: newData - }; -} - -function set(m, key, d) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_MapDict.set(m.data, key, d, cmp) - }; -} - -function mergeMany(m, e) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_MapDict.mergeMany(m.data, e, cmp) - }; -} - -function update(m, key, f) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_MapDict.update(m.data, key, f, cmp) - }; -} - -function split(m, x) { - let cmp = m.cmp; - let match = Belt_MapDict.split(m.data, x, cmp); - let match$1 = match[0]; - return [ - [ - { - cmp: cmp, - data: match$1[0] - }, - { - cmp: cmp, - data: match$1[1] - } - ], - match[1] - ]; -} - -function merge(s1, s2, f) { - let cmp = s1.cmp; - return { - cmp: cmp, - data: Belt_MapDict.merge(s1.data, s2.data, f, cmp) - }; -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function isEmpty(map) { - return Belt_MapDict.isEmpty(map.data); -} - -function findFirstBy(m, f) { - return Belt_MapDict.findFirstBy(m.data, f); -} - -function forEach(m, f) { - Belt_MapDict.forEach(m.data, f); -} - -function reduce(m, acc, f) { - return Belt_MapDict.reduce(m.data, acc, f); -} - -function every(m, f) { - return Belt_MapDict.every(m.data, f); -} - -function some(m, f) { - return Belt_MapDict.some(m.data, f); -} - -function keep(m, f) { - return { - cmp: m.cmp, - data: Belt_MapDict.keep(m.data, f) - }; -} - -function partition(m, p) { - let cmp = m.cmp; - let match = Belt_MapDict.partition(m.data, p); - return [ - { - cmp: cmp, - data: match[0] - }, - { - cmp: cmp, - data: match[1] - } - ]; -} - -function map(m, f) { - return { - cmp: m.cmp, - data: Belt_MapDict.map(m.data, f) - }; -} - -function mapWithKey(m, f) { - return { - cmp: m.cmp, - data: Belt_MapDict.mapWithKey(m.data, f) - }; -} - -function size(map) { - return Belt_MapDict.size(map.data); -} - -function toList(map) { - return Belt_MapDict.toList(map.data); -} - -function toArray(m) { - return Belt_MapDict.toArray(m.data); -} - -function keysToArray(m) { - return Belt_MapDict.keysToArray(m.data); -} - -function valuesToArray(m) { - return Belt_MapDict.valuesToArray(m.data); -} - -function minKey(m) { - return Belt_MapDict.minKey(m.data); -} - -function maxKey(m) { - return Belt_MapDict.maxKey(m.data); -} - -function minimum(m) { - return Belt_MapDict.minimum(m.data); -} - -function maximum(m) { - return Belt_MapDict.maximum(m.data); -} - -function get(map, x) { - return Belt_MapDict.get(map.data, x, map.cmp); -} - -function getWithDefault(map, x, def) { - return Belt_MapDict.getWithDefault(map.data, x, def, map.cmp); -} - -function getOrThrow(map, x) { - return Belt_MapDict.getOrThrow(map.data, x, map.cmp); -} - -function has(map, x) { - return Belt_MapDict.has(map.data, x, map.cmp); -} - -function checkInvariantInternal(m) { - Belt_MapDict.checkInvariantInternal(m.data); -} - -function eq(m1, m2, veq) { - return Belt_MapDict.eq(m1.data, m2.data, m1.cmp, veq); -} - -function cmp(m1, m2, vcmp) { - return Belt_MapDict.cmp(m1.data, m2.data, m1.cmp, vcmp); -} - -function getData(m) { - return m.data; -} - -function getId(m) { - let cmp = m.cmp; - return { - cmp: cmp - }; -} - -function packIdData(id, data) { - return { - cmp: id.cmp, - data: data - }; -} - -let Int; - -let $$String; - -let Dict; - -let cmpU = cmp; - -let eqU = eq; - -let findFirstByU = findFirstBy; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mergeU = merge; - -let keepU = keep; - -let partitionU = partition; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -exports.Int = Int; -exports.$$String = $$String; -exports.Dict = Dict; -exports.make = make; -exports.isEmpty = isEmpty; -exports.has = has; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.findFirstByU = findFirstByU; -exports.findFirstBy = findFirstBy; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.size = size; -exports.toArray = toArray; -exports.toList = toList; -exports.fromArray = fromArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.remove = remove; -exports.removeMany = removeMany; -exports.set = set; -exports.updateU = updateU; -exports.update = update; -exports.mergeMany = mergeMany; -exports.mergeU = mergeU; -exports.merge = merge; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.split = split; -exports.mapU = mapU; -exports.map = map; -exports.mapWithKeyU = mapWithKeyU; -exports.mapWithKey = mapWithKey; -exports.getData = getData; -exports.getId = getId; -exports.packIdData = packIdData; -exports.checkInvariantInternal = checkInvariantInternal; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MapDict.cjs b/packages/@rescript/belt/lib/js/src/Belt_MapDict.cjs deleted file mode 100644 index ef04c8d6662..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MapDict.cjs +++ /dev/null @@ -1,392 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); - -function set(t, newK, newD, cmp) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(newK, newD); - } - let k = t.k; - let c = cmp(newK, k); - if (c === 0) { - return Belt_internalAVLtree.updateValue(t, newD); - } - let l = t.l; - let r = t.r; - let v = t.v; - if (c < 0) { - return Belt_internalAVLtree.bal(set(l, newK, newD, cmp), k, v, r); - } else { - return Belt_internalAVLtree.bal(l, k, v, set(r, newK, newD, cmp)); - } -} - -function update(t, newK, f, cmp) { - if (t !== undefined) { - let k = t.k; - let c = cmp(newK, k); - if (c === 0) { - let newD = f(Primitive_option.some(t.v)); - if (newD !== undefined) { - return Belt_internalAVLtree.updateValue(t, Primitive_option.valFromOption(newD)); - } - let l = t.l; - let r = t.r; - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - let l$1 = t.l; - let r$2 = t.r; - let v = t.v; - if (c < 0) { - let ll = update(l$1, newK, f, cmp); - if (l$1 === ll) { - return t; - } else { - return Belt_internalAVLtree.bal(ll, k, v, r$2); - } - } - let rr = update(r$2, newK, f, cmp); - if (r$2 === rr) { - return t; - } else { - return Belt_internalAVLtree.bal(l$1, k, v, rr); - } - } - let newD$1 = f(undefined); - if (newD$1 !== undefined) { - return Belt_internalAVLtree.singleton(newK, Primitive_option.valFromOption(newD$1)); - } else { - return t; - } -} - -function removeAux0(n, x, cmp) { - let v = n.k; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - if (c < 0) { - if (l === undefined) { - return n; - } - let ll = removeAux0(l, x, cmp); - if (ll === l) { - return n; - } else { - return Belt_internalAVLtree.bal(ll, v, n.v, r); - } - } - if (r === undefined) { - return n; - } - let rr = removeAux0(r, x, cmp); - if (rr === r) { - return n; - } else { - return Belt_internalAVLtree.bal(l, v, n.v, rr); - } -} - -function remove(n, x, cmp) { - if (n !== undefined) { - return removeAux0(n, x, cmp); - } -} - -function mergeMany(h, arr, cmp) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - v = set(v, match[0], match[1], cmp); - } - return v; -} - -function splitAuxPivot(n, x, pres, cmp) { - let v = n.k; - let d = n.v; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - pres.contents = Primitive_option.some(d); - return [ - l, - r - ]; - } - if (c < 0) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(l, x, pres, cmp); - return [ - match[0], - Belt_internalAVLtree.join(match[1], v, d, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(r, x, pres, cmp); - return [ - Belt_internalAVLtree.join(l, v, d, match$1[0]), - match$1[1] - ]; -} - -function split(n, x, cmp) { - if (n === undefined) { - return [ - [ - undefined, - undefined - ], - undefined - ]; - } - let pres = { - contents: undefined - }; - let v = splitAuxPivot(n, x, pres, cmp); - return [ - v, - pres.contents - ]; -} - -function merge(s1, s2, f, cmp) { - if (s1 === undefined) { - if (s2 !== undefined) { - return Belt_internalAVLtree.keepMap(s2, (k, v) => f(k, undefined, Primitive_option.some(v))); - } else { - return; - } - } - if (s2 === undefined) { - return Belt_internalAVLtree.keepMap(s1, (k, v) => f(k, Primitive_option.some(v), undefined)); - } - if (s1.h >= s2.h) { - let v1 = s1.k; - let d1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let d2 = { - contents: undefined - }; - let match = splitAuxPivot(s2, v1, d2, cmp); - let d2$1 = d2.contents; - let newLeft = merge(l1, match[0], f, cmp); - let newD = f(v1, Primitive_option.some(d1), d2$1); - let newRight = merge(r1, match[1], f, cmp); - return Belt_internalAVLtree.concatOrJoin(newLeft, v1, newD, newRight); - } - let v2 = s2.k; - let d2$2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let d1$1 = { - contents: undefined - }; - let match$1 = splitAuxPivot(s1, v2, d1$1, cmp); - let d1$2 = d1$1.contents; - let newLeft$1 = merge(match$1[0], l2, f, cmp); - let newD$1 = f(v2, d1$2, Primitive_option.some(d2$2)); - let newRight$1 = merge(match$1[1], r2, f, cmp); - return Belt_internalAVLtree.concatOrJoin(newLeft$1, v2, newD$1, newRight$1); -} - -function removeMany(t, keys, cmp) { - let len = keys.length; - if (t !== undefined) { - let _t = t; - let _i = 0; - while (true) { - let i = _i; - let t$1 = _t; - if (i >= len) { - return t$1; - } - let ele = keys[i]; - let u = removeAux0(t$1, ele, cmp); - if (u === undefined) { - return u; - } - _i = i + 1 | 0; - _t = u; - continue; - }; - } -} - -let empty; - -let isEmpty = Belt_internalAVLtree.isEmpty; - -let has = Belt_internalAVLtree.has; - -let cmpU = Belt_internalAVLtree.cmp; - -let cmp = Belt_internalAVLtree.cmp; - -let eqU = Belt_internalAVLtree.eq; - -let eq = Belt_internalAVLtree.eq; - -let findFirstByU = Belt_internalAVLtree.findFirstBy; - -let findFirstBy = Belt_internalAVLtree.findFirstBy; - -let forEachU = Belt_internalAVLtree.forEach; - -let forEach = Belt_internalAVLtree.forEach; - -let reduceU = Belt_internalAVLtree.reduce; - -let reduce = Belt_internalAVLtree.reduce; - -let everyU = Belt_internalAVLtree.every; - -let every = Belt_internalAVLtree.every; - -let someU = Belt_internalAVLtree.some; - -let some = Belt_internalAVLtree.some; - -let size = Belt_internalAVLtree.size; - -let toList = Belt_internalAVLtree.toList; - -let toArray = Belt_internalAVLtree.toArray; - -let fromArray = Belt_internalAVLtree.fromArray; - -let keysToArray = Belt_internalAVLtree.keysToArray; - -let valuesToArray = Belt_internalAVLtree.valuesToArray; - -let minKey = Belt_internalAVLtree.minKey; - -let maxKey = Belt_internalAVLtree.maxKey; - -let minimum = Belt_internalAVLtree.minimum; - -let maximum = Belt_internalAVLtree.maximum; - -let get = Belt_internalAVLtree.get; - -let getWithDefault = Belt_internalAVLtree.getWithDefault; - -let getExn = Belt_internalAVLtree.getOrThrow; - -let getOrThrow = Belt_internalAVLtree.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLtree.checkInvariantInternal; - -let updateU = update; - -let mergeU = merge; - -let keepU = Belt_internalAVLtree.keepShared; - -let keep = Belt_internalAVLtree.keepShared; - -let partitionU = Belt_internalAVLtree.partitionShared; - -let partition = Belt_internalAVLtree.partitionShared; - -let mapU = Belt_internalAVLtree.map; - -let map = Belt_internalAVLtree.map; - -let mapWithKeyU = Belt_internalAVLtree.mapWithKey; - -let mapWithKey = Belt_internalAVLtree.mapWithKey; - -exports.empty = empty; -exports.isEmpty = isEmpty; -exports.has = has; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.findFirstByU = findFirstByU; -exports.findFirstBy = findFirstBy; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.checkInvariantInternal = checkInvariantInternal; -exports.remove = remove; -exports.removeMany = removeMany; -exports.set = set; -exports.updateU = updateU; -exports.update = update; -exports.mergeU = mergeU; -exports.merge = merge; -exports.mergeMany = mergeMany; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.split = split; -exports.mapU = mapU; -exports.map = map; -exports.mapWithKeyU = mapWithKeyU; -exports.mapWithKey = mapWithKey; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MapInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_MapInt.cjs deleted file mode 100644 index efcbb75ea35..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MapInt.cjs +++ /dev/null @@ -1,288 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalMapInt = require("./Belt_internalMapInt.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); - -function set(t, newK, newD) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(newK, newD); - } - let k = t.k; - if (newK === k) { - return Belt_internalAVLtree.updateValue(t, newD); - } - let v = t.v; - if (newK < k) { - return Belt_internalAVLtree.bal(set(t.l, newK, newD), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, set(t.r, newK, newD)); - } -} - -function update(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (x === k) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - return Belt_internalAVLtree.updateValue(t, Primitive_option.valFromOption(data)); - } - let l = t.l; - let r = t.r; - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - let v = t.v; - let l$1 = t.l; - let r$2 = t.r; - if (x < k) { - let ll = update(l$1, x, f); - if (l$1 === ll) { - return t; - } else { - return Belt_internalAVLtree.bal(ll, k, v, r$2); - } - } - let rr = update(r$2, x, f); - if (r$2 === rr) { - return t; - } else { - return Belt_internalAVLtree.bal(l$1, k, v, rr); - } - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function removeAux(n, x) { - let v = n.k; - let l = n.l; - let r = n.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - if (x < v) { - if (l === undefined) { - return n; - } - let ll = removeAux(l, x); - if (ll === l) { - return n; - } else { - return Belt_internalAVLtree.bal(ll, v, n.v, r); - } - } - if (r === undefined) { - return n; - } - let rr = removeAux(r, x); - return Belt_internalAVLtree.bal(l, v, n.v, rr); -} - -function remove(n, x) { - if (n !== undefined) { - return removeAux(n, x); - } -} - -function removeMany(t, keys) { - let len = keys.length; - if (t !== undefined) { - let _t = t; - let _i = 0; - while (true) { - let i = _i; - let t$1 = _t; - if (i >= len) { - return t$1; - } - let ele = keys[i]; - let u = removeAux(t$1, ele); - if (u === undefined) { - return u; - } - _i = i + 1 | 0; - _t = u; - continue; - }; - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - v = set(v, match[0], match[1]); - } - return v; -} - -let empty; - -let isEmpty = Belt_internalAVLtree.isEmpty; - -let has = Belt_internalMapInt.has; - -let cmpU = Belt_internalMapInt.cmp; - -let cmp = Belt_internalMapInt.cmp; - -let eqU = Belt_internalMapInt.eq; - -let eq = Belt_internalMapInt.eq; - -let findFirstByU = Belt_internalAVLtree.findFirstBy; - -let findFirstBy = Belt_internalAVLtree.findFirstBy; - -let forEachU = Belt_internalAVLtree.forEach; - -let forEach = Belt_internalAVLtree.forEach; - -let reduceU = Belt_internalAVLtree.reduce; - -let reduce = Belt_internalAVLtree.reduce; - -let everyU = Belt_internalAVLtree.every; - -let every = Belt_internalAVLtree.every; - -let someU = Belt_internalAVLtree.some; - -let some = Belt_internalAVLtree.some; - -let size = Belt_internalAVLtree.size; - -let toList = Belt_internalAVLtree.toList; - -let toArray = Belt_internalAVLtree.toArray; - -let fromArray = Belt_internalMapInt.fromArray; - -let keysToArray = Belt_internalAVLtree.keysToArray; - -let valuesToArray = Belt_internalAVLtree.valuesToArray; - -let minKey = Belt_internalAVLtree.minKey; - -let maxKey = Belt_internalAVLtree.maxKey; - -let minimum = Belt_internalAVLtree.minimum; - -let maximum = Belt_internalAVLtree.maximum; - -let get = Belt_internalMapInt.get; - -let getWithDefault = Belt_internalMapInt.getWithDefault; - -let getExn = Belt_internalMapInt.getOrThrow; - -let getOrThrow = Belt_internalMapInt.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLtree.checkInvariantInternal; - -let updateU = update; - -let mergeU = Belt_internalMapInt.merge; - -let merge = Belt_internalMapInt.merge; - -let keepU = Belt_internalAVLtree.keepShared; - -let keep = Belt_internalAVLtree.keepShared; - -let partitionU = Belt_internalAVLtree.partitionShared; - -let partition = Belt_internalAVLtree.partitionShared; - -let split = Belt_internalMapInt.split; - -let mapU = Belt_internalAVLtree.map; - -let map = Belt_internalAVLtree.map; - -let mapWithKeyU = Belt_internalAVLtree.mapWithKey; - -let mapWithKey = Belt_internalAVLtree.mapWithKey; - -exports.empty = empty; -exports.isEmpty = isEmpty; -exports.has = has; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.findFirstByU = findFirstByU; -exports.findFirstBy = findFirstBy; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.checkInvariantInternal = checkInvariantInternal; -exports.remove = remove; -exports.removeMany = removeMany; -exports.set = set; -exports.updateU = updateU; -exports.update = update; -exports.mergeU = mergeU; -exports.merge = merge; -exports.mergeMany = mergeMany; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.split = split; -exports.mapU = mapU; -exports.map = map; -exports.mapWithKeyU = mapWithKeyU; -exports.mapWithKey = mapWithKey; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MapString.cjs b/packages/@rescript/belt/lib/js/src/Belt_MapString.cjs deleted file mode 100644 index efd44ddfaf5..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MapString.cjs +++ /dev/null @@ -1,288 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); -let Belt_internalMapString = require("./Belt_internalMapString.cjs"); - -function set(t, newK, newD) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(newK, newD); - } - let k = t.k; - if (newK === k) { - return Belt_internalAVLtree.updateValue(t, newD); - } - let v = t.v; - if (newK < k) { - return Belt_internalAVLtree.bal(set(t.l, newK, newD), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, set(t.r, newK, newD)); - } -} - -function update(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (x === k) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - return Belt_internalAVLtree.updateValue(t, Primitive_option.valFromOption(data)); - } - let l = t.l; - let r = t.r; - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - let v = t.v; - let l$1 = t.l; - let r$2 = t.r; - if (x < k) { - let ll = update(l$1, x, f); - if (l$1 === ll) { - return t; - } else { - return Belt_internalAVLtree.bal(ll, k, v, r$2); - } - } - let rr = update(r$2, x, f); - if (r$2 === rr) { - return t; - } else { - return Belt_internalAVLtree.bal(l$1, k, v, rr); - } - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function removeAux(n, x) { - let v = n.k; - let l = n.l; - let r = n.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); - } - if (x < v) { - if (l === undefined) { - return n; - } - let ll = removeAux(l, x); - if (ll === l) { - return n; - } else { - return Belt_internalAVLtree.bal(ll, v, n.v, r); - } - } - if (r === undefined) { - return n; - } - let rr = removeAux(r, x); - return Belt_internalAVLtree.bal(l, v, n.v, rr); -} - -function remove(n, x) { - if (n !== undefined) { - return removeAux(n, x); - } -} - -function removeMany(t, keys) { - let len = keys.length; - if (t !== undefined) { - let _t = t; - let _i = 0; - while (true) { - let i = _i; - let t$1 = _t; - if (i >= len) { - return t$1; - } - let ele = keys[i]; - let u = removeAux(t$1, ele); - if (u === undefined) { - return u; - } - _i = i + 1 | 0; - _t = u; - continue; - }; - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let match = arr[i]; - v = set(v, match[0], match[1]); - } - return v; -} - -let empty; - -let isEmpty = Belt_internalAVLtree.isEmpty; - -let has = Belt_internalMapString.has; - -let cmpU = Belt_internalMapString.cmp; - -let cmp = Belt_internalMapString.cmp; - -let eqU = Belt_internalMapString.eq; - -let eq = Belt_internalMapString.eq; - -let findFirstByU = Belt_internalAVLtree.findFirstBy; - -let findFirstBy = Belt_internalAVLtree.findFirstBy; - -let forEachU = Belt_internalAVLtree.forEach; - -let forEach = Belt_internalAVLtree.forEach; - -let reduceU = Belt_internalAVLtree.reduce; - -let reduce = Belt_internalAVLtree.reduce; - -let everyU = Belt_internalAVLtree.every; - -let every = Belt_internalAVLtree.every; - -let someU = Belt_internalAVLtree.some; - -let some = Belt_internalAVLtree.some; - -let size = Belt_internalAVLtree.size; - -let toList = Belt_internalAVLtree.toList; - -let toArray = Belt_internalAVLtree.toArray; - -let fromArray = Belt_internalMapString.fromArray; - -let keysToArray = Belt_internalAVLtree.keysToArray; - -let valuesToArray = Belt_internalAVLtree.valuesToArray; - -let minKey = Belt_internalAVLtree.minKey; - -let maxKey = Belt_internalAVLtree.maxKey; - -let minimum = Belt_internalAVLtree.minimum; - -let maximum = Belt_internalAVLtree.maximum; - -let get = Belt_internalMapString.get; - -let getWithDefault = Belt_internalMapString.getWithDefault; - -let getExn = Belt_internalMapString.getOrThrow; - -let getOrThrow = Belt_internalMapString.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLtree.checkInvariantInternal; - -let updateU = update; - -let mergeU = Belt_internalMapString.merge; - -let merge = Belt_internalMapString.merge; - -let keepU = Belt_internalAVLtree.keepShared; - -let keep = Belt_internalAVLtree.keepShared; - -let partitionU = Belt_internalAVLtree.partitionShared; - -let partition = Belt_internalAVLtree.partitionShared; - -let split = Belt_internalMapString.split; - -let mapU = Belt_internalAVLtree.map; - -let map = Belt_internalAVLtree.map; - -let mapWithKeyU = Belt_internalAVLtree.mapWithKey; - -let mapWithKey = Belt_internalAVLtree.mapWithKey; - -exports.empty = empty; -exports.isEmpty = isEmpty; -exports.has = has; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.findFirstByU = findFirstByU; -exports.findFirstBy = findFirstBy; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.checkInvariantInternal = checkInvariantInternal; -exports.remove = remove; -exports.removeMany = removeMany; -exports.set = set; -exports.updateU = updateU; -exports.update = update; -exports.mergeU = mergeU; -exports.merge = merge; -exports.mergeMany = mergeMany; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.split = split; -exports.mapU = mapU; -exports.map = map; -exports.mapWithKeyU = mapWithKeyU; -exports.mapWithKey = mapWithKey; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableMap.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableMap.cjs deleted file mode 100644 index ea90a5cf8d7..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableMap.cjs +++ /dev/null @@ -1,347 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); - -function removeMutateAux(nt, x, cmp) { - let k = nt.k; - let c = cmp(x, k); - if (c === 0) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLtree.balMutate(nt); - } else { - return l; - } - } else if (r !== undefined) { - return r; - } else { - return l; - } - } - if (c < 0) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeMutateAux(l$1, x, cmp); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeMutateAux(r$1, x, cmp); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, k) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = removeMutateAux(oldRoot, k, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeArrayMutateAux(_t, xs, _i, len, cmp) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = removeMutateAux(t, ele, cmp); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - let newRoot = removeArrayMutateAux(oldRoot, xs, 0, len, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function updateDone(t, x, f, cmp) { - if (t !== undefined) { - let k = t.k; - let c = cmp(x, k); - if (c === 0) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - t.v = Primitive_option.valFromOption(data); - return t; - } - let l = t.l; - let r = t.r; - if (l !== undefined) { - if (r !== undefined) { - t.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(t, r); - return Belt_internalAVLtree.balMutate(t); - } else { - return l; - } - } else if (r !== undefined) { - return r; - } else { - return l; - } - } - if (c < 0) { - t.l = updateDone(t.l, x, f, cmp); - } else { - t.r = updateDone(t.r, x, f, cmp); - } - return Belt_internalAVLtree.balMutate(t); - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function update(t, x, f) { - let oldRoot = t.data; - let newRoot = updateDone(oldRoot, x, f, t.cmp); - if (newRoot !== oldRoot) { - t.data = newRoot; - return; - } -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function clear(m) { - m.data = undefined; -} - -function isEmpty(d) { - let x = d.data; - return x === undefined; -} - -function minKey(m) { - return Belt_internalAVLtree.minKey(m.data); -} - -function maxKey(m) { - return Belt_internalAVLtree.maxKey(m.data); -} - -function minimum(m) { - return Belt_internalAVLtree.minimum(m.data); -} - -function maximum(m) { - return Belt_internalAVLtree.maximum(m.data); -} - -function forEach(d, f) { - Belt_internalAVLtree.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLtree.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLtree.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLtree.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLtree.size(d.data); -} - -function toList(d) { - return Belt_internalAVLtree.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLtree.toArray(d.data); -} - -function keysToArray(d) { - return Belt_internalAVLtree.keysToArray(d.data); -} - -function valuesToArray(d) { - return Belt_internalAVLtree.valuesToArray(d.data); -} - -function checkInvariantInternal(d) { - Belt_internalAVLtree.checkInvariantInternal(d.data); -} - -function cmp(m1, m2, cmp$1) { - return Belt_internalAVLtree.cmp(m1.data, m2.data, m1.cmp, cmp$1); -} - -function eq(m1, m2, cmp) { - return Belt_internalAVLtree.eq(m1.data, m2.data, m1.cmp, cmp); -} - -function map(m, f) { - return { - cmp: m.cmp, - data: Belt_internalAVLtree.map(m.data, f) - }; -} - -function mapWithKey(m, f) { - return { - cmp: m.cmp, - data: Belt_internalAVLtree.mapWithKey(m.data, f) - }; -} - -function get(m, x) { - return Belt_internalAVLtree.get(m.data, x, m.cmp); -} - -function getWithDefault(m, x, def) { - return Belt_internalAVLtree.getWithDefault(m.data, x, def, m.cmp); -} - -function getOrThrow(m, x) { - return Belt_internalAVLtree.getOrThrow(m.data, x, m.cmp); -} - -function has(m, x) { - return Belt_internalAVLtree.has(m.data, x, m.cmp); -} - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_internalAVLtree.fromArray(data, cmp) - }; -} - -function set(m, e, v) { - let oldRoot = m.data; - let newRoot = Belt_internalAVLtree.updateMutate(oldRoot, e, v, m.cmp); - if (newRoot !== oldRoot) { - m.data = newRoot; - return; - } -} - -function mergeManyAux(t, xs, cmp) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - let match = xs[i]; - v = Belt_internalAVLtree.updateMutate(v, match[0], match[1], cmp); - } - return v; -} - -function mergeMany(d, xs) { - let oldRoot = d.data; - let newRoot = mergeManyAux(oldRoot, xs, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -let Int; - -let $$String; - -let cmpU = cmp; - -let eqU = eq; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -exports.Int = Int; -exports.$$String = $$String; -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.has = has; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.checkInvariantInternal = checkInvariantInternal; -exports.remove = remove; -exports.removeMany = removeMany; -exports.set = set; -exports.updateU = updateU; -exports.update = update; -exports.mergeMany = mergeMany; -exports.mapU = mapU; -exports.map = map; -exports.mapWithKeyU = mapWithKeyU; -exports.mapWithKey = mapWithKey; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableMapInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableMapInt.cjs deleted file mode 100644 index 2198e278b30..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableMapInt.cjs +++ /dev/null @@ -1,315 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalMapInt = require("./Belt_internalMapInt.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); - -function make() { - return { - data: undefined - }; -} - -function isEmpty(m) { - let x = m.data; - return x === undefined; -} - -function clear(m) { - m.data = undefined; -} - -function minKey(m) { - return Belt_internalAVLtree.minKey(m.data); -} - -function maxKey(m) { - return Belt_internalAVLtree.maxKey(m.data); -} - -function minimum(m) { - return Belt_internalAVLtree.minimum(m.data); -} - -function maximum(m) { - return Belt_internalAVLtree.maximum(m.data); -} - -function set(m, k, v) { - let old_data = m.data; - let v$1 = Belt_internalMapInt.addMutate(old_data, k, v); - if (v$1 !== old_data) { - m.data = v$1; - return; - } -} - -function forEach(d, f) { - Belt_internalAVLtree.forEach(d.data, f); -} - -function map(d, f) { - return { - data: Belt_internalAVLtree.map(d.data, f) - }; -} - -function mapWithKey(d, f) { - return { - data: Belt_internalAVLtree.mapWithKey(d.data, f) - }; -} - -function reduce(d, acc, f) { - return Belt_internalAVLtree.reduce(d.data, acc, f); -} - -function every(d, f) { - return Belt_internalAVLtree.every(d.data, f); -} - -function some(d, f) { - return Belt_internalAVLtree.some(d.data, f); -} - -function size(d) { - return Belt_internalAVLtree.size(d.data); -} - -function toList(d) { - return Belt_internalAVLtree.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLtree.toArray(d.data); -} - -function keysToArray(d) { - return Belt_internalAVLtree.keysToArray(d.data); -} - -function valuesToArray(d) { - return Belt_internalAVLtree.valuesToArray(d.data); -} - -function checkInvariantInternal(d) { - Belt_internalAVLtree.checkInvariantInternal(d.data); -} - -function has(d, v) { - return Belt_internalMapInt.has(d.data, v); -} - -function removeMutateAux(nt, x) { - let k = nt.k; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLtree.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeMutateAux(l$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeMutateAux(r$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = removeMutateAux(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function updateDone(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (k === x) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - t.v = Primitive_option.valFromOption(data); - return t; - } - let l = t.l; - let r = t.r; - if (l !== undefined) { - if (r !== undefined) { - t.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(t, r); - return Belt_internalAVLtree.balMutate(t); - } else { - return l; - } - } else { - return r; - } - } - let l$1 = t.l; - let r$1 = t.r; - if (x < k) { - let ll = updateDone(l$1, x, f); - t.l = ll; - } else { - t.r = updateDone(r$1, x, f); - } - return Belt_internalAVLtree.balMutate(t); - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function update(t, x, f) { - let oldRoot = t.data; - let newRoot = updateDone(oldRoot, x, f); - if (newRoot !== oldRoot) { - t.data = newRoot; - return; - } -} - -function removeArrayMutateAux(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = removeMutateAux(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - let newRoot = removeArrayMutateAux(oldRoot, xs, 0, len); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function fromArray(xs) { - return { - data: Belt_internalMapInt.fromArray(xs) - }; -} - -function cmp(d0, d1, f) { - return Belt_internalMapInt.cmp(d0.data, d1.data, f); -} - -function eq(d0, d1, f) { - return Belt_internalMapInt.eq(d0.data, d1.data, f); -} - -function get(d, x) { - return Belt_internalMapInt.get(d.data, x); -} - -function getWithDefault(d, x, def) { - return Belt_internalMapInt.getWithDefault(d.data, x, def); -} - -function getOrThrow(d, x) { - return Belt_internalMapInt.getOrThrow(d.data, x); -} - -let cmpU = cmp; - -let eqU = eq; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.has = has; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.checkInvariantInternal = checkInvariantInternal; -exports.remove = remove; -exports.removeMany = removeMany; -exports.set = set; -exports.updateU = updateU; -exports.update = update; -exports.mapU = mapU; -exports.map = map; -exports.mapWithKeyU = mapWithKeyU; -exports.mapWithKey = mapWithKey; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableMapString.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableMapString.cjs deleted file mode 100644 index 5cf59381770..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableMapString.cjs +++ /dev/null @@ -1,315 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); -let Belt_internalMapString = require("./Belt_internalMapString.cjs"); - -function make() { - return { - data: undefined - }; -} - -function isEmpty(m) { - let x = m.data; - return x === undefined; -} - -function clear(m) { - m.data = undefined; -} - -function minKey(m) { - return Belt_internalAVLtree.minKey(m.data); -} - -function maxKey(m) { - return Belt_internalAVLtree.maxKey(m.data); -} - -function minimum(m) { - return Belt_internalAVLtree.minimum(m.data); -} - -function maximum(m) { - return Belt_internalAVLtree.maximum(m.data); -} - -function set(m, k, v) { - let old_data = m.data; - let v$1 = Belt_internalMapString.addMutate(old_data, k, v); - if (v$1 !== old_data) { - m.data = v$1; - return; - } -} - -function forEach(d, f) { - Belt_internalAVLtree.forEach(d.data, f); -} - -function map(d, f) { - return { - data: Belt_internalAVLtree.map(d.data, f) - }; -} - -function mapWithKey(d, f) { - return { - data: Belt_internalAVLtree.mapWithKey(d.data, f) - }; -} - -function reduce(d, acc, f) { - return Belt_internalAVLtree.reduce(d.data, acc, f); -} - -function every(d, f) { - return Belt_internalAVLtree.every(d.data, f); -} - -function some(d, f) { - return Belt_internalAVLtree.some(d.data, f); -} - -function size(d) { - return Belt_internalAVLtree.size(d.data); -} - -function toList(d) { - return Belt_internalAVLtree.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLtree.toArray(d.data); -} - -function keysToArray(d) { - return Belt_internalAVLtree.keysToArray(d.data); -} - -function valuesToArray(d) { - return Belt_internalAVLtree.valuesToArray(d.data); -} - -function checkInvariantInternal(d) { - Belt_internalAVLtree.checkInvariantInternal(d.data); -} - -function has(d, v) { - return Belt_internalMapString.has(d.data, v); -} - -function removeMutateAux(nt, x) { - let k = nt.k; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLtree.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeMutateAux(l$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeMutateAux(r$1, x); - return Belt_internalAVLtree.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = removeMutateAux(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function updateDone(t, x, f) { - if (t !== undefined) { - let k = t.k; - if (k === x) { - let data = f(Primitive_option.some(t.v)); - if (data !== undefined) { - t.v = Primitive_option.valFromOption(data); - return t; - } - let l = t.l; - let r = t.r; - if (l !== undefined) { - if (r !== undefined) { - t.r = Belt_internalAVLtree.removeMinAuxWithRootMutate(t, r); - return Belt_internalAVLtree.balMutate(t); - } else { - return l; - } - } else { - return r; - } - } - let l$1 = t.l; - let r$1 = t.r; - if (x < k) { - let ll = updateDone(l$1, x, f); - t.l = ll; - } else { - t.r = updateDone(r$1, x, f); - } - return Belt_internalAVLtree.balMutate(t); - } - let data$1 = f(undefined); - if (data$1 !== undefined) { - return Belt_internalAVLtree.singleton(x, Primitive_option.valFromOption(data$1)); - } else { - return t; - } -} - -function update(t, x, f) { - let oldRoot = t.data; - let newRoot = updateDone(oldRoot, x, f); - if (newRoot !== oldRoot) { - t.data = newRoot; - return; - } -} - -function removeArrayMutateAux(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = removeMutateAux(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - let newRoot = removeArrayMutateAux(oldRoot, xs, 0, len); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function fromArray(xs) { - return { - data: Belt_internalMapString.fromArray(xs) - }; -} - -function cmp(d0, d1, f) { - return Belt_internalMapString.cmp(d0.data, d1.data, f); -} - -function eq(d0, d1, f) { - return Belt_internalMapString.eq(d0.data, d1.data, f); -} - -function get(d, x) { - return Belt_internalMapString.get(d.data, x); -} - -function getWithDefault(d, x, def) { - return Belt_internalMapString.getWithDefault(d.data, x, def); -} - -function getOrThrow(d, x) { - return Belt_internalMapString.getOrThrow(d.data, x); -} - -let cmpU = cmp; - -let eqU = eq; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let getExn = getOrThrow; - -let updateU = update; - -let mapU = map; - -let mapWithKeyU = mapWithKey; - -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.has = has; -exports.cmpU = cmpU; -exports.cmp = cmp; -exports.eqU = eqU; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.fromArray = fromArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.checkInvariantInternal = checkInvariantInternal; -exports.remove = remove; -exports.removeMany = removeMany; -exports.set = set; -exports.updateU = updateU; -exports.update = update; -exports.mapU = mapU; -exports.map = map; -exports.mapWithKeyU = mapWithKeyU; -exports.mapWithKey = mapWithKey; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableQueue.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableQueue.cjs deleted file mode 100644 index 95842f5c257..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableQueue.cjs +++ /dev/null @@ -1,269 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function make() { - return { - length: 0, - first: undefined, - last: undefined - }; -} - -function clear(q) { - q.length = 0; - q.first = undefined; - q.last = undefined; -} - -function add(q, x) { - let cell = { - content: x, - next: undefined - }; - let last = q.last; - if (last !== undefined) { - q.length = q.length + 1 | 0; - last.next = cell; - q.last = cell; - } else { - q.length = 1; - q.first = cell; - q.last = cell; - } -} - -function peek(q) { - let v = q.first; - if (v !== undefined) { - return Primitive_option.some(v.content); - } -} - -function peekOrThrow(q) { - let v = q.first; - if (v !== undefined) { - return v.content; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function pop(q) { - let x = q.first; - if (x === undefined) { - return; - } - let next = x.next; - if (next === undefined) { - clear(q); - return Primitive_option.some(x.content); - } else { - q.length = q.length - 1 | 0; - q.first = next; - return Primitive_option.some(x.content); - } -} - -function popOrThrow(q) { - let x = q.first; - if (x !== undefined) { - let next = x.next; - if (next === undefined) { - clear(q); - return x.content; - } else { - q.length = q.length - 1 | 0; - q.first = next; - return x.content; - } - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function copy(q) { - let qRes = { - length: q.length, - first: undefined, - last: undefined - }; - let _prev; - let _cell = q.first; - while (true) { - let cell = _cell; - let prev = _prev; - if (cell !== undefined) { - let content = cell.content; - let res = { - content: content, - next: undefined - }; - if (prev !== undefined) { - prev.next = res; - } else { - qRes.first = res; - } - _cell = cell.next; - _prev = res; - continue; - } - qRes.last = prev; - return qRes; - }; -} - -function map(q, f) { - let qRes = { - length: q.length, - first: undefined, - last: undefined - }; - let _prev; - let _cell = q.first; - while (true) { - let cell = _cell; - let prev = _prev; - if (cell !== undefined) { - let content = f(cell.content); - let res = { - content: content, - next: undefined - }; - if (prev !== undefined) { - prev.next = res; - } else { - qRes.first = res; - } - _cell = cell.next; - _prev = res; - continue; - } - qRes.last = prev; - return qRes; - }; -} - -function isEmpty(q) { - return q.length === 0; -} - -function size(q) { - return q.length; -} - -function forEach(q, f) { - let _cell = q.first; - while (true) { - let cell = _cell; - if (cell === undefined) { - return; - } - f(cell.content); - _cell = cell.next; - continue; - }; -} - -function reduce(q, accu, f) { - let _accu = accu; - let _cell = q.first; - while (true) { - let cell = _cell; - let accu$1 = _accu; - if (cell === undefined) { - return accu$1; - } - let accu$2 = f(accu$1, cell.content); - _cell = cell.next; - _accu = accu$2; - continue; - }; -} - -function transfer(q1, q2) { - if (q1.length <= 0) { - return; - } - let l = q2.last; - if (l !== undefined) { - q2.length = q2.length + q1.length | 0; - l.next = q1.first; - q2.last = q1.last; - return clear(q1); - } else { - q2.length = q1.length; - q2.first = q1.first; - q2.last = q1.last; - return clear(q1); - } -} - -function fillAux(_i, arr, _cell) { - while (true) { - let cell = _cell; - let i = _i; - if (cell === undefined) { - return; - } - arr[i] = cell.content; - _cell = cell.next; - _i = i + 1 | 0; - continue; - }; -} - -function toArray(x) { - let v = new Array(x.length); - fillAux(0, v, x.first); - return v; -} - -function fromArray(arr) { - let q = { - length: 0, - first: undefined, - last: undefined - }; - for (let i = 0, i_finish = arr.length; i < i_finish; ++i) { - add(q, arr[i]); - } - return q; -} - -let peekExn = peekOrThrow; - -let popExn = popOrThrow; - -let mapU = map; - -let forEachU = forEach; - -let reduceU = reduce; - -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -exports.fromArray = fromArray; -exports.add = add; -exports.peek = peek; -exports.peekExn = peekExn; -exports.peekOrThrow = peekOrThrow; -exports.pop = pop; -exports.popExn = popExn; -exports.popOrThrow = popOrThrow; -exports.copy = copy; -exports.size = size; -exports.mapU = mapU; -exports.map = map; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.transfer = transfer; -exports.toArray = toArray; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableSet.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableSet.cjs deleted file mode 100644 index 9227552a6c1..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableSet.cjs +++ /dev/null @@ -1,510 +0,0 @@ -'use strict'; - -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Belt_SortArray = require("./Belt_SortArray.cjs"); -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); - -function remove0(nt, x, cmp) { - let k = nt.v; - let c = cmp(x, k); - if (c === 0) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (c < 0) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = remove0(l$1, x, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = remove0(r$1, x, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = remove0(oldRoot, v, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeMany0(_t, xs, _i, len, cmp) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = remove0(t, ele, cmp); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - d.data = removeMany0(oldRoot, xs, 0, len, d.cmp); -} - -function removeCheck0(nt, x, removed, cmp) { - let k = nt.v; - let c = cmp(x, k); - if (c === 0) { - removed.contents = true; - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (c < 0) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeCheck0(l$1, x, removed, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeCheck0(r$1, x, removed, cmp); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function removeCheck(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return false; - } - let removed = { - contents: false - }; - let newRoot = removeCheck0(oldRoot, v, removed, d.cmp); - if (newRoot !== oldRoot) { - d.data = newRoot; - } - return removed.contents; -} - -function addCheck0(t, x, added, cmp) { - if (t !== undefined) { - let k = t.v; - let c = cmp(x, k); - if (c === 0) { - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = addCheck0(l, x, added, cmp); - t.l = ll; - } else { - t.r = addCheck0(r, x, added, cmp); - } - return Belt_internalAVLset.balMutate(t); - } - added.contents = true; - return Belt_internalAVLset.singleton(x); -} - -function addCheck(m, e) { - let oldRoot = m.data; - let added = { - contents: false - }; - let newRoot = addCheck0(oldRoot, e, added, m.cmp); - if (newRoot !== oldRoot) { - m.data = newRoot; - } - return added.contents; -} - -function add(m, e) { - let oldRoot = m.data; - let newRoot = Belt_internalAVLset.addMutate(m.cmp, oldRoot, e); - if (newRoot !== oldRoot) { - m.data = newRoot; - return; - } -} - -function addArrayMutate(t, xs, cmp) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - v = Belt_internalAVLset.addMutate(cmp, v, xs[i]); - } - return v; -} - -function mergeMany(d, xs) { - d.data = addArrayMutate(d.data, xs, d.cmp); -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function isEmpty(d) { - let n = d.data; - return n === undefined; -} - -function minimum(d) { - return Belt_internalAVLset.minimum(d.data); -} - -function maximum(d) { - return Belt_internalAVLset.maximum(d.data); -} - -function forEach(d, f) { - Belt_internalAVLset.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLset.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLset.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLset.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLset.size(d.data); -} - -function toList(d) { - return Belt_internalAVLset.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLset.toArray(d.data); -} - -function fromSortedArrayUnsafe(xs, id) { - return { - cmp: id.cmp, - data: Belt_internalAVLset.fromSortedArrayUnsafe(xs) - }; -} - -function checkInvariantInternal(d) { - Belt_internalAVLset.checkInvariantInternal(d.data); -} - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_internalAVLset.fromArray(data, cmp) - }; -} - -function cmp(d0, d1) { - return Belt_internalAVLset.cmp(d0.data, d1.data, d0.cmp); -} - -function eq(d0, d1) { - return Belt_internalAVLset.eq(d0.data, d1.data, d0.cmp); -} - -function get(d, x) { - return Belt_internalAVLset.get(d.data, x, d.cmp); -} - -function getOrThrow(d, x) { - return Belt_internalAVLset.getOrThrow(d.data, x, d.cmp); -} - -function split(d, key) { - let arr = Belt_internalAVLset.toArray(d.data); - let cmp = d.cmp; - let i = Belt_SortArray.binarySearchBy(arr, key, cmp); - let len = arr.length; - if (i >= 0) { - return [ - [ - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, i) - }, - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, i + 1 | 0, (len - i | 0) - 1 | 0) - } - ], - true - ]; - } - let next = (-i | 0) - 1 | 0; - return [ - [ - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, next) - }, - { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(arr, next, len - next | 0) - } - ], - false - ]; -} - -function keep(d, p) { - return { - cmp: d.cmp, - data: Belt_internalAVLset.keepCopy(d.data, p) - }; -} - -function partition(d, p) { - let cmp = d.cmp; - let match = Belt_internalAVLset.partitionCopy(d.data, p); - return [ - { - cmp: cmp, - data: match[0] - }, - { - cmp: cmp, - data: match[1] - } - ]; -} - -function subset(a, b) { - return Belt_internalAVLset.subset(a.data, b.data, a.cmp); -} - -function intersect(a, b) { - let cmp = a.cmp; - let match = a.data; - let match$1 = b.data; - if (match === undefined) { - return { - cmp: cmp, - data: undefined - }; - } - if (match$1 === undefined) { - return { - cmp: cmp, - data: undefined - }; - } - let sizea = Belt_internalAVLset.lengthNode(match); - let sizeb = Belt_internalAVLset.lengthNode(match$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(match, 0, tmp); - Belt_internalAVLset.fillArray(match$1, sizea, tmp); - if (cmp(tmp[sizea - 1 | 0], tmp[sizea]) < 0 || cmp(tmp[totalSize - 1 | 0], tmp[0]) < 0) { - return { - cmp: cmp, - data: undefined - }; - } - let tmp2 = new Array(Primitive_int.min(sizea, sizeb)); - let k = Belt_SortArray.intersect(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0, cmp); - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function diff(a, b) { - let cmp = a.cmp; - let dataa = a.data; - let match = b.data; - if (dataa === undefined) { - return { - cmp: cmp, - data: undefined - }; - } - if (match === undefined) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(dataa) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa); - let sizeb = Belt_internalAVLset.lengthNode(match); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa, 0, tmp); - Belt_internalAVLset.fillArray(match, sizea, tmp); - if (cmp(tmp[sizea - 1 | 0], tmp[sizea]) < 0 || cmp(tmp[totalSize - 1 | 0], tmp[0]) < 0) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(dataa) - }; - } - let tmp2 = new Array(sizea); - let k = Belt_SortArray.diff(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0, cmp); - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function union(a, b) { - let cmp = a.cmp; - let dataa = a.data; - let datab = b.data; - if (dataa === undefined) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(datab) - }; - } - if (datab === undefined) { - return { - cmp: cmp, - data: Belt_internalAVLset.copy(dataa) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa); - let sizeb = Belt_internalAVLset.lengthNode(datab); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa, 0, tmp); - Belt_internalAVLset.fillArray(datab, sizea, tmp); - if (cmp(tmp[sizea - 1 | 0], tmp[sizea]) < 0) { - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp, 0, totalSize) - }; - } - let tmp2 = new Array(totalSize); - let k = Belt_SortArray.union(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0, cmp); - return { - cmp: cmp, - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function has(d, x) { - return Belt_internalAVLset.has(d.data, x, d.cmp); -} - -function copy(d) { - return { - cmp: d.cmp, - data: Belt_internalAVLset.copy(d.data) - }; -} - -let Int; - -let $$String; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -exports.Int = Int; -exports.$$String = $$String; -exports.make = make; -exports.fromArray = fromArray; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.copy = copy; -exports.isEmpty = isEmpty; -exports.has = has; -exports.add = add; -exports.addCheck = addCheck; -exports.mergeMany = mergeMany; -exports.remove = remove; -exports.removeCheck = removeCheck; -exports.removeMany = removeMany; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -exports.subset = subset; -exports.cmp = cmp; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.split = split; -exports.checkInvariantInternal = checkInvariantInternal; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableSetInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableSetInt.cjs deleted file mode 100644 index 93e86c0b314..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableSetInt.cjs +++ /dev/null @@ -1,473 +0,0 @@ -'use strict'; - -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Belt_SortArrayInt = require("./Belt_SortArrayInt.cjs"); -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); -let Belt_internalSetInt = require("./Belt_internalSetInt.cjs"); - -function remove0(nt, x) { - let k = nt.v; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = remove0(l$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = remove0(r$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = remove0(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeMany0(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = remove0(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - d.data = removeMany0(oldRoot, xs, 0, len); -} - -function removeCheck0(nt, x, removed) { - let k = nt.v; - if (x === k) { - removed.contents = true; - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeCheck0(l$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeCheck0(r$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function removeCheck(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return false; - } - let removed = { - contents: false - }; - let newRoot = removeCheck0(oldRoot, v, removed); - if (newRoot !== oldRoot) { - d.data = newRoot; - } - return removed.contents; -} - -function addCheck0(t, x, added) { - if (t !== undefined) { - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addCheck0(l, x, added); - t.l = ll; - } else { - t.r = addCheck0(r, x, added); - } - return Belt_internalAVLset.balMutate(t); - } - added.contents = true; - return Belt_internalAVLset.singleton(x); -} - -function addCheck(m, e) { - let oldRoot = m.data; - let added = { - contents: false - }; - let newRoot = addCheck0(oldRoot, e, added); - if (newRoot !== oldRoot) { - m.data = newRoot; - } - return added.contents; -} - -function add(d, k) { - let oldRoot = d.data; - let v = Belt_internalSetInt.addMutate(oldRoot, k); - if (v !== oldRoot) { - d.data = v; - return; - } -} - -function addArrayMutate(t, xs) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - v = Belt_internalSetInt.addMutate(v, xs[i]); - } - return v; -} - -function mergeMany(d, arr) { - d.data = addArrayMutate(d.data, arr); -} - -function make() { - return { - data: undefined - }; -} - -function isEmpty(d) { - let n = d.data; - return n === undefined; -} - -function minimum(d) { - return Belt_internalAVLset.minimum(d.data); -} - -function maximum(d) { - return Belt_internalAVLset.maximum(d.data); -} - -function forEach(d, f) { - Belt_internalAVLset.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLset.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLset.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLset.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLset.size(d.data); -} - -function toList(d) { - return Belt_internalAVLset.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLset.toArray(d.data); -} - -function fromSortedArrayUnsafe(xs) { - return { - data: Belt_internalAVLset.fromSortedArrayUnsafe(xs) - }; -} - -function checkInvariantInternal(d) { - Belt_internalAVLset.checkInvariantInternal(d.data); -} - -function fromArray(xs) { - return { - data: Belt_internalSetInt.fromArray(xs) - }; -} - -function cmp(d0, d1) { - return Belt_internalSetInt.cmp(d0.data, d1.data); -} - -function eq(d0, d1) { - return Belt_internalSetInt.eq(d0.data, d1.data); -} - -function get(d, x) { - return Belt_internalSetInt.get(d.data, x); -} - -function getOrThrow(d, x) { - return Belt_internalSetInt.getOrThrow(d.data, x); -} - -function split(d, key) { - let arr = Belt_internalAVLset.toArray(d.data); - let i = Belt_SortArrayInt.binarySearch(arr, key); - let len = arr.length; - if (i >= 0) { - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, i) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, i + 1 | 0, (len - i | 0) - 1 | 0) - } - ], - true - ]; - } - let next = (-i | 0) - 1 | 0; - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, next) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, next, len - next | 0) - } - ], - false - ]; -} - -function keep(d, p) { - return { - data: Belt_internalAVLset.keepCopy(d.data, p) - }; -} - -function partition(d, p) { - let match = Belt_internalAVLset.partitionCopy(d.data, p); - return [ - { - data: match[0] - }, - { - data: match[1] - } - ]; -} - -function subset(a, b) { - return Belt_internalSetInt.subset(a.data, b.data); -} - -function intersect(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: undefined - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: undefined - }; - } - let tmp2 = new Array(Primitive_int.min(sizea, sizeb)); - let k = Belt_SortArrayInt.intersect(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function diff(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let tmp2 = new Array(sizea); - let k = Belt_SortArrayInt.diff(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function union(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: Belt_internalAVLset.copy(datab$1) - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea]) { - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp, 0, totalSize) - }; - } - let tmp2 = new Array(totalSize); - let k = Belt_SortArrayInt.union(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function has(d, x) { - return Belt_internalSetInt.has(d.data, x); -} - -function copy(d) { - return { - data: Belt_internalAVLset.copy(d.data) - }; -} - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -exports.make = make; -exports.fromArray = fromArray; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.copy = copy; -exports.isEmpty = isEmpty; -exports.has = has; -exports.add = add; -exports.addCheck = addCheck; -exports.mergeMany = mergeMany; -exports.remove = remove; -exports.removeCheck = removeCheck; -exports.removeMany = removeMany; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -exports.subset = subset; -exports.cmp = cmp; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.split = split; -exports.checkInvariantInternal = checkInvariantInternal; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableSetString.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableSetString.cjs deleted file mode 100644 index e2ca6a3320b..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableSetString.cjs +++ /dev/null @@ -1,473 +0,0 @@ -'use strict'; - -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); -let Belt_SortArrayString = require("./Belt_SortArrayString.cjs"); -let Belt_internalSetString = require("./Belt_internalSetString.cjs"); - -function remove0(nt, x) { - let k = nt.v; - if (x === k) { - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = remove0(l$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = remove0(r$1, x); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function remove(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let newRoot = remove0(oldRoot, v); - if (newRoot !== oldRoot) { - d.data = newRoot; - return; - } -} - -function removeMany0(_t, xs, _i, len) { - while (true) { - let i = _i; - let t = _t; - if (i >= len) { - return t; - } - let ele = xs[i]; - let u = remove0(t, ele); - if (u === undefined) { - return; - } - _i = i + 1 | 0; - _t = u; - continue; - }; -} - -function removeMany(d, xs) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return; - } - let len = xs.length; - d.data = removeMany0(oldRoot, xs, 0, len); -} - -function removeCheck0(nt, x, removed) { - let k = nt.v; - if (x === k) { - removed.contents = true; - let l = nt.l; - let r = nt.r; - if (l !== undefined) { - if (r !== undefined) { - nt.r = Belt_internalAVLset.removeMinAuxWithRootMutate(nt, r); - return Belt_internalAVLset.balMutate(nt); - } else { - return l; - } - } else { - return r; - } - } - if (x < k) { - let l$1 = nt.l; - if (l$1 !== undefined) { - nt.l = removeCheck0(l$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } - } - let r$1 = nt.r; - if (r$1 !== undefined) { - nt.r = removeCheck0(r$1, x, removed); - return Belt_internalAVLset.balMutate(nt); - } else { - return nt; - } -} - -function removeCheck(d, v) { - let oldRoot = d.data; - if (oldRoot === undefined) { - return false; - } - let removed = { - contents: false - }; - let newRoot = removeCheck0(oldRoot, v, removed); - if (newRoot !== oldRoot) { - d.data = newRoot; - } - return removed.contents; -} - -function addCheck0(t, x, added) { - if (t !== undefined) { - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addCheck0(l, x, added); - t.l = ll; - } else { - t.r = addCheck0(r, x, added); - } - return Belt_internalAVLset.balMutate(t); - } - added.contents = true; - return Belt_internalAVLset.singleton(x); -} - -function addCheck(m, e) { - let oldRoot = m.data; - let added = { - contents: false - }; - let newRoot = addCheck0(oldRoot, e, added); - if (newRoot !== oldRoot) { - m.data = newRoot; - } - return added.contents; -} - -function add(d, k) { - let oldRoot = d.data; - let v = Belt_internalSetString.addMutate(oldRoot, k); - if (v !== oldRoot) { - d.data = v; - return; - } -} - -function addArrayMutate(t, xs) { - let v = t; - for (let i = 0, i_finish = xs.length; i < i_finish; ++i) { - v = Belt_internalSetString.addMutate(v, xs[i]); - } - return v; -} - -function mergeMany(d, arr) { - d.data = addArrayMutate(d.data, arr); -} - -function make() { - return { - data: undefined - }; -} - -function isEmpty(d) { - let n = d.data; - return n === undefined; -} - -function minimum(d) { - return Belt_internalAVLset.minimum(d.data); -} - -function maximum(d) { - return Belt_internalAVLset.maximum(d.data); -} - -function forEach(d, f) { - Belt_internalAVLset.forEach(d.data, f); -} - -function reduce(d, acc, cb) { - return Belt_internalAVLset.reduce(d.data, acc, cb); -} - -function every(d, p) { - return Belt_internalAVLset.every(d.data, p); -} - -function some(d, p) { - return Belt_internalAVLset.some(d.data, p); -} - -function size(d) { - return Belt_internalAVLset.size(d.data); -} - -function toList(d) { - return Belt_internalAVLset.toList(d.data); -} - -function toArray(d) { - return Belt_internalAVLset.toArray(d.data); -} - -function fromSortedArrayUnsafe(xs) { - return { - data: Belt_internalAVLset.fromSortedArrayUnsafe(xs) - }; -} - -function checkInvariantInternal(d) { - Belt_internalAVLset.checkInvariantInternal(d.data); -} - -function fromArray(xs) { - return { - data: Belt_internalSetString.fromArray(xs) - }; -} - -function cmp(d0, d1) { - return Belt_internalSetString.cmp(d0.data, d1.data); -} - -function eq(d0, d1) { - return Belt_internalSetString.eq(d0.data, d1.data); -} - -function get(d, x) { - return Belt_internalSetString.get(d.data, x); -} - -function getOrThrow(d, x) { - return Belt_internalSetString.getOrThrow(d.data, x); -} - -function split(d, key) { - let arr = Belt_internalAVLset.toArray(d.data); - let i = Belt_SortArrayString.binarySearch(arr, key); - let len = arr.length; - if (i >= 0) { - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, i) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, i + 1 | 0, (len - i | 0) - 1 | 0) - } - ], - true - ]; - } - let next = (-i | 0) - 1 | 0; - return [ - [ - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, 0, next) - }, - { - data: Belt_internalAVLset.fromSortedArrayAux(arr, next, len - next | 0) - } - ], - false - ]; -} - -function keep(d, p) { - return { - data: Belt_internalAVLset.keepCopy(d.data, p) - }; -} - -function partition(d, p) { - let match = Belt_internalAVLset.partitionCopy(d.data, p); - return [ - { - data: match[0] - }, - { - data: match[1] - } - ]; -} - -function subset(a, b) { - return Belt_internalSetString.subset(a.data, b.data); -} - -function intersect(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: undefined - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: undefined - }; - } - let tmp2 = new Array(Primitive_int.min(sizea, sizeb)); - let k = Belt_SortArrayString.intersect(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function diff(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: undefined - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea] || tmp[totalSize - 1 | 0] < tmp[0]) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let tmp2 = new Array(sizea); - let k = Belt_SortArrayString.diff(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function union(dataa, datab) { - let dataa$1 = dataa.data; - let datab$1 = datab.data; - if (dataa$1 === undefined) { - return { - data: Belt_internalAVLset.copy(datab$1) - }; - } - if (datab$1 === undefined) { - return { - data: Belt_internalAVLset.copy(dataa$1) - }; - } - let sizea = Belt_internalAVLset.lengthNode(dataa$1); - let sizeb = Belt_internalAVLset.lengthNode(datab$1); - let totalSize = sizea + sizeb | 0; - let tmp = new Array(totalSize); - Belt_internalAVLset.fillArray(dataa$1, 0, tmp); - Belt_internalAVLset.fillArray(datab$1, sizea, tmp); - if (tmp[sizea - 1 | 0] < tmp[sizea]) { - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp, 0, totalSize) - }; - } - let tmp2 = new Array(totalSize); - let k = Belt_SortArrayString.union(tmp, 0, sizea, tmp, sizea, sizeb, tmp2, 0); - return { - data: Belt_internalAVLset.fromSortedArrayAux(tmp2, 0, k) - }; -} - -function has(d, x) { - return Belt_internalSetString.has(d.data, x); -} - -function copy(d) { - return { - data: Belt_internalAVLset.copy(d.data) - }; -} - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -exports.make = make; -exports.fromArray = fromArray; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.copy = copy; -exports.isEmpty = isEmpty; -exports.has = has; -exports.add = add; -exports.addCheck = addCheck; -exports.mergeMany = mergeMany; -exports.remove = remove; -exports.removeCheck = removeCheck; -exports.removeMany = removeMany; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -exports.subset = subset; -exports.cmp = cmp; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.split = split; -exports.checkInvariantInternal = checkInvariantInternal; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_MutableStack.cjs b/packages/@rescript/belt/lib/js/src/Belt_MutableStack.cjs deleted file mode 100644 index 79a188cf18f..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_MutableStack.cjs +++ /dev/null @@ -1,122 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function make() { - return { - root: undefined - }; -} - -function clear(s) { - s.root = undefined; -} - -function copy(s) { - return { - root: s.root - }; -} - -function push(s, x) { - s.root = { - head: x, - tail: s.root - }; -} - -function top(s) { - let x = s.root; - if (x !== undefined) { - return Primitive_option.some(x.head); - } -} - -function isEmpty(s) { - return s.root === undefined; -} - -function pop(s) { - let x = s.root; - if (x !== undefined) { - s.root = x.tail; - return Primitive_option.some(x.head); - } -} - -function popOrThrow(s) { - let x = s.root; - if (x !== undefined) { - s.root = x.tail; - return x.head; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function size(s) { - let x = s.root; - if (x !== undefined) { - let _x = x; - let _acc = 0; - while (true) { - let acc = _acc; - let x$1 = _x; - let x$2 = x$1.tail; - if (x$2 === undefined) { - return acc + 1 | 0; - } - _acc = acc + 1 | 0; - _x = x$2; - continue; - }; - } else { - return 0; - } -} - -function forEach(s, f) { - let _s = s.root; - while (true) { - let s$1 = _s; - if (s$1 === undefined) { - return; - } - f(s$1.head); - _s = s$1.tail; - continue; - }; -} - -function dynamicPopIter(s, f) { - while (true) { - let match = s.root; - if (match === undefined) { - return; - } - s.root = match.tail; - f(match.head); - continue; - }; -} - -let forEachU = forEach; - -let dynamicPopIterU = dynamicPopIter; - -exports.make = make; -exports.clear = clear; -exports.copy = copy; -exports.push = push; -exports.pop = pop; -exports.popOrThrow = popOrThrow; -exports.top = top; -exports.isEmpty = isEmpty; -exports.size = size; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.dynamicPopIterU = dynamicPopIterU; -exports.dynamicPopIter = dynamicPopIter; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Option.cjs b/packages/@rescript/belt/lib/js/src/Belt_Option.cjs deleted file mode 100644 index 7ba158656cd..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Option.cjs +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; - -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function keep(opt, p) { - if (opt !== undefined && p(Primitive_option.valFromOption(opt))) { - return opt; - } -} - -function forEach(opt, f) { - if (opt !== undefined) { - return f(Primitive_option.valFromOption(opt)); - } -} - -function getOrThrow(x) { - if (x !== undefined) { - return Primitive_option.valFromOption(x); - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function mapWithDefault(opt, $$default, f) { - if (opt !== undefined) { - return f(Primitive_option.valFromOption(opt)); - } else { - return $$default; - } -} - -function map(opt, f) { - if (opt !== undefined) { - return Primitive_option.some(f(Primitive_option.valFromOption(opt))); - } -} - -function flatMap(opt, f) { - if (opt !== undefined) { - return f(Primitive_option.valFromOption(opt)); - } -} - -function getWithDefault(opt, $$default) { - if (opt !== undefined) { - return Primitive_option.valFromOption(opt); - } else { - return $$default; - } -} - -function orElse(opt, other) { - if (opt !== undefined) { - return opt; - } else { - return other; - } -} - -function isSome(x) { - return x !== undefined; -} - -function isNone(x) { - return x === undefined; -} - -function eq(a, b, f) { - if (a !== undefined) { - if (b !== undefined) { - return f(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); - } else { - return false; - } - } else { - return b === undefined; - } -} - -function cmp(a, b, f) { - if (a !== undefined) { - if (b !== undefined) { - return f(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); - } else { - return 1; - } - } else if (b !== undefined) { - return -1; - } else { - return 0; - } -} - -let keepU = keep; - -let forEachU = forEach; - -let getExn = getOrThrow; - -let mapWithDefaultU = mapWithDefault; - -let mapU = map; - -let flatMapU = flatMap; - -let eqU = eq; - -let cmpU = cmp; - -exports.keepU = keepU; -exports.keep = keep; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.mapWithDefaultU = mapWithDefaultU; -exports.mapWithDefault = mapWithDefault; -exports.mapU = mapU; -exports.map = map; -exports.flatMapU = flatMapU; -exports.flatMap = flatMap; -exports.getWithDefault = getWithDefault; -exports.orElse = orElse; -exports.isSome = isSome; -exports.isNone = isNone; -exports.eqU = eqU; -exports.eq = eq; -exports.cmpU = cmpU; -exports.cmp = cmp; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Range.cjs b/packages/@rescript/belt/lib/js/src/Belt_Range.cjs deleted file mode 100644 index d7b7278b904..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Range.cjs +++ /dev/null @@ -1,96 +0,0 @@ -'use strict'; - - -function forEach(s, f, action) { - for (let i = s; i <= f; ++i) { - action(i); - } -} - -function every(_s, f, p) { - while (true) { - let s = _s; - if (s > f) { - return true; - } - if (!p(s)) { - return false; - } - _s = s + 1 | 0; - continue; - }; -} - -function everyBy(s, f, step, p) { - if (step > 0) { - let _s = s; - while (true) { - let s$1 = _s; - if (s$1 > f) { - return true; - } - if (!p(s$1)) { - return false; - } - _s = s$1 + step | 0; - continue; - }; - } else { - return true; - } -} - -function some(_s, f, p) { - while (true) { - let s = _s; - if (s > f) { - return false; - } - if (p(s)) { - return true; - } - _s = s + 1 | 0; - continue; - }; -} - -function someBy(s, f, step, p) { - if (step > 0) { - let _s = s; - while (true) { - let s$1 = _s; - if (s$1 > f) { - return false; - } - if (p(s$1)) { - return true; - } - _s = s$1 + step | 0; - continue; - }; - } else { - return false; - } -} - -let forEachU = forEach; - -let everyU = every; - -let everyByU = everyBy; - -let someU = some; - -let someByU = someBy; - -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.everyU = everyU; -exports.every = every; -exports.everyByU = everyByU; -exports.everyBy = everyBy; -exports.someU = someU; -exports.some = some; -exports.someByU = someByU; -exports.someBy = someBy; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Result.cjs b/packages/@rescript/belt/lib/js/src/Belt_Result.cjs deleted file mode 100644 index 004803e805a..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Result.cjs +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - - -function getOrThrow(x) { - if (x.TAG === "Ok") { - return x._0; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -function mapWithDefault(opt, $$default, f) { - if (opt.TAG === "Ok") { - return f(opt._0); - } else { - return $$default; - } -} - -function map(opt, f) { - if (opt.TAG === "Ok") { - return { - TAG: "Ok", - _0: f(opt._0) - }; - } else { - return { - TAG: "Error", - _0: opt._0 - }; - } -} - -function flatMap(opt, f) { - if (opt.TAG === "Ok") { - return f(opt._0); - } else { - return { - TAG: "Error", - _0: opt._0 - }; - } -} - -function getWithDefault(opt, $$default) { - if (opt.TAG === "Ok") { - return opt._0; - } else { - return $$default; - } -} - -function isOk(x) { - return x.TAG === "Ok"; -} - -function isError(x) { - return x.TAG !== "Ok"; -} - -function eq(a, b, f) { - if (a.TAG === "Ok") { - if (b.TAG === "Ok") { - return f(a._0, b._0); - } else { - return false; - } - } else { - return b.TAG !== "Ok"; - } -} - -function cmp(a, b, f) { - if (a.TAG === "Ok") { - if (b.TAG === "Ok") { - return f(a._0, b._0); - } else { - return 1; - } - } else if (b.TAG === "Ok") { - return -1; - } else { - return 0; - } -} - -let getExn = getOrThrow; - -let mapWithDefaultU = mapWithDefault; - -let mapU = map; - -let flatMapU = flatMap; - -let eqU = eq; - -let cmpU = cmp; - -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.mapWithDefaultU = mapWithDefaultU; -exports.mapWithDefault = mapWithDefault; -exports.mapU = mapU; -exports.map = map; -exports.flatMapU = flatMapU; -exports.flatMap = flatMap; -exports.getWithDefault = getWithDefault; -exports.isOk = isOk; -exports.isError = isError; -exports.eqU = eqU; -exports.eq = eq; -exports.cmpU = cmpU; -exports.cmp = cmp; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_Set.cjs b/packages/@rescript/belt/lib/js/src/Belt_Set.cjs deleted file mode 100644 index 4211817ed5e..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_Set.cjs +++ /dev/null @@ -1,287 +0,0 @@ -'use strict'; - -let Belt_SetDict = require("./Belt_SetDict.cjs"); - -function fromArray(data, id) { - let cmp = id.cmp; - return { - cmp: cmp, - data: Belt_SetDict.fromArray(data, cmp) - }; -} - -function remove(m, e) { - let data = m.data; - let cmp = m.cmp; - let newData = Belt_SetDict.remove(data, e, cmp); - if (newData === data) { - return m; - } else { - return { - cmp: cmp, - data: newData - }; - } -} - -function add(m, e) { - let data = m.data; - let cmp = m.cmp; - let newData = Belt_SetDict.add(data, e, cmp); - if (newData === data) { - return m; - } else { - return { - cmp: cmp, - data: newData - }; - } -} - -function mergeMany(m, e) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.mergeMany(m.data, e, cmp) - }; -} - -function removeMany(m, e) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.removeMany(m.data, e, cmp) - }; -} - -function union(m, n) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.union(m.data, n.data, cmp) - }; -} - -function intersect(m, n) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.intersect(m.data, n.data, cmp) - }; -} - -function diff(m, n) { - let cmp = m.cmp; - return { - cmp: cmp, - data: Belt_SetDict.diff(m.data, n.data, cmp) - }; -} - -function subset(m, n) { - let cmp = m.cmp; - return Belt_SetDict.subset(m.data, n.data, cmp); -} - -function split(m, e) { - let cmp = m.cmp; - let match = Belt_SetDict.split(m.data, e, cmp); - let match$1 = match[0]; - return [ - [ - { - cmp: cmp, - data: match$1[0] - }, - { - cmp: cmp, - data: match$1[1] - } - ], - match[1] - ]; -} - -function make(id) { - return { - cmp: id.cmp, - data: undefined - }; -} - -function isEmpty(m) { - return Belt_SetDict.isEmpty(m.data); -} - -function cmp(m, n) { - let cmp$1 = m.cmp; - return Belt_SetDict.cmp(m.data, n.data, cmp$1); -} - -function eq(m, n) { - return Belt_SetDict.eq(m.data, n.data, m.cmp); -} - -function forEach(m, f) { - Belt_SetDict.forEach(m.data, f); -} - -function reduce(m, acc, f) { - return Belt_SetDict.reduce(m.data, acc, f); -} - -function every(m, f) { - return Belt_SetDict.every(m.data, f); -} - -function some(m, f) { - return Belt_SetDict.some(m.data, f); -} - -function keep(m, f) { - return { - cmp: m.cmp, - data: Belt_SetDict.keep(m.data, f) - }; -} - -function partition(m, f) { - let match = Belt_SetDict.partition(m.data, f); - let cmp = m.cmp; - return [ - { - cmp: cmp, - data: match[0] - }, - { - cmp: cmp, - data: match[1] - } - ]; -} - -function size(m) { - return Belt_SetDict.size(m.data); -} - -function toList(m) { - return Belt_SetDict.toList(m.data); -} - -function toArray(m) { - return Belt_SetDict.toArray(m.data); -} - -function minimum(m) { - return Belt_SetDict.minimum(m.data); -} - -function maximum(m) { - return Belt_SetDict.maximum(m.data); -} - -function get(m, e) { - return Belt_SetDict.get(m.data, e, m.cmp); -} - -function getOrThrow(m, e) { - return Belt_SetDict.getOrThrow(m.data, e, m.cmp); -} - -function has(m, e) { - return Belt_SetDict.has(m.data, e, m.cmp); -} - -function fromSortedArrayUnsafe(xs, id) { - return { - cmp: id.cmp, - data: Belt_SetDict.fromSortedArrayUnsafe(xs) - }; -} - -function getData(m) { - return m.data; -} - -function getId(m) { - let cmp = m.cmp; - return { - cmp: cmp - }; -} - -function packIdData(id, data) { - return { - cmp: id.cmp, - data: data - }; -} - -function checkInvariantInternal(d) { - Belt_SetDict.checkInvariantInternal(d.data); -} - -let Int; - -let $$String; - -let Dict; - -let forEachU = forEach; - -let reduceU = reduce; - -let everyU = every; - -let someU = some; - -let keepU = keep; - -let partitionU = partition; - -let getExn = getOrThrow; - -exports.Int = Int; -exports.$$String = $$String; -exports.Dict = Dict; -exports.make = make; -exports.fromArray = fromArray; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.isEmpty = isEmpty; -exports.has = has; -exports.add = add; -exports.mergeMany = mergeMany; -exports.remove = remove; -exports.removeMany = removeMany; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -exports.subset = subset; -exports.cmp = cmp; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.size = size; -exports.toArray = toArray; -exports.toList = toList; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.split = split; -exports.checkInvariantInternal = checkInvariantInternal; -exports.getData = getData; -exports.getId = getId; -exports.packIdData = packIdData; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_SetDict.cjs b/packages/@rescript/belt/lib/js/src/Belt_SetDict.cjs deleted file mode 100644 index 55849d49cd4..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_SetDict.cjs +++ /dev/null @@ -1,354 +0,0 @@ -'use strict'; - -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); - -function add(t, x, cmp) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let k = t.v; - let c = cmp(x, k); - if (c === 0) { - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = add(l, x, cmp); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, k, r); - } - } - let rr = add(r, x, cmp); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, k, rr); - } -} - -function remove(t, x, cmp) { - if (t === undefined) { - return t; - } - let v = t.v; - let l = t.l; - let r = t.r; - let c = cmp(x, v); - if (c === 0) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let v$1 = { - contents: r.v - }; - let r$1 = Belt_internalAVLset.removeMinAuxWithRef(r, v$1); - return Belt_internalAVLset.bal(l, v$1.contents, r$1); - } - if (c < 0) { - let ll = remove(l, x, cmp); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = remove(r, x, cmp); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function mergeMany(h, arr, cmp) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = add(v, key, cmp); - } - return v; -} - -function removeMany(h, arr, cmp) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = remove(v, key, cmp); - } - return v; -} - -function splitAuxNoPivot(cmp, n, x) { - let v = n.v; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - return [ - l, - r - ]; - } - if (c < 0) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxNoPivot(cmp, l, x); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxNoPivot(cmp, r, x); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function splitAuxPivot(cmp, n, x, pres) { - let v = n.v; - let l = n.l; - let r = n.r; - let c = cmp(x, v); - if (c === 0) { - pres.contents = true; - return [ - l, - r - ]; - } - if (c < 0) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(cmp, l, x, pres); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(cmp, r, x, pres); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function split(t, x, cmp) { - if (t === undefined) { - return [ - [ - undefined, - undefined - ], - false - ]; - } - let pres = { - contents: false - }; - let v = splitAuxPivot(cmp, t, x, pres); - return [ - v, - pres.contents - ]; -} - -function union(s1, s2, cmp) { - if (s1 === undefined) { - return s2; - } - if (s2 === undefined) { - return s1; - } - let h1 = s1.h; - let h2 = s2.h; - if (h1 >= h2) { - if (h2 === 1) { - return add(s1, s2.v, cmp); - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = splitAuxNoPivot(cmp, s2, v1); - return Belt_internalAVLset.joinShared(union(l1, match[0], cmp), v1, union(r1, match[1], cmp)); - } - if (h1 === 1) { - return add(s2, s1.v, cmp); - } - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = splitAuxNoPivot(cmp, s1, v2); - return Belt_internalAVLset.joinShared(union(match$1[0], l2, cmp), v2, union(match$1[1], r2, cmp)); -} - -function intersect(s1, s2, cmp) { - if (s1 === undefined) { - return; - } - if (s2 === undefined) { - return; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(cmp, s2, v1, pres); - let ll = intersect(l1, match[0], cmp); - let rr = intersect(r1, match[1], cmp); - if (pres.contents) { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } else { - return Belt_internalAVLset.concatShared(ll, rr); - } -} - -function diff(s1, s2, cmp) { - if (s1 === undefined) { - return s1; - } - if (s2 === undefined) { - return s1; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(cmp, s2, v1, pres); - let ll = diff(l1, match[0], cmp); - let rr = diff(r1, match[1], cmp); - if (pres.contents) { - return Belt_internalAVLset.concatShared(ll, rr); - } else { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } -} - -let empty; - -let fromArray = Belt_internalAVLset.fromArray; - -let fromSortedArrayUnsafe = Belt_internalAVLset.fromSortedArrayUnsafe; - -let isEmpty = Belt_internalAVLset.isEmpty; - -let has = Belt_internalAVLset.has; - -let subset = Belt_internalAVLset.subset; - -let cmp = Belt_internalAVLset.cmp; - -let eq = Belt_internalAVLset.eq; - -let forEachU = Belt_internalAVLset.forEach; - -let forEach = Belt_internalAVLset.forEach; - -let reduceU = Belt_internalAVLset.reduce; - -let reduce = Belt_internalAVLset.reduce; - -let everyU = Belt_internalAVLset.every; - -let every = Belt_internalAVLset.every; - -let someU = Belt_internalAVLset.some; - -let some = Belt_internalAVLset.some; - -let keepU = Belt_internalAVLset.keepShared; - -let keep = Belt_internalAVLset.keepShared; - -let partitionU = Belt_internalAVLset.partitionShared; - -let partition = Belt_internalAVLset.partitionShared; - -let size = Belt_internalAVLset.size; - -let toList = Belt_internalAVLset.toList; - -let toArray = Belt_internalAVLset.toArray; - -let minimum = Belt_internalAVLset.minimum; - -let maximum = Belt_internalAVLset.maximum; - -let get = Belt_internalAVLset.get; - -let getExn = Belt_internalAVLset.getOrThrow; - -let getOrThrow = Belt_internalAVLset.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLset.checkInvariantInternal; - -exports.empty = empty; -exports.fromArray = fromArray; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.isEmpty = isEmpty; -exports.has = has; -exports.add = add; -exports.mergeMany = mergeMany; -exports.remove = remove; -exports.removeMany = removeMany; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -exports.subset = subset; -exports.cmp = cmp; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.split = split; -exports.checkInvariantInternal = checkInvariantInternal; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_SetInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_SetInt.cjs deleted file mode 100644 index 6dba04e05ff..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_SetInt.cjs +++ /dev/null @@ -1,351 +0,0 @@ -'use strict'; - -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); -let Belt_internalSetInt = require("./Belt_internalSetInt.cjs"); - -function add(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let v = t.v; - if (x === v) { - return t; - } - let l = t.l; - let r = t.r; - if (x < v) { - let ll = add(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = add(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = add(v, key); - } - return v; -} - -function remove(t, x) { - if (t === undefined) { - return t; - } - let v = t.v; - let l = t.l; - let r = t.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let v$1 = { - contents: r.v - }; - let r$1 = Belt_internalAVLset.removeMinAuxWithRef(r, v$1); - return Belt_internalAVLset.bal(l, v$1.contents, r$1); - } - if (x < v) { - let ll = remove(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = remove(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function removeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = remove(v, key); - } - return v; -} - -function splitAuxNoPivot(n, x) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxNoPivot(l, x); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxNoPivot(r, x); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function splitAuxPivot(n, x, pres) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - pres.contents = true; - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(l, x, pres); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(r, x, pres); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function split(t, x) { - if (t === undefined) { - return [ - [ - undefined, - undefined - ], - false - ]; - } - let pres = { - contents: false - }; - let v = splitAuxPivot(t, x, pres); - return [ - v, - pres.contents - ]; -} - -function union(s1, s2) { - if (s1 === undefined) { - return s2; - } - if (s2 === undefined) { - return s1; - } - let h1 = s1.h; - let h2 = s2.h; - if (h1 >= h2) { - if (h2 === 1) { - return add(s1, s2.v); - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = splitAuxNoPivot(s2, v1); - return Belt_internalAVLset.joinShared(union(l1, match[0]), v1, union(r1, match[1])); - } - if (h1 === 1) { - return add(s2, s1.v); - } - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = splitAuxNoPivot(s1, v2); - return Belt_internalAVLset.joinShared(union(match$1[0], l2), v2, union(match$1[1], r2)); -} - -function intersect(s1, s2) { - if (s1 === undefined) { - return; - } - if (s2 === undefined) { - return; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = intersect(l1, match[0]); - let rr = intersect(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } else { - return Belt_internalAVLset.concatShared(ll, rr); - } -} - -function diff(s1, s2) { - if (s1 === undefined) { - return s1; - } - if (s2 === undefined) { - return s1; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = diff(l1, match[0]); - let rr = diff(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.concatShared(ll, rr); - } else { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } -} - -let empty; - -let fromArray = Belt_internalSetInt.fromArray; - -let fromSortedArrayUnsafe = Belt_internalAVLset.fromSortedArrayUnsafe; - -let isEmpty = Belt_internalAVLset.isEmpty; - -let has = Belt_internalSetInt.has; - -let subset = Belt_internalSetInt.subset; - -let cmp = Belt_internalSetInt.cmp; - -let eq = Belt_internalSetInt.eq; - -let forEachU = Belt_internalAVLset.forEach; - -let forEach = Belt_internalAVLset.forEach; - -let reduceU = Belt_internalAVLset.reduce; - -let reduce = Belt_internalAVLset.reduce; - -let everyU = Belt_internalAVLset.every; - -let every = Belt_internalAVLset.every; - -let someU = Belt_internalAVLset.some; - -let some = Belt_internalAVLset.some; - -let keepU = Belt_internalAVLset.keepShared; - -let keep = Belt_internalAVLset.keepShared; - -let partitionU = Belt_internalAVLset.partitionShared; - -let partition = Belt_internalAVLset.partitionShared; - -let size = Belt_internalAVLset.size; - -let toList = Belt_internalAVLset.toList; - -let toArray = Belt_internalAVLset.toArray; - -let minimum = Belt_internalAVLset.minimum; - -let maximum = Belt_internalAVLset.maximum; - -let get = Belt_internalSetInt.get; - -let getExn = Belt_internalSetInt.getOrThrow; - -let getOrThrow = Belt_internalSetInt.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLset.checkInvariantInternal; - -exports.empty = empty; -exports.fromArray = fromArray; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.isEmpty = isEmpty; -exports.has = has; -exports.add = add; -exports.mergeMany = mergeMany; -exports.remove = remove; -exports.removeMany = removeMany; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -exports.subset = subset; -exports.cmp = cmp; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.split = split; -exports.checkInvariantInternal = checkInvariantInternal; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_SetString.cjs b/packages/@rescript/belt/lib/js/src/Belt_SetString.cjs deleted file mode 100644 index a30162bdc04..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_SetString.cjs +++ /dev/null @@ -1,351 +0,0 @@ -'use strict'; - -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); -let Belt_internalSetString = require("./Belt_internalSetString.cjs"); - -function add(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let v = t.v; - if (x === v) { - return t; - } - let l = t.l; - let r = t.r; - if (x < v) { - let ll = add(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = add(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function mergeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = add(v, key); - } - return v; -} - -function remove(t, x) { - if (t === undefined) { - return t; - } - let v = t.v; - let l = t.l; - let r = t.r; - if (x === v) { - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let v$1 = { - contents: r.v - }; - let r$1 = Belt_internalAVLset.removeMinAuxWithRef(r, v$1); - return Belt_internalAVLset.bal(l, v$1.contents, r$1); - } - if (x < v) { - let ll = remove(l, x); - if (ll === l) { - return t; - } else { - return Belt_internalAVLset.bal(ll, v, r); - } - } - let rr = remove(r, x); - if (rr === r) { - return t; - } else { - return Belt_internalAVLset.bal(l, v, rr); - } -} - -function removeMany(h, arr) { - let len = arr.length; - let v = h; - for (let i = 0; i < len; ++i) { - let key = arr[i]; - v = remove(v, key); - } - return v; -} - -function splitAuxNoPivot(n, x) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxNoPivot(l, x); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxNoPivot(r, x); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function splitAuxPivot(n, x, pres) { - let v = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - pres.contents = true; - return [ - l, - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - n - ]; - } - let match = splitAuxPivot(l, x, pres); - return [ - match[0], - Belt_internalAVLset.joinShared(match[1], v, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined - ]; - } - let match$1 = splitAuxPivot(r, x, pres); - return [ - Belt_internalAVLset.joinShared(l, v, match$1[0]), - match$1[1] - ]; -} - -function split(t, x) { - if (t === undefined) { - return [ - [ - undefined, - undefined - ], - false - ]; - } - let pres = { - contents: false - }; - let v = splitAuxPivot(t, x, pres); - return [ - v, - pres.contents - ]; -} - -function union(s1, s2) { - if (s1 === undefined) { - return s2; - } - if (s2 === undefined) { - return s1; - } - let h1 = s1.h; - let h2 = s2.h; - if (h1 >= h2) { - if (h2 === 1) { - return add(s1, s2.v); - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = splitAuxNoPivot(s2, v1); - return Belt_internalAVLset.joinShared(union(l1, match[0]), v1, union(r1, match[1])); - } - if (h1 === 1) { - return add(s2, s1.v); - } - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = splitAuxNoPivot(s1, v2); - return Belt_internalAVLset.joinShared(union(match$1[0], l2), v2, union(match$1[1], r2)); -} - -function intersect(s1, s2) { - if (s1 === undefined) { - return; - } - if (s2 === undefined) { - return; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = intersect(l1, match[0]); - let rr = intersect(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } else { - return Belt_internalAVLset.concatShared(ll, rr); - } -} - -function diff(s1, s2) { - if (s1 === undefined) { - return s1; - } - if (s2 === undefined) { - return s1; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let pres = { - contents: false - }; - let match = splitAuxPivot(s2, v1, pres); - let ll = diff(l1, match[0]); - let rr = diff(r1, match[1]); - if (pres.contents) { - return Belt_internalAVLset.concatShared(ll, rr); - } else { - return Belt_internalAVLset.joinShared(ll, v1, rr); - } -} - -let empty; - -let fromArray = Belt_internalSetString.fromArray; - -let fromSortedArrayUnsafe = Belt_internalAVLset.fromSortedArrayUnsafe; - -let isEmpty = Belt_internalAVLset.isEmpty; - -let has = Belt_internalSetString.has; - -let subset = Belt_internalSetString.subset; - -let cmp = Belt_internalSetString.cmp; - -let eq = Belt_internalSetString.eq; - -let forEachU = Belt_internalAVLset.forEach; - -let forEach = Belt_internalAVLset.forEach; - -let reduceU = Belt_internalAVLset.reduce; - -let reduce = Belt_internalAVLset.reduce; - -let everyU = Belt_internalAVLset.every; - -let every = Belt_internalAVLset.every; - -let someU = Belt_internalAVLset.some; - -let some = Belt_internalAVLset.some; - -let keepU = Belt_internalAVLset.keepShared; - -let keep = Belt_internalAVLset.keepShared; - -let partitionU = Belt_internalAVLset.partitionShared; - -let partition = Belt_internalAVLset.partitionShared; - -let size = Belt_internalAVLset.size; - -let toList = Belt_internalAVLset.toList; - -let toArray = Belt_internalAVLset.toArray; - -let minimum = Belt_internalAVLset.minimum; - -let maximum = Belt_internalAVLset.maximum; - -let get = Belt_internalSetString.get; - -let getExn = Belt_internalSetString.getOrThrow; - -let getOrThrow = Belt_internalSetString.getOrThrow; - -let checkInvariantInternal = Belt_internalAVLset.checkInvariantInternal; - -exports.empty = empty; -exports.fromArray = fromArray; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.isEmpty = isEmpty; -exports.has = has; -exports.add = add; -exports.mergeMany = mergeMany; -exports.remove = remove; -exports.removeMany = removeMany; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -exports.subset = subset; -exports.cmp = cmp; -exports.eq = eq; -exports.forEachU = forEachU; -exports.forEach = forEach; -exports.reduceU = reduceU; -exports.reduce = reduce; -exports.everyU = everyU; -exports.every = every; -exports.someU = someU; -exports.some = some; -exports.keepU = keepU; -exports.keep = keep; -exports.partitionU = partitionU; -exports.partition = partition; -exports.size = size; -exports.toList = toList; -exports.toArray = toArray; -exports.minimum = minimum; -exports.maximum = maximum; -exports.get = get; -exports.getExn = getExn; -exports.getOrThrow = getOrThrow; -exports.split = split; -exports.checkInvariantInternal = checkInvariantInternal; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_SortArray.cjs b/packages/@rescript/belt/lib/js/src/Belt_SortArray.cjs deleted file mode 100644 index 3b53acb32b6..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_SortArray.cjs +++ /dev/null @@ -1,408 +0,0 @@ -'use strict'; - -let Belt_Array = require("./Belt_Array.cjs"); - -function sortedLengthAuxMore(xs, _prec, _acc, len, lt) { - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (!lt(v, prec)) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; -} - -function strictlySortedLength(xs, lt) { - let len = xs.length; - if (len === 0 || len === 1) { - return len; - } - let x0 = xs[0]; - let x1 = xs[1]; - if (lt(x0, x1)) { - let _prec = x1; - let _acc = 2; - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (!lt(prec, v)) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; - } else if (lt(x1, x0)) { - return -sortedLengthAuxMore(xs, x1, 2, len, lt) | 0; - } else { - return 1; - } -} - -function isSorted(a, cmp) { - let len = a.length; - if (len === 0) { - return true; - } else { - let _i = 0; - let last_bound = len - 1 | 0; - while (true) { - let i = _i; - if (i === last_bound) { - return true; - } - if (cmp(a[i], a[i + 1 | 0]) > 0) { - return false; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function merge(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (cmp(s1, s2) <= 0) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return Belt_Array.blitUnsafe(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - dst[d] = s2; - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return Belt_Array.blitUnsafe(src, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = src2[i2$1]; - _i2 = i2$1; - continue; - }; -} - -function union(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - let c = cmp(s1, s2); - if (c < 0) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - let d$1 = d + 1 | 0; - if (i1$1 < src1r) { - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - Belt_Array.blitUnsafe(src2, i2, dst, d$1, src2r - i2 | 0); - return (d$1 + src2r | 0) - i2 | 0; - } - if (c === 0) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$2 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - Belt_Array.blitUnsafe(src2, i2$1, dst, d$2, src2r - i2$1 | 0); - return (d$2 + src2r | 0) - i2$1 | 0; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d$2, src1r - i1$2 | 0); - return (d$2 + src1r | 0) - i1$2 | 0; - } - } - _d = d$2; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - dst[d] = s2; - let i2$2 = i2 + 1 | 0; - let d$3 = d + 1 | 0; - if (i2$2 < src2r) { - _d = d$3; - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d$3, src1r - i1 | 0); - return (d$3 + src1r | 0) - i1 | 0; - }; -} - -function intersect(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - let c = cmp(s1, s2); - if (c < 0) { - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d; - } - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (c === 0) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$1 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - return d$1; - } - _d = d$1; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 >= src2r) { - return d; - } - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - }; -} - -function diff(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs, cmp) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - let c = cmp(s1, s2); - if (c < 0) { - dst[d] = s1; - let d$1 = d + 1 | 0; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d$1; - } - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (c === 0) { - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - return d; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d, src1r - i1$2 | 0); - return (d + src1r | 0) - i1$2 | 0; - } - } - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 < src2r) { - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d, src1r - i1 | 0); - return (d + src1r | 0) - i1 | 0; - }; -} - -function insertionSort(src, srcofs, dst, dstofs, len, cmp) { - for (let i = 0; i < len; ++i) { - let e = src[srcofs + i | 0]; - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && cmp(dst[j], e) > 0) { - dst[j + 1 | 0] = dst[j]; - j = j - 1 | 0; - }; - dst[j + 1 | 0] = e; - } -} - -function sortTo(src, srcofs, dst, dstofs, len, cmp) { - if (len <= 5) { - return insertionSort(src, srcofs, dst, dstofs, len, cmp); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortTo(src, srcofs + l1 | 0, dst, dstofs + l1 | 0, l2, cmp); - sortTo(src, srcofs, src, srcofs + l2 | 0, l1, cmp); - merge(src, srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs, cmp); -} - -function stableSortInPlaceBy(a, cmp) { - let l = a.length; - if (l <= 5) { - return insertionSort(a, 0, a, 0, l, cmp); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let t = new Array(l2); - sortTo(a, l1, t, 0, l2, cmp); - sortTo(a, 0, a, l2, l1, cmp); - merge(a, l2, l1, t, 0, l2, a, 0, cmp); -} - -function stableSortBy(a, cmp) { - let b = a.slice(0); - stableSortInPlaceBy(b, cmp); - return b; -} - -function binarySearchBy(sorted, key, cmp) { - let len = sorted.length; - if (len === 0) { - return -1; - } - let lo = sorted[0]; - let c = cmp(key, lo); - if (c < 0) { - return -1; - } - let hi = sorted[len - 1 | 0]; - let c2 = cmp(key, hi); - if (c2 > 0) { - return -(len + 1 | 0) | 0; - } else { - let _lo = 0; - let _hi = len - 1 | 0; - while (true) { - let hi$1 = _hi; - let lo$1 = _lo; - let mid = (lo$1 + hi$1 | 0) / 2 | 0; - let midVal = sorted[mid]; - let c$1 = cmp(key, midVal); - if (c$1 === 0) { - return mid; - } - if (c$1 < 0) { - if (hi$1 === mid) { - if (cmp(sorted[lo$1], key) === 0) { - return lo$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _hi = mid; - continue; - } - if (lo$1 === mid) { - if (cmp(sorted[hi$1], key) === 0) { - return hi$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _lo = mid; - continue; - }; - } -} - -let Int; - -let $$String; - -let strictlySortedLengthU = strictlySortedLength; - -let isSortedU = isSorted; - -let stableSortInPlaceByU = stableSortInPlaceBy; - -let stableSortByU = stableSortBy; - -let binarySearchByU = binarySearchBy; - -let unionU = union; - -let intersectU = intersect; - -let diffU = diff; - -exports.Int = Int; -exports.$$String = $$String; -exports.strictlySortedLengthU = strictlySortedLengthU; -exports.strictlySortedLength = strictlySortedLength; -exports.isSortedU = isSortedU; -exports.isSorted = isSorted; -exports.stableSortInPlaceByU = stableSortInPlaceByU; -exports.stableSortInPlaceBy = stableSortInPlaceBy; -exports.stableSortByU = stableSortByU; -exports.stableSortBy = stableSortBy; -exports.binarySearchByU = binarySearchByU; -exports.binarySearchBy = binarySearchBy; -exports.unionU = unionU; -exports.union = union; -exports.intersectU = intersectU; -exports.intersect = intersect; -exports.diffU = diffU; -exports.diff = diff; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_SortArrayInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_SortArrayInt.cjs deleted file mode 100644 index 59b8de2c930..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_SortArrayInt.cjs +++ /dev/null @@ -1,372 +0,0 @@ -'use strict'; - -let Belt_Array = require("./Belt_Array.cjs"); - -function sortedLengthAuxMore(xs, _prec, _acc, len) { - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec <= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; -} - -function strictlySortedLength(xs) { - let len = xs.length; - if (len === 0 || len === 1) { - return len; - } - let x0 = xs[0]; - let x1 = xs[1]; - if (x0 < x1) { - let _prec = x1; - let _acc = 2; - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec >= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; - } else if (x0 > x1) { - return -sortedLengthAuxMore(xs, x1, 2, len) | 0; - } else { - return 1; - } -} - -function isSorted(a) { - let len = a.length; - if (len === 0) { - return true; - } else { - let _i = 0; - let last_bound = len - 1 | 0; - while (true) { - let i = _i; - if (i === last_bound) { - return true; - } - if (a[i] > a[i + 1 | 0]) { - return false; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function merge(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 <= s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return Belt_Array.blitUnsafe(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - dst[d] = s2; - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return Belt_Array.blitUnsafe(src, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = src2[i2$1]; - _i2 = i2$1; - continue; - }; -} - -function union(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - let d$1 = d + 1 | 0; - if (i1$1 < src1r) { - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - Belt_Array.blitUnsafe(src2, i2, dst, d$1, src2r - i2 | 0); - return (d$1 + src2r | 0) - i2 | 0; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$2 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - Belt_Array.blitUnsafe(src2, i2$1, dst, d$2, src2r - i2$1 | 0); - return (d$2 + src2r | 0) - i2$1 | 0; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d$2, src1r - i1$2 | 0); - return (d$2 + src1r | 0) - i1$2 | 0; - } - } - _d = d$2; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - dst[d] = s2; - let i2$2 = i2 + 1 | 0; - let d$3 = d + 1 | 0; - if (i2$2 < src2r) { - _d = d$3; - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d$3, src1r - i1 | 0); - return (d$3 + src1r | 0) - i1 | 0; - }; -} - -function intersect(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d; - } - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$1 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - return d$1; - } - _d = d$1; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 >= src2r) { - return d; - } - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - }; -} - -function diff(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let d$1 = d + 1 | 0; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d$1; - } - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - return d; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d, src1r - i1$2 | 0); - return (d + src1r | 0) - i1$2 | 0; - } - } - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 < src2r) { - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d, src1r - i1 | 0); - return (d + src1r | 0) - i1 | 0; - }; -} - -function insertionSort(src, srcofs, dst, dstofs, len) { - for (let i = 0; i < len; ++i) { - let e = src[srcofs + i | 0]; - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && dst[j] > e) { - dst[j + 1 | 0] = dst[j]; - j = j - 1 | 0; - }; - dst[j + 1 | 0] = e; - } -} - -function sortTo(src, srcofs, dst, dstofs, len) { - if (len <= 5) { - return insertionSort(src, srcofs, dst, dstofs, len); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortTo(src, srcofs + l1 | 0, dst, dstofs + l1 | 0, l2); - sortTo(src, srcofs, src, srcofs + l2 | 0, l1); - merge(src, srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs); -} - -function stableSortInPlace(a) { - let l = a.length; - if (l <= 5) { - return insertionSort(a, 0, a, 0, l); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let t = new Array(l2); - sortTo(a, l1, t, 0, l2); - sortTo(a, 0, a, l2, l1); - merge(a, l2, l1, t, 0, l2, a, 0); -} - -function stableSort(a) { - let b = a.slice(0); - stableSortInPlace(b); - return b; -} - -function binarySearch(sorted, key) { - let len = sorted.length; - if (len === 0) { - return -1; - } - let lo = sorted[0]; - if (key < lo) { - return -1; - } - let hi = sorted[len - 1 | 0]; - if (key > hi) { - return -(len + 1 | 0) | 0; - } else { - let _lo = 0; - let _hi = len - 1 | 0; - while (true) { - let hi$1 = _hi; - let lo$1 = _lo; - let mid = (lo$1 + hi$1 | 0) / 2 | 0; - let midVal = sorted[mid]; - if (key === midVal) { - return mid; - } - if (key < midVal) { - if (hi$1 === mid) { - if (sorted[lo$1] === key) { - return lo$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _hi = mid; - continue; - } - if (lo$1 === mid) { - if (sorted[hi$1] === key) { - return hi$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _lo = mid; - continue; - }; - } -} - -exports.strictlySortedLength = strictlySortedLength; -exports.isSorted = isSorted; -exports.stableSortInPlace = stableSortInPlace; -exports.stableSort = stableSort; -exports.binarySearch = binarySearch; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_SortArrayString.cjs b/packages/@rescript/belt/lib/js/src/Belt_SortArrayString.cjs deleted file mode 100644 index 59b8de2c930..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_SortArrayString.cjs +++ /dev/null @@ -1,372 +0,0 @@ -'use strict'; - -let Belt_Array = require("./Belt_Array.cjs"); - -function sortedLengthAuxMore(xs, _prec, _acc, len) { - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec <= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; -} - -function strictlySortedLength(xs) { - let len = xs.length; - if (len === 0 || len === 1) { - return len; - } - let x0 = xs[0]; - let x1 = xs[1]; - if (x0 < x1) { - let _prec = x1; - let _acc = 2; - while (true) { - let acc = _acc; - let prec = _prec; - if (acc >= len) { - return acc; - } - let v = xs[acc]; - if (prec >= v) { - return acc; - } - _acc = acc + 1 | 0; - _prec = v; - continue; - }; - } else if (x0 > x1) { - return -sortedLengthAuxMore(xs, x1, 2, len) | 0; - } else { - return 1; - } -} - -function isSorted(a) { - let len = a.length; - if (len === 0) { - return true; - } else { - let _i = 0; - let last_bound = len - 1 | 0; - while (true) { - let i = _i; - if (i === last_bound) { - return true; - } - if (a[i] > a[i + 1 | 0]) { - return false; - } - _i = i + 1 | 0; - continue; - }; - } -} - -function merge(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 <= s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return Belt_Array.blitUnsafe(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - dst[d] = s2; - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return Belt_Array.blitUnsafe(src, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = src2[i2$1]; - _i2 = i2$1; - continue; - }; -} - -function union(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let i1$1 = i1 + 1 | 0; - let d$1 = d + 1 | 0; - if (i1$1 < src1r) { - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - Belt_Array.blitUnsafe(src2, i2, dst, d$1, src2r - i2 | 0); - return (d$1 + src2r | 0) - i2 | 0; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$2 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - Belt_Array.blitUnsafe(src2, i2$1, dst, d$2, src2r - i2$1 | 0); - return (d$2 + src2r | 0) - i2$1 | 0; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d$2, src1r - i1$2 | 0); - return (d$2 + src1r | 0) - i1$2 | 0; - } - } - _d = d$2; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - dst[d] = s2; - let i2$2 = i2 + 1 | 0; - let d$3 = d + 1 | 0; - if (i2$2 < src2r) { - _d = d$3; - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d$3, src1r - i1 | 0); - return (d$3 + src1r | 0) - i1 | 0; - }; -} - -function intersect(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d; - } - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - dst[d] = s1; - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - let d$1 = d + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - return d$1; - } - _d = d$1; - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 >= src2r) { - return d; - } - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - }; -} - -function diff(src, src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = src[src1ofs]; - let _i2 = src2ofs; - let _s2 = src2[src2ofs]; - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (s1 < s2) { - dst[d] = s1; - let d$1 = d + 1 | 0; - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return d$1; - } - _d = d$1; - _s1 = src[i1$1]; - _i1 = i1$1; - continue; - } - if (s1 === s2) { - let i1$2 = i1 + 1 | 0; - let i2$1 = i2 + 1 | 0; - if (!(i1$2 < src1r && i2$1 < src2r)) { - if (i1$2 === src1r) { - return d; - } else { - Belt_Array.blitUnsafe(src, i1$2, dst, d, src1r - i1$2 | 0); - return (d + src1r | 0) - i1$2 | 0; - } - } - _s2 = src2[i2$1]; - _i2 = i2$1; - _s1 = src[i1$2]; - _i1 = i1$2; - continue; - } - let i2$2 = i2 + 1 | 0; - if (i2$2 < src2r) { - _s2 = src2[i2$2]; - _i2 = i2$2; - continue; - } - Belt_Array.blitUnsafe(src, i1, dst, d, src1r - i1 | 0); - return (d + src1r | 0) - i1 | 0; - }; -} - -function insertionSort(src, srcofs, dst, dstofs, len) { - for (let i = 0; i < len; ++i) { - let e = src[srcofs + i | 0]; - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && dst[j] > e) { - dst[j + 1 | 0] = dst[j]; - j = j - 1 | 0; - }; - dst[j + 1 | 0] = e; - } -} - -function sortTo(src, srcofs, dst, dstofs, len) { - if (len <= 5) { - return insertionSort(src, srcofs, dst, dstofs, len); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortTo(src, srcofs + l1 | 0, dst, dstofs + l1 | 0, l2); - sortTo(src, srcofs, src, srcofs + l2 | 0, l1); - merge(src, srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs); -} - -function stableSortInPlace(a) { - let l = a.length; - if (l <= 5) { - return insertionSort(a, 0, a, 0, l); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let t = new Array(l2); - sortTo(a, l1, t, 0, l2); - sortTo(a, 0, a, l2, l1); - merge(a, l2, l1, t, 0, l2, a, 0); -} - -function stableSort(a) { - let b = a.slice(0); - stableSortInPlace(b); - return b; -} - -function binarySearch(sorted, key) { - let len = sorted.length; - if (len === 0) { - return -1; - } - let lo = sorted[0]; - if (key < lo) { - return -1; - } - let hi = sorted[len - 1 | 0]; - if (key > hi) { - return -(len + 1 | 0) | 0; - } else { - let _lo = 0; - let _hi = len - 1 | 0; - while (true) { - let hi$1 = _hi; - let lo$1 = _lo; - let mid = (lo$1 + hi$1 | 0) / 2 | 0; - let midVal = sorted[mid]; - if (key === midVal) { - return mid; - } - if (key < midVal) { - if (hi$1 === mid) { - if (sorted[lo$1] === key) { - return lo$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _hi = mid; - continue; - } - if (lo$1 === mid) { - if (sorted[hi$1] === key) { - return hi$1; - } else { - return -(hi$1 + 1 | 0) | 0; - } - } - _lo = mid; - continue; - }; - } -} - -exports.strictlySortedLength = strictlySortedLength; -exports.isSorted = isSorted; -exports.stableSortInPlace = stableSortInPlace; -exports.stableSort = stableSort; -exports.binarySearch = binarySearch; -exports.union = union; -exports.intersect = intersect; -exports.diff = diff; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalAVLset.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalAVLset.cjs deleted file mode 100644 index fe66676e477..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalAVLset.cjs +++ /dev/null @@ -1,843 +0,0 @@ -'use strict'; - -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Belt_SortArray = require("./Belt_SortArray.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function copy(n) { - if (n !== undefined) { - return { - v: n.v, - h: n.h, - l: copy(n.l), - r: copy(n.r) - }; - } else { - return n; - } -} - -function create(l, v, r) { - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - return { - v: v, - h: ( - hl >= hr ? hl : hr - ) + 1 | 0, - l: l, - r: r - }; -} - -function singleton(x) { - return { - v: x, - h: 1, - l: undefined, - r: undefined - }; -} - -function heightGe(l, r) { - if (r !== undefined) { - if (l !== undefined) { - return l.h >= r.h; - } else { - return false; - } - } else { - return true; - } -} - -function bal(l, v, r) { - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - if (hl > (hr + 2 | 0)) { - let ll = l.l; - let lr = l.r; - if (heightGe(ll, lr)) { - return create(ll, l.v, create(lr, v, r)); - } else { - return create(create(ll, l.v, lr.l), lr.v, create(lr.r, v, r)); - } - } - if (hr <= (hl + 2 | 0)) { - return { - v: v, - h: ( - hl >= hr ? hl : hr - ) + 1 | 0, - l: l, - r: r - }; - } - let rl = r.l; - let rr = r.r; - if (heightGe(rr, rl)) { - return create(create(l, v, rl), r.v, rr); - } else { - return create(create(l, v, rl.l), rl.v, create(rl.r, r.v, rr)); - } -} - -function min0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.l; - if (n$1 === undefined) { - return n.v; - } - _n = n$1; - continue; - }; -} - -function minimum(n) { - if (n !== undefined) { - return Primitive_option.some(min0Aux(n)); - } -} - -function max0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.r; - if (n$1 === undefined) { - return n.v; - } - _n = n$1; - continue; - }; -} - -function maximum(n) { - if (n !== undefined) { - return Primitive_option.some(max0Aux(n)); - } -} - -function removeMinAuxWithRef(n, v) { - let ln = n.l; - if (ln !== undefined) { - return bal(removeMinAuxWithRef(ln, v), n.v, n.r); - } else { - v.contents = n.v; - return n.r; - } -} - -function isEmpty(n) { - return n === undefined; -} - -function stackAllLeft(_v, _s) { - while (true) { - let s = _s; - let v = _v; - if (v === undefined) { - return s; - } - _s = {hd: v, tl: s}; - _v = v.l; - continue; - }; -} - -function forEach(_n, f) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - forEach(n.l, f); - f(n.v); - _n = n.r; - continue; - }; -} - -function reduce(_s, _accu, f) { - while (true) { - let accu = _accu; - let s = _s; - if (s === undefined) { - return accu; - } - _accu = f(reduce(s.l, accu, f), s.v); - _s = s.r; - continue; - }; -} - -function every(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return true; - } - if (!p(n.v)) { - return false; - } - if (!every(n.l, p)) { - return false; - } - _n = n.r; - continue; - }; -} - -function some(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - if (p(n.v)) { - return true; - } - if (some(n.l, p)) { - return true; - } - _n = n.r; - continue; - }; -} - -function addMinElement(n, v) { - if (n !== undefined) { - return bal(addMinElement(n.l, v), n.v, n.r); - } else { - return singleton(v); - } -} - -function addMaxElement(n, v) { - if (n !== undefined) { - return bal(n.l, n.v, addMaxElement(n.r, v)); - } else { - return singleton(v); - } -} - -function joinShared(ln, v, rn) { - if (ln === undefined) { - return addMinElement(rn, v); - } - if (rn === undefined) { - return addMaxElement(ln, v); - } - let lh = ln.h; - let rh = rn.h; - if (lh > (rh + 2 | 0)) { - return bal(ln.l, ln.v, joinShared(ln.r, v, rn)); - } else if (rh > (lh + 2 | 0)) { - return bal(joinShared(ln, v, rn.l), rn.v, rn.r); - } else { - return create(ln, v, rn); - } -} - -function concatShared(t1, t2) { - if (t1 === undefined) { - return t2; - } - if (t2 === undefined) { - return t1; - } - let v = { - contents: t2.v - }; - let t2r = removeMinAuxWithRef(t2, v); - return joinShared(t1, v.contents, t2r); -} - -function partitionShared(n, p) { - if (n === undefined) { - return [ - undefined, - undefined - ]; - } - let value = n.v; - let match = partitionShared(n.l, p); - let lf = match[1]; - let lt = match[0]; - let pv = p(value); - let match$1 = partitionShared(n.r, p); - let rf = match$1[1]; - let rt = match$1[0]; - if (pv) { - return [ - joinShared(lt, value, rt), - concatShared(lf, rf) - ]; - } else { - return [ - concatShared(lt, rt), - joinShared(lf, value, rf) - ]; - } -} - -function lengthNode(n) { - let l = n.l; - let r = n.r; - let sizeL = l !== undefined ? lengthNode(l) : 0; - let sizeR = r !== undefined ? lengthNode(r) : 0; - return (1 + sizeL | 0) + sizeR | 0; -} - -function size(n) { - if (n !== undefined) { - return lengthNode(n); - } else { - return 0; - } -} - -function toListAux(_n, _accu) { - while (true) { - let accu = _accu; - let n = _n; - if (n === undefined) { - return accu; - } - _accu = {hd: n.v, tl: toListAux(n.r, accu)}; - _n = n.l; - continue; - }; -} - -function toList(s) { - return toListAux(s, /* [] */0); -} - -function checkInvariantInternal(_v) { - while (true) { - let v = _v; - if (v === undefined) { - return; - } - let l = v.l; - let r = v.r; - let diff = ( - l !== undefined ? l.h : 0 - ) - ( - r !== undefined ? r.h : 0 - ) | 0; - if (!(diff <= 2 && diff >= -2)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_internalAVLset.res", - 280, - 4 - ], - Error: new Error() - }; - } - checkInvariantInternal(l); - _v = r; - continue; - }; -} - -function fillArray(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let v = n.v; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArray(l, i, arr) : i; - arr[next] = v; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function fillArrayWithPartition(_n, cursor, arr, p) { - while (true) { - let n = _n; - let v = n.v; - let l = n.l; - let r = n.r; - if (l !== undefined) { - fillArrayWithPartition(l, cursor, arr, p); - } - if (p(v)) { - let c = cursor.forward; - arr[c] = v; - cursor.forward = c + 1 | 0; - } else { - let c$1 = cursor.backward; - arr[c$1] = v; - cursor.backward = c$1 - 1 | 0; - } - if (r === undefined) { - return; - } - _n = r; - continue; - }; -} - -function fillArrayWithFilter(_n, _i, arr, p) { - while (true) { - let i = _i; - let n = _n; - let v = n.v; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArrayWithFilter(l, i, arr, p) : i; - let rnext = p(v) ? (arr[next] = v, next + 1 | 0) : next; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function toArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArray(n, 0, v); - return v; -} - -function fromSortedArrayRevAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - return singleton(arr[off]); - case 2 : - let x0 = arr[off]; - let x1 = arr[off - 1 | 0]; - return { - v: x1, - h: 2, - l: singleton(x0), - r: undefined - }; - case 3 : - let x0$1 = arr[off]; - let x1$1 = arr[off - 1 | 0]; - let x2 = arr[off - 2 | 0]; - return { - v: x1$1, - h: 2, - l: singleton(x0$1), - r: singleton(x2) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayRevAux(arr, off, nl); - let mid = arr[off - nl | 0]; - let right = fromSortedArrayRevAux(arr, (off - nl | 0) - 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, mid, right); - } -} - -function fromSortedArrayAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - return singleton(arr[off]); - case 2 : - let x0 = arr[off]; - let x1 = arr[off + 1 | 0]; - return { - v: x1, - h: 2, - l: singleton(x0), - r: undefined - }; - case 3 : - let x0$1 = arr[off]; - let x1$1 = arr[off + 1 | 0]; - let x2 = arr[off + 2 | 0]; - return { - v: x1$1, - h: 2, - l: singleton(x0$1), - r: singleton(x2) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayAux(arr, off, nl); - let mid = arr[off + nl | 0]; - let right = fromSortedArrayAux(arr, (off + nl | 0) + 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, mid, right); - } -} - -function fromSortedArrayUnsafe(arr) { - return fromSortedArrayAux(arr, 0, arr.length); -} - -function keepShared(n, p) { - if (n === undefined) { - return; - } - let v = n.v; - let l = n.l; - let r = n.r; - let newL = keepShared(l, p); - let pv = p(v); - let newR = keepShared(r, p); - if (pv) { - if (l === newL && r === newR) { - return n; - } else { - return joinShared(newL, v, newR); - } - } else { - return concatShared(newL, newR); - } -} - -function keepCopy(n, p) { - if (n === undefined) { - return; - } - let size = lengthNode(n); - let v = new Array(size); - let last = fillArrayWithFilter(n, 0, v, p); - return fromSortedArrayAux(v, 0, last); -} - -function partitionCopy(n, p) { - if (n === undefined) { - return [ - undefined, - undefined - ]; - } - let size = lengthNode(n); - let v = new Array(size); - let backward = size - 1 | 0; - let cursor = { - forward: 0, - backward: backward - }; - fillArrayWithPartition(n, cursor, v, p); - let forwardLen = cursor.forward; - return [ - fromSortedArrayAux(v, 0, forwardLen), - fromSortedArrayRevAux(v, backward, size - forwardLen | 0) - ]; -} - -function has(_t, x, cmp) { - while (true) { - let t = _t; - if (t === undefined) { - return false; - } - let v = t.v; - let c = cmp(x, v); - if (c === 0) { - return true; - } - _t = c < 0 ? t.l : t.r; - continue; - }; -} - -function cmp(s1, s2, cmp$1) { - let len1 = size(s1); - let len2 = size(s2); - if (len1 === len2) { - let _e1 = stackAllLeft(s1, /* [] */0); - let _e2 = stackAllLeft(s2, /* [] */0); - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = cmp$1(h1.v, h2.v); - if (c !== 0) { - return c; - } - _e2 = stackAllLeft(h2.r, e2.tl); - _e1 = stackAllLeft(h1.r, e1.tl); - continue; - }; - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2, c) { - return cmp(s1, s2, c) === 0; -} - -function subset(_s1, _s2, cmp) { - while (true) { - let s2 = _s2; - let s1 = _s1; - if (s1 === undefined) { - return true; - } - if (s2 === undefined) { - return false; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let c = cmp(v1, v2); - if (c === 0) { - if (!subset(l1, l2, cmp)) { - return false; - } - _s2 = r2; - _s1 = r1; - continue; - } - if (c < 0) { - if (!subset(create(l1, v1, undefined), l2, cmp)) { - return false; - } - _s1 = r1; - continue; - } - if (!subset(create(undefined, v1, r1), r2, cmp)) { - return false; - } - _s1 = l1; - continue; - }; -} - -function get(_n, x, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.v; - let c = cmp(x, v); - if (c === 0) { - return Primitive_option.some(v); - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x, cmp) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.v; - let c = cmp(x, v); - if (c === 0) { - return v; - } - _n = c < 0 ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function rotateWithLeftChild(k2) { - let k1 = k2.l; - k2.l = k1.r; - k1.r = k2; - let n = k2.l; - let hlk2 = n !== undefined ? n.h : 0; - let n$1 = k2.r; - let hrk2 = n$1 !== undefined ? n$1.h : 0; - k2.h = Primitive_int.max(hlk2, hrk2) + 1 | 0; - let n$2 = k1.l; - let hlk1 = n$2 !== undefined ? n$2.h : 0; - let hk2 = k2.h; - k1.h = Primitive_int.max(hlk1, hk2) + 1 | 0; - return k1; -} - -function rotateWithRightChild(k1) { - let k2 = k1.r; - k1.r = k2.l; - k2.l = k1; - let n = k1.l; - let hlk1 = n !== undefined ? n.h : 0; - let n$1 = k1.r; - let hrk1 = n$1 !== undefined ? n$1.h : 0; - k1.h = Primitive_int.max(hlk1, hrk1) + 1 | 0; - let n$2 = k2.r; - let hrk2 = n$2 !== undefined ? n$2.h : 0; - let hk1 = k1.h; - k2.h = Primitive_int.max(hrk2, hk1) + 1 | 0; - return k2; -} - -function doubleWithLeftChild(k3) { - let k3l = k3.l; - let v = rotateWithRightChild(k3l); - k3.l = v; - return rotateWithLeftChild(k3); -} - -function doubleWithRightChild(k2) { - let k2r = k2.r; - let v = rotateWithLeftChild(k2r); - k2.r = v; - return rotateWithRightChild(k2); -} - -function heightUpdateMutate(t) { - let n = t.l; - let hlt = n !== undefined ? n.h : 0; - let n$1 = t.r; - let hrt = n$1 !== undefined ? n$1.h : 0; - t.h = Primitive_int.max(hlt, hrt) + 1 | 0; - return t; -} - -function balMutate(nt) { - let l = nt.l; - let r = nt.r; - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - if (hl > (2 + hr | 0)) { - let ll = l.l; - let lr = l.r; - if (heightGe(ll, lr)) { - return heightUpdateMutate(rotateWithLeftChild(nt)); - } else { - return heightUpdateMutate(doubleWithLeftChild(nt)); - } - } - if (hr > (2 + hl | 0)) { - let rl = r.l; - let rr = r.r; - if (heightGe(rr, rl)) { - return heightUpdateMutate(rotateWithRightChild(nt)); - } else { - return heightUpdateMutate(doubleWithRightChild(nt)); - } - } - nt.h = Primitive_int.max(hl, hr) + 1 | 0; - return nt; -} - -function addMutate(cmp, t, x) { - if (t === undefined) { - return singleton(x); - } - let k = t.v; - let c = cmp(x, k); - if (c === 0) { - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = addMutate(cmp, l, x); - t.l = ll; - } else { - t.r = addMutate(cmp, r, x); - } - return balMutate(t); -} - -function fromArray(xs, cmp) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (x, y) => cmp(x, y) < 0); - let result; - if (next >= 0) { - result = fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - result = addMutate(cmp, result, xs[i]); - } - return result; -} - -function removeMinAuxWithRootMutate(nt, n) { - let ln = n.l; - let rn = n.r; - if (ln !== undefined) { - n.l = removeMinAuxWithRootMutate(nt, ln); - return balMutate(n); - } else { - nt.v = n.v; - return rn; - } -} - -exports.copy = copy; -exports.create = create; -exports.bal = bal; -exports.singleton = singleton; -exports.minimum = minimum; -exports.maximum = maximum; -exports.removeMinAuxWithRef = removeMinAuxWithRef; -exports.isEmpty = isEmpty; -exports.stackAllLeft = stackAllLeft; -exports.forEach = forEach; -exports.reduce = reduce; -exports.every = every; -exports.some = some; -exports.joinShared = joinShared; -exports.concatShared = concatShared; -exports.keepShared = keepShared; -exports.keepCopy = keepCopy; -exports.partitionShared = partitionShared; -exports.partitionCopy = partitionCopy; -exports.lengthNode = lengthNode; -exports.size = size; -exports.toList = toList; -exports.checkInvariantInternal = checkInvariantInternal; -exports.fillArray = fillArray; -exports.toArray = toArray; -exports.fromSortedArrayAux = fromSortedArrayAux; -exports.fromSortedArrayRevAux = fromSortedArrayRevAux; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.has = has; -exports.cmp = cmp; -exports.eq = eq; -exports.subset = subset; -exports.get = get; -exports.getOrThrow = getOrThrow; -exports.fromArray = fromArray; -exports.addMutate = addMutate; -exports.balMutate = balMutate; -exports.removeMinAuxWithRootMutate = removeMinAuxWithRootMutate; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalAVLtree.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalAVLtree.cjs deleted file mode 100644 index 14d3625603f..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalAVLtree.cjs +++ /dev/null @@ -1,1010 +0,0 @@ -'use strict'; - -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Belt_SortArray = require("./Belt_SortArray.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function treeHeight(n) { - if (n !== undefined) { - return n.h; - } else { - return 0; - } -} - -function copy(n) { - if (n !== undefined) { - return { - k: n.k, - v: n.v, - h: n.h, - l: copy(n.l), - r: copy(n.r) - }; - } else { - return n; - } -} - -function create(l, x, d, r) { - let hl = treeHeight(l); - let hr = treeHeight(r); - return { - k: x, - v: d, - h: hl >= hr ? hl + 1 | 0 : hr + 1 | 0, - l: l, - r: r - }; -} - -function singleton(x, d) { - return { - k: x, - v: d, - h: 1, - l: undefined, - r: undefined - }; -} - -function heightGe(l, r) { - if (r !== undefined) { - if (l !== undefined) { - return l.h >= r.h; - } else { - return false; - } - } else { - return true; - } -} - -function updateValue(n, newValue) { - if (n.v === newValue) { - return n; - } else { - return { - k: n.k, - v: newValue, - h: n.h, - l: n.l, - r: n.r - }; - } -} - -function bal(l, x, d, r) { - let hl = l !== undefined ? l.h : 0; - let hr = r !== undefined ? r.h : 0; - if (hl > (hr + 2 | 0)) { - let ll = l.l; - let lr = l.r; - if (treeHeight(ll) >= treeHeight(lr)) { - return create(ll, l.k, l.v, create(lr, x, d, r)); - } else { - return create(create(ll, l.k, l.v, lr.l), lr.k, lr.v, create(lr.r, x, d, r)); - } - } - if (hr <= (hl + 2 | 0)) { - return { - k: x, - v: d, - h: hl >= hr ? hl + 1 | 0 : hr + 1 | 0, - l: l, - r: r - }; - } - let rl = r.l; - let rr = r.r; - if (treeHeight(rr) >= treeHeight(rl)) { - return create(create(l, x, d, rl), r.k, r.v, rr); - } else { - return create(create(l, x, d, rl.l), rl.k, rl.v, create(rl.r, r.k, r.v, rr)); - } -} - -function minKey0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.l; - if (n$1 === undefined) { - return n.k; - } - _n = n$1; - continue; - }; -} - -function minKey(n) { - if (n !== undefined) { - return Primitive_option.some(minKey0Aux(n)); - } -} - -function maxKey0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.r; - if (n$1 === undefined) { - return n.k; - } - _n = n$1; - continue; - }; -} - -function maxKey(n) { - if (n !== undefined) { - return Primitive_option.some(maxKey0Aux(n)); - } -} - -function minKV0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.l; - if (n$1 === undefined) { - return [ - n.k, - n.v - ]; - } - _n = n$1; - continue; - }; -} - -function minimum(n) { - if (n !== undefined) { - return minKV0Aux(n); - } -} - -function maxKV0Aux(_n) { - while (true) { - let n = _n; - let n$1 = n.r; - if (n$1 === undefined) { - return [ - n.k, - n.v - ]; - } - _n = n$1; - continue; - }; -} - -function maximum(n) { - if (n !== undefined) { - return maxKV0Aux(n); - } -} - -function removeMinAuxWithRef(n, kr, vr) { - let ln = n.l; - if (ln !== undefined) { - return bal(removeMinAuxWithRef(ln, kr, vr), n.k, n.v, n.r); - } else { - kr.contents = n.k; - vr.contents = n.v; - return n.r; - } -} - -function isEmpty(x) { - return x === undefined; -} - -function stackAllLeft(_v, _s) { - while (true) { - let s = _s; - let v = _v; - if (v === undefined) { - return s; - } - _s = {hd: v, tl: s}; - _v = v.l; - continue; - }; -} - -function findFirstBy(n, p) { - if (n === undefined) { - return; - } - let left = findFirstBy(n.l, p); - if (left !== undefined) { - return left; - } - let v = n.k; - let d = n.v; - let pvd = p(v, d); - if (pvd) { - return [ - v, - d - ]; - } - let right = findFirstBy(n.r, p); - if (right !== undefined) { - return right; - } -} - -function forEach(_n, f) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - forEach(n.l, f); - f(n.k, n.v); - _n = n.r; - continue; - }; -} - -function map(n, f) { - if (n === undefined) { - return; - } - let newLeft = map(n.l, f); - let newD = f(n.v); - let newRight = map(n.r, f); - return { - k: n.k, - v: newD, - h: n.h, - l: newLeft, - r: newRight - }; -} - -function mapWithKey(n, f) { - if (n === undefined) { - return; - } - let key = n.k; - let newLeft = mapWithKey(n.l, f); - let newD = f(key, n.v); - let newRight = mapWithKey(n.r, f); - return { - k: key, - v: newD, - h: n.h, - l: newLeft, - r: newRight - }; -} - -function reduce(_m, _accu, f) { - while (true) { - let accu = _accu; - let m = _m; - if (m === undefined) { - return accu; - } - let v = m.k; - let d = m.v; - let l = m.l; - let r = m.r; - _accu = f(reduce(l, accu, f), v, d); - _m = r; - continue; - }; -} - -function every(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return true; - } - if (!p(n.k, n.v)) { - return false; - } - if (!every(n.l, p)) { - return false; - } - _n = n.r; - continue; - }; -} - -function some(_n, p) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - if (p(n.k, n.v)) { - return true; - } - if (some(n.l, p)) { - return true; - } - _n = n.r; - continue; - }; -} - -function addMinElement(n, k, v) { - if (n !== undefined) { - return bal(addMinElement(n.l, k, v), n.k, n.v, n.r); - } else { - return singleton(k, v); - } -} - -function addMaxElement(n, k, v) { - if (n !== undefined) { - return bal(n.l, n.k, n.v, addMaxElement(n.r, k, v)); - } else { - return singleton(k, v); - } -} - -function join(ln, v, d, rn) { - if (ln === undefined) { - return addMinElement(rn, v, d); - } - if (rn === undefined) { - return addMaxElement(ln, v, d); - } - let lv = ln.k; - let ld = ln.v; - let lh = ln.h; - let ll = ln.l; - let lr = ln.r; - let rv = rn.k; - let rd = rn.v; - let rh = rn.h; - let rl = rn.l; - let rr = rn.r; - if (lh > (rh + 2 | 0)) { - return bal(ll, lv, ld, join(lr, v, d, rn)); - } else if (rh > (lh + 2 | 0)) { - return bal(join(ln, v, d, rl), rv, rd, rr); - } else { - return create(ln, v, d, rn); - } -} - -function concat(t1, t2) { - if (t1 === undefined) { - return t2; - } - if (t2 === undefined) { - return t1; - } - let kr = { - contents: t2.k - }; - let vr = { - contents: t2.v - }; - let t2r = removeMinAuxWithRef(t2, kr, vr); - return join(t1, kr.contents, vr.contents, t2r); -} - -function concatOrJoin(t1, v, d, t2) { - if (d !== undefined) { - return join(t1, v, Primitive_option.valFromOption(d), t2); - } else { - return concat(t1, t2); - } -} - -function keepShared(n, p) { - if (n === undefined) { - return; - } - let v = n.k; - let d = n.v; - let newLeft = keepShared(n.l, p); - let pvd = p(v, d); - let newRight = keepShared(n.r, p); - if (pvd) { - return join(newLeft, v, d, newRight); - } else { - return concat(newLeft, newRight); - } -} - -function keepMap(n, p) { - if (n === undefined) { - return; - } - let v = n.k; - let d = n.v; - let newLeft = keepMap(n.l, p); - let pvd = p(v, d); - let newRight = keepMap(n.r, p); - if (pvd !== undefined) { - return join(newLeft, v, Primitive_option.valFromOption(pvd), newRight); - } else { - return concat(newLeft, newRight); - } -} - -function partitionShared(n, p) { - if (n === undefined) { - return [ - undefined, - undefined - ]; - } - let key = n.k; - let value = n.v; - let match = partitionShared(n.l, p); - let lf = match[1]; - let lt = match[0]; - let pvd = p(key, value); - let match$1 = partitionShared(n.r, p); - let rf = match$1[1]; - let rt = match$1[0]; - if (pvd) { - return [ - join(lt, key, value, rt), - concat(lf, rf) - ]; - } else { - return [ - concat(lt, rt), - join(lf, key, value, rf) - ]; - } -} - -function lengthNode(n) { - let l = n.l; - let r = n.r; - let sizeL = l !== undefined ? lengthNode(l) : 0; - let sizeR = r !== undefined ? lengthNode(r) : 0; - return (1 + sizeL | 0) + sizeR | 0; -} - -function size(n) { - if (n !== undefined) { - return lengthNode(n); - } else { - return 0; - } -} - -function toListAux(_n, _accu) { - while (true) { - let accu = _accu; - let n = _n; - if (n === undefined) { - return accu; - } - let k = n.k; - let v = n.v; - let l = n.l; - let r = n.r; - _accu = {hd: [ - k, - v - ], tl: toListAux(r, accu)}; - _n = l; - continue; - }; -} - -function toList(s) { - return toListAux(s, /* [] */0); -} - -function checkInvariantInternal(_v) { - while (true) { - let v = _v; - if (v === undefined) { - return; - } - let l = v.l; - let r = v.r; - let diff = treeHeight(l) - treeHeight(r) | 0; - if (!(diff <= 2 && diff >= -2)) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Belt_internalAVLtree.res", - 408, - 4 - ], - Error: new Error() - }; - } - checkInvariantInternal(l); - _v = r; - continue; - }; -} - -function fillArrayKey(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let v = n.k; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArrayKey(l, i, arr) : i; - arr[next] = v; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function fillArrayValue(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let l = n.l; - let r = n.r; - let next = l !== undefined ? fillArrayValue(l, i, arr) : i; - arr[next] = n.v; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function fillArray(_n, _i, arr) { - while (true) { - let i = _i; - let n = _n; - let l = n.l; - let v = n.k; - let r = n.r; - let next = l !== undefined ? fillArray(l, i, arr) : i; - arr[next] = [ - v, - n.v - ]; - let rnext = next + 1 | 0; - if (r === undefined) { - return rnext; - } - _i = rnext; - _n = r; - continue; - }; -} - -function toArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArray(n, 0, v); - return v; -} - -function keysToArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArrayKey(n, 0, v); - return v; -} - -function valuesToArray(n) { - if (n === undefined) { - return []; - } - let size = lengthNode(n); - let v = new Array(size); - fillArrayValue(n, 0, v); - return v; -} - -function fromSortedArrayRevAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - let match = arr[off]; - return singleton(match[0], match[1]); - case 2 : - let match_0 = arr[off]; - let match_1 = arr[off - 1 | 0]; - let match$1 = match_1; - let match$2 = match_0; - return { - k: match$1[0], - v: match$1[1], - h: 2, - l: singleton(match$2[0], match$2[1]), - r: undefined - }; - case 3 : - let match_0$1 = arr[off]; - let match_1$1 = arr[off - 1 | 0]; - let match_2 = arr[off - 2 | 0]; - let match$3 = match_2; - let match$4 = match_1$1; - let match$5 = match_0$1; - return { - k: match$4[0], - v: match$4[1], - h: 2, - l: singleton(match$5[0], match$5[1]), - r: singleton(match$3[0], match$3[1]) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayRevAux(arr, off, nl); - let match$6 = arr[off - nl | 0]; - let right = fromSortedArrayRevAux(arr, (off - nl | 0) - 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, match$6[0], match$6[1], right); - } -} - -function fromSortedArrayAux(arr, off, len) { - switch (len) { - case 0 : - return; - case 1 : - let match = arr[off]; - return singleton(match[0], match[1]); - case 2 : - let match_0 = arr[off]; - let match_1 = arr[off + 1 | 0]; - let match$1 = match_1; - let match$2 = match_0; - return { - k: match$1[0], - v: match$1[1], - h: 2, - l: singleton(match$2[0], match$2[1]), - r: undefined - }; - case 3 : - let match_0$1 = arr[off]; - let match_1$1 = arr[off + 1 | 0]; - let match_2 = arr[off + 2 | 0]; - let match$3 = match_2; - let match$4 = match_1$1; - let match$5 = match_0$1; - return { - k: match$4[0], - v: match$4[1], - h: 2, - l: singleton(match$5[0], match$5[1]), - r: singleton(match$3[0], match$3[1]) - }; - default: - let nl = len / 2 | 0; - let left = fromSortedArrayAux(arr, off, nl); - let match$6 = arr[off + nl | 0]; - let right = fromSortedArrayAux(arr, (off + nl | 0) + 1 | 0, (len - nl | 0) - 1 | 0); - return create(left, match$6[0], match$6[1], right); - } -} - -function fromSortedArrayUnsafe(arr) { - return fromSortedArrayAux(arr, 0, arr.length); -} - -function cmp(s1, s2, kcmp, vcmp) { - let len1 = size(s1); - let len2 = size(s2); - if (len1 === len2) { - let _e1 = stackAllLeft(s1, /* [] */0); - let _e2 = stackAllLeft(s2, /* [] */0); - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = kcmp(h1.k, h2.k); - if (c !== 0) { - return c; - } - let cx = vcmp(h1.v, h2.v); - if (cx !== 0) { - return cx; - } - _e2 = stackAllLeft(h2.r, e2.tl); - _e1 = stackAllLeft(h1.r, e1.tl); - continue; - }; - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2, kcmp, veq) { - let len1 = size(s1); - let len2 = size(s2); - if (len1 === len2) { - let _e1 = stackAllLeft(s1, /* [] */0); - let _e2 = stackAllLeft(s2, /* [] */0); - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return true; - } - if (e2 === 0) { - return true; - } - let h2 = e2.hd; - let h1 = e1.hd; - if (!(kcmp(h1.k, h2.k) === 0 && veq(h1.v, h2.v))) { - return false; - } - _e2 = stackAllLeft(h2.r, e2.tl); - _e1 = stackAllLeft(h1.r, e1.tl); - continue; - }; - } else { - return false; - } -} - -function get(_n, x, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return Primitive_option.some(n.v); - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x, cmp) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return n.v; - } - _n = c < 0 ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function getWithDefault(_n, x, def, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return def; - } - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return n.v; - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function has(_n, x, cmp) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - let v = n.k; - let c = cmp(x, v); - if (c === 0) { - return true; - } - _n = c < 0 ? n.l : n.r; - continue; - }; -} - -function rotateWithLeftChild(k2) { - let k1 = k2.l; - k2.l = k1.r; - k1.r = k2; - let hlk2 = treeHeight(k2.l); - let hrk2 = treeHeight(k2.r); - k2.h = Primitive_int.max(hlk2, hrk2) + 1 | 0; - let hlk1 = treeHeight(k1.l); - let hk2 = k2.h; - k1.h = Primitive_int.max(hlk1, hk2) + 1 | 0; - return k1; -} - -function rotateWithRightChild(k1) { - let k2 = k1.r; - k1.r = k2.l; - k2.l = k1; - let hlk1 = treeHeight(k1.l); - let hrk1 = treeHeight(k1.r); - k1.h = Primitive_int.max(hlk1, hrk1) + 1 | 0; - let hrk2 = treeHeight(k2.r); - let hk1 = k1.h; - k2.h = Primitive_int.max(hrk2, hk1) + 1 | 0; - return k2; -} - -function doubleWithLeftChild(k3) { - let x = k3.l; - let v = rotateWithRightChild(x); - k3.l = v; - return rotateWithLeftChild(k3); -} - -function doubleWithRightChild(k2) { - let x = k2.r; - let v = rotateWithLeftChild(x); - k2.r = v; - return rotateWithRightChild(k2); -} - -function heightUpdateMutate(t) { - let hlt = treeHeight(t.l); - let hrt = treeHeight(t.r); - t.h = Primitive_int.max(hlt, hrt) + 1 | 0; - return t; -} - -function balMutate(nt) { - let l = nt.l; - let r = nt.r; - let hl = treeHeight(l); - let hr = treeHeight(r); - if (hl > (2 + hr | 0)) { - let ll = l.l; - let lr = l.r; - if (heightGe(ll, lr)) { - return heightUpdateMutate(rotateWithLeftChild(nt)); - } else { - return heightUpdateMutate(doubleWithLeftChild(nt)); - } - } - if (hr > (2 + hl | 0)) { - let rl = r.l; - let rr = r.r; - if (heightGe(rr, rl)) { - return heightUpdateMutate(rotateWithRightChild(nt)); - } else { - return heightUpdateMutate(doubleWithRightChild(nt)); - } - } - nt.h = Primitive_int.max(hl, hr) + 1 | 0; - return nt; -} - -function updateMutate(t, x, data, cmp) { - if (t === undefined) { - return singleton(x, data); - } - let k = t.k; - let c = cmp(x, k); - if (c === 0) { - t.v = data; - return t; - } - let l = t.l; - let r = t.r; - if (c < 0) { - let ll = updateMutate(l, x, data, cmp); - t.l = ll; - } else { - t.r = updateMutate(r, x, data, cmp); - } - return balMutate(t); -} - -function fromArray(xs, cmp) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (param, param$1) => cmp(param[0], param$1[0]) < 0); - let result; - if (next >= 0) { - result = fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - let match = xs[i]; - result = updateMutate(result, match[0], match[1], cmp); - } - return result; -} - -function removeMinAuxWithRootMutate(nt, n) { - let rn = n.r; - let ln = n.l; - if (ln !== undefined) { - n.l = removeMinAuxWithRootMutate(nt, ln); - return balMutate(n); - } else { - nt.k = n.k; - nt.v = n.v; - return rn; - } -} - -exports.copy = copy; -exports.create = create; -exports.bal = bal; -exports.singleton = singleton; -exports.updateValue = updateValue; -exports.minKey = minKey; -exports.maxKey = maxKey; -exports.minimum = minimum; -exports.maximum = maximum; -exports.removeMinAuxWithRef = removeMinAuxWithRef; -exports.isEmpty = isEmpty; -exports.stackAllLeft = stackAllLeft; -exports.findFirstBy = findFirstBy; -exports.forEach = forEach; -exports.map = map; -exports.mapWithKey = mapWithKey; -exports.reduce = reduce; -exports.every = every; -exports.some = some; -exports.join = join; -exports.concat = concat; -exports.concatOrJoin = concatOrJoin; -exports.keepShared = keepShared; -exports.keepMap = keepMap; -exports.partitionShared = partitionShared; -exports.lengthNode = lengthNode; -exports.size = size; -exports.toList = toList; -exports.checkInvariantInternal = checkInvariantInternal; -exports.fillArray = fillArray; -exports.toArray = toArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.fromSortedArrayAux = fromSortedArrayAux; -exports.fromSortedArrayRevAux = fromSortedArrayRevAux; -exports.fromSortedArrayUnsafe = fromSortedArrayUnsafe; -exports.cmp = cmp; -exports.eq = eq; -exports.get = get; -exports.getWithDefault = getWithDefault; -exports.getOrThrow = getOrThrow; -exports.has = has; -exports.fromArray = fromArray; -exports.updateMutate = updateMutate; -exports.balMutate = balMutate; -exports.removeMinAuxWithRootMutate = removeMinAuxWithRootMutate; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalBuckets.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalBuckets.cjs deleted file mode 100644 index 55e211a3725..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalBuckets.cjs +++ /dev/null @@ -1,256 +0,0 @@ -'use strict'; - -let Belt_Array = require("./Belt_Array.cjs"); -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); - -function copyAuxCont(_c, _prec) { - while (true) { - let prec = _prec; - let c = _c; - if (c === undefined) { - return; - } - let ncopy = { - key: c.key, - value: c.value, - next: undefined - }; - prec.next = ncopy; - _prec = ncopy; - _c = c.next; - continue; - }; -} - -function copyBucket(c) { - if (c === undefined) { - return c; - } - let head = { - key: c.key, - value: c.value, - next: undefined - }; - copyAuxCont(c.next, head); - return head; -} - -function copyBuckets(buckets) { - let len = buckets.length; - let newBuckets = new Array(len); - for (let i = 0; i < len; ++i) { - newBuckets[i] = copyBucket(buckets[i]); - } - return newBuckets; -} - -function copy(x) { - return { - size: x.size, - buckets: copyBuckets(x.buckets), - hash: x.hash, - eq: x.eq - }; -} - -function bucketLength(_accu, _buckets) { - while (true) { - let buckets = _buckets; - let accu = _accu; - if (buckets === undefined) { - return accu; - } - _buckets = buckets.next; - _accu = accu + 1 | 0; - continue; - }; -} - -function do_bucket_iter(f, _buckets) { - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - f(buckets.key, buckets.value); - _buckets = buckets.next; - continue; - }; -} - -function forEach(h, f) { - let d = h.buckets; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - do_bucket_iter(f, d[i]); - } -} - -function do_bucket_fold(f, _b, _accu) { - while (true) { - let accu = _accu; - let b = _b; - if (b === undefined) { - return accu; - } - _accu = f(accu, b.key, b.value); - _b = b.next; - continue; - }; -} - -function reduce(h, init, f) { - let d = h.buckets; - let accu = init; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - accu = do_bucket_fold(f, d[i], accu); - } - return accu; -} - -function getMaxBucketLength(h) { - return Belt_Array.reduce(h.buckets, 0, (m, b) => { - let len = bucketLength(0, b); - return Primitive_int.max(m, len); - }); -} - -function getBucketHistogram(h) { - let mbl = getMaxBucketLength(h); - let histo = Belt_Array.makeBy(mbl + 1 | 0, param => 0); - Belt_Array.forEach(h.buckets, b => { - let l = bucketLength(0, b); - histo[l] = histo[l] + 1 | 0; - }); - return histo; -} - -function logStats(h) { - let histogram = getBucketHistogram(h); - console.log({ - bindings: h.size, - buckets: h.buckets.length, - histogram: histogram - }); -} - -function filterMapInplaceBucket(f, h, i, _prec, _cell) { - while (true) { - let cell = _cell; - let prec = _prec; - let n = cell.next; - let data = f(cell.key, cell.value); - if (data !== undefined) { - if (prec !== undefined) { - cell.next = cell; - } else { - h.buckets[i] = cell; - } - cell.value = Primitive_option.valFromOption(data); - if (n === undefined) { - cell.next = n; - return; - } - _cell = n; - _prec = cell; - continue; - } - h.size = h.size - 1 | 0; - if (n === undefined) { - if (prec !== undefined) { - prec.next = n; - } else { - h.buckets[i] = prec; - } - return; - } - _cell = n; - continue; - }; -} - -function keepMapInPlace(h, f) { - let h_buckets = h.buckets; - for (let i = 0, i_finish = h_buckets.length; i < i_finish; ++i) { - let v = h_buckets[i]; - if (v !== undefined) { - filterMapInplaceBucket(f, h, i, undefined, v); - } - } -} - -function fillArray(_i, arr, _cell) { - while (true) { - let cell = _cell; - let i = _i; - arr[i] = [ - cell.key, - cell.value - ]; - let v = cell.next; - if (v === undefined) { - return i + 1 | 0; - } - _cell = v; - _i = i + 1 | 0; - continue; - }; -} - -function fillArrayMap(_i, arr, _cell, f) { - while (true) { - let cell = _cell; - let i = _i; - arr[i] = f(cell); - let v = cell.next; - if (v === undefined) { - return i + 1 | 0; - } - _cell = v; - _i = i + 1 | 0; - continue; - }; -} - -function linear(h, f) { - let d = h.buckets; - let current = 0; - let arr = new Array(h.size); - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - let cell = d[i]; - if (cell !== undefined) { - current = fillArrayMap(current, arr, cell, f); - } - } - return arr; -} - -function keysToArray(h) { - return linear(h, x => x.key); -} - -function valuesToArray(h) { - return linear(h, x => x.value); -} - -function toArray(h) { - return linear(h, x => [ - x.key, - x.value - ]); -} - -let C; - -exports.C = C; -exports.copy = copy; -exports.forEach = forEach; -exports.reduce = reduce; -exports.logStats = logStats; -exports.keepMapInPlace = keepMapInPlace; -exports.fillArray = fillArray; -exports.keysToArray = keysToArray; -exports.valuesToArray = valuesToArray; -exports.toArray = toArray; -exports.getBucketHistogram = getBucketHistogram; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalBucketsType.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalBucketsType.cjs deleted file mode 100644 index afd6d078916..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalBucketsType.cjs +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - - -function power_2_above(_x, n) { - while (true) { - let x = _x; - if (x >= n) { - return x; - } - if ((x << 1) < x) { - return x; - } - _x = (x << 1); - continue; - }; -} - -function make(hash, eq, hintSize) { - let s = power_2_above(16, hintSize); - return { - size: 0, - buckets: new Array(s), - hash: hash, - eq: eq - }; -} - -function clear(h) { - h.size = 0; - let h_buckets = h.buckets; - let len = h_buckets.length; - for (let i = 0; i < len; ++i) { - h_buckets[i] = undefined; - } -} - -function isEmpty(h) { - return h.size === 0; -} - -let emptyOpt; - -exports.emptyOpt = emptyOpt; -exports.make = make; -exports.clear = clear; -exports.isEmpty = isEmpty; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalMapInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalMapInt.cjs deleted file mode 100644 index 99c2cca9b85..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalMapInt.cjs +++ /dev/null @@ -1,328 +0,0 @@ -'use strict'; - -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); -let Belt_SortArray = require("./Belt_SortArray.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); - -function add(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - return Belt_internalAVLtree.updateValue(t, data); - } - let v = t.v; - if (x < k) { - return Belt_internalAVLtree.bal(add(t.l, x, data), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, add(t.r, x, data)); - } -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.k; - if (x === v) { - return Primitive_option.some(n.v); - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function getWithDefault(_n, x, def) { - while (true) { - let n = _n; - if (n === undefined) { - return def; - } - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function has(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - let v = n.k; - if (x === v) { - return true; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function remove(n, x) { - if (n === undefined) { - return n; - } - let v = n.k; - let l = n.l; - let r = n.r; - if (x !== v) { - if (x < v) { - return Belt_internalAVLtree.bal(remove(l, x), v, n.v, r); - } else { - return Belt_internalAVLtree.bal(l, v, n.v, remove(r, x)); - } - } - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); -} - -function splitAux(x, n) { - let v = n.k; - let d = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - Primitive_option.some(d), - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - undefined, - n - ]; - } - let match = splitAux(x, l); - return [ - match[0], - match[1], - Belt_internalAVLtree.join(match[2], v, d, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined, - undefined - ]; - } - let match$1 = splitAux(x, r); - return [ - Belt_internalAVLtree.join(l, v, d, match$1[0]), - match$1[1], - match$1[2] - ]; -} - -function split(x, n) { - if (n !== undefined) { - return splitAux(x, n); - } else { - return [ - undefined, - undefined, - undefined - ]; - } -} - -function merge(s1, s2, f) { - if (s1 !== undefined) { - if (s1.h >= ( - s2 !== undefined ? s2.h : 0 - )) { - let v1 = s1.k; - let d1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = split(v1, s2); - return Belt_internalAVLtree.concatOrJoin(merge(l1, match[0], f), v1, f(v1, Primitive_option.some(d1), match[1]), merge(r1, match[2], f)); - } - } else if (s2 === undefined) { - return; - } - let v2 = s2.k; - let d2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = split(v2, s1); - return Belt_internalAVLtree.concatOrJoin(merge(match$1[0], l2, f), v2, f(v2, match$1[1], Primitive_option.some(d2)), merge(match$1[2], r2, f)); -} - -function compareAux(_e1, _e2, vcmp) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = Primitive_int.compare(h1.k, h2.k); - if (c !== 0) { - return c; - } - let cx = vcmp(h1.v, h2.v); - if (cx !== 0) { - return cx; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2, cmp$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), cmp$1); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eqAux(_e1, _e2, eq) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return true; - } - if (e2 === 0) { - return true; - } - let h2 = e2.hd; - let h1 = e1.hd; - if (!(h1.k === h2.k && eq(h1.v, h2.v))) { - return false; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function eq(s1, s2, eq$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return eqAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), eq$1); - } else { - return false; - } -} - -function addMutate(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - t.k = x; - t.v = data; - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addMutate(l, x, data); - t.l = ll; - } else { - t.r = addMutate(r, x, data); - } - return Belt_internalAVLtree.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (param, param$1) => param[0] < param$1[0]); - let result; - if (next >= 0) { - result = Belt_internalAVLtree.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLtree.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - let match = xs[i]; - result = addMutate(result, match[0], match[1]); - } - return result; -} - -let N; - -let A; - -let S; - -exports.N = N; -exports.A = A; -exports.S = S; -exports.add = add; -exports.get = get; -exports.getOrThrow = getOrThrow; -exports.getWithDefault = getWithDefault; -exports.has = has; -exports.remove = remove; -exports.splitAux = splitAux; -exports.split = split; -exports.merge = merge; -exports.compareAux = compareAux; -exports.cmp = cmp; -exports.eqAux = eqAux; -exports.eq = eq; -exports.addMutate = addMutate; -exports.fromArray = fromArray; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalMapString.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalMapString.cjs deleted file mode 100644 index d847937e5fb..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalMapString.cjs +++ /dev/null @@ -1,328 +0,0 @@ -'use strict'; - -let Belt_SortArray = require("./Belt_SortArray.cjs"); -let Primitive_option = require("@rescript/runtime/lib/js/Primitive_option.cjs"); -let Primitive_string = require("@rescript/runtime/lib/js/Primitive_string.cjs"); -let Belt_internalAVLtree = require("./Belt_internalAVLtree.cjs"); - -function add(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - return Belt_internalAVLtree.updateValue(t, data); - } - let v = t.v; - if (x < k) { - return Belt_internalAVLtree.bal(add(t.l, x, data), k, v, t.r); - } else { - return Belt_internalAVLtree.bal(t.l, k, v, add(t.r, x, data)); - } -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.k; - if (x === v) { - return Primitive_option.some(n.v); - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function getWithDefault(_n, x, def) { - while (true) { - let n = _n; - if (n === undefined) { - return def; - } - let v = n.k; - if (x === v) { - return n.v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function has(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return false; - } - let v = n.k; - if (x === v) { - return true; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function remove(n, x) { - if (n === undefined) { - return n; - } - let v = n.k; - let l = n.l; - let r = n.r; - if (x !== v) { - if (x < v) { - return Belt_internalAVLtree.bal(remove(l, x), v, n.v, r); - } else { - return Belt_internalAVLtree.bal(l, v, n.v, remove(r, x)); - } - } - if (l === undefined) { - return r; - } - if (r === undefined) { - return l; - } - let kr = { - contents: r.k - }; - let vr = { - contents: r.v - }; - let r$1 = Belt_internalAVLtree.removeMinAuxWithRef(r, kr, vr); - return Belt_internalAVLtree.bal(l, kr.contents, vr.contents, r$1); -} - -function splitAux(x, n) { - let v = n.k; - let d = n.v; - let l = n.l; - let r = n.r; - if (x === v) { - return [ - l, - Primitive_option.some(d), - r - ]; - } - if (x < v) { - if (l === undefined) { - return [ - undefined, - undefined, - n - ]; - } - let match = splitAux(x, l); - return [ - match[0], - match[1], - Belt_internalAVLtree.join(match[2], v, d, r) - ]; - } - if (r === undefined) { - return [ - n, - undefined, - undefined - ]; - } - let match$1 = splitAux(x, r); - return [ - Belt_internalAVLtree.join(l, v, d, match$1[0]), - match$1[1], - match$1[2] - ]; -} - -function split(x, n) { - if (n !== undefined) { - return splitAux(x, n); - } else { - return [ - undefined, - undefined, - undefined - ]; - } -} - -function merge(s1, s2, f) { - if (s1 !== undefined) { - if (s1.h >= ( - s2 !== undefined ? s2.h : 0 - )) { - let v1 = s1.k; - let d1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let match = split(v1, s2); - return Belt_internalAVLtree.concatOrJoin(merge(l1, match[0], f), v1, f(v1, Primitive_option.some(d1), match[1]), merge(r1, match[2], f)); - } - } else if (s2 === undefined) { - return; - } - let v2 = s2.k; - let d2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - let match$1 = split(v2, s1); - return Belt_internalAVLtree.concatOrJoin(merge(match$1[0], l2, f), v2, f(v2, match$1[1], Primitive_option.some(d2)), merge(match$1[2], r2, f)); -} - -function compareAux(_e1, _e2, vcmp) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let c = Primitive_string.compare(h1.k, h2.k); - if (c !== 0) { - return c; - } - let cx = vcmp(h1.v, h2.v); - if (cx !== 0) { - return cx; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2, cmp$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), cmp$1); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eqAux(_e1, _e2, eq) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return true; - } - if (e2 === 0) { - return true; - } - let h2 = e2.hd; - let h1 = e1.hd; - if (!(h1.k === h2.k && eq(h1.v, h2.v))) { - return false; - } - _e2 = Belt_internalAVLtree.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLtree.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function eq(s1, s2, eq$1) { - let len1 = Belt_internalAVLtree.size(s1); - let len2 = Belt_internalAVLtree.size(s2); - if (len1 === len2) { - return eqAux(Belt_internalAVLtree.stackAllLeft(s1, /* [] */0), Belt_internalAVLtree.stackAllLeft(s2, /* [] */0), eq$1); - } else { - return false; - } -} - -function addMutate(t, x, data) { - if (t === undefined) { - return Belt_internalAVLtree.singleton(x, data); - } - let k = t.k; - if (x === k) { - t.k = x; - t.v = data; - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - let ll = addMutate(l, x, data); - t.l = ll; - } else { - t.r = addMutate(r, x, data); - } - return Belt_internalAVLtree.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArray.strictlySortedLength(xs, (param, param$1) => param[0] < param$1[0]); - let result; - if (next >= 0) { - result = Belt_internalAVLtree.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLtree.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - let match = xs[i]; - result = addMutate(result, match[0], match[1]); - } - return result; -} - -let N; - -let A; - -let S; - -exports.N = N; -exports.A = A; -exports.S = S; -exports.add = add; -exports.get = get; -exports.getOrThrow = getOrThrow; -exports.getWithDefault = getWithDefault; -exports.has = has; -exports.remove = remove; -exports.splitAux = splitAux; -exports.split = split; -exports.merge = merge; -exports.compareAux = compareAux; -exports.cmp = cmp; -exports.eqAux = eqAux; -exports.eq = eq; -exports.addMutate = addMutate; -exports.fromArray = fromArray; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalSetBuckets.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalSetBuckets.cjs deleted file mode 100644 index 2c13e6c816a..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalSetBuckets.cjs +++ /dev/null @@ -1,172 +0,0 @@ -'use strict'; - -let Belt_Array = require("./Belt_Array.cjs"); -let Primitive_int = require("@rescript/runtime/lib/js/Primitive_int.cjs"); - -function copyAuxCont(_c, _prec) { - while (true) { - let prec = _prec; - let c = _c; - if (c === undefined) { - return; - } - let ncopy = { - key: c.key, - next: undefined - }; - prec.next = ncopy; - _prec = ncopy; - _c = c.next; - continue; - }; -} - -function copyBucket(c) { - if (c === undefined) { - return c; - } - let head = { - key: c.key, - next: undefined - }; - copyAuxCont(c.next, head); - return head; -} - -function copyBuckets(buckets) { - let len = buckets.length; - let newBuckets = new Array(len); - for (let i = 0; i < len; ++i) { - newBuckets[i] = copyBucket(buckets[i]); - } - return newBuckets; -} - -function copy(x) { - return { - size: x.size, - buckets: copyBuckets(x.buckets), - hash: x.hash, - eq: x.eq - }; -} - -function bucketLength(_accu, _buckets) { - while (true) { - let buckets = _buckets; - let accu = _accu; - if (buckets === undefined) { - return accu; - } - _buckets = buckets.next; - _accu = accu + 1 | 0; - continue; - }; -} - -function doBucketIter(f, _buckets) { - while (true) { - let buckets = _buckets; - if (buckets === undefined) { - return; - } - f(buckets.key); - _buckets = buckets.next; - continue; - }; -} - -function forEach(h, f) { - let d = h.buckets; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - doBucketIter(f, d[i]); - } -} - -function fillArray(_i, arr, _cell) { - while (true) { - let cell = _cell; - let i = _i; - arr[i] = cell.key; - let v = cell.next; - if (v === undefined) { - return i + 1 | 0; - } - _cell = v; - _i = i + 1 | 0; - continue; - }; -} - -function toArray(h) { - let d = h.buckets; - let current = 0; - let arr = new Array(h.size); - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - let cell = d[i]; - if (cell !== undefined) { - current = fillArray(current, arr, cell); - } - } - return arr; -} - -function doBucketFold(f, _b, _accu) { - while (true) { - let accu = _accu; - let b = _b; - if (b === undefined) { - return accu; - } - _accu = f(accu, b.key); - _b = b.next; - continue; - }; -} - -function reduce(h, init, f) { - let d = h.buckets; - let accu = init; - for (let i = 0, i_finish = d.length; i < i_finish; ++i) { - accu = doBucketFold(f, d[i], accu); - } - return accu; -} - -function getMaxBucketLength(h) { - return Belt_Array.reduce(h.buckets, 0, (m, b) => { - let len = bucketLength(0, b); - return Primitive_int.max(m, len); - }); -} - -function getBucketHistogram(h) { - let mbl = getMaxBucketLength(h); - let histo = Belt_Array.makeBy(mbl + 1 | 0, param => 0); - Belt_Array.forEach(h.buckets, b => { - let l = bucketLength(0, b); - histo[l] = histo[l] + 1 | 0; - }); - return histo; -} - -function logStats(h) { - let histogram = getBucketHistogram(h); - console.log({ - bindings: h.size, - buckets: h.buckets.length, - histogram: histogram - }); -} - -let C; - -exports.C = C; -exports.copy = copy; -exports.forEach = forEach; -exports.fillArray = fillArray; -exports.toArray = toArray; -exports.reduce = reduce; -exports.logStats = logStats; -exports.getBucketHistogram = getBucketHistogram; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalSetInt.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalSetInt.cjs deleted file mode 100644 index 37156dd7ced..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalSetInt.cjs +++ /dev/null @@ -1,191 +0,0 @@ -'use strict'; - -let Belt_SortArrayInt = require("./Belt_SortArrayInt.cjs"); -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); - -function has(_t, x) { - while (true) { - let t = _t; - if (t === undefined) { - return false; - } - let v = t.v; - if (x === v) { - return true; - } - _t = x < v ? t.l : t.r; - continue; - }; -} - -function compareAux(_e1, _e2) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let k1 = h1.v; - let k2 = h2.v; - if (k1 !== k2) { - if (k1 < k2) { - return -1; - } else { - return 1; - } - } - _e2 = Belt_internalAVLset.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLset.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2) { - let len1 = Belt_internalAVLset.size(s1); - let len2 = Belt_internalAVLset.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLset.stackAllLeft(s1, /* [] */0), Belt_internalAVLset.stackAllLeft(s2, /* [] */0)); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2) { - return cmp(s1, s2) === 0; -} - -function subset(_s1, _s2) { - while (true) { - let s2 = _s2; - let s1 = _s1; - if (s1 === undefined) { - return true; - } - if (s2 === undefined) { - return false; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - if (v1 === v2) { - if (!subset(l1, l2)) { - return false; - } - _s2 = r2; - _s1 = r1; - continue; - } - if (v1 < v2) { - if (!subset(Belt_internalAVLset.create(l1, v1, undefined), l2)) { - return false; - } - _s1 = r1; - continue; - } - if (!subset(Belt_internalAVLset.create(undefined, v1, r1), r2)) { - return false; - } - _s1 = l1; - continue; - }; -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function addMutate(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - t.l = addMutate(l, x); - } else { - t.r = addMutate(r, x); - } - return Belt_internalAVLset.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArrayInt.strictlySortedLength(xs); - let result; - if (next >= 0) { - result = Belt_internalAVLset.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLset.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - result = addMutate(result, xs[i]); - } - return result; -} - -let S; - -let N; - -let A; - -exports.S = S; -exports.N = N; -exports.A = A; -exports.has = has; -exports.compareAux = compareAux; -exports.cmp = cmp; -exports.eq = eq; -exports.subset = subset; -exports.get = get; -exports.getOrThrow = getOrThrow; -exports.addMutate = addMutate; -exports.fromArray = fromArray; -/* No side effect */ diff --git a/packages/@rescript/belt/lib/js/src/Belt_internalSetString.cjs b/packages/@rescript/belt/lib/js/src/Belt_internalSetString.cjs deleted file mode 100644 index 15786f83f6c..00000000000 --- a/packages/@rescript/belt/lib/js/src/Belt_internalSetString.cjs +++ /dev/null @@ -1,191 +0,0 @@ -'use strict'; - -let Belt_internalAVLset = require("./Belt_internalAVLset.cjs"); -let Belt_SortArrayString = require("./Belt_SortArrayString.cjs"); - -function has(_t, x) { - while (true) { - let t = _t; - if (t === undefined) { - return false; - } - let v = t.v; - if (x === v) { - return true; - } - _t = x < v ? t.l : t.r; - continue; - }; -} - -function compareAux(_e1, _e2) { - while (true) { - let e2 = _e2; - let e1 = _e1; - if (e1 === 0) { - return 0; - } - if (e2 === 0) { - return 0; - } - let h2 = e2.hd; - let h1 = e1.hd; - let k1 = h1.v; - let k2 = h2.v; - if (k1 !== k2) { - if (k1 < k2) { - return -1; - } else { - return 1; - } - } - _e2 = Belt_internalAVLset.stackAllLeft(h2.r, e2.tl); - _e1 = Belt_internalAVLset.stackAllLeft(h1.r, e1.tl); - continue; - }; -} - -function cmp(s1, s2) { - let len1 = Belt_internalAVLset.size(s1); - let len2 = Belt_internalAVLset.size(s2); - if (len1 === len2) { - return compareAux(Belt_internalAVLset.stackAllLeft(s1, /* [] */0), Belt_internalAVLset.stackAllLeft(s2, /* [] */0)); - } else if (len1 < len2) { - return -1; - } else { - return 1; - } -} - -function eq(s1, s2) { - return cmp(s1, s2) === 0; -} - -function subset(_s1, _s2) { - while (true) { - let s2 = _s2; - let s1 = _s1; - if (s1 === undefined) { - return true; - } - if (s2 === undefined) { - return false; - } - let v1 = s1.v; - let l1 = s1.l; - let r1 = s1.r; - let v2 = s2.v; - let l2 = s2.l; - let r2 = s2.r; - if (v1 === v2) { - if (!subset(l1, l2)) { - return false; - } - _s2 = r2; - _s1 = r1; - continue; - } - if (v1 < v2) { - if (!subset(Belt_internalAVLset.create(l1, v1, undefined), l2)) { - return false; - } - _s1 = r1; - continue; - } - if (!subset(Belt_internalAVLset.create(undefined, v1, r1), r2)) { - return false; - } - _s1 = l1; - continue; - }; -} - -function get(_n, x) { - while (true) { - let n = _n; - if (n === undefined) { - return; - } - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - }; -} - -function getOrThrow(_n, x) { - while (true) { - let n = _n; - if (n !== undefined) { - let v = n.v; - if (x === v) { - return v; - } - _n = x < v ? n.l : n.r; - continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - }; -} - -function addMutate(t, x) { - if (t === undefined) { - return Belt_internalAVLset.singleton(x); - } - let k = t.v; - if (x === k) { - return t; - } - let l = t.l; - let r = t.r; - if (x < k) { - t.l = addMutate(l, x); - } else { - t.r = addMutate(r, x); - } - return Belt_internalAVLset.balMutate(t); -} - -function fromArray(xs) { - let len = xs.length; - if (len === 0) { - return; - } - let next = Belt_SortArrayString.strictlySortedLength(xs); - let result; - if (next >= 0) { - result = Belt_internalAVLset.fromSortedArrayAux(xs, 0, next); - } else { - next = -next | 0; - result = Belt_internalAVLset.fromSortedArrayRevAux(xs, next - 1 | 0, next); - } - for (let i = next; i < len; ++i) { - result = addMutate(result, xs[i]); - } - return result; -} - -let S; - -let N; - -let A; - -exports.S = S; -exports.N = N; -exports.A = A; -exports.has = has; -exports.compareAux = compareAux; -exports.cmp = cmp; -exports.eq = eq; -exports.subset = subset; -exports.get = get; -exports.getOrThrow = getOrThrow; -exports.addMutate = addMutate; -exports.fromArray = fromArray; -/* No side effect */ diff --git a/packages/@rescript/darwin-arm64/RE_LICENSE.md b/packages/@rescript/darwin-arm64/RE_LICENSE.md new file mode 100644 index 00000000000..f79ddd2b654 --- /dev/null +++ b/packages/@rescript/darwin-arm64/RE_LICENSE.md @@ -0,0 +1,521 @@ +This Software is distributed under the terms of the GNU Lesser +General Public License version 2.1 (included below), or (at your +option) any later version. + +As a special exception to the GNU Library General Public License, you +may link, statically or dynamically, a "work that uses the Library" +with a publicly distributed version of the Library to produce an +executable file containing portions of the Library, and distribute +that executable file under terms of your choice, without any of the +additional requirements listed in clause 6 of the GNU Library General +Public License. By "a publicly distributed version of the Library", +we mean either the unmodified Library, or a modified version of the +Library that is distributed under the conditions defined in clause 3 +of the GNU Library General Public License. This exception does not +however invalidate any other reasons why the executable file might be +covered by the GNU Library General Public License. + +---------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/packages/@rescript/darwin-arm64/THIRD_PARTY_NOTICES_REWATCH.md b/packages/@rescript/darwin-arm64/THIRD_PARTY_NOTICES_REWATCH.md new file mode 100644 index 00000000000..0214b053d40 --- /dev/null +++ b/packages/@rescript/darwin-arm64/THIRD_PARTY_NOTICES_REWATCH.md @@ -0,0 +1,133 @@ +# Third-party notices for the OCaml ReScript build system + +The `rescript.exe` OCaml build-system binary includes the following +third-party software. These notices supplement the package's declared license. + +## Cmdliner + +Copyright (c) 2011 The cmdliner programmers + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Yojson + +Copyright (c) 2010-2012, Martin Jambon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +- Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +## Re + +Copyright (C) 2001 Jerome Vouillon + +Re is distributed under the GNU Lesser General Public License version 2.1 or, +at your option, any later version, with the OCaml linking exception. The full +license and exception are included in `RE_LICENSE.md`. + +## Spawn, Luv, libuv, ctypes, and integers + +- Spawn: Copyright (c) 2016-2018 Jane Street Group, LLC +- Luv: Copyright (c) 2018-2023 Anton Bachin +- libuv: Copyright (c) 2015-present libuv project contributors +- ctypes: Copyright (c) 2013 Jeremy Yallop +- integers: Copyright (c) 2013-2016 Jeremy Yallop + +Each project listed in this section is distributed under the MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +## Externally maintained parts of libuv + +Parts of libuv originating from https://github.com/joyent/libuv: +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +They are distributed under the MIT License reproduced above. + +`tree.h` (from FreeBSD): + +Copyright 2002 Niels Provos +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +`inet_pton` and `inet_ntop` (in `src/inet.c`): + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996-1999 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/@rescript/darwin-arm64/bin.d.ts b/packages/@rescript/darwin-arm64/bin.d.ts index f6fa8daaca5..d6e39948452 100644 --- a/packages/@rescript/darwin-arm64/bin.d.ts +++ b/packages/@rescript/darwin-arm64/bin.d.ts @@ -7,4 +7,5 @@ export type BinaryPaths = { rescript_tools_exe: string; rescript_editor_analysis_exe: string; rescript_exe: string; + rescript_rust_exe: string; }; diff --git a/packages/@rescript/darwin-arm64/bin.js b/packages/@rescript/darwin-arm64/bin.js index ffea0133950..716959be006 100644 --- a/packages/@rescript/darwin-arm64/bin.js +++ b/packages/@rescript/darwin-arm64/bin.js @@ -15,4 +15,5 @@ export const binPaths = { "rescript-editor-analysis.exe", ), rescript_exe: path.join(binDir, "rescript.exe"), + rescript_rust_exe: path.join(binDir, "rescript-rust.exe"), }; diff --git a/packages/@rescript/darwin-arm64/package.json b/packages/@rescript/darwin-arm64/package.json index 7e4fe8860d1..05d01e65305 100644 --- a/packages/@rescript/darwin-arm64/package.json +++ b/packages/@rescript/darwin-arm64/package.json @@ -35,7 +35,8 @@ "./bin/bsc.exe", "./bin/rescript-editor-analysis.exe", "./bin/rescript-tools.exe", - "./bin/rescript.exe" + "./bin/rescript.exe", + "./bin/rescript-rust.exe" ] }, "engines": { @@ -50,6 +51,8 @@ "files": [ "bin.js", "bin.d.ts", + "THIRD_PARTY_NOTICES_REWATCH.md", + "RE_LICENSE.md", "bin/" ], "exports": "./bin.js", diff --git a/packages/@rescript/darwin-x64/RE_LICENSE.md b/packages/@rescript/darwin-x64/RE_LICENSE.md new file mode 100644 index 00000000000..f79ddd2b654 --- /dev/null +++ b/packages/@rescript/darwin-x64/RE_LICENSE.md @@ -0,0 +1,521 @@ +This Software is distributed under the terms of the GNU Lesser +General Public License version 2.1 (included below), or (at your +option) any later version. + +As a special exception to the GNU Library General Public License, you +may link, statically or dynamically, a "work that uses the Library" +with a publicly distributed version of the Library to produce an +executable file containing portions of the Library, and distribute +that executable file under terms of your choice, without any of the +additional requirements listed in clause 6 of the GNU Library General +Public License. By "a publicly distributed version of the Library", +we mean either the unmodified Library, or a modified version of the +Library that is distributed under the conditions defined in clause 3 +of the GNU Library General Public License. This exception does not +however invalidate any other reasons why the executable file might be +covered by the GNU Library General Public License. + +---------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/packages/@rescript/darwin-x64/THIRD_PARTY_NOTICES_REWATCH.md b/packages/@rescript/darwin-x64/THIRD_PARTY_NOTICES_REWATCH.md new file mode 100644 index 00000000000..0214b053d40 --- /dev/null +++ b/packages/@rescript/darwin-x64/THIRD_PARTY_NOTICES_REWATCH.md @@ -0,0 +1,133 @@ +# Third-party notices for the OCaml ReScript build system + +The `rescript.exe` OCaml build-system binary includes the following +third-party software. These notices supplement the package's declared license. + +## Cmdliner + +Copyright (c) 2011 The cmdliner programmers + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Yojson + +Copyright (c) 2010-2012, Martin Jambon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +- Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +## Re + +Copyright (C) 2001 Jerome Vouillon + +Re is distributed under the GNU Lesser General Public License version 2.1 or, +at your option, any later version, with the OCaml linking exception. The full +license and exception are included in `RE_LICENSE.md`. + +## Spawn, Luv, libuv, ctypes, and integers + +- Spawn: Copyright (c) 2016-2018 Jane Street Group, LLC +- Luv: Copyright (c) 2018-2023 Anton Bachin +- libuv: Copyright (c) 2015-present libuv project contributors +- ctypes: Copyright (c) 2013 Jeremy Yallop +- integers: Copyright (c) 2013-2016 Jeremy Yallop + +Each project listed in this section is distributed under the MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +## Externally maintained parts of libuv + +Parts of libuv originating from https://github.com/joyent/libuv: +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +They are distributed under the MIT License reproduced above. + +`tree.h` (from FreeBSD): + +Copyright 2002 Niels Provos +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +`inet_pton` and `inet_ntop` (in `src/inet.c`): + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996-1999 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/@rescript/darwin-x64/bin.d.ts b/packages/@rescript/darwin-x64/bin.d.ts index f6fa8daaca5..d6e39948452 100644 --- a/packages/@rescript/darwin-x64/bin.d.ts +++ b/packages/@rescript/darwin-x64/bin.d.ts @@ -7,4 +7,5 @@ export type BinaryPaths = { rescript_tools_exe: string; rescript_editor_analysis_exe: string; rescript_exe: string; + rescript_rust_exe: string; }; diff --git a/packages/@rescript/darwin-x64/bin.js b/packages/@rescript/darwin-x64/bin.js index ffea0133950..716959be006 100644 --- a/packages/@rescript/darwin-x64/bin.js +++ b/packages/@rescript/darwin-x64/bin.js @@ -15,4 +15,5 @@ export const binPaths = { "rescript-editor-analysis.exe", ), rescript_exe: path.join(binDir, "rescript.exe"), + rescript_rust_exe: path.join(binDir, "rescript-rust.exe"), }; diff --git a/packages/@rescript/darwin-x64/package.json b/packages/@rescript/darwin-x64/package.json index b5a4fc87158..9e4c219f639 100644 --- a/packages/@rescript/darwin-x64/package.json +++ b/packages/@rescript/darwin-x64/package.json @@ -35,7 +35,8 @@ "./bin/bsc.exe", "./bin/rescript-editor-analysis.exe", "./bin/rescript-tools.exe", - "./bin/rescript.exe" + "./bin/rescript.exe", + "./bin/rescript-rust.exe" ] }, "engines": { @@ -50,6 +51,8 @@ "files": [ "bin.js", "bin.d.ts", + "THIRD_PARTY_NOTICES_REWATCH.md", + "RE_LICENSE.md", "bin/" ], "exports": "./bin.js", diff --git a/packages/@rescript/linux-arm64/RE_LICENSE.md b/packages/@rescript/linux-arm64/RE_LICENSE.md new file mode 100644 index 00000000000..f79ddd2b654 --- /dev/null +++ b/packages/@rescript/linux-arm64/RE_LICENSE.md @@ -0,0 +1,521 @@ +This Software is distributed under the terms of the GNU Lesser +General Public License version 2.1 (included below), or (at your +option) any later version. + +As a special exception to the GNU Library General Public License, you +may link, statically or dynamically, a "work that uses the Library" +with a publicly distributed version of the Library to produce an +executable file containing portions of the Library, and distribute +that executable file under terms of your choice, without any of the +additional requirements listed in clause 6 of the GNU Library General +Public License. By "a publicly distributed version of the Library", +we mean either the unmodified Library, or a modified version of the +Library that is distributed under the conditions defined in clause 3 +of the GNU Library General Public License. This exception does not +however invalidate any other reasons why the executable file might be +covered by the GNU Library General Public License. + +---------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/packages/@rescript/linux-arm64/THIRD_PARTY_NOTICES_REWATCH.md b/packages/@rescript/linux-arm64/THIRD_PARTY_NOTICES_REWATCH.md new file mode 100644 index 00000000000..0214b053d40 --- /dev/null +++ b/packages/@rescript/linux-arm64/THIRD_PARTY_NOTICES_REWATCH.md @@ -0,0 +1,133 @@ +# Third-party notices for the OCaml ReScript build system + +The `rescript.exe` OCaml build-system binary includes the following +third-party software. These notices supplement the package's declared license. + +## Cmdliner + +Copyright (c) 2011 The cmdliner programmers + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Yojson + +Copyright (c) 2010-2012, Martin Jambon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +- Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +## Re + +Copyright (C) 2001 Jerome Vouillon + +Re is distributed under the GNU Lesser General Public License version 2.1 or, +at your option, any later version, with the OCaml linking exception. The full +license and exception are included in `RE_LICENSE.md`. + +## Spawn, Luv, libuv, ctypes, and integers + +- Spawn: Copyright (c) 2016-2018 Jane Street Group, LLC +- Luv: Copyright (c) 2018-2023 Anton Bachin +- libuv: Copyright (c) 2015-present libuv project contributors +- ctypes: Copyright (c) 2013 Jeremy Yallop +- integers: Copyright (c) 2013-2016 Jeremy Yallop + +Each project listed in this section is distributed under the MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +## Externally maintained parts of libuv + +Parts of libuv originating from https://github.com/joyent/libuv: +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +They are distributed under the MIT License reproduced above. + +`tree.h` (from FreeBSD): + +Copyright 2002 Niels Provos +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +`inet_pton` and `inet_ntop` (in `src/inet.c`): + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996-1999 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/@rescript/linux-arm64/bin.d.ts b/packages/@rescript/linux-arm64/bin.d.ts index f6fa8daaca5..d6e39948452 100644 --- a/packages/@rescript/linux-arm64/bin.d.ts +++ b/packages/@rescript/linux-arm64/bin.d.ts @@ -7,4 +7,5 @@ export type BinaryPaths = { rescript_tools_exe: string; rescript_editor_analysis_exe: string; rescript_exe: string; + rescript_rust_exe: string; }; diff --git a/packages/@rescript/linux-arm64/bin.js b/packages/@rescript/linux-arm64/bin.js index ffea0133950..716959be006 100644 --- a/packages/@rescript/linux-arm64/bin.js +++ b/packages/@rescript/linux-arm64/bin.js @@ -15,4 +15,5 @@ export const binPaths = { "rescript-editor-analysis.exe", ), rescript_exe: path.join(binDir, "rescript.exe"), + rescript_rust_exe: path.join(binDir, "rescript-rust.exe"), }; diff --git a/packages/@rescript/linux-arm64/package.json b/packages/@rescript/linux-arm64/package.json index d8a123e1ad0..4093e7d5d5f 100644 --- a/packages/@rescript/linux-arm64/package.json +++ b/packages/@rescript/linux-arm64/package.json @@ -35,7 +35,8 @@ "./bin/bsc.exe", "./bin/rescript-editor-analysis.exe", "./bin/rescript-tools.exe", - "./bin/rescript.exe" + "./bin/rescript.exe", + "./bin/rescript-rust.exe" ] }, "engines": { @@ -50,6 +51,8 @@ "files": [ "bin.js", "bin.d.ts", + "THIRD_PARTY_NOTICES_REWATCH.md", + "RE_LICENSE.md", "bin/" ], "exports": "./bin.js", diff --git a/packages/@rescript/linux-x64/RE_LICENSE.md b/packages/@rescript/linux-x64/RE_LICENSE.md new file mode 100644 index 00000000000..f79ddd2b654 --- /dev/null +++ b/packages/@rescript/linux-x64/RE_LICENSE.md @@ -0,0 +1,521 @@ +This Software is distributed under the terms of the GNU Lesser +General Public License version 2.1 (included below), or (at your +option) any later version. + +As a special exception to the GNU Library General Public License, you +may link, statically or dynamically, a "work that uses the Library" +with a publicly distributed version of the Library to produce an +executable file containing portions of the Library, and distribute +that executable file under terms of your choice, without any of the +additional requirements listed in clause 6 of the GNU Library General +Public License. By "a publicly distributed version of the Library", +we mean either the unmodified Library, or a modified version of the +Library that is distributed under the conditions defined in clause 3 +of the GNU Library General Public License. This exception does not +however invalidate any other reasons why the executable file might be +covered by the GNU Library General Public License. + +---------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/packages/@rescript/linux-x64/THIRD_PARTY_NOTICES_REWATCH.md b/packages/@rescript/linux-x64/THIRD_PARTY_NOTICES_REWATCH.md new file mode 100644 index 00000000000..0214b053d40 --- /dev/null +++ b/packages/@rescript/linux-x64/THIRD_PARTY_NOTICES_REWATCH.md @@ -0,0 +1,133 @@ +# Third-party notices for the OCaml ReScript build system + +The `rescript.exe` OCaml build-system binary includes the following +third-party software. These notices supplement the package's declared license. + +## Cmdliner + +Copyright (c) 2011 The cmdliner programmers + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Yojson + +Copyright (c) 2010-2012, Martin Jambon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +- Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +## Re + +Copyright (C) 2001 Jerome Vouillon + +Re is distributed under the GNU Lesser General Public License version 2.1 or, +at your option, any later version, with the OCaml linking exception. The full +license and exception are included in `RE_LICENSE.md`. + +## Spawn, Luv, libuv, ctypes, and integers + +- Spawn: Copyright (c) 2016-2018 Jane Street Group, LLC +- Luv: Copyright (c) 2018-2023 Anton Bachin +- libuv: Copyright (c) 2015-present libuv project contributors +- ctypes: Copyright (c) 2013 Jeremy Yallop +- integers: Copyright (c) 2013-2016 Jeremy Yallop + +Each project listed in this section is distributed under the MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +## Externally maintained parts of libuv + +Parts of libuv originating from https://github.com/joyent/libuv: +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +They are distributed under the MIT License reproduced above. + +`tree.h` (from FreeBSD): + +Copyright 2002 Niels Provos +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +`inet_pton` and `inet_ntop` (in `src/inet.c`): + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996-1999 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/@rescript/linux-x64/bin.d.ts b/packages/@rescript/linux-x64/bin.d.ts index f6fa8daaca5..d6e39948452 100644 --- a/packages/@rescript/linux-x64/bin.d.ts +++ b/packages/@rescript/linux-x64/bin.d.ts @@ -7,4 +7,5 @@ export type BinaryPaths = { rescript_tools_exe: string; rescript_editor_analysis_exe: string; rescript_exe: string; + rescript_rust_exe: string; }; diff --git a/packages/@rescript/linux-x64/bin.js b/packages/@rescript/linux-x64/bin.js index ffea0133950..716959be006 100644 --- a/packages/@rescript/linux-x64/bin.js +++ b/packages/@rescript/linux-x64/bin.js @@ -15,4 +15,5 @@ export const binPaths = { "rescript-editor-analysis.exe", ), rescript_exe: path.join(binDir, "rescript.exe"), + rescript_rust_exe: path.join(binDir, "rescript-rust.exe"), }; diff --git a/packages/@rescript/linux-x64/package.json b/packages/@rescript/linux-x64/package.json index c780002f0e5..21048941062 100644 --- a/packages/@rescript/linux-x64/package.json +++ b/packages/@rescript/linux-x64/package.json @@ -35,7 +35,8 @@ "./bin/bsc.exe", "./bin/rescript-editor-analysis.exe", "./bin/rescript-tools.exe", - "./bin/rescript.exe" + "./bin/rescript.exe", + "./bin/rescript-rust.exe" ] }, "engines": { @@ -50,6 +51,8 @@ "files": [ "bin.js", "bin.d.ts", + "THIRD_PARTY_NOTICES_REWATCH.md", + "RE_LICENSE.md", "bin/" ], "exports": "./bin.js", diff --git a/packages/@rescript/win32-x64/RE_LICENSE.md b/packages/@rescript/win32-x64/RE_LICENSE.md new file mode 100644 index 00000000000..f79ddd2b654 --- /dev/null +++ b/packages/@rescript/win32-x64/RE_LICENSE.md @@ -0,0 +1,521 @@ +This Software is distributed under the terms of the GNU Lesser +General Public License version 2.1 (included below), or (at your +option) any later version. + +As a special exception to the GNU Library General Public License, you +may link, statically or dynamically, a "work that uses the Library" +with a publicly distributed version of the Library to produce an +executable file containing portions of the Library, and distribute +that executable file under terms of your choice, without any of the +additional requirements listed in clause 6 of the GNU Library General +Public License. By "a publicly distributed version of the Library", +we mean either the unmodified Library, or a modified version of the +Library that is distributed under the conditions defined in clause 3 +of the GNU Library General Public License. This exception does not +however invalidate any other reasons why the executable file might be +covered by the GNU Library General Public License. + +---------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/packages/@rescript/win32-x64/THIRD_PARTY_NOTICES_REWATCH.md b/packages/@rescript/win32-x64/THIRD_PARTY_NOTICES_REWATCH.md new file mode 100644 index 00000000000..0214b053d40 --- /dev/null +++ b/packages/@rescript/win32-x64/THIRD_PARTY_NOTICES_REWATCH.md @@ -0,0 +1,133 @@ +# Third-party notices for the OCaml ReScript build system + +The `rescript.exe` OCaml build-system binary includes the following +third-party software. These notices supplement the package's declared license. + +## Cmdliner + +Copyright (c) 2011 The cmdliner programmers + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Yojson + +Copyright (c) 2010-2012, Martin Jambon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +- Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +## Re + +Copyright (C) 2001 Jerome Vouillon + +Re is distributed under the GNU Lesser General Public License version 2.1 or, +at your option, any later version, with the OCaml linking exception. The full +license and exception are included in `RE_LICENSE.md`. + +## Spawn, Luv, libuv, ctypes, and integers + +- Spawn: Copyright (c) 2016-2018 Jane Street Group, LLC +- Luv: Copyright (c) 2018-2023 Anton Bachin +- libuv: Copyright (c) 2015-present libuv project contributors +- ctypes: Copyright (c) 2013 Jeremy Yallop +- integers: Copyright (c) 2013-2016 Jeremy Yallop + +Each project listed in this section is distributed under the MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +## Externally maintained parts of libuv + +Parts of libuv originating from https://github.com/joyent/libuv: +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +They are distributed under the MIT License reproduced above. + +`tree.h` (from FreeBSD): + +Copyright 2002 Niels Provos +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +`inet_pton` and `inet_ntop` (in `src/inet.c`): + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996-1999 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/@rescript/win32-x64/bin.d.ts b/packages/@rescript/win32-x64/bin.d.ts index f6fa8daaca5..d6e39948452 100644 --- a/packages/@rescript/win32-x64/bin.d.ts +++ b/packages/@rescript/win32-x64/bin.d.ts @@ -7,4 +7,5 @@ export type BinaryPaths = { rescript_tools_exe: string; rescript_editor_analysis_exe: string; rescript_exe: string; + rescript_rust_exe: string; }; diff --git a/packages/@rescript/win32-x64/bin.js b/packages/@rescript/win32-x64/bin.js index ffea0133950..716959be006 100644 --- a/packages/@rescript/win32-x64/bin.js +++ b/packages/@rescript/win32-x64/bin.js @@ -15,4 +15,5 @@ export const binPaths = { "rescript-editor-analysis.exe", ), rescript_exe: path.join(binDir, "rescript.exe"), + rescript_rust_exe: path.join(binDir, "rescript-rust.exe"), }; diff --git a/packages/@rescript/win32-x64/package.json b/packages/@rescript/win32-x64/package.json index 6ca159ea368..a85aa355a94 100644 --- a/packages/@rescript/win32-x64/package.json +++ b/packages/@rescript/win32-x64/package.json @@ -35,7 +35,8 @@ "./bin/bsc.exe", "./bin/rescript-editor-analysis.exe", "./bin/rescript-tools.exe", - "./bin/rescript.exe" + "./bin/rescript.exe", + "./bin/rescript-rust.exe" ] }, "engines": { @@ -51,6 +52,8 @@ "files": [ "bin.js", "bin.d.ts", + "THIRD_PARTY_NOTICES_REWATCH.md", + "RE_LICENSE.md", "bin/" ], "exports": "./bin.js", diff --git a/packages/artifacts.json b/packages/artifacts.json index 20ab33ba762..5ae97ffc6b8 100644 --- a/packages/artifacts.json +++ b/packages/artifacts.json @@ -11,9 +11,11 @@ "cli/common/bins.cjs", "cli/common/bins.js", "cli/common/platform.cjs", + "cli/common/runBuildSystem.js", "cli/common/runtime.js", "cli/common/tools.cjs", "cli/common/tools.js", + "cli/rescript-rust.js", "cli/rescript-tools.js", "cli/rescript.js", "docs/docson/build-schema.json", @@ -825,5 +827,70 @@ "src/Belt_internalSetBuckets.resi", "src/Belt_internalSetInt.res", "src/Belt_internalSetString.res" + ], + "@rescript/darwin-arm64": [ + "RE_LICENSE.md", + "THIRD_PARTY_NOTICES_REWATCH.md", + "bin.d.ts", + "bin.js", + "bin/.gitkeep", + "bin/bsc.exe", + "bin/rescript-editor-analysis.exe", + "bin/rescript-rust.exe", + "bin/rescript-tools.exe", + "bin/rescript.exe", + "package.json" + ], + "@rescript/darwin-x64": [ + "RE_LICENSE.md", + "THIRD_PARTY_NOTICES_REWATCH.md", + "bin.d.ts", + "bin.js", + "bin/.gitkeep", + "bin/bsc.exe", + "bin/rescript-editor-analysis.exe", + "bin/rescript-rust.exe", + "bin/rescript-tools.exe", + "bin/rescript.exe", + "package.json" + ], + "@rescript/linux-arm64": [ + "RE_LICENSE.md", + "THIRD_PARTY_NOTICES_REWATCH.md", + "bin.d.ts", + "bin.js", + "bin/.gitkeep", + "bin/bsc.exe", + "bin/rescript-editor-analysis.exe", + "bin/rescript-rust.exe", + "bin/rescript-tools.exe", + "bin/rescript.exe", + "package.json" + ], + "@rescript/linux-x64": [ + "RE_LICENSE.md", + "THIRD_PARTY_NOTICES_REWATCH.md", + "bin.d.ts", + "bin.js", + "bin/.gitkeep", + "bin/bsc.exe", + "bin/rescript-editor-analysis.exe", + "bin/rescript-rust.exe", + "bin/rescript-tools.exe", + "bin/rescript.exe", + "package.json" + ], + "@rescript/win32-x64": [ + "RE_LICENSE.md", + "THIRD_PARTY_NOTICES_REWATCH.md", + "bin.d.ts", + "bin.js", + "bin/.gitkeep", + "bin/bsc.exe", + "bin/rescript-editor-analysis.exe", + "bin/rescript-rust.exe", + "bin/rescript-tools.exe", + "bin/rescript.exe", + "package.json" ] } \ No newline at end of file diff --git a/rescript.opam b/rescript.opam index bbae7e26ad5..f09bd89a351 100644 --- a/rescript.opam +++ b/rescript.opam @@ -15,6 +15,10 @@ depends: [ "wtf8" "ocamlformat" {with-test & = "0.29.0"} "yojson" {= "3.0.0"} + "spawn" {= "v0.17.0"} + "cmdliner" {= "2.1.1"} + "luv" {= "0.5.14"} + "re" {= "1.14.0"} "ounit2" {with-test & = "2.2.7"} "odoc" {with-doc} "ocaml-lsp-server" {with-dev-setup & >= "1.23.0"} diff --git a/rewatch-ocaml/AGENTS.md b/rewatch-ocaml/AGENTS.md new file mode 100644 index 00000000000..77c4e5c33d2 --- /dev/null +++ b/rewatch-ocaml/AGENTS.md @@ -0,0 +1,43 @@ +# OCaml rewatch agent instructions + +Read these alongside the [root instructions](../AGENTS.md) and the +[OCaml rewatch guide](README.md). Paths and commands are relative to the +repository root. + +## Compatibility with Rust rewatch + +- Both implementations ship and run the same `rewatch/tests` suite. A change in + observable behavior (output, exit status, generated files, configuration + handling) must either be made in [`rewatch`](../rewatch) too, or be added to + the intentional differences in the README and covered by a test. +- Don't edit the shared tests or their snapshots to make this implementation + pass. Fix the implementation, or document the difference. +- When master changes Rust rewatch, check whether the same change is needed + here. + +## Platforms + +- Every change must work on Windows as well as Unix. Put OS-specific code + behind `platform.mli` and implement it in both `platform_unix.ml` and + `platform_windows.ml`. Don't add Unix-only calls (signals, process groups, + `select` on pipes, symlink assumptions) to shared modules. +- The Windows backend is type-checked on every platform through + `tests/rewatch_ounit_tests`, but its process code only runs on Windows CI. + +## Processes and state + +- Every child process, pipe, thread, lock, and temporary file needs an owner + that releases it on success, failure, and interruption. Use the existing + owners in `process_child.ml`, `build_lock.ml`, and `build_attempt.ml`. +- Signal handlers only record the request. Work stops at the next poll point. +- Keep state that lives across watch rebuilds in `build_session.ml` and state + for one attempt in `build_attempt.ml`. + +## Testing + +- Unit tests: `dune runtest tests/rewatch_ounit_tests`. +- Focused end-to-end tests: + `sh rewatch-ocaml/tests/run.sh "$PWD/packages/@rescript//bin/rescript.exe"`. +- Shared suite: `make test-rewatch`. Run it for any change to build behavior. +- Add a test for every bug fix. Prefer the shared suite when Rust behaves the + same. Poll for observable conditions instead of sleeping. diff --git a/rewatch-ocaml/CLAUDE.md b/rewatch-ocaml/CLAUDE.md new file mode 120000 index 00000000000..47dc3e3d863 --- /dev/null +++ b/rewatch-ocaml/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/rewatch-ocaml/README.md b/rewatch-ocaml/README.md new file mode 100644 index 00000000000..a0384eed240 --- /dev/null +++ b/rewatch-ocaml/README.md @@ -0,0 +1,124 @@ +# OCaml rewatch + +This directory contains the OCaml implementation of ReScript's build system and +CLI (`rescript build`, `watch`, `clean`, `format`, and `compiler-args`). It +ships as `rescript` in the `@rescript/` packages. The Rust +implementation in [`../rewatch`](../rewatch) ships next to it as +`rescript-rust`, and both are tested with the shared integration suite in +[`../rewatch/tests`](../rewatch/tests). + +The port follows Rust rewatch's architecture and algorithms. Every parse and +compile runs `bsc` as a separate process. + +## Building and running + +From the repository root, with the OPAM dependencies of `rescript.opam` +installed: + +```sh +make # builds bsc and packages/@rescript//bin/rescript.exe +dune build rewatch-ocaml/rescript_ocaml.exe # just this executable +``` + +The packaged `rescript.exe` finds `bsc.exe` next to itself, and the npm +launcher (`cli/rescript.js`) supplies the runtime path. To run the dune +executable directly, point it at a compiler and runtime: + +```sh +export RESCRIPT_BSC_EXE="$PWD/packages/@rescript/linux-arm64/bin/bsc.exe" +export RESCRIPT_RUNTIME="$PWD/packages/@rescript/runtime" +_build/default/rewatch-ocaml/rescript_ocaml.exe build path/to/project +``` + +Linux release builds use dune's `static` profile, so the published executable +does not depend on the runner's libc. The version lives in +`rewatch_version.ml` and is kept in sync with the compiler and Rust rewatch by +`yarn constraints --fix`. + +## Layout + +| Area | Modules | +|---|---| +| CLI and entry point | `cli`, `rescript_ocaml`, `output` | +| Configuration | `config_types`, `config_decode` (strict JSON decoding), `config` | +| Projects and packages | `project_context` (workspace roots and dependency lookup), `package_resolution`, `package_traversal`, `package_graph`, `package_plan`, `package_diagnostics` | +| Sources | `source`, `source_filter` (`--filter`), `source_dirs` | +| Build orchestration | `build` (one build or watch rebuild), `build_preparation`, `build_session` (state kept across watch rebuilds), `build_attempt` (state of one attempt), `build_state`, `build_report` | +| Parsing and compiling | `package_parse`, `package_compilation`, `compiler_args`, `compiler_process`, `compiler_scheduler`, `compiler_info` (fingerprints that decide when a package is cleaned), `compile_assets`, `module_graph`, `graph` | +| Artifacts | `build_artifacts` (output paths, publication, stale cleanup), `build_freshness`, `clean`, `file_util` | +| Processes | `process` (worker pool), `process_child` (one child and its pipes), `after_build` | +| Platform | `platform.mli` implemented by `platform_unix.ml` or `platform_windows.ml` (selected by dune), `windows_job_stubs.c`, `termination_signals`, `build_lock` | +| Watching | `watcher` (rebuild loop), `watch_scope` (what to watch), `watch_snapshot` (filesystem snapshots), `native_watcher` (libuv notifications) | +| Other commands | `format`, `compiler_args_command` | + +Native filesystem notifications only wake the watcher. The snapshot taken +afterwards decides what changed, so merged, reordered, or dropped events can't +cause missed rebuilds. + +## Differences from Rust rewatch + +These are intentional: + +- `rescript.json` maps that the build system interprets reject duplicate keys + instead of using the last one. +- A `namespace-entry` without a namespace is an error. +- Configuration errors use the compiler-style form `path: message`, and JSON + syntax errors use `path:line:column: message`. Messages name the field and + the accepted values instead of the parser's internal types. +- Dependencies are rebuilt when the root's package-specs change. Rust keeps + their artifacts until `rescript clean` + ([#8540](https://github.com/rescript-lang/rescript/pull/8540)). +- `rescript clean` also removes out-of-source JavaScript outputs. +- The CLI uses Cmdliner: + - help is rendered as a man page; + - `--no-timing` takes no value; + - help takes precedence over version, and `--version` also works after a + subcommand. +- `--filter` supports the common subset of Rust's regular expression syntax and + rejects other constructs, such as `(?i)`, with an error. Non-ASCII names are + matched byte-wise. +- A failing `--after-build` command fails the build. On Unix, hooks inherit + redirected stdin but not an interactive terminal, because they run in their + own process group. +- `format -v` and `compiler-args -v` write their logs to stderr, so stdout + remains formatted source or JSON. Rust writes them to stdout. +- OpenTelemetry export is not implemented. + +## Platforms + +- **Unix:** children are started with `spawn` in their own process groups. + SIGINT, SIGTERM, SIGHUP, and SIGQUIT terminate those groups before + `rescript` exits. +- **Windows:** children are started through `windows_job_stubs.c`, which + assigns each child to a Job Object before it runs. Cancellation then also + ends its descendants. +- **Pipes:** each child's stdout and stderr are drained by reader threads, + because Windows can't `select` on anonymous pipes. +- **Watching:** uses libuv through `luv`. `.github/opam-repository` holds a + patched luv package for static arm64 musl builds. + +The test suite compiles `platform_windows.ml` on every platform, so the Windows +backend is always type-checked. Its process and Job Object paths only run on +Windows CI. + +## Testing + +```sh +dune runtest tests/rewatch_ounit_tests # unit tests +sh rewatch-ocaml/tests/run.sh "$PWD/packages/@rescript//bin/rescript.exe" # focused end-to-end tests +make test-rewatch # shared suite in rewatch/tests +``` + +The scripts in `tests/check_*.sh` compare the OCaml and Rust executables on +configuration acceptance, command validation, and verbose and interactive +output. `tests/check_canonical_test_coverage.sh` ensures that every shared test +script is run by `rewatch/tests/suite.sh`. Benchmarks and their equivalence +checks are described in [`bench/README.md`](bench/README.md). + +## Packaging + +Each platform package contains `bin/rescript.exe` (this implementation) and +`bin/rescript-rust.exe`, together with `THIRD_PARTY_NOTICES_REWATCH.md` and +`RE_LICENSE.md` for the bundled OCaml libraries. After a build, +`node scripts/updateArtifactList.js` must leave `packages/artifacts.json` +unchanged. diff --git a/rewatch-ocaml/after_build.ml b/rewatch-ocaml/after_build.ml new file mode 100644 index 00000000000..593227ab12d --- /dev/null +++ b/rewatch-ocaml/after_build.ml @@ -0,0 +1,27 @@ +exception Error = Project_context.Error + +let run ?poll ~root command = + let program, args = + match Str.split (Str.regexp "[ \t\r\n]+") command with + | program :: args -> (program, args) + | [] -> raise (Error "--after-build command cannot be empty") + in + let result = + try Process.run_streaming ?poll ~cwd:root program args with + | Process.Error message | Sys_error message -> + raise + (Error + (Printf.sprintf "Could not run --after-build command %S: %s" command + message)) + | Unix.Unix_error (error, operation, argument) -> + let target = if argument = "" then program else argument in + raise + (Error + (Printf.sprintf "Could not run --after-build command %S: %s (%s %s)" + command (Unix.error_message error) operation target)) + in + if not (Process.succeeded result) then + raise + (Error + (Printf.sprintf "--after-build command failed with %s" + (Process.status_string result.status))) diff --git a/rewatch-ocaml/after_build.mli b/rewatch-ocaml/after_build.mli new file mode 100644 index 00000000000..04e812c9fcb --- /dev/null +++ b/rewatch-ocaml/after_build.mli @@ -0,0 +1 @@ +val run : ?poll:(unit -> unit) -> root:string -> string -> unit diff --git a/rewatch-ocaml/ast_header.ml b/rewatch-ocaml/ast_header.ml new file mode 100644 index 00000000000..e5a8cc1c693 --- /dev/null +++ b/rewatch-ocaml/ast_header.ml @@ -0,0 +1,20 @@ +type t = {dependencies: string list; source: string option} + +let read path = + let descriptor = Unix.openfile path [Unix.O_RDONLY; Unix.O_CLOEXEC] 0 in + let channel = Unix.in_channel_of_descr descriptor in + Fun.protect + ~finally:(fun () -> close_in_noerr channel) + (fun () -> + (try ignore (input_line channel) with End_of_file -> ()); + let rec loop dependencies = + match input_line channel with + | line -> + let line = String.trim line in + if line = "" then loop dependencies + else if Filename.is_relative line then loop (line :: dependencies) + else {dependencies = List.rev dependencies; source = Some line} + | exception End_of_file -> + {dependencies = List.rev dependencies; source = None} + in + loop []) diff --git a/rewatch-ocaml/ast_header.mli b/rewatch-ocaml/ast_header.mli new file mode 100644 index 00000000000..3c41db44d24 --- /dev/null +++ b/rewatch-ocaml/ast_header.mli @@ -0,0 +1,7 @@ +type t = {dependencies: string list; source: string option} +(** Published AST headers are read without deserializing the compiler's full AST. + Cleanup needs the original source path, while graph construction needs only + dependency names; keeping one reader prevents those wire-format rules from + drifting. *) + +val read : string -> t diff --git a/rewatch-ocaml/bench/README.md b/rewatch-ocaml/bench/README.md new file mode 100644 index 00000000000..747a1a42977 --- /dev/null +++ b/rewatch-ocaml/bench/README.md @@ -0,0 +1,114 @@ +# Performance and work-equivalence gate + +`performance_gate.sh` compares release builds on two fully isolated copies of +the tracked `rewatch/testrepo` fixture. It deliberately archives both the +fixture and its external Belt/runtime targets and copies all installed, +Git-ignored dependency trees (including nohoisted dependencies) separately +into each root. Cleaning one +implementation therefore cannot warm or remove artifacts used by the other. + +The gate performs one warm-up per implementation, at least five interleaved +clean builds, and reports median wall time, peak summed process-tree RSS, and +peak process-tree task count. Wall time and RSS are acceptance criteria; task +count is diagnostic evidence for subprocess-management overhead. It then traces +clean, unchanged, and single-edit builds with `strace` and requires identical +normalized package/phase/input multisets as well as identical counts for parser, +namespace, compiler, interface, and PPX process launches. The edit targets the +same leaf source in each isolated fixture. This sequence detects superfluous +incremental parsing or compilation that a clean-only comparison cannot expose. +Finally, both implementations clean and build a third fixture at the same +absolute path. The gate first requires the complete post-build +file-name sets to match, including auxiliary cache and editor-control files, +and then requires byte-identical generated JavaScript, compiler interfaces +(`.cmi`), JavaScript IR (`.cmj`), parser AST caches, namespace maps, copied +sources, source-directory metadata, and `build.ninja` markers, including those +below installed dependency trees. It does not treat typed debug metadata +(`.cmt`/`.cmti`), compiler logs, or `compiler-info.json` as byte-stable: those +contain compiler debug data, timestamps, or intentionally +implementation-specific state and are covered by file-set and integration +checks instead. The default +acceptance threshold requires both OCaml medians to be no more than 125% of +Rust. + +This is one part of equivalence checking, not a substitute for the test suites. +Before accepting a performance increment, also run the OCaml unit/focused tests +and the canonical Rust rewatch integration suite against the OCaml executable: + +```sh +opam exec -- dune runtest tests/rewatch_ounit_tests +bash rewatch-ocaml/tests/run.sh \ + _build/default/rewatch-ocaml/rescript_ocaml.exe +(cd rewatch/tests && \ + bash ./suite.sh ../../_build/default/rewatch-ocaml/rescript_ocaml.exe) +``` + +Together these cover three different failure classes: + +- the canonical and focused suites check observable command/build/watch + behavior; +- the three `strace` classifications check that a speed result did not hide + skipped or superfluous clean/incremental module or PPX work (argument + semantics remain covered by the compiler-argument and integration tests); +- the fresh-tree comparisons check the complete post-build file set plus the + byte contents of every stable generated artifact class. + +The manifest comparison intentionally recreates its fixture between runners. +Using only each implementation's `clean` command would allow a Rust-only file +to survive into the OCaml run and could conceal a missing-output bug. + +Build both release executables and run: + +```sh +cargo build --manifest-path rewatch/Cargo.toml --release +opam exec -- dune build --profile release rewatch-ocaml/rescript_ocaml.exe + +rewatch-ocaml/bench/performance_gate.sh \ + rewatch/target/release/rescript \ + _build/default/rewatch-ocaml/rescript_ocaml.exe \ + 5 +``` + +By default the harness uses the compiler and runtime selected by +`rewatch/tests/get_bin_paths.js`. Set both `RESCRIPT_BSC_EXE` and +`RESCRIPT_RUNTIME` to compare with another local compiler build; the harness +preserves them only when both are set, so the two implementations still use +the same inputs. + +The authoritative gate requires Linux (`/proc`), `strace`, GNU-compatible +nanosecond `date`, and a stable plugged-in host with no competing heavy work. +Keep the isolated fixtures on a case-sensitive Linux filesystem. A Linux +container backed by a case-insensitive macOS bind mount can transiently report +that a differently-cased recreated CMI exists to `stat` and then return +`ENOENT` from the immediately following `open`; that host-filesystem artifact +is not valid scheduler or benchmark evidence. The harness's default `mktemp` +workspace normally stays on the container filesystem. +Set `REWATCH_PERFORMANCE_THRESHOLD_PERCENT` to change the 125% threshold. Set `KEEP_REWATCH_BENCHMARK_WORKDIR=1` to retain traces and raw +stdout/stderr for investigation. For a quick correctness-only check, an odd run +count below five is accepted only with `REWATCH_ALLOW_SMOKE_RUN=1`; its timing +is not a meaningful measurement. + +## Watch performance gate + +The retained-watch performance and resource gate exercises several ordinary +edits through one long-lived watcher: + +```sh +rewatch-ocaml/bench/watch_performance_gate.sh \ + rewatch/target/release/rescript \ + _build/default/rewatch-ocaml/rescript_ocaml.exe \ + 7 +``` + +It warms both implementations, interleaves an odd number of timed edits, +requires byte-identical generated JavaScript and normalized parser/compiler +argument logs, and samples file descriptors, tasks, and RSS after every build. +This catches retained-state implementations that appear fast by skipping work, +as well as resource growth that a single build cannot show. The +default median-latency limit is 150% of Rust because individual watch events +include operating-system notification and 50 ms polling intervals; override it +with `REWATCH_WATCH_PERFORMANCE_THRESHOLD_PERCENT` only for investigation. +The build gate's lower-noise 125% clean/incremental threshold remains the +authoritative general performance criterion. Set +`KEEP_REWATCH_WATCH_PERFORMANCE=1` to retain output, compiler-call logs, +latencies, and fixtures. This gate requires Linux `/proc`, GNU-compatible +millisecond `date`, and `setsid`. diff --git a/rewatch-ocaml/bench/performance_gate.sh b/rewatch-ocaml/bench/performance_gate.sh new file mode 100755 index 00000000000..4118d7fc651 --- /dev/null +++ b/rewatch-ocaml/bench/performance_gate.sh @@ -0,0 +1,364 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 2 || $# -gt 3 ]]; then + echo "Usage: $0 RUST_REWATCH OCAML_REWATCH [RUNS]" >&2 + exit 2 +fi + +repo_root=$(cd "$(dirname "$0")/../.." && pwd) +rust_executable=$(cd "$(dirname "$1")" && pwd)/$(basename "$1") +ocaml_executable=$(cd "$(dirname "$2")" && pwd)/$(basename "$2") +runs=${3:-5} +threshold_percent=${REWATCH_PERFORMANCE_THRESHOLD_PERCENT:-125} + +if [[ ! -x "$rust_executable" || ! -x "$ocaml_executable" ]]; then + echo "Both rewatch executables must exist and be executable." >&2 + exit 2 +fi +if [[ ! "$runs" =~ ^[1-9][0-9]*$ || $((runs % 2)) -eq 0 ]]; then + echo "RUNS must be a positive odd integer so the median is unambiguous." >&2 + exit 2 +fi +if ((runs < 5)) && [[ ${REWATCH_ALLOW_SMOKE_RUN:-0} != 1 ]]; then + echo "RUNS must be at least 5 for the quality gate." >&2 + echo "Set REWATCH_ALLOW_SMOKE_RUN=1 only for a non-authoritative smoke run." >&2 + exit 2 +fi +for command in awk basename cmp cp date diff dirname find getconf git grep head \ + mktemp node ps sed sha256sum sleep sort strace tar uname xargs; do + command -v "$command" >/dev/null || { + echo "Missing required command: $command" >&2 + exit 2 + } +done +if [[ ! -d /proc ]]; then + echo "This gate requires Linux /proc for process-tree RSS sampling." >&2 + exit 2 +fi + +work_root=$(mktemp -d "${TMPDIR:-/tmp}/rewatch-performance.XXXXXX") +cleanup() { + if [[ ${KEEP_REWATCH_BENCHMARK_WORKDIR:-0} == 1 ]]; then + echo "Kept benchmark workdir: $work_root" >&2 + else + find "$work_root" -depth -delete + fi +} +trap cleanup EXIT INT TERM + +prepare_fixture() { + local destination=$1 + mkdir -p "$destination" + git -C "$repo_root" archive HEAD \ + rewatch/testrepo packages/@rescript/belt packages/@rescript/runtime \ + | tar -x -C "$destination" + # Dependencies and workspace links are intentionally ignored by Git. Keep a + # separate installed tree in each root so neither implementation can affect + # the other's generated dependency artifacts. + while IFS= read -r dependency_tree; do + local relative_tree=${dependency_tree#"$repo_root/"} + mkdir -p "$(dirname "$destination/$relative_tree")" + cp -a --reflink=auto "$dependency_tree" "$destination/$relative_tree" + done < <(find "$repo_root/rewatch/testrepo" -type d -name node_modules \ + -prune -print) +} + +rust_root="$work_root/rust" +ocaml_root="$work_root/ocaml" +prepare_fixture "$rust_root" +prepare_fixture "$ocaml_root" +rust_fixture="$rust_root/rewatch/testrepo" +ocaml_fixture="$ocaml_root/rewatch/testrepo" + +if [[ -z ${RESCRIPT_BSC_EXE:-} || -z ${RESCRIPT_RUNTIME:-} ]]; then + eval "$(cd "$repo_root/rewatch/tests" && node ./get_bin_paths.js)" +fi +export RESCRIPT_BSC_EXE RESCRIPT_RUNTIME + +results="$work_root/results.csv" +echo "implementation,iteration,wall_ms,peak_tree_rss_kib,peak_tree_tasks" \ + >"$results" + +tree_resources() { + local root_pid=$1 + ps -e -o pid=,ppid=,rss=,nlwp= | awk -v root="$root_pid" ' + { pids[NR] = $1; parent[$1] = $2; memory[$1] = $3; tasks[$1] = $4 } + END { + live[root] = 1 + for (pass = 0; pass < NR; pass++) + for (i = 1; i <= NR; i++) + if (live[parent[pids[i]]]) live[pids[i]] = 1 + for (pid in live) { + total_memory += memory[pid] + total_tasks += tasks[pid] + } + print total_memory + 0, total_tasks + 0 + }' +} + +clean_and_build() { + local executable=$1 fixture=$2 output=$3 + "$executable" clean "$fixture" >/dev/null 2>&1 + "$executable" build "$fixture" >"$output" 2>"$output.stderr" +} + +measure() { + local implementation=$1 executable=$2 fixture=$3 iteration=$4 + local output="$work_root/${implementation}-${iteration}" + "$executable" clean "$fixture" >/dev/null 2>&1 + local start_ns root_pid peak_rss=0 peak_tasks=0 rss tasks end_ns wall_ms + start_ns=$(date +%s%N) + "$executable" build "$fixture" >"$output" 2>"$output.stderr" & + root_pid=$! + while kill -0 "$root_pid" 2>/dev/null; do + read -r rss tasks < <(tree_resources "$root_pid") + if ((rss > peak_rss)); then + peak_rss=$rss + fi + if ((tasks > peak_tasks)); then + peak_tasks=$tasks + fi + sleep 0.02 + done + wait "$root_pid" + end_ns=$(date +%s%N) + wall_ms=$(((end_ns - start_ns) / 1000000)) + echo "$implementation,$iteration,$wall_ms,$peak_rss,$peak_tasks" >>"$results" + printf '%-5s run %d: %6d ms %8d KiB %4d tasks\n' \ + "$implementation" "$iteration" "$wall_ms" "$peak_rss" "$peak_tasks" +} + +median_column() { + local implementation=$1 column=$2 middle=$((runs / 2 + 1)) + awk -F, -v implementation="$implementation" \ + '$1 == implementation { print $'"$column"' }' "$results" \ + | sort -n | sed -n "${middle}p" +} + +echo "Rewatch clean-build performance gate" +echo "commit: $(git -C "$repo_root" rev-parse HEAD)" +echo "host: $(uname -a)" +echo "cpus: $(getconf _NPROCESSORS_ONLN 2>/dev/null || echo unknown)" +echo "runs: $runs (interleaved after one warm-up each)" +echo "threshold: ${threshold_percent}% of Rust median wall and RSS" + +clean_and_build "$rust_executable" "$rust_fixture" "$work_root/rust-warmup" +clean_and_build "$ocaml_executable" "$ocaml_fixture" "$work_root/ocaml-warmup" + +for ((iteration = 1; iteration <= runs; iteration++)); do + if ((iteration % 2 == 1)); then + measure rust "$rust_executable" "$rust_fixture" "$iteration" + measure ocaml "$ocaml_executable" "$ocaml_fixture" "$iteration" + else + measure ocaml "$ocaml_executable" "$ocaml_fixture" "$iteration" + measure rust "$rust_executable" "$rust_fixture" "$iteration" + fi +done + +rust_wall=$(median_column rust 3) +ocaml_wall=$(median_column ocaml 3) +rust_rss=$(median_column rust 4) +ocaml_rss=$(median_column ocaml 4) +rust_tasks=$(median_column rust 5) +ocaml_tasks=$(median_column ocaml 5) +printf 'median Rust: %6d ms %8d KiB %4d peak tasks\n' \ + "$rust_wall" "$rust_rss" "$rust_tasks" +printf 'median OCaml: %6d ms %8d KiB %4d peak tasks\n' \ + "$ocaml_wall" "$ocaml_rss" "$ocaml_tasks" + +trace_and_classify() { + local implementation=$1 scenario=$2 executable=$3 fixture=$4 manifest=$5 + local clean_first=$6 + local trace_prefix="$work_root/${implementation}-${scenario}.execve" + if [[ "$clean_first" == 1 ]]; then + "$executable" clean "$fixture" >/dev/null 2>&1 + fi + strace -f -ff -qq -s 4096 -e trace=execve,chdir -o "$trace_prefix" \ + "$executable" build "$fixture" \ + >"$work_root/${implementation}-${scenario}-trace.out" \ + 2>"$work_root/${implementation}-${scenario}-trace.stderr" + local trace_files=("$trace_prefix".*) + local implementation_root=${fixture%/rewatch/testrepo} + local trace_file exec_line argv cwd_line cwd phase input identity + : >"$manifest.unsorted" + for trace_file in "${trace_files[@]}"; do + exec_line=$(grep -m1 -F "execve(\"$RESCRIPT_BSC_EXE\"" "$trace_file" \ + || grep -m1 -E 'execve\("[^"]*sury-ppx' "$trace_file" || true) + if [[ -z "$exec_line" ]]; then + continue + fi + argv=${exec_line#*, } + argv=${argv%%], 0x*}] + cwd_line=$(grep -m1 '^chdir("' "$trace_file" || true) + cwd=${cwd_line#chdir(\"} + cwd=${cwd%%\"*} + if [[ "$exec_line" == *"execve(\"$RESCRIPT_BSC_EXE\""* ]]; then + if [[ "$argv" == *'"-bs-ast"'* ]]; then + phase=parse + elif [[ "$argv" == *'.mlmap"'* ]]; then + phase=namespace + else + phase=compile + fi + input=${argv##*, } + input=${input%]} + identity="$cwd"$'\t'"$phase"$'\t'"$input" + else + # PPX temporary input/output names are deliberately randomized. Its + # executable identity and count are the stable unit of work. + identity=ppx$'\t'"${argv%%,*}" + fi + printf '%s\n' "$identity" \ + | sed "s#$implementation_root##g" >>"$manifest.unsorted" + done + sort "$manifest.unsorted" >"$manifest" + local invocations parse namespace compile interface ppx + invocations=$(grep -hF -c "execve(\"$RESCRIPT_BSC_EXE\"" "${trace_files[@]}" \ + | awk '{ total += $1 } END { print total + 0 }') + parse=$(grep -hF "execve(\"$RESCRIPT_BSC_EXE\"" "${trace_files[@]}" \ + | grep -F -c '"-bs-ast"' || true) + namespace=$(grep -hF "execve(\"$RESCRIPT_BSC_EXE\"" "${trace_files[@]}" \ + | grep -E -c '\.mlmap"' || true) + interface=$(grep -hF "execve(\"$RESCRIPT_BSC_EXE\"" "${trace_files[@]}" \ + | grep -vF '"-bs-ast"' | grep -vE '\.mlmap"' \ + | grep -E -c '\.iast"' || true) + compile=$((invocations - parse - namespace)) + ppx=$(grep -hE -c 'execve\("[^"]*sury-ppx' "${trace_files[@]}" \ + | awk '{ total += $1 } END { print total + 0 }') + echo "$invocations,$parse,$namespace,$compile,$interface,$ppx" +} + +rust_clean_invocations="$work_root/rust-clean-invocations.txt" +ocaml_clean_invocations="$work_root/ocaml-clean-invocations.txt" +rust_clean_work=$(trace_and_classify rust clean "$rust_executable" \ + "$rust_fixture" "$rust_clean_invocations" 1) +ocaml_clean_work=$(trace_and_classify ocaml clean "$ocaml_executable" \ + "$ocaml_fixture" "$ocaml_clean_invocations" 1) + +rust_unchanged_invocations="$work_root/rust-unchanged-invocations.txt" +ocaml_unchanged_invocations="$work_root/ocaml-unchanged-invocations.txt" +rust_unchanged_work=$(trace_and_classify rust unchanged "$rust_executable" \ + "$rust_fixture" "$rust_unchanged_invocations" 0) +ocaml_unchanged_work=$(trace_and_classify ocaml unchanged "$ocaml_executable" \ + "$ocaml_fixture" "$ocaml_unchanged_invocations" 0) + +printf '\n// benchmark single edit\n' \ + >>"$rust_fixture/packages/watch-warnings/src/B.res" +printf '\n// benchmark single edit\n' \ + >>"$ocaml_fixture/packages/watch-warnings/src/B.res" +rust_edit_invocations="$work_root/rust-edit-invocations.txt" +ocaml_edit_invocations="$work_root/ocaml-edit-invocations.txt" +rust_edit_work=$(trace_and_classify rust edit "$rust_executable" \ + "$rust_fixture" "$rust_edit_invocations" 0) +ocaml_edit_work=$(trace_and_classify ocaml edit "$ocaml_executable" \ + "$ocaml_fixture" "$ocaml_edit_invocations" 0) + +echo "work columns: bsc_total,parse,namespace,compile,interfaces,ppx" +echo "clean Rust: $rust_clean_work" +echo "clean OCaml: $ocaml_clean_work" +echo "unchanged Rust: $rust_unchanged_work" +echo "unchanged OCaml: $ocaml_unchanged_work" +echo "edit Rust: $rust_edit_work" +echo "edit OCaml: $ocaml_edit_work" + +artifact_manifest() { + local root=$1 output=$2 + find "$root" -type f \ + \( -name '*.ast' -o -name '*.iast' -o -name '*.cmi' -o -name '*.cmj' \ + -o -name '*.mlmap' \ + -o -name '*.js' -o -name '*.mjs' -o -name '*.cjs' -o -name '*.map' \ + -o -name '*.res' -o -name '*.resi' -o -name '.sourcedirs.json' \ + -o -name build.ninja \) \ + ! -name '.compiler.log' ! -name compiler-info.json -print0 \ + | sort -z | xargs -0 sha256sum | sed "s#$root/##" >"$output" +} + +file_set_manifest() { + local root=$1 output=$2 + find "$root" -type f -printf '%P\n' | sort >"$output" +} + +# Use the same absolute path for both builds so paths embedded in binary +# compiler artifacts are directly comparable byte for byte. +equivalence_root="$work_root/equivalence" +prepare_fixture "$equivalence_root" +equivalence_fixture="$equivalence_root/rewatch/testrepo" +rust_artifacts="$work_root/rust-artifacts.sha256" +ocaml_artifacts="$work_root/ocaml-artifacts.sha256" +rust_files="$work_root/rust-files.txt" +ocaml_files="$work_root/ocaml-files.txt" +clean_and_build "$rust_executable" "$equivalence_fixture" \ + "$work_root/rust-equivalence" +artifact_manifest "$equivalence_root" "$rust_artifacts" +file_set_manifest "$equivalence_root" "$rust_files" +# Recreate, rather than clean, the fixture so OCaml cannot inherit an artifact +# that only Rust produced. Reusing the same pathname keeps embedded paths equal. +find "$equivalence_root" -depth -delete +prepare_fixture "$equivalence_root" +clean_and_build "$ocaml_executable" "$equivalence_fixture" \ + "$work_root/ocaml-equivalence" +artifact_manifest "$equivalence_root" "$ocaml_artifacts" +file_set_manifest "$equivalence_root" "$ocaml_files" +if cmp -s "$rust_files" "$ocaml_files"; then + file_set_equivalence=1 + echo "files: identical complete post-build file sets" +else + file_set_equivalence=0 + echo "complete post-build file-set diff:" >&2 + diff -u "$rust_files" "$ocaml_files" >&2 || true +fi +if cmp -s "$rust_artifacts" "$ocaml_artifacts"; then + artifact_equivalence=1 + echo "artifacts: identical generated file sets and contents" +else + artifact_equivalence=0 + echo "artifact manifest diff:" >&2 + diff -u "$rust_artifacts" "$ocaml_artifacts" >&2 || true +fi + +failed=0 +if ((runs >= 5 && ocaml_wall * 100 > rust_wall * threshold_percent)); then + echo "FAIL: OCaml median wall time exceeds the threshold." >&2 + failed=1 +fi +if ((runs >= 5 && ocaml_rss * 100 > rust_rss * threshold_percent)); then + echo "FAIL: OCaml median peak tree RSS exceeds the threshold." >&2 + failed=1 +fi +for scenario in clean unchanged edit; do + rust_work_variable="rust_${scenario}_work" + ocaml_work_variable="ocaml_${scenario}_work" + rust_manifest_variable="rust_${scenario}_invocations" + ocaml_manifest_variable="ocaml_${scenario}_invocations" + rust_work_value=${!rust_work_variable} + ocaml_work_value=${!ocaml_work_variable} + rust_manifest=${!rust_manifest_variable} + ocaml_manifest=${!ocaml_manifest_variable} + if [[ "$rust_work_value" != "$ocaml_work_value" ]]; then + echo "FAIL: Rust and OCaml performed different $scenario compiler work." >&2 + failed=1 + fi + if ! cmp -s "$rust_manifest" "$ocaml_manifest"; then + echo "FAIL: Rust and OCaml performed different $scenario module/PPX work." >&2 + diff -u "$rust_manifest" "$ocaml_manifest" >&2 || true + failed=1 + fi +done +if ((file_set_equivalence == 0)); then + echo "FAIL: Rust and OCaml produced different post-build file sets." >&2 + failed=1 +fi +if ((artifact_equivalence == 0)); then + echo "FAIL: Rust and OCaml generated different artifacts." >&2 + failed=1 +fi + +if ((failed)); then + exit 1 +fi +if ((runs < 5)); then + echo "PASS: correctness smoke checks passed; performance gate not evaluated." +else + echo "PASS: timing, memory, compiler-work, and artifact-equivalence gates passed." +fi diff --git a/rewatch-ocaml/bench/watch_performance_gate.sh b/rewatch-ocaml/bench/watch_performance_gate.sh new file mode 100755 index 00000000000..b21f38c5307 --- /dev/null +++ b/rewatch-ocaml/bench/watch_performance_gate.sh @@ -0,0 +1,287 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -lt 2 || $# -gt 3 ]]; then + echo "Usage: $0 RUST_REWATCH OCAML_REWATCH [RUNS]" >&2 + exit 2 +fi + +repo_root=$(cd "$(dirname "$0")/../.." && pwd) +rust_executable=$(cd "$(dirname "$1")" && pwd)/$(basename "$1") +ocaml_executable=$(cd "$(dirname "$2")" && pwd)/$(basename "$2") +runs=${3:-7} +threshold_percent=${REWATCH_WATCH_PERFORMANCE_THRESHOLD_PERCENT:-150} + +if ((runs < 5 || runs % 2 == 0)); then + echo "RUNS must be an odd number of at least five." >&2 + exit 2 +fi +for command in awk cat cmp cp date find grep mktemp node sed seq setsid sleep sort tail wc; do + command -v "$command" >/dev/null || { + echo "Missing required command: $command" >&2 + exit 2 + } +done +if [[ ! -x $rust_executable || ! -x $ocaml_executable ]]; then + echo "Both rewatch executables must exist and be executable." >&2 + exit 2 +fi +if [[ ! -d /proc/self/fd ]]; then + echo "The retained-watch performance gate requires Linux /proc." >&2 + exit 2 +fi + +if [[ -z ${RESCRIPT_BSC_EXE:-} || -z ${RESCRIPT_RUNTIME:-} ]]; then + eval "$(cd "$repo_root/rewatch/tests" && node ./get_bin_paths.js)" +fi +real_bsc=$RESCRIPT_BSC_EXE +runtime=$RESCRIPT_RUNTIME +counting_bsc="$repo_root/_build/default/tests/rewatch_ounit_tests/rewatch_bsc_test_proxy.exe" + +work_root=$(mktemp -d "${TMPDIR:-/tmp}/rewatch-watch-performance.XXXXXX") +declare -A pids=() +terminate_group() { + local pid=$1 + local reaped=false state + if ! kill -TERM -- "-$pid" 2>/dev/null; then + kill -TERM "$pid" 2>/dev/null || true + fi + for _ in $(seq 1 100); do + if [[ $reaped == false && -r /proc/$pid/stat ]]; then + state=$(awk '{print $3}' "/proc/$pid/stat" 2>/dev/null || true) + if [[ $state == Z ]]; then + wait "$pid" 2>/dev/null || true + reaped=true + fi + fi + if ! kill -0 -- "-$pid" 2>/dev/null; then + if [[ $reaped == false ]]; then wait "$pid" 2>/dev/null || true; fi + return + fi + sleep 0.05 + done + kill -KILL -- "-$pid" 2>/dev/null || true + if [[ $reaped == false ]]; then kill -KILL "$pid" 2>/dev/null || true; fi + if [[ $reaped == false ]]; then wait "$pid" 2>/dev/null || true; fi +} +cleanup() { + trap - EXIT INT TERM + local implementation pid + for implementation in "${!pids[@]}"; do + pid=${pids[$implementation]} + terminate_group "$pid" + done + if [[ ${KEEP_REWATCH_WATCH_PERFORMANCE:-0} == 1 ]]; then + echo "Kept watch performance workdir: $work_root" >&2 + else + find "$work_root" -depth -delete + fi +} +trap cleanup EXIT INT TERM + +marker_script="$work_root/mark-build.mjs" +printf '%s\n' \ + 'import fs from "node:fs";' \ + 'fs.appendFileSync(process.env.REWATCH_WATCH_MARKER, `${Date.now()}\n`);' \ + >"$marker_script" + +wait_for_lines() { + local path=$1 expected=$2 + for _ in $(seq 1 400); do + if [[ -f $path ]] && [[ $(wc -l <"$path") -ge $expected ]]; then return; fi + sleep 0.05 + done + echo "Timed out waiting for $expected lines in $path" >&2 + exit 1 +} + +wait_for_text_count() { + local path=$1 text=$2 expected=$3 + for _ in $(seq 1 400); do + if [[ -f $path ]] && \ + [[ $(grep -cF "$text" "$path" 2>/dev/null || true) -ge $expected ]]; then + return + fi + sleep 0.05 + done + echo "Timed out waiting for occurrence $expected of '$text' in $path" >&2 + exit 1 +} + +wait_for_idle() { + local pid=$1 + for _ in $(seq 1 400); do + if [[ ! -d /proc/$pid ]]; then + echo "Watcher $pid exited before becoming idle." >&2 + exit 1 + fi + local children state + children=$(cat "/proc/$pid/task/$pid/children" 2>/dev/null || true) + state=$(awk '{print $3}' "/proc/$pid/stat") + if [[ -z $children && $state == S ]]; then return; fi + sleep 0.01 + done + echo "Timed out waiting for watcher $pid to become idle." >&2 + exit 1 +} + +resource_value() { + local pid=$1 kind=$2 + case $kind in + fd) find "/proc/$pid/fd" -mindepth 1 -maxdepth 1 | wc -l ;; + tasks) find "/proc/$pid/task" -mindepth 1 -maxdepth 1 -type d | wc -l ;; + rss) awk '/^VmRSS:/ {print $2}' "/proc/$pid/status" ;; + esac +} + +start_watcher() { + local implementation=$1 executable=$2 fixture + fixture="$work_root/$implementation" + cp -R "$repo_root/rewatch-ocaml/tests/basic" "$fixture" + : >"$work_root/$implementation.bsc" + setsid env \ + RESCRIPT_BSC_EXE="$counting_bsc" \ + REWATCH_BSC_PROXY_MODE=counting \ + RESCRIPT_RUNTIME="$runtime" \ + REWATCH_REAL_BSC="$real_bsc" \ + REWATCH_BSC_CALL_LOG="$work_root/$implementation.bsc" \ + REWATCH_WATCH_MARKER="$work_root/$implementation.marker" \ + "$executable" watch --after-build "node $marker_script" "$fixture" \ + >"$work_root/$implementation.stdout" \ + 2>"$work_root/$implementation.stderr" & + pids[$implementation]=$! + wait_for_lines "$work_root/$implementation.marker" 1 + wait_for_text_count "$work_root/$implementation.stdout" \ + "Finished initial compilation" 1 + wait_for_idle "${pids[$implementation]}" +} + +start_watcher rust "$rust_executable" +start_watcher ocaml "$ocaml_executable" + +# One unmeasured edit pays any first-incremental initialization cost before the +# retained-state samples begin. +for implementation in rust ocaml; do + printf 'let answer = A.value + 1\n// warm retained edit\n' \ + >"$work_root/$implementation/src/B.res" + wait_for_lines "$work_root/$implementation.marker" 2 + wait_for_text_count "$work_root/$implementation.stdout" \ + "Finished incremental compilation" 1 + wait_for_idle "${pids[$implementation]}" + : >"$work_root/$implementation.bsc" +done + +declare -A baseline_fd baseline_tasks baseline_rss max_fd max_tasks max_rss +for implementation in rust ocaml; do + pid=${pids[$implementation]} + baseline_fd[$implementation]=$(resource_value "$pid" fd) + baseline_tasks[$implementation]=$(resource_value "$pid" tasks) + baseline_rss[$implementation]=$(resource_value "$pid" rss) + max_fd[$implementation]=${baseline_fd[$implementation]} + max_tasks[$implementation]=${baseline_tasks[$implementation]} + max_rss[$implementation]=${baseline_rss[$implementation]} + : >"$work_root/$implementation.latencies" +done + +measure_edit() { + local implementation=$1 round=$2 expected=$((round + 2)) + local started finished latency pid value + started=$(date +%s%3N) + printf 'let answer = A.value + 1\n// retained edit %d\n' "$round" \ + >"$work_root/$implementation/src/B.res" + wait_for_lines "$work_root/$implementation.marker" "$expected" + finished=$(tail -n 1 "$work_root/$implementation.marker") + latency=$((finished - started)) + printf '%d\n' "$latency" >>"$work_root/$implementation.latencies" + wait_for_text_count "$work_root/$implementation.stdout" \ + "Finished incremental compilation" "$((round + 1))" + wait_for_idle "${pids[$implementation]}" + pid=${pids[$implementation]} + for kind in fd tasks rss; do + value=$(resource_value "$pid" "$kind") + case $kind in + fd) if ((value > max_fd[$implementation])); then max_fd[$implementation]=$value; fi ;; + tasks) if ((value > max_tasks[$implementation])); then max_tasks[$implementation]=$value; fi ;; + rss) if ((value > max_rss[$implementation])); then max_rss[$implementation]=$value; fi ;; + esac + done +} + +for round in $(seq 1 "$runs"); do + if ((round % 2 == 1)); then + measure_edit rust "$round" + measure_edit ocaml "$round" + else + measure_edit ocaml "$round" + measure_edit rust "$round" + fi + if ! cmp -s "$work_root/rust/src/B.mjs" "$work_root/ocaml/src/B.mjs"; then + echo "Generated output differs after retained edit $round." >&2 + exit 1 + fi +done + +median() { + sort -n "$1" | sed -n "$((runs / 2 + 1))p" +} +rust_median=$(median "$work_root/rust.latencies") +ocaml_median=$(median "$work_root/ocaml.latencies") + +normalize_calls() { + local implementation=$1 + sed "s#$work_root/$implementation##g" \ + "$work_root/$implementation.bsc" >"$work_root/$implementation.bsc.normalized" +} +normalize_calls rust +normalize_calls ocaml +if ! cmp -s "$work_root/rust.bsc.normalized" \ + "$work_root/ocaml.bsc.normalized"; then + echo "Rust and OCaml retained edits performed different compiler work." >&2 + exit 1 +fi +for implementation in rust ocaml; do + parse_count=$(grep -cF -- '-bs-ast' "$work_root/$implementation.bsc" || true) + total_count=$(wc -l <"$work_root/$implementation.bsc") + if ((parse_count != runs || total_count != runs * 2)); then + printf '%s retained work was %d parser / %d total calls; expected %d / %d.\n' \ + "$implementation" "$parse_count" "$total_count" "$runs" "$((runs * 2))" >&2 + exit 1 + fi +done + +for implementation in rust ocaml; do + pid=${pids[$implementation]} + final_fd=$(resource_value "$pid" fd) + final_tasks=$(resource_value "$pid" tasks) + final_rss=$(resource_value "$pid" rss) + if ((max_fd[$implementation] > baseline_fd[$implementation] + 4 || + max_tasks[$implementation] > baseline_tasks[$implementation] + 2 || + max_rss[$implementation] > baseline_rss[$implementation] + 16384)); then + echo "$implementation watcher resource growth exceeded the retained gate." >&2 + exit 1 + fi + printf '%-5s resources: fd %d→%d (max %d), tasks %d→%d (max %d), RSS %d→%d KiB (max %d)\n' \ + "$implementation" "${baseline_fd[$implementation]}" "$final_fd" \ + "${max_fd[$implementation]}" "${baseline_tasks[$implementation]}" \ + "$final_tasks" "${max_tasks[$implementation]}" \ + "${baseline_rss[$implementation]}" "$final_rss" "${max_rss[$implementation]}" +done + +if ((ocaml_median * 100 > rust_median * threshold_percent)); then + printf 'OCaml retained-watch median %d ms exceeds %d%% of Rust median %d ms.\n' \ + "$ocaml_median" "$threshold_percent" "$rust_median" >&2 + exit 1 +fi + +printf 'retained-watch median: Rust %d ms, OCaml %d ms (limit %d%%)\n' \ + "$rust_median" "$ocaml_median" "$threshold_percent" +printf 'compiler work: %d parser and %d compiler calls per implementation\n' \ + "$runs" "$runs" + +for implementation in rust ocaml; do + rm -f "$work_root/$implementation/lib/watch.lock" + wait "${pids[$implementation]}" + unset "pids[$implementation]" +done + +echo "Retained-watch performance, work, output, and resource gates passed" diff --git a/rewatch-ocaml/build.ml b/rewatch-ocaml/build.ml new file mode 100644 index 00000000000..824f0472361 --- /dev/null +++ b/rewatch-ocaml/build.ml @@ -0,0 +1,569 @@ +exception Error = Project_context.Error +exception Package_error = Project_context.Package_error +exception Build_failure = Compiler_scheduler.Build_failure +exception Parse_failure of string +exception Reported_failure of string +exception Full_rebuild_required + +type retained_build = { + root_config: Config.t; + build_lock_root: string; + session: Build_session.t; +} + +type attempt_request = + | One_shot_attempt + | Initial_watch_attempt + | Full_watch_attempt of retained_build option + | Retained_watch_attempt of { + previous: retained_build; + changes: Watcher.change list; + } + +let report_kind = function + | One_shot_attempt -> Build_report.One_shot + | Initial_watch_attempt -> Build_report.Initial_watch + | Full_watch_attempt _ -> Build_report.Full_watch + | Retained_watch_attempt _ -> Build_report.Incremental_watch + +(* Only a retained watch attempt reuses the previous build's session. A full + watch rebuild starts a new session and uses the previous one only to carry + compile dirtiness forward. *) +let reused_build = function + | Retained_watch_attempt {previous; changes = _} -> Some previous + | One_shot_attempt | Initial_watch_attempt | Full_watch_attempt _ -> None + +let carry_forward_compile_dirtiness previous next_session next_state = + match Build_session.prepared previous.session with + | None -> () + | Some previous_prepared -> + (* Module keys are unique within a session, so a key names the same source + in both sessions when its package root and source path match. *) + let same_source key = + match + ( Build_session.find_global_module previous.session key, + Build_session.find_global_module next_session key ) + with + | Some previous_node, Some next_node -> + previous_node.Module_graph.package_root = next_node.package_root + && previous_node.source_path = next_node.source_path + | Some _, None | None, _ -> false + in + Build_state.carry_forward_compile_dirty + ~previous:previous_prepared.build_state ~next:next_state ~same_source + +type incremental_source = { + package: Package_plan.t; + source: Build_session.source_reference; + key: string; +} + +let run_scheduled_modules (attempt : Build_attempt.t) + (prepared : Build_session.prepared) ~compile_step ~namespace_count = + Compiler_scheduler.run ~poll:attempt.process_poll + ~warning_state:(Build_session.warning_state attempt.session) + ~compile_assets:prepared.compile_assets ~build_state:prepared.build_state + ~candidates:(Build_attempt.take_compile_candidates attempt) + ~mark_compiled:(fun () -> attempt.compiled <- attempt.compiled + 1) + ~mark_had_warnings:(fun () -> attempt.had_warnings <- true) + ~progress:attempt.progress ~compile_step ~namespace_count + ~verbosity:attempt.verbosity + +let run_namespace_jobs (attempt : Build_attempt.t) = + let jobs = Build_attempt.take_namespace_jobs attempt in + let started_at = Unix.gettimeofday () in + Fun.protect + ~finally:(fun () -> + attempt.parse_seconds <- + attempt.parse_seconds +. (Unix.gettimeofday () -. started_at)) + (fun () -> + let results = + Process.run_parallel ?poll:attempt.process_poll + (List.map (fun job -> job.Build_attempt.job) jobs) + in + List.iter2 + (fun job result -> job.Build_attempt.finish result) + jobs results); + List.length jobs + +let write_build_ninja (attempt : Build_attempt.t) = + (* This empty file is a cache-invalidation marker consumed by editor tooling, + not a serialized build plan. Only commands that reconstruct the project + graph call this function. *) + Build_session.iter_package_plans attempt.session (fun _ package -> + let path = Filename.concat package.Package_plan.build_dir "build.ninja" in + let channel = open_out_bin path in + close_out channel) + +let incremental_sources (previous : retained_build) changes = + (* Reusing the graph is safe only for modifications of already-known source + paths. Additions, removals, and unknown paths can change module identity or + package topology, so their caller must reconstruct the build instead. *) + let included = Hashtbl.create (List.length changes) in + let sources = ref [] in + let add normalized_path = + if not (Hashtbl.mem included normalized_path) then ( + Hashtbl.add included normalized_path (); + match + Build_session.find_source_reference previous.session normalized_path + with + | Some source -> + let package = + match + Build_session.find_package_plan previous.session source.package_root + with + | Some package -> package + | None -> raise Full_rebuild_required + in + let key = + Source.compiler_basename package.compile_config source.module_.name + in + sources := {package; source; key} :: !sources + | None -> raise Full_rebuild_required) + in + List.iter + (fun (change : Watcher.change) -> + match change.kind with + | Watcher.Added | Watcher.Removed -> raise Full_rebuild_required + | Watcher.Modified -> + add (Platform.normalize_path_for_comparison change.path)) + changes; + Build_session.pending_parse_paths previous.session + |> List.sort String.compare |> List.iter add; + List.rev !sources + +let prepare_incremental previous changes (attempt : Build_attempt.t) + (prepared : Build_session.prepared) ~parse_step = + (* A retained edit reparses only the reported paths, then replaces the + affected modules' dependency edges in memory. This keeps the long-lived + graph coherent without rediscovering the package tree. *) + let sources = incremental_sources previous changes in + let bsc = prepared.compiler_context.bsc_path in + let started_at = Unix.gettimeofday () in + List.iter + (fun source -> + Build_session.mark_parse_pending attempt.session + (Platform.normalize_path_for_comparison source.source.absolute_path); + (Build_state.find_exn prepared.build_state source.key).compile_dirty <- + true) + sources; + sources + |> List.map (fun source -> source.key) + |> List.sort_uniq String.compare + |> List.iter (fun name -> + Output.debug ~verbosity:attempt.verbosity + ("Generating AST for module: " ^ name)); + let parse_completed = + Output.Progress.start_grouped attempt.progress ~step:parse_step + ~symbol:Platform.parse_symbol ~label:"Parsing" + (List.map + (fun source -> + source.package.root ^ "\000" ^ source.source.module_.Source.name) + sources) + in + let results = + Process.run_parallel_map ?poll:attempt.process_poll + ~on_complete:parse_completed sources ~job:(fun source -> + Compiler_process.parse_job ~bsc ~build_dir:source.package.build_dir + ~config:source.package.compile_config source.source.relative_path) + in + let affected_modules = Hashtbl.create (List.length sources) in + let dependency_updates = ref [] in + List.iter2 + (fun source result -> + Hashtbl.replace attempt.preliminary_parses source.source.absolute_path + (Build_attempt.preliminary_parse result); + (try + let modified = (Unix.stat source.source.absolute_path).Unix.st_mtime in + Hashtbl.replace source.package.source_mtimes + source.source.relative_path modified + with Unix.Unix_error _ | Sys_error _ -> raise Full_rebuild_required); + let parse_failed = not (Process.succeeded result) in + let parse_failed = + match Hashtbl.find_opt affected_modules source.key with + | Some (_, _, previous_failed) -> previous_failed || parse_failed + | None -> parse_failed + in + Hashtbl.replace affected_modules source.key + (source.package, source.source.module_, parse_failed)) + sources results; + Hashtbl.iter + (fun key (package, module_, changed_parse_failed) -> + if not changed_parse_failed then + let raw_dependencies = + Module_graph.raw_dependencies + ~build_dir:package.Package_plan.build_dir + ~parse_failed:(fun _ -> false) + module_ + in + let node = + match Build_session.find_global_module attempt.session key with + | Some node -> node + | None -> raise Full_rebuild_required + in + if node.raw_dependencies <> raw_dependencies then + dependency_updates := + (key, node, raw_dependencies) :: !dependency_updates) + affected_modules; + attempt.parse_seconds <- Unix.gettimeofday () -. started_at; + if !dependency_updates <> [] then ( + Build_session.invalidate_graph_cycle attempt.session; + List.iter + (fun (key, node, raw_dependencies) -> + node.Module_graph.raw_dependencies <- raw_dependencies; + Build_state.set_dependencies prepared.build_state ~key + (Module_graph.resolved_dependencies + ~find_module:(Build_session.find_global_module attempt.session) + ~find_namespace_maps: + (Build_session.find_namespace_maps attempt.session) + node)) + !dependency_updates); + match Build_session.graph_cycle attempt.session with + | Build_session.Known_cycle cycle -> cycle + | Build_session.Unknown_cycle -> + let cycle = + Module_graph.find_cycle + (Build_session.global_module_values attempt.session) + (Build_session.namespace_map_values attempt.session) + prepared.build_state + in + Build_session.set_graph_cycle attempt.session cycle; + cycle + +let run_with_warning_state ~poll ~warning_state ~request ~no_timing ~verbosity + ~folder ~prod ~features ~warn_error ~after_build ~filter ~on_state = + let started_at = Unix.gettimeofday () in + let interactive = Unix.isatty Unix.stdout && Unix.isatty Unix.stderr in + let show_progress = verbosity >= 0 in + let colors = Output.colors_enabled ~interactive in + let progress = + Output.Progress.create ~enabled:(interactive && show_progress) ~color:colors + in + let poll () = + poll (); + Output.Progress.tick progress + in + let process_poll = Some poll in + let kind = report_kind request in + let one_shot = kind = Build_report.One_shot in + let watch = not one_shot in + let is_rebuild = kind = Build_report.Incremental_watch in + let should_write_build_ninja = + match kind with + | Build_report.One_shot | Build_report.Full_watch -> true + | Build_report.Initial_watch | Build_report.Incremental_watch -> false + in + let root = Project_context.canonical_project_root folder in + let root_config = + match reused_build request with + | Some previous -> previous.root_config + | None -> Config.load_root root + in + let workspace_config = Project_context.workspace_config_for root_config in + let build_lock_root = workspace_config.root in + Output.debug ~verbosity + (Project_context.describe root_config ~workspace:workspace_config); + let visited = Hashtbl.create 32 in + let attempt : Build_attempt.t = + match reused_build request with + | Some previous -> + Build_attempt.create_retained ~session:previous.session ~process_poll + ~progress ~verbosity + | None -> + Build_attempt.create_full ~warning_state ~process_poll ~progress + ~verbosity + in + let parse_messages () = List.rev attempt.parse_messages in + let parse_output messages = + messages + |> List.map (function + | Build_attempt.Parse_warning output | Build_attempt.Parse_error output + -> output) + |> String.concat "" + in + let parse_failed = Build_attempt.has_parse_error in + (* A watch build must keep the attempted session even when later parsing or + compilation fails, because its successful ASTs and artifact inventory let + the next edit rebuild incrementally. Hand the session to the caller before + any fallible phase starts. *) + on_state {root_config; build_lock_root; session = attempt.session}; + let report = + Build_report.create ~started_at ~interactive ~show_progress ~colors + ~no_timing ~kind ~attempt + in + (* Each build reaches this at most once: the failure reports end by raising + Reported_failure, and a parse failure is raised before any other outcome + writes the marker. *) + let write_build_ninja () = + if should_write_build_ninja then write_build_ninja attempt + in + let phase_seconds seconds = if no_timing then 0. else seconds in + let parse_step = Build_report.parse_step report in + let compile_step = Build_report.compile_step report in + let report_failure ~compile_seconds output = + Build_attempt.finalize_logs attempt; + if attempt.freshness_mode = Build_attempt.Initialize_freshness then + Source_dirs.write_build ~root_config attempt.session; + Build_report.report_failure report ~compile_seconds; + prerr_string output; + prerr_newline (); + Build_attempt.cleanup_artifacts attempt; + write_build_ninja (); + raise + (Reported_failure + ("Incremental build failed. Error: \027[2K\r Failed to Compile. " + ^ "See Errors Above")) + in + let report_parse_failure output = + Build_attempt.finalize_logs attempt; + Build_report.report_parse_failure report ~output; + Build_attempt.cleanup_artifacts attempt; + write_build_ninja (); + raise + (Reported_failure + "Incremental build failed. Error: \027[2K\r Could not parse Source \ + Files") + in + let format_cycle cycle (by_key : (string, Module_graph.cycle_node) Hashtbl.t) + = + let format_node name = + match Hashtbl.find_opt by_key name with + | None -> name + | Some node -> ( + match node.source_path with + | Some source_path -> + let absolute = Filename.concat node.package_root source_path in + Printf.sprintf "%s (%s)" node.display_name + (Project_context.relative_or_absolute ~root:root_config.root + absolute) + | None -> + Printf.sprintf "%s (%s namespace map)" node.display_name + (Project_context.relative_or_absolute ~root:root_config.root + node.package_root)) + in + "\nCan't continue... Found a circular dependency in your code:\n" + ^ (cycle |> List.map format_node |> String.concat "\n → ") + ^ "\n\ + Possible solutions:\n\ + - Extract shared code into a new module both depend on.\n" + in + let execute ~release_build_lock = + poll (); + let prepared, cycle = + match request with + | Retained_watch_attempt {previous; changes} -> ( + match Build_session.prepared attempt.session with + | Some prepared -> + ( prepared, + prepare_incremental previous changes attempt prepared ~parse_step ) + | None -> raise Full_rebuild_required) + | One_shot_attempt | Initial_watch_attempt | Full_watch_attempt _ -> + let preparation = + Build_preparation.run ~root_config ~prod ~features ~warn_error ~filter + ~watch ~attempt ~parse_step ~on_cleanup:(fun seconds -> + if interactive && show_progress && not is_rebuild then ( + if attempt.compiler_cleaned then + print_endline + (Output.compiler_cleanup_message ~color:colors ~step:"1/3"); + print_endline + (Output.cleanup_message ~color:colors ~step:"1/3" + ~cleaned:attempt.cleaned ~total:attempt.previous_asts + ~seconds:(phase_seconds seconds)))) + in + (preparation.prepared, preparation.cycle) + in + (match request with + | Full_watch_attempt (Some previous) -> + carry_forward_compile_dirtiness previous attempt.session + prepared.build_state + | One_shot_attempt | Initial_watch_attempt + | Full_watch_attempt None + | Retained_watch_attempt _ -> + ()); + poll (); + if attempt.compiler_cleaned && show_progress && not interactive then + print_endline "Cleaned previous build due to compiler update"; + Option.iter + (fun (cycle_info : Module_graph.cycle_info) -> + List.iter + (fun name -> Hashtbl.replace attempt.blocked_modules name ()) + cycle_info.blocked) + cycle; + let root_package = + match Build_session.find_package_plan attempt.session root with + | Some package -> package + | None -> raise (Error ("Package graph was not prepared for " ^ root)) + in + Package_build.prepare_tree ~seen:visited ~package:root_package ~prepared + ~watch ~attempt; + Build_session.mark_freshness_initialized attempt.session; + let parse_messages = parse_messages () in + let parse_output = parse_output parse_messages in + if parse_failed parse_messages then raise (Parse_failure parse_output); + poll (); + let namespace_count = + try run_namespace_jobs attempt + with Build_failure output -> + raise (Parse_failure (parse_output ^ output)) + in + Output.Progress.finish progress; + if interactive && show_progress then + print_endline + (Output.parsing_message ~color:colors ~step:parse_step + ~count:attempt.parsed + ~seconds:(phase_seconds attempt.parse_seconds)); + flush stdout; + prerr_string parse_output; + flush stderr; + let compile_started = Unix.gettimeofday () in + let compile_failure = + try + run_scheduled_modules attempt prepared ~compile_step ~namespace_count; + None + with Build_failure output -> Some output + in + Output.Progress.finish progress; + let compile_seconds = + phase_seconds (Unix.gettimeofday () -. compile_started) + in + match (compile_failure, cycle) with + | Some output, _ -> report_failure ~compile_seconds output + | None, Some cycle_info -> + let output = format_cycle cycle_info.cycle cycle_info.nodes_by_key in + cycle_info.cycle + |> List.filter_map (Hashtbl.find_opt cycle_info.nodes_by_key) + |> List.map (fun (node : Module_graph.cycle_node) -> node.package_root) + |> List.sort_uniq String.compare + |> List.iter (fun package_root -> Compiler_log.append package_root output); + report_failure ~compile_seconds output + | None, None -> + Build_attempt.finalize_logs attempt; + if attempt.freshness_mode = Build_attempt.Initialize_freshness then + Source_dirs.write_build ~root_config attempt.session; + let diagnostics = + Build_report.print_success_details report ~compile_seconds + in + let context = prepared.compiler_context in + Build_session.publish_compiler_info attempt.session (fun package -> + let package_context = + Compiler_info.for_package context + package.Package_plan.compile_config + in + Compiler_info.write_package package_context package.config); + if one_shot then Build_report.report_completion report diagnostics; + Build_attempt.cleanup_artifacts attempt; + write_build_ninja (); + release_build_lock (); + Option.iter + (fun command -> After_build.run ?poll:process_poll ~root command) + after_build; + if not one_shot then Build_report.report_completion report diagnostics + in + Build_lock.with_build ~poll build_lock_root + (fun ~release:release_build_lock -> + Build_attempt.protect attempt (fun () -> + try execute ~release_build_lock + with Parse_failure output -> report_parse_failure output)); + {root_config; build_lock_root; session = attempt.session} + +let run ~poll ~verbosity ~folder ~prod ~features ~warn_error ~after_build + ~filter ~no_timing = + try + run_with_warning_state ~warning_state:(Warning_state.create ()) ~poll + ~request:One_shot_attempt ~no_timing ~verbosity ~folder ~prod ~features + ~warn_error ~after_build ~filter ~on_state:(fun _ -> ()) + |> ignore + with Reported_failure message -> raise (Error message) + +let remove_compile_warning_freshness warning_state = + Warning_state.entries warning_state + |> List.iter (fun (entry : Warning_state.entry) -> + let implementation = + if Filename.check_suffix entry.path ".resi" then + Filename.chop_suffix entry.path "i" + else entry.path + in + [implementation; implementation ^ "i"] + |> List.iter (fun source -> + File_util.remove_file + (Build_artifacts.published_ast_path + ~ocaml_dir:(Build_artifacts.lib_path entry.package_root "ocaml") + source))) + +let watch ~verbosity ~folder ~prod ~features ~warn_error ~after_build ~filter + ~clear_screen = + let root = Project_context.canonical_project_root folder in + let warning_state = Warning_state.create () in + let initial_build = ref true in + let retained = ref None in + let force_full_rebuild = ref false in + let build ~poll ~changes = + let is_initial = !initial_build in + initial_build := false; + try + let run request = + let attempted = ref None in + try + run_with_warning_state ~poll ~warning_state ~request ~no_timing:false + ~verbosity ~folder ~prod ~features ~warn_error ~after_build ~filter + ~on_state:(fun state -> attempted := Some state) + with exn -> + (* A failed initial or incremental attempt still leaves useful parsed + state in its session. A failed full rebuild keeps its session only + once preparation finished, because before that its graph may be + only partially discovered. *) + (match (request, !attempted) with + | (Initial_watch_attempt | Retained_watch_attempt _), Some state -> + retained := Some state + | Full_watch_attempt _, Some state + when Option.is_some (Build_session.prepared state.session) -> + retained := Some state; + force_full_rebuild := false + | (One_shot_attempt | Full_watch_attempt _), _ | _, None -> ()); + raise exn + in + let next = + match (!retained, changes, !force_full_rebuild) with + | Some previous, Some changes, false -> ( + try run (Retained_watch_attempt {previous; changes}) + with Full_rebuild_required -> + force_full_rebuild := true; + run (Full_watch_attempt (Some previous))) + | Some previous, _, _ -> run (Full_watch_attempt (Some previous)) + | None, _, _ -> + run + (if is_initial then Initial_watch_attempt + else Full_watch_attempt None) + in + retained := Some next; + force_full_rebuild := false; + Watcher.Succeeded + with + | Reported_failure _ -> Watcher.Failed + | Package_error message + | Error message + | Config.Error message + | Source.Error message + | Process.Error message -> + prerr_endline message; + Watcher.Failed + | (Sys_error _ as exn) | (Unix.Unix_error _ as exn) -> + prerr_endline (Printexc.to_string exn); + Watcher.Failed + in + Fun.protect + (fun () -> + Watcher.run ~root ~prod ~features ~filter ~clear_screen + ~show_progress:(verbosity >= 0) ~verbosity ~build) + ~finally:(fun () -> + if Warning_state.entries warning_state <> [] then + match !retained with + | Some state -> ( + (* Best effort: this only makes the next build show the session's + warnings again. Exiting must not wait for another build's lock, + so give up after about two seconds. *) + try + Build_lock.with_build ~attempts:40 state.build_lock_root + (fun ~release:_ -> remove_compile_warning_freshness warning_state) + with Project_context.Error _ -> ()) + | None -> ()) diff --git a/rewatch-ocaml/build.mli b/rewatch-ocaml/build.mli new file mode 100644 index 00000000000..d851e6c82a4 --- /dev/null +++ b/rewatch-ocaml/build.mli @@ -0,0 +1,22 @@ +val run : + poll:(unit -> unit) -> + verbosity:int -> + folder:string -> + prod:bool -> + features:string list option -> + warn_error:string option -> + after_build:string option -> + filter:Source_filter.t option -> + no_timing:bool -> + unit + +val watch : + verbosity:int -> + folder:string -> + prod:bool -> + features:string list option -> + warn_error:string option -> + after_build:string option -> + filter:Source_filter.t option -> + clear_screen:bool -> + unit diff --git a/rewatch-ocaml/build_artifacts.ml b/rewatch-ocaml/build_artifacts.ml new file mode 100644 index 00000000000..19d00d4dd65 --- /dev/null +++ b/rewatch-ocaml/build_artifacts.ml @@ -0,0 +1,353 @@ +let lib_path root directory = File_util.path_of_parts root ["lib"; directory] + +let relative_output_directory path (spec : Config.package_spec) = + let directory = Filename.dirname path in + if spec.in_source then directory + else + Filename.concat + (match spec.module_format with + | Config.Esmodule -> lib_path "" "es6" + | Config.Commonjs -> lib_path "" "js") + directory + +let generated_js_path (config : Config.t) path (spec : Config.package_spec) = + let output_dir = relative_output_directory path spec in + Filename.concat config.root + (Filename.concat output_dir + (Filename.remove_extension (Filename.basename path) + ^ Config.package_spec_suffix config spec)) + +let published_ast_path ~ocaml_dir source = + Filename.concat ocaml_dir (Filename.basename (Source.ast_path source)) + +let generated_build_js_path ~build_dir (config : Config.t) path + (spec : Config.package_spec) = + Filename.concat build_dir + (Filename.remove_extension path ^ Config.package_spec_suffix config spec) + +let remove_public_outputs (config : Config.t) implementation_paths = + List.iter + (fun implementation -> + List.iter + (fun spec -> + let output = generated_js_path config implementation spec in + File_util.remove_file output; + File_util.remove_file (output ^ ".map")) + config.package_specs) + implementation_paths + +let generated_output_suffixes = + [ + ".bs.mjs"; + ".bs.cjs"; + ".bs.js"; + ".res.mjs"; + ".res.cjs"; + ".res.js"; + ".mjs"; + ".cjs"; + ".js"; + ] + +let generated_output_details_for_suffixes suffixes path = + let output_path = + if Filename.check_suffix path ".map" then Filename.chop_suffix path ".map" + else path + in + suffixes + |> List.find_map (fun suffix -> + if Filename.check_suffix output_path suffix then + Some + ( ( Filename.basename output_path |> fun basename -> + Filename.chop_suffix basename suffix ), + suffix, + output_path ) + else None) + +type cleanup_result = { + removed_modules: string list; + previous_ast_count: int; + present_public_outputs: (string, unit) Hashtbl.t; +} + +let cleanup_stale ~ocaml_files ~ast_sources ~source_files ~present_source_files + ~on_removed_module ~on_deferred_artifact ~root ~is_local (config : Config.t) + modules = + let build_dir = lib_path root "bs" in + (* The caller passes one inventory of each artifact tree to avoid repeating + directory and metadata work during every cleanup phase. Paths removed + below can safely remain in the inventory: later phases only classify their + names or call the idempotent File_util.remove_file. *) + (* Published ASTs contain the absolute source path used to create them, which + is enough to address their working artifacts without scanning for them. + Keep the recursive walk lazy for malformed or legacy ASTs that cannot be + mapped; normal unchanged builds must not inventory the whole lib/bs tree. *) + let fallback_build_files_by_basename = + lazy + (let by_basename = Hashtbl.create 32 in + File_util.files_under build_dir + |> List.iter (fun path -> + let basename = Filename.basename path in + let paths = + Hashtbl.find_opt by_basename basename |> Option.value ~default:[] + in + Hashtbl.replace by_basename basename (path :: paths)); + by_basename) + in + let output_files = + [lib_path "" "es6"; lib_path "" "js"] + |> List.map (fun directory -> + let output_dir = Filename.concat root directory in + (output_dir, File_util.files_under output_dir)) + in + let configured_suffixes = + List.map (Config.package_spec_suffix config) config.package_specs + in + let output_suffixes = + configured_suffixes @ generated_output_suffixes + |> List.sort_uniq (fun left right -> + let length_order = + Int.compare (String.length right) (String.length left) + in + if length_order = 0 then String.compare left right else length_order) + in + let output_details = generated_output_details_for_suffixes output_suffixes in + let present_public_outputs = Hashtbl.create 64 in + present_source_files @ List.concat_map snd output_files + |> List.iter (fun path -> + if Option.is_some (output_details path) && File_util.is_regular_file path + then Hashtbl.replace present_public_outputs path ()); + (* Expected outputs may use arbitrary configured suffixes, including suffixes + that do not resemble JavaScript. Probe those paths directly rather than + treating a filename heuristic as the source of truth. *) + List.iter + (fun module_ -> + List.iter + (fun spec -> + let output = + generated_js_path config module_.Source.implementation spec + in + if + (not (Hashtbl.mem present_public_outputs output)) + && File_util.is_regular_file output + then Hashtbl.replace present_public_outputs output ()) + config.package_specs) + modules; + let expected_artifacts = Hashtbl.create (List.length modules * 8) in + let owned_output_names = Hashtbl.create (List.length modules * 2) in + let current_sources = Hashtbl.create (List.length modules * 2) in + List.iter + (fun module_ -> + module_.Source.implementation :: Option.to_list module_.Source.interface + |> List.iter (fun source -> + Filename.concat root source |> Platform.normalize_path_for_comparison + |> fun source -> Hashtbl.replace current_sources source ())) + modules; + let stale_ast_basenames = Hashtbl.create 8 in + let removed_output_paths = Hashtbl.create 8 in + List.iter + (fun (ast_source : Compile_assets.ast_source) -> + let source = + Platform.normalize_path_for_comparison ast_source.source_path + in + if not (Hashtbl.mem current_sources source) then ( + Hashtbl.replace stale_ast_basenames + (Filename.basename ast_source.ast_path) + (); + Project_context.relative_to_opt root ast_source.source_path + |> Option.iter (fun relative_source -> + List.iter + (fun spec -> + Hashtbl.replace removed_output_paths + (generated_js_path config relative_source spec) + ()) + config.package_specs))) + ast_sources; + let add_expected base extensions = + List.iter + (fun extension -> + Hashtbl.replace expected_artifacts (base ^ extension) ()) + extensions + in + let previous_ast_count = ref 0 in + ocaml_files + |> List.iter (fun path -> + let basename = Filename.basename path in + if Filename.check_suffix basename ".ast" then ( + incr previous_ast_count; + Hashtbl.replace owned_output_names + (Filename.chop_suffix basename ".ast") + ()) + else if Filename.check_suffix basename ".iast" then ( + incr previous_ast_count; + Hashtbl.replace owned_output_names + (Filename.chop_suffix basename ".iast") + ())); + List.iter + (fun module_ -> + let source_base = + module_.Source.implementation |> Filename.basename + |> Filename.remove_extension + in + let compiler_base = + Source.compiler_asset_basename config module_.Source.implementation + in + Hashtbl.replace owned_output_names source_base (); + add_expected source_base [".ast"; ".res"]; + if Option.is_some module_.Source.interface then ( + add_expected source_base [".iast"; ".resi"]; + add_expected compiler_base [".cmti"]); + add_expected compiler_base [".cmi"; ".cmj"; ".cmt"]) + modules; + Config.namespace_compiler_name config.namespace + |> Option.iter (fun namespace -> + add_expected namespace [".cmi"; ".cmj"; ".cmt"; ".mlmap"]); + let removed_modules = ref [] in + (* Once the published CMI is removed, bsc still consults the working CMI to + produce its source-located missing-module diagnostic. Keep only that copy + through compilation; the command finalizer removes every deferred path. *) + let defer_working_cmi_until_after_compile basename = + Filename.check_suffix basename ".cmi" + in + let mapped_source_directories = + Hashtbl.create (List.length ast_sources * 2) + in + let add_mapped_source_directory key directory = + let directories = + Hashtbl.find_opt mapped_source_directories key |> Option.value ~default:[] + in + Hashtbl.replace mapped_source_directories key (directory :: directories) + in + List.iter + (fun (ast_source : Compile_assets.ast_source) -> + let source = ast_source.source_path in + Project_context.relative_to_opt root source + |> Option.iter (fun relative_source -> + let directory = Filename.dirname relative_source in + let source_base = + relative_source |> Filename.basename |> Filename.remove_extension + in + add_mapped_source_directory source_base directory; + add_mapped_source_directory + (Source.compiler_asset_basename config relative_source) + directory)) + ast_sources; + let directly_mapped_working_paths basename = + let extension = Filename.extension basename in + if extension = ".mlmap" then [Filename.concat build_dir basename] + else + Hashtbl.find_opt mapped_source_directories + (Filename.remove_extension basename) + |> Option.value ~default:[] + |> List.map (fun directory -> + Filename.concat build_dir (Filename.concat directory basename)) + |> List.sort_uniq String.compare + in + let working_paths basename = + match directly_mapped_working_paths basename with + | _ :: _ as paths -> paths + | [] -> + Hashtbl.find_opt (Lazy.force fallback_build_files_by_basename) basename + |> Option.value ~default:[] + in + ocaml_files + |> List.iter (fun path -> + let basename = Filename.basename path in + let managed = Compile_assets.is_managed_basename basename in + if + managed + && ((not (Hashtbl.mem expected_artifacts basename)) + || Hashtbl.mem stale_ast_basenames basename) + then ( + if + Filename.check_suffix basename ".ast" + || Filename.check_suffix basename ".iast" + then ( + let module_name = Source.module_name basename in + on_removed_module module_name; + removed_modules := module_name :: !removed_modules); + File_util.remove_file path; + working_paths basename + |> List.iter (fun build_path -> + if defer_working_cmi_until_after_compile basename then + on_deferred_artifact build_path + else File_util.remove_file build_path))); + let relative_under directory path = + let prefix = directory ^ Filename.dir_sep in + String.sub path (String.length prefix) + (String.length path - String.length prefix) + in + let expected_outputs = + Hashtbl.create (List.length modules * List.length config.package_specs) + in + List.iter + (fun module_ -> + List.iter + (fun spec -> + Hashtbl.replace expected_outputs + (generated_js_path config module_.Source.implementation spec) + ()) + config.package_specs) + modules; + let should_remove_output ~build_relative path = + output_details path + |> Option.fold ~none:false ~some:(fun (name, _, output_path) -> + (not (Hashtbl.mem expected_outputs output_path)) + && (Hashtbl.mem removed_output_paths output_path + || Hashtbl.mem owned_output_names name + (* A map alone is not enough provenance to delete a public file. The + mirrored output has the same relative path below lib/bs, so probe + that one path instead of scanning the entire working tree. *) + && is_local + && File_util.exists (Filename.concat build_dir build_relative))) + in + let planned_outputs = Hashtbl.create 16 in + let plan_output ~build_relative path = + output_details path + |> Option.iter (fun (_, _, output_path) -> + if should_remove_output ~build_relative output_path then + Hashtbl.replace planned_outputs output_path build_relative) + in + source_files + |> List.iter (fun path -> + output_details path + |> Option.iter (fun (_, _, output_path) -> + plan_output + ~build_relative:(relative_under root output_path) + output_path)); + ast_sources + |> List.iter (fun (ast_source : Compile_assets.ast_source) -> + let source = ast_source.source_path in + Project_context.relative_to_opt root source + |> Option.iter (fun relative_source -> + List.iter + (fun spec -> + let output = generated_js_path config relative_source spec in + plan_output ~build_relative:(relative_under root output) output) + config.package_specs)); + output_files + |> List.iter (fun (output_dir, files) -> + files + |> List.iter (fun path -> + output_details path + |> Option.iter (fun (_, _, output_path) -> + plan_output + ~build_relative:(relative_under output_dir output_path) + output_path))); + let remove_output (path, build_relative) = + Hashtbl.remove present_public_outputs path; + Hashtbl.remove present_public_outputs (path ^ ".map"); + File_util.remove_file path; + File_util.remove_file (path ^ ".map"); + let working_output = Filename.concat build_dir build_relative in + File_util.remove_file working_output; + File_util.remove_file (working_output ^ ".map") + in + planned_outputs |> Hashtbl.to_seq |> List.of_seq + |> List.sort (fun (left, _) (right, _) -> String.compare left right) + |> List.iter remove_output; + { + removed_modules = !removed_modules; + previous_ast_count = !previous_ast_count; + present_public_outputs; + } diff --git a/rewatch-ocaml/build_artifacts.mli b/rewatch-ocaml/build_artifacts.mli new file mode 100644 index 00000000000..e72b9c7c649 --- /dev/null +++ b/rewatch-ocaml/build_artifacts.mli @@ -0,0 +1,33 @@ +type cleanup_result = { + removed_modules: string list; + previous_ast_count: int; + present_public_outputs: (string, unit) Hashtbl.t; +} +(** Artifact cleanup first classifies ownership and builds a deletion plan. + Public JavaScript, source maps, and compiler artifacts are then removed as + one unit so an earlier deletion cannot erase evidence needed for a later + ownership decision. *) + +val lib_path : string -> string -> string +val relative_output_directory : string -> Config.package_spec -> string +val published_ast_path : ocaml_dir:string -> string -> string + +val generated_js_path : Config.t -> string -> Config.package_spec -> string + +val generated_build_js_path : + build_dir:string -> Config.t -> string -> Config.package_spec -> string + +val remove_public_outputs : Config.t -> string list -> unit + +val cleanup_stale : + ocaml_files:string list -> + ast_sources:Compile_assets.ast_source list -> + source_files:string list -> + present_source_files:string list -> + on_removed_module:(string -> unit) -> + on_deferred_artifact:(string -> unit) -> + root:string -> + is_local:bool -> + Config.t -> + Source.module_ list -> + cleanup_result diff --git a/rewatch-ocaml/build_attempt.ml b/rewatch-ocaml/build_attempt.ml new file mode 100644 index 00000000000..61bdbd19a8a --- /dev/null +++ b/rewatch-ocaml/build_attempt.ml @@ -0,0 +1,186 @@ +type freshness_mode = Initialize_freshness | Reuse_freshness + +type parse_message = Parse_warning of string | Parse_error of string + +let has_parse_error messages = + List.exists + (function + | Parse_error _ -> true + | Parse_warning _ -> false) + messages + +type preliminary_parse = + | Parsed_successfully of {stderr: string} + | Parse_failed of {stdout: string; stderr: string} + | Use_existing_ast + +let preliminary_parse result = + if Process.succeeded result then Parsed_successfully {stderr = result.stderr} + else Parse_failed {stdout = result.stdout; stderr = result.stderr} + +type namespace_job = {job: Process.job; finish: Process.result -> unit} + +type pending_work = { + mutable namespace_jobs: namespace_job list; + mutable compile_candidates: Compiler_scheduler.candidate list; +} + +type finalization_state = { + mutable actions: (unit -> unit) list; + mutable artifacts: string list; + initialized_logs: (string, unit) Hashtbl.t; + mutable artifacts_cleaned: bool; + mutable logs_finalized: bool; +} + +type t = { + freshness_mode: freshness_mode; + session: Build_session.t; + mutable cleaned: int; + mutable previous_asts: int; + mutable parsed: int; + mutable compiled: int; + mutable parse_seconds: float; + mutable parse_messages: parse_message list; + mutable diagnostics: string list; + removed_modules: (string, unit) Hashtbl.t; + preliminary_parses: (string, preliminary_parse) Hashtbl.t; + blocked_modules: (string, unit) Hashtbl.t; + namespace_freshness: (string, float option) Hashtbl.t; + package_removed_modules: (string, string list) Hashtbl.t; + pending_work: pending_work; + finalization: finalization_state; + mutable compiler_cleaned: bool; + mutable had_warnings: bool; + process_poll: (unit -> unit) option; + progress: Output.Progress.t; + verbosity: int; +} + +let create ~freshness_mode ~session ~process_poll ~progress ~verbosity = + let removed_modules = Hashtbl.create 16 in + Build_session.pending_removed_modules session + |> List.iter (fun name -> Hashtbl.replace removed_modules name ()); + { + freshness_mode; + session; + cleaned = 0; + previous_asts = 0; + parsed = 0; + compiled = 0; + parse_seconds = 0.; + parse_messages = []; + diagnostics = []; + removed_modules; + preliminary_parses = Hashtbl.create 16; + blocked_modules = Hashtbl.create 16; + namespace_freshness = Hashtbl.create 16; + package_removed_modules = Hashtbl.create 32; + pending_work = {namespace_jobs = []; compile_candidates = []}; + finalization = + { + actions = []; + artifacts = []; + initialized_logs = Hashtbl.create 16; + artifacts_cleaned = false; + logs_finalized = false; + }; + compiler_cleaned = false; + had_warnings = false; + process_poll; + progress; + verbosity; + } + +let create_full ~warning_state ~process_poll ~progress ~verbosity = + create ~freshness_mode:Initialize_freshness + ~session:(Build_session.create ~warning_state) + ~process_poll ~progress ~verbosity + +let create_retained ~session ~process_poll ~progress ~verbosity = + let freshness_mode = + if Build_session.is_ready session then Reuse_freshness + else Initialize_freshness + in + create ~freshness_mode ~session ~process_poll ~progress ~verbosity + +let register_cleanup attempt action = + attempt.finalization.actions <- action :: attempt.finalization.actions + +let defer_artifact_cleanup attempt paths = + attempt.finalization.artifacts <- paths @ attempt.finalization.artifacts + +let set_cleanup_result attempt root (result : Build_artifacts.cleanup_result) = + Hashtbl.replace attempt.package_removed_modules root result.removed_modules; + Build_session.set_public_outputs attempt.session root + result.present_public_outputs + +let removed_package_modules attempt root = + Hashtbl.find_opt attempt.package_removed_modules root + |> Option.value ~default:[] + +let add_namespace_job attempt job = + attempt.pending_work.namespace_jobs <- + job :: attempt.pending_work.namespace_jobs + +let take_namespace_jobs attempt = + let jobs = List.rev attempt.pending_work.namespace_jobs in + attempt.pending_work.namespace_jobs <- []; + jobs + +let add_compile_candidates attempt candidates = + attempt.pending_work.compile_candidates <- + candidates @ attempt.pending_work.compile_candidates + +let take_compile_candidates attempt = + let candidates = attempt.pending_work.compile_candidates in + attempt.pending_work.compile_candidates <- []; + candidates + +let mark_log_initialized attempt root = + Hashtbl.replace attempt.finalization.initialized_logs root () + +let run_all actions = + let first_error = ref None in + List.iter + (fun action -> + try action () + with error -> + if Option.is_none !first_error then first_error := Some error) + actions; + Option.iter raise !first_error + +let cleanup_artifacts attempt = + if not attempt.finalization.artifacts_cleaned then ( + attempt.finalization.artifacts_cleaned <- true; + run_all + (attempt.finalization.actions + @ List.map + (fun path () -> File_util.remove_file path) + attempt.finalization.artifacts)) + +let finalize_logs attempt = + if not attempt.finalization.logs_finalized then ( + attempt.finalization.logs_finalized <- true; + let package_roots = + attempt.finalization.initialized_logs |> Hashtbl.to_seq_keys + |> List.of_seq + in + run_all + ((fun () -> Output.Progress.finish attempt.progress) + :: List.map + (fun package_root () -> Compiler_log.finalize package_root) + package_roots)) + +let finish_attempt attempt = + run_all + [(fun () -> cleanup_artifacts attempt); (fun () -> finalize_logs attempt)] + +let protect attempt action = + match action () with + | result -> + finish_attempt attempt; + result + | exception error -> + finish_attempt attempt; + raise error diff --git a/rewatch-ocaml/build_attempt.mli b/rewatch-ocaml/build_attempt.mli new file mode 100644 index 00000000000..11fcfe99607 --- /dev/null +++ b/rewatch-ocaml/build_attempt.mli @@ -0,0 +1,79 @@ +(** An attempt owns all mutable work and reporting state for one build. This + boundary lets finalization drain cleanup exactly once while the associated + {!Build_session} remains reusable after failures. *) + +type freshness_mode = Initialize_freshness | Reuse_freshness + +type parse_message = Parse_warning of string | Parse_error of string +val has_parse_error : parse_message list -> bool + +(** Preliminary parsing distinguishes successful new ASTs, failed source text, + and deliberately retained ASTs. Keeping these cases explicit prevents a + failed parse from being mistaken for an unchanged source. *) +type preliminary_parse = + | Parsed_successfully of {stderr: string} + | Parse_failed of {stdout: string; stderr: string} + | Use_existing_ast + +val preliminary_parse : Process.result -> preliminary_parse + +type namespace_job = {job: Process.job; finish: Process.result -> unit} +type pending_work +type finalization_state + +type t = { + freshness_mode: freshness_mode; + session: Build_session.t; + mutable cleaned: int; + mutable previous_asts: int; + mutable parsed: int; + mutable compiled: int; + mutable parse_seconds: float; + mutable parse_messages: parse_message list; + mutable diagnostics: string list; + removed_modules: (string, unit) Hashtbl.t; + preliminary_parses: (string, preliminary_parse) Hashtbl.t; + blocked_modules: (string, unit) Hashtbl.t; + namespace_freshness: (string, float option) Hashtbl.t; + package_removed_modules: (string, string list) Hashtbl.t; + pending_work: pending_work; + finalization: finalization_state; + mutable compiler_cleaned: bool; + mutable had_warnings: bool; + process_poll: (unit -> unit) option; + progress: Output.Progress.t; + verbosity: int; +} + +val create_full : + warning_state:Warning_state.t -> + process_poll:(unit -> unit) option -> + progress:Output.Progress.t -> + verbosity:int -> + t + +val create_retained : + session:Build_session.t -> + process_poll:(unit -> unit) option -> + progress:Output.Progress.t -> + verbosity:int -> + t + +val register_cleanup : t -> (unit -> unit) -> unit +val defer_artifact_cleanup : t -> string list -> unit + +val set_cleanup_result : t -> string -> Build_artifacts.cleanup_result -> unit +(** Records the modules this attempt removed from a package, and keeps the + package's public output inventory in the session for later attempts. *) + +val removed_package_modules : t -> string -> string list +(** The modules this attempt removed from the package at the given root. *) + +val add_namespace_job : t -> namespace_job -> unit +val take_namespace_jobs : t -> namespace_job list +val add_compile_candidates : t -> Compiler_scheduler.candidate list -> unit +val take_compile_candidates : t -> Compiler_scheduler.candidate list +val mark_log_initialized : t -> string -> unit +val cleanup_artifacts : t -> unit +val finalize_logs : t -> unit +val protect : t -> (unit -> 'a) -> 'a diff --git a/rewatch-ocaml/build_freshness.ml b/rewatch-ocaml/build_freshness.ml new file mode 100644 index 00000000000..93eb79b707e --- /dev/null +++ b/rewatch-ocaml/build_freshness.ml @@ -0,0 +1,35 @@ +let source_requires_parse source_modified artifact_modified = + match (source_modified, artifact_modified) with + | Some source_time, Some artifact_time -> source_time >= artifact_time + | Some _, None -> true + | None, _ -> false + +let source_is_not_older_than_ast compile_assets ~root ~source_mtimes path = + let absolute = Filename.concat root path in + let source_modified = + match Hashtbl.find_opt source_mtimes path with + | Some modified -> Some modified + | None -> File_util.modification_time absolute + in + let artifact_modified = + match Compile_assets.ast compile_assets absolute with + | Some ast -> Some ast.modified + | None -> + let published_ast = + Build_artifacts.published_ast_path + ~ocaml_dir:(Build_artifacts.lib_path root "ocaml") + path + in + let belongs_to_source = + try + match (Ast_header.read published_ast).source with + | Some source -> + Platform.normalize_path_for_comparison source + = Platform.normalize_path_for_comparison absolute + | None -> false + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> false + in + if belongs_to_source then File_util.modification_time published_ast + else None + in + source_requires_parse source_modified artifact_modified diff --git a/rewatch-ocaml/build_freshness.mli b/rewatch-ocaml/build_freshness.mli new file mode 100644 index 00000000000..4fb259a6fcb --- /dev/null +++ b/rewatch-ocaml/build_freshness.mli @@ -0,0 +1,6 @@ +val source_is_not_older_than_ast : + Compile_assets.t -> + root:string -> + source_mtimes:(string, float) Hashtbl.t -> + string -> + bool diff --git a/rewatch-ocaml/build_lock.ml b/rewatch-ocaml/build_lock.ml new file mode 100644 index 00000000000..dd4d8d8f015 --- /dev/null +++ b/rewatch-ocaml/build_lock.ml @@ -0,0 +1,182 @@ +type watch = {path: string; pid: string} + +let read_owner path = + try Some (File_util.read_file path) + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> None + +let valid_owner value = + match Int64.of_string_opt value with + | Some pid -> pid >= 0L && pid <= 0xffff_ffffL + | None -> false + +let malformed_error () = + Project_context.Error + "Could not start Rescript build: Could not parse lockfile PID\n\ + \ (try removing it and running the command again)" + +(* A writer that cannot link creates the lock and then writes its PID, as Rust + rewatch always does, so an empty lock is usually still being written. One + that stays empty belongs to a writer that died in between. *) +let being_written path = + match Unix.stat path with + | stats -> Unix.gettimeofday () -. stats.Unix.st_mtime < 5.0 + | exception Unix.Unix_error _ -> false + +(* Linking a fully written candidate publishes the lock atomically. Some + filesystems (FAT, exFAT, and some network or virtual-machine shares) have no + hard links; there the lock is created exclusively and then written. Falling + back on any other link error is safe because the exclusive create reports + the existing lock or the real error itself. *) +let publish ~candidate ~path ~contents = + try + Unix.link candidate path; + true + with + | Unix.Unix_error (Unix.EEXIST, _, _) -> false + | Unix.Unix_error _ -> ( + match + Unix.openfile path [Unix.O_WRONLY; Unix.O_CREAT; Unix.O_EXCL] 0o644 + with + | exception Unix.Unix_error (Unix.EEXIST, _, _) -> false + | descriptor -> + (try + Fun.protect + ~finally:(fun () -> Unix.close descriptor) + (fun () -> + let length = String.length contents in + if Unix.write_substring descriptor contents 0 length <> length then + failwith ("short write to " ^ path)) + with error -> + (try Unix.unlink path with Unix.Unix_error _ -> ()); + raise error); + true) + +let process_is_active ?poll value = + Platform.process_is_active value ~run:(fun program args -> + try + let result = + Process.run ?poll ~cwd:(Filename.get_temp_dir_name ()) program args + in + Some (result.Process.status, result.stdout) + with Process.Error _ | Unix.Unix_error _ | Sys_error _ -> None) + +let with_candidate ~lock_dir prefix pid action = + let path, output = Filename.open_temp_file ~temp_dir:lock_dir prefix ".tmp" in + Fun.protect + ~finally:(fun () -> File_util.remove_file_best_effort path) + (fun () -> + (try + output_string output pid; + close_out output + with exn -> + close_out_noerr output; + raise exn); + action path) + +let clear_stale ?poll ~candidate ~pid path = + let takeover = path ^ ".takeover" in + if publish ~candidate ~path:takeover ~contents:pid then ( + Fun.protect + ~finally:(fun () -> File_util.remove_file_best_effort takeover) + (fun () -> + match read_owner path with + | Some "" when being_written path -> () + | Some "" -> File_util.remove_file_best_effort path + | Some owner when not (valid_owner owner) -> raise (malformed_error ()) + | Some owner when process_is_active ?poll owner -> () + | Some _ -> File_util.remove_file_best_effort path + | None -> ()); + true) + else ( + (match read_owner takeover with + | Some "" when being_written takeover -> () + | Some owner when owner <> "" && process_is_active ?poll owner -> () + | _ -> File_util.remove_file_best_effort takeover); + false) + +let unlink_existing path = + try Unix.unlink path with Unix.Unix_error (Unix.ENOENT, _, _) -> () + +let release_owned path pid = + if read_owner path = Some pid then unlink_existing path + +type owned_lock = {path: string; pid: string; mutable released: bool} + +let release lock = + if not lock.released then ( + release_owned lock.path lock.pid; + lock.released <- true) + +let with_acquired ~candidate ~path ~pid action = + let lock = {path; pid; released = false} in + match + unlink_existing candidate; + action lock + with + | result -> + release lock; + result + | exception original -> + release lock; + raise original + +let acquire ?poll ~name ~prefix ~attempts ~delay ~timeout ~on_live_owner root + action = + let lock_dir = Filename.concat root "lib" in + File_util.ensure_dir lock_dir; + let path = Filename.concat lock_dir name in + let pid = string_of_int (Platform.current_process_id ()) in + with_candidate ~lock_dir prefix pid (fun candidate -> + let rec attempt remaining = + Option.iter (fun poll -> poll ()) poll; + if remaining = 0 then raise (Project_context.Error timeout); + if publish ~candidate ~path ~contents:pid then + with_acquired ~candidate ~path ~pid action + else ( + (match read_owner path with + | Some "" when being_written path -> delay () + | Some owner when owner <> "" && not (valid_owner owner) -> + raise (malformed_error ()) + | Some owner when process_is_active ?poll owner -> + on_live_owner ~first_attempt:(remaining = attempts) owner; + delay () + | _ -> if not (clear_stale ?poll ~candidate ~pid path) then delay ()); + attempt (remaining - 1)) + in + attempt attempts) + +let retry_delay poll = + (try ignore (Unix.select [] [] [] 0.05) + with Unix.Unix_error (Unix.EINTR, _, _) -> ()); + poll () + +let with_build ?(poll = fun () -> ()) ?(attempts = 1200) root action = + acquire ~poll ~name:"build.lock" ~prefix:".build-lock-" ~attempts + ~delay:(fun () -> retry_delay poll) + ~timeout:"Timed out waiting for another ReScript build to finish" + ~on_live_owner:(fun ~first_attempt _owner -> + if first_attempt then ( + print_endline "Waiting for other build to finish..."; + flush stdout)) + root + (fun lock -> action ~release:(fun () -> release lock)) + +let with_watch root action = + acquire ~name:"watch.lock" ~prefix:".watch-lock-" ~attempts:1000 + ~delay:(fun () -> ignore (Unix.select [] [] [] 0.01)) + ~timeout:"Timed out recovering a stale ReScript watch lock" + ~on_live_owner:(fun ~first_attempt:_ owner -> + raise + (Project_context.Error + (Printf.sprintf + "Could not start Rescript build: A ReScript build is already \ + running. The process ID (PID) is %s" + owner))) + root + (fun (lock : owned_lock) -> action {path = lock.path; pid = lock.pid}) + +let is_owned (watch : watch) = read_owner watch.path = Some watch.pid + +module For_test = struct + let publish = publish +end diff --git a/rewatch-ocaml/build_lock.mli b/rewatch-ocaml/build_lock.mli new file mode 100644 index 00000000000..593aee79e40 --- /dev/null +++ b/rewatch-ocaml/build_lock.mli @@ -0,0 +1,20 @@ +type watch + +val read_owner : string -> string option +val valid_owner : string -> bool + +val with_build : + ?poll:(unit -> unit) -> + ?attempts:int -> + string -> + (release:(unit -> unit) -> 'a) -> + 'a +(** Waits for another build's lock, by default for up to a minute + ([attempts] times 50 ms). *) + +val with_watch : string -> (watch -> 'a) -> 'a +val is_owned : watch -> bool + +module For_test : sig + val publish : candidate:string -> path:string -> contents:string -> bool +end diff --git a/rewatch-ocaml/build_preparation.ml b/rewatch-ocaml/build_preparation.ml new file mode 100644 index 00000000000..cdae985d7c8 --- /dev/null +++ b/rewatch-ocaml/build_preparation.ml @@ -0,0 +1,259 @@ +exception Error = Project_context.Error + +type result = { + prepared: Build_session.prepared; + cycle: Module_graph.cycle_info option; +} + +let bsc_path () = + try Toolchain.bsc () with Toolchain.Error message -> raise (Error message) + +let runtime_path root = + try Toolchain.runtime ~find_package:(Project_context.dependency_path root) + with Toolchain.Error message -> raise (Error message) + +let run ~(root_config : Config.t) ~prod ~features ~warn_error ~filter ~watch + ~(attempt : Build_attempt.t) ~parse_step ~on_cleanup = + let bsc = bsc_path () in + let workspace_config = Project_context.workspace_config_for root_config in + let package_plans = + Package_graph.discover ~root_config ~workspace_config ~prod ~features + ~warn_error ~filter ~attempt + in + Module_graph.validate_visible_namespaces ~root_config package_plans; + let runtime = runtime_path root_config.root in + let source_map_args = Compiler_args.source_map_args workspace_config ~watch in + let compiler_context = + Compiler_info.make_context ~bsc_path:bsc ~runtime_path:runtime + ~source_map_args + ~inherited_compiler_args: + (workspace_config.jsx_args @ workspace_config.experimental_args) + ~package_output_specs: + (Compiler_info.package_output_specs workspace_config) + in + let previous_compile_assets = + package_plans + |> List.map (fun (package : Package_plan.t) -> package.ocaml_dir) + |> Compile_assets.create + in + let dependents_by_raw_dependency = Hashtbl.create 64 in + package_plans + |> List.concat_map (fun (package : Package_plan.t) -> + Compile_assets.ast_sources previous_compile_assets package.ocaml_dir) + |> List.iter (fun (ast_source : Compile_assets.ast_source) -> + Compile_assets.ast_dependencies previous_compile_assets + ast_source.ast_path + |> List.iter (fun dependency -> + let dependents = + Hashtbl.find_opt dependents_by_raw_dependency dependency + |> Option.value ~default:[] + in + Hashtbl.replace dependents_by_raw_dependency dependency + (ast_source.ast_path :: dependents))); + let invalidate_removed_module module_name = + if not (Hashtbl.mem attempt.removed_modules module_name) then ( + Hashtbl.add attempt.removed_modules module_name (); + Build_session.mark_module_removed attempt.session module_name; + let dependent_asts = + Hashtbl.find_opt dependents_by_raw_dependency module_name + |> Option.value ~default:[] + in + (* A cleanup failure can end the attempt before dependency preparation + records why consumers need recompilation. Remove their freshness + markers when the attempt finishes so the next invocation cannot reuse + them, while the current invocation can still compile from the existing + AST and report the source-level missing-module error. *) + Build_attempt.register_cleanup attempt (fun () -> + List.iter File_util.remove_file dependent_asts)) + in + let cleanup_stale (package : Package_plan.t) ~on_deferred_artifact = + Build_artifacts.cleanup_stale + ~ocaml_files: + (Compile_assets.files previous_compile_assets package.ocaml_dir) + ~ast_sources: + (Compile_assets.ast_sources previous_compile_assets package.ocaml_dir) + ~root:package.root ~source_files:package.source_files + ~present_source_files:package.present_source_files + ~on_removed_module:invalidate_removed_module ~on_deferred_artifact + ~is_local:package.is_local package.compile_config package.modules + in + (* Outputs written under the previous package-specs are removed before the + package is cleaned, because the new specs no longer name them. *) + let remove_previous_spec_outputs (package : Package_plan.t) package_context = + Compiler_info.changed_package_output_specs package_context package.config + |> Option.iter (fun previous_specs -> + let previous_config = + Compiler_info.config_with_package_output_specs package.compile_config + previous_specs + in + let previous_implementations = + List.map + (fun (module_ : Source.module_) -> module_.implementation) + package.modules + @ (Compile_assets.ast_sources previous_compile_assets + package.ocaml_dir + |> List.filter_map (fun (source : Compile_assets.ast_source) -> + if Filename.check_suffix source.ast_path ".iast" then None + else + Project_context.relative_to_opt package.root + source.source_path)) + |> List.sort_uniq String.compare + in + Build_artifacts.remove_public_outputs previous_config + previous_implementations) + in + let cleanup_started = Unix.gettimeofday () in + (* A package that needs cleaning has its stale outputs removed before its + lib/bs and lib/ocaml trees are wiped, while the lib/bs mirror still + identifies which public outputs it owns. That cleanup result is final, so + the second pass only cleans up the remaining packages. *) + let cleanups_before_clean = + List.map + (fun (package : Package_plan.t) -> + let package_context = + Compiler_info.for_package compiler_context package.compile_config + in + let cleanup = + if Compiler_info.needs_clean package_context package.config then ( + remove_previous_spec_outputs package package_context; + let cleanup = + cleanup_stale package ~on_deferred_artifact:File_util.remove_file + in + Compiler_info.clean_package package.config; + attempt.compiler_cleaned <- true; + Some cleanup) + else None + in + File_util.ensure_dir package.build_dir; + File_util.ensure_dir package.ocaml_dir; + (package, cleanup)) + package_plans + in + List.iter + (fun ((package : Package_plan.t), cleanup) -> + let cleanup = + match cleanup with + | Some cleanup -> cleanup + | None -> + cleanup_stale package ~on_deferred_artifact:(fun path -> + Build_attempt.defer_artifact_cleanup attempt [path]) + in + Build_attempt.set_cleanup_result attempt package.root cleanup; + attempt.cleaned <- attempt.cleaned + List.length cleanup.removed_modules; + attempt.previous_asts <- + attempt.previous_asts + cleanup.previous_ast_count) + cleanups_before_clean; + let compile_assets = + if attempt.compiler_cleaned || Hashtbl.length attempt.removed_modules > 0 + then + package_plans + |> List.map (fun (package : Package_plan.t) -> package.ocaml_dir) + |> Compile_assets.create + else previous_compile_assets + in + on_cleanup (Unix.gettimeofday () -. cleanup_started); + let parse_started = Unix.gettimeofday () in + let parse_entries = + package_plans + |> List.concat_map (fun (package : Package_plan.t) -> + package.modules + |> List.concat_map (fun module_ -> + let paths = + module_.Source.implementation + :: Option.to_list module_.Source.interface + in + let dirty_paths = + paths + |> List.filter (fun path -> + Build_freshness.source_is_not_older_than_ast compile_assets + ~root:package.root ~source_mtimes:package.source_mtimes path) + in + if dirty_paths <> [] then + Output.debug ~verbosity:attempt.verbosity + ("Generating AST for module: " + ^ Source.compiler_basename package.compile_config + module_.Source.name); + let group = package.root ^ "\000" ^ module_.Source.name in + List.map (fun path -> (package, path, group)) dirty_paths)) + in + let parse_completed = + Output.Progress.start_grouped attempt.progress ~step:parse_step + ~symbol:Platform.parse_symbol ~label:"Parsing" + (List.map (fun (_, _, group) -> group) parse_entries) + in + let parse_results = + Process.run_parallel_map ?poll:attempt.process_poll + ~on_complete:parse_completed parse_entries + ~job:(fun ((package : Package_plan.t), path, _) -> + Compiler_process.parse_job ~bsc ~build_dir:package.build_dir + ~config:package.compile_config path) + in + let failed_parse_paths = Hashtbl.create 8 in + List.iter2 + (fun ((package : Package_plan.t), path, _) result -> + let absolute_path = Filename.concat package.root path in + let outcome = Build_attempt.preliminary_parse result in + Hashtbl.replace attempt.preliminary_parses absolute_path outcome; + match outcome with + | Build_attempt.Parse_failed _ -> + Hashtbl.replace failed_parse_paths absolute_path () + | Build_attempt.Parsed_successfully _ | Build_attempt.Use_existing_ast -> + ()) + parse_entries parse_results; + let graph = + Module_graph.initialize ~root_config ~package_plans ~compile_assets + ~failed_parse_paths + in + List.iter + (fun path -> + if not (Hashtbl.mem attempt.preliminary_parses path) then + Hashtbl.replace attempt.preliminary_parses path + Build_attempt.Use_existing_ast) + graph.use_existing_ast_paths; + List.iter + (fun (node : Module_graph.module_node) -> + Build_session.add_global_module attempt.session node.key node) + graph.nodes; + List.iter + (Build_session.add_namespace_map attempt.session) + graph.namespace_maps; + let nodes = graph.nodes in + let namespace_maps = graph.namespace_maps in + let build_state = graph.build_state in + let packages = Hashtbl.create (List.length package_plans) in + List.iter + (fun (package : Package_plan.t) -> + let regular_dependency_dirs, development_dependency_dirs = + List.fold_left + (fun (regular, development) (dependency : Package_plan.dependency) -> + let directory = + Build_artifacts.lib_path dependency.directory "ocaml" + in + match dependency.kind with + | Package_traversal.Regular -> (directory :: regular, development) + | Package_traversal.Development -> + (regular, directory :: development)) + ([], []) package.dependencies + |> fun (regular, development) -> (List.rev regular, List.rev development) + in + let common_args dependency_dirs = + Compiler_args.compiler_common_arguments ~config:package.compile_config + ~runtime ~dependency_dirs ~watch + ~gentype_dependency_args:package.gentype_dependency_args + in + Hashtbl.add packages package.root + Package_plan. + { + regular_common_args = common_args regular_dependency_dirs; + development_common_args = + common_args (development_dependency_dirs @ regular_dependency_dirs); + }) + package_plans; + let prepared = + Build_session.{compiler_context; compile_assets; build_state; packages} + in + Build_session.install_prepared attempt.session prepared; + let cycle = Module_graph.find_cycle nodes namespace_maps build_state in + Build_session.set_graph_cycle attempt.session cycle; + attempt.parse_seconds <- Unix.gettimeofday () -. parse_started; + {prepared; cycle} diff --git a/rewatch-ocaml/build_preparation.mli b/rewatch-ocaml/build_preparation.mli new file mode 100644 index 00000000000..75a95cd78a9 --- /dev/null +++ b/rewatch-ocaml/build_preparation.mli @@ -0,0 +1,16 @@ +type result = { + prepared: Build_session.prepared; + cycle: Module_graph.cycle_info option; +} + +val run : + root_config:Config.t -> + prod:bool -> + features:string list option -> + warn_error:string option -> + filter:Source_filter.t option -> + watch:bool -> + attempt:Build_attempt.t -> + parse_step:string -> + on_cleanup:(float -> unit) -> + result diff --git a/rewatch-ocaml/build_report.ml b/rewatch-ocaml/build_report.ml new file mode 100644 index 00000000000..9ba6ae4da9a --- /dev/null +++ b/rewatch-ocaml/build_report.ml @@ -0,0 +1,115 @@ +type kind = One_shot | Initial_watch | Incremental_watch | Full_watch + +type t = { + started_at: float; + interactive: bool; + show_progress: bool; + colors: bool; + no_timing: bool; + kind: kind; + attempt: Build_attempt.t; +} + +let create ~started_at ~interactive ~show_progress ~colors ~no_timing ~kind + ~attempt = + {started_at; interactive; show_progress; colors; no_timing; kind; attempt} + +let parse_step report = + match report.kind with + | Incremental_watch -> "1/2" + | One_shot | Initial_watch | Full_watch -> "2/3" + +let compile_step report = + match report.kind with + | Incremental_watch -> "2/2" + | One_shot | Initial_watch | Full_watch -> "3/3" + +let output_kind report = + match report.kind with + | Initial_watch -> Output.Initial + | Incremental_watch -> Output.Incremental + | One_shot | Full_watch -> Output.Standard + +let prepare report ~success ~compile_seconds = + let attempt = report.attempt in + if report.show_progress then + if report.interactive then + if success then + print_endline + (Output.compiling_message ~color:report.colors + ~step:(compile_step report) ~count:attempt.compiled + ~seconds:compile_seconds) + else + prerr_endline + (Output.compilation_failed_message ~color:report.colors + ~step:(compile_step report) ~count:attempt.compiled + ~seconds:compile_seconds) + else ( + (match report.kind with + | One_shot | Initial_watch | Full_watch -> + Printf.printf "Cleaned %d/%d\n%!" attempt.cleaned attempt.previous_asts + | Incremental_watch -> ()); + Printf.printf "Parsed %d source files\n%!" attempt.parsed; + if success then Printf.printf "Compiled %d modules\n%!" attempt.compiled + else Printf.eprintf "Compiled %d modules\n%!" attempt.compiled); + let diagnostics = + match report.kind with + | Incremental_watch | Full_watch -> [] + | One_shot | Initial_watch -> + attempt.diagnostics |> List.rev |> List.sort_uniq String.compare + in + let warning_entries = + Warning_state.entries (Build_session.warning_state attempt.session) + in + List.iter + (fun entry -> prerr_string entry.Warning_state.output) + warning_entries; + if warning_entries <> [] then prerr_newline (); + flush stderr; + if diagnostics <> [] then + diagnostics + |> List.map (fun diagnostic -> + if report.colors then Output.yellow diagnostic else diagnostic) + |> String.concat "\n\n" |> prerr_endline; + diagnostics + +let report_completion report diagnostics = + if report.interactive && report.show_progress then + let seconds = + if report.no_timing then 0. else Unix.gettimeofday () -. report.started_at + in + Printf.printf "\n%s\n%!" + (Output.finished_compilation_message ~label:(output_kind report) + ~warnings: + (report.attempt.had_warnings || diagnostics <> [] + || Warning_state.entries + (Build_session.warning_state report.attempt.session) + <> []) + ~seconds) + else if report.kind <> One_shot && report.show_progress then + Printf.printf "Finished %scompilation\n%!" + (match report.kind with + | Initial_watch -> "initial " + | Incremental_watch -> "incremental " + | One_shot | Full_watch -> "") + +let report_failure report ~compile_seconds = + ignore (prepare report ~success:false ~compile_seconds) + +let print_success_details report ~compile_seconds = + prepare report ~success:true ~compile_seconds + +let report_parse_failure report ~output = + (if report.interactive && report.show_progress then + prerr_endline + (Output.parsing_failed_message ~color:report.colors + ~step:(parse_step report) + ~seconds: + (if report.no_timing then 0. else report.attempt.parse_seconds)) + else if report.show_progress then + match report.kind with + | One_shot | Initial_watch | Full_watch -> + Printf.printf "Cleaned %d/%d\n%!" report.attempt.cleaned + report.attempt.previous_asts + | Incremental_watch -> ()); + prerr_endline output diff --git a/rewatch-ocaml/build_report.mli b/rewatch-ocaml/build_report.mli new file mode 100644 index 00000000000..ad91a7e18f7 --- /dev/null +++ b/rewatch-ocaml/build_report.mli @@ -0,0 +1,29 @@ +type t + +(** Which output a build reports: watch builds print a completion line, and + incremental rebuilds skip the cleanup phase. *) +type kind = + | One_shot + | Initial_watch + | Incremental_watch + | Full_watch + (** Reporting owns presentation state independently of build execution. This + keeps terminal progress, timing, and final diagnostics from influencing + cleanup or retained-state transitions. *) + +val create : + started_at:float -> + interactive:bool -> + show_progress:bool -> + colors:bool -> + no_timing:bool -> + kind:kind -> + attempt:Build_attempt.t -> + t + +val parse_step : t -> string +val compile_step : t -> string +val report_failure : t -> compile_seconds:float -> unit +val print_success_details : t -> compile_seconds:float -> string list +val report_completion : t -> string list -> unit +val report_parse_failure : t -> output:string -> unit diff --git a/rewatch-ocaml/build_session.ml b/rewatch-ocaml/build_session.ml new file mode 100644 index 00000000000..1e2914b44a7 --- /dev/null +++ b/rewatch-ocaml/build_session.ml @@ -0,0 +1,149 @@ +type prepared = { + compiler_context: Compiler_info.context; + compile_assets: Compile_assets.t; + build_state: Build_state.t; + packages: (string, Package_plan.compilation) Hashtbl.t; +} + +type source_reference = { + package_root: string; + module_: Source.module_; + relative_path: string; + absolute_path: string; +} + +type readiness = + | Not_prepared + | Freshness_pending of prepared + | Ready of prepared + +type compiler_info_state = Needs_publication | Published +type cycle_cache = + | Unknown_cycle + | Known_cycle of Module_graph.cycle_info option + +type t = { + global_modules: (string, Module_graph.module_node) Hashtbl.t; + namespace_maps: (string, Module_graph.namespace_map) Hashtbl.t; + namespace_maps_by_name: (string, Module_graph.namespace_map list) Hashtbl.t; + mutable graph_cycle: cycle_cache; + package_plans: (string, Package_plan.t) Hashtbl.t; + source_index: (string, source_reference) Hashtbl.t; + pending_parse_paths: (string, unit) Hashtbl.t; + pending_removed_modules: (string, unit) Hashtbl.t; + public_outputs: (string, (string, unit) Hashtbl.t) Hashtbl.t; + mutable readiness: readiness; + mutable compiler_info_state: compiler_info_state; + warning_state: Warning_state.t; +} + +let create ~warning_state = + { + global_modules = Hashtbl.create 64; + namespace_maps = Hashtbl.create 16; + namespace_maps_by_name = Hashtbl.create 16; + graph_cycle = Unknown_cycle; + package_plans = Hashtbl.create 32; + source_index = Hashtbl.create 64; + pending_parse_paths = Hashtbl.create 16; + pending_removed_modules = Hashtbl.create 16; + public_outputs = Hashtbl.create 32; + readiness = Not_prepared; + compiler_info_state = Needs_publication; + warning_state; + } + +let is_ready session = + match session.readiness with + | Ready _ -> true + | _ -> false + +let prepared session = + match session.readiness with + | Freshness_pending prepared | Ready prepared -> Some prepared + | Not_prepared -> None + +let install_prepared session prepared = + session.readiness <- Freshness_pending prepared + +let mark_freshness_initialized session = + match session.readiness with + | Freshness_pending prepared -> + session.readiness <- Ready prepared; + Hashtbl.clear session.pending_removed_modules + | Ready _ -> () + | Not_prepared -> invalid_arg "build state has not been prepared" + +let find_global_module session key = Hashtbl.find_opt session.global_modules key + +let add_global_module session key module_ = + Hashtbl.add session.global_modules key module_ + +let global_module_values session = + Hashtbl.to_seq_values session.global_modules |> List.of_seq + +let find_namespace_maps session name = + Hashtbl.find_opt session.namespace_maps_by_name name + +let add_namespace_map session namespace_map = + Hashtbl.add session.namespace_maps namespace_map.Module_graph.key + namespace_map; + let existing = + find_namespace_maps session namespace_map.namespace + |> Option.value ~default:[] + in + Hashtbl.replace session.namespace_maps_by_name namespace_map.namespace + (namespace_map :: existing) + +let find_namespace_map session key = Hashtbl.find session.namespace_maps key + +let namespace_map_values session = + Hashtbl.to_seq_values session.namespace_maps |> List.of_seq + +let graph_cycle session = session.graph_cycle +let invalidate_graph_cycle session = session.graph_cycle <- Unknown_cycle +let set_graph_cycle session cycle = session.graph_cycle <- Known_cycle cycle + +let add_package_plan session package = + Hashtbl.replace session.package_plans package.Package_plan.root package + +let find_package_plan session root = Hashtbl.find_opt session.package_plans root + +let iter_package_plans session f = Hashtbl.iter f session.package_plans +let package_plan_values session = Hashtbl.to_seq_values session.package_plans + +let publish_compiler_info session write = + match session.compiler_info_state with + | Published -> () + | Needs_publication -> + Hashtbl.iter (fun _ package -> write package) session.package_plans; + session.compiler_info_state <- Published + +let add_source_reference session normalized_path source = + Hashtbl.replace session.source_index normalized_path source + +let find_source_reference session normalized_path = + Hashtbl.find_opt session.source_index normalized_path + +let pending_parse_paths session = + session.pending_parse_paths |> Hashtbl.to_seq_keys |> List.of_seq + +let mark_parse_pending session path = + Hashtbl.replace session.pending_parse_paths path () + +let clear_parse_pending session path = + Hashtbl.remove session.pending_parse_paths path + +let mark_module_removed session name = + Hashtbl.replace session.pending_removed_modules name () + +let pending_removed_modules session = + session.pending_removed_modules |> Hashtbl.to_seq_keys |> List.of_seq + +let set_public_outputs session root outputs = + Hashtbl.replace session.public_outputs root outputs + +let find_public_outputs session root = + Hashtbl.find_opt session.public_outputs root + +let warning_state session = session.warning_state diff --git a/rewatch-ocaml/build_session.mli b/rewatch-ocaml/build_session.mli new file mode 100644 index 00000000000..d89cfb5e9e0 --- /dev/null +++ b/rewatch-ocaml/build_session.mli @@ -0,0 +1,59 @@ +type t +(** A session keeps only state that must survive from one watch build to the + next. Per-attempt diagnostics, counters, and cleanup actions deliberately + live in {!Build_attempt} so a failed attempt cannot leak transient state + into its successor. *) + +type prepared = { + compiler_context: Compiler_info.context; + compile_assets: Compile_assets.t; + build_state: Build_state.t; + packages: (string, Package_plan.compilation) Hashtbl.t; +} + +type source_reference = { + package_root: string; + module_: Source.module_; + relative_path: string; + absolute_path: string; +} + +(** Cycle results are cached because ordinary implementation edits do not + change dependency edges. [Unknown_cycle] means that graph analysis is + required; [Known_cycle None] means it ran and found an acyclic graph. *) +type cycle_cache = + | Unknown_cycle + | Known_cycle of Module_graph.cycle_info option + +val create : warning_state:Warning_state.t -> t +val is_ready : t -> bool +val prepared : t -> prepared option +val install_prepared : t -> prepared -> unit +val mark_freshness_initialized : t -> unit +val find_global_module : t -> string -> Module_graph.module_node option +val add_global_module : t -> string -> Module_graph.module_node -> unit +val global_module_values : t -> Module_graph.module_node list +val find_namespace_maps : t -> string -> Module_graph.namespace_map list option +val add_namespace_map : t -> Module_graph.namespace_map -> unit +val find_namespace_map : t -> string -> Module_graph.namespace_map +val namespace_map_values : t -> Module_graph.namespace_map list +val graph_cycle : t -> cycle_cache +val invalidate_graph_cycle : t -> unit +val set_graph_cycle : t -> Module_graph.cycle_info option -> unit +val add_package_plan : t -> Package_plan.t -> unit +val find_package_plan : t -> string -> Package_plan.t option +val iter_package_plans : t -> (string -> Package_plan.t -> unit) -> unit +val package_plan_values : t -> Package_plan.t Seq.t +val publish_compiler_info : t -> (Package_plan.t -> unit) -> unit +val add_source_reference : t -> string -> source_reference -> unit +val find_source_reference : t -> string -> source_reference option +val pending_parse_paths : t -> string list +val mark_parse_pending : t -> string -> unit +val clear_parse_pending : t -> string -> unit +val mark_module_removed : t -> string -> unit +val pending_removed_modules : t -> string list + +val set_public_outputs : t -> string -> (string, unit) Hashtbl.t -> unit +val find_public_outputs : t -> string -> (string, unit) Hashtbl.t option + +val warning_state : t -> Warning_state.t diff --git a/rewatch-ocaml/build_state.ml b/rewatch-ocaml/build_state.ml new file mode 100644 index 00000000000..853f5b8e0ac --- /dev/null +++ b/rewatch-ocaml/build_state.ml @@ -0,0 +1,122 @@ +module String_set = Set.Make (String) + +type module_kind = Source_module | Namespace_map +type cmi_change = Cmi_changed | Cmi_unchanged | Cmi_change_unknown + +type module_ = { + key: string; + kind: module_kind; + mutable dependencies: string list; + mutable dependents: String_set.t; + mutable compile_dirty: bool; + mutable last_compiled_cmi: float option; + mutable last_compiled_cmt: float option; +} + +type t = {modules: (string, module_) Hashtbl.t} + +let create capacity = {modules = Hashtbl.create capacity} + +let add state ~key ~kind ~last_compiled_cmi ~last_compiled_cmt = + Hashtbl.add state.modules key + { + key; + kind; + dependencies = []; + dependents = String_set.empty; + compile_dirty = false; + last_compiled_cmi; + last_compiled_cmt; + } + +let find state key = Hashtbl.find_opt state.modules key + +let find_exn state key = + match find state key with + | Some module_ -> module_ + | None -> raise (Invalid_argument ("unknown build module " ^ key)) + +let carry_forward_compile_dirty ~previous ~next ~same_source = + Hashtbl.iter + (fun key next_module -> + match find previous key with + | Some previous_module + when previous_module.compile_dirty && same_source key -> + next_module.compile_dirty <- true + | Some _ | None -> ()) + next.modules + +let has_complete_compile_assets module_ = + Option.is_some module_.last_compiled_cmi + && Option.is_some module_.last_compiled_cmt + +let dependency_tree_compiled_after ?(namespace_freshness = Hashtbl.create 4) + state module_ dependency = + let rec latest_cmi dependency = + match dependency.kind with + | Source_module -> dependency.last_compiled_cmi + | Namespace_map -> ( + match Hashtbl.find_opt namespace_freshness dependency.key with + | Some modified -> modified + | None -> + let modified = + dependency.dependencies + |> List.fold_left + (fun latest key -> + match (latest, latest_cmi (find_exn state key)) with + | None, member -> member + | latest, None -> latest + | Some latest, Some member -> Some (max latest member)) + None + in + Hashtbl.add namespace_freshness dependency.key modified; + modified) + in + match (latest_cmi dependency, module_.last_compiled_cmt) with + | Some dependency_time, Some module_time -> dependency_time > module_time + | None, _ | _, None -> false + +let set_dependencies state ~key dependencies = + let module_ = find_exn state key in + List.iter + (fun dependency -> + let dependency_module = find_exn state dependency in + dependency_module.dependents <- + String_set.remove key dependency_module.dependents) + module_.dependencies; + module_.dependencies <- dependencies; + List.iter + (fun dependency -> + let dependency_module = find_exn state dependency in + dependency_module.dependents <- + String_set.add key dependency_module.dependents) + dependencies + +let mark_dependents_compile_dirty ?(visited = Hashtbl.create 8) state module_ = + let rec mark dependent = + if not (Hashtbl.mem visited dependent) then ( + Hashtbl.add visited dependent (); + let dependent_module = find_exn state dependent in + match dependent_module.kind with + | Source_module -> dependent_module.compile_dirty <- true + | Namespace_map -> String_set.iter mark dependent_module.dependents) + in + String_set.iter mark module_.dependents + +let record_published_cmi ?dirty_propagation state ~compile_assets module_ ~path + change = + (match change with + | Cmi_unchanged -> () + | Cmi_changed | Cmi_change_unknown -> + mark_dependents_compile_dirty ?visited:dirty_propagation state module_); + Compile_assets.refresh_cmi compile_assets ~key:module_.key ~path; + module_.last_compiled_cmi <- + Compile_assets.cmi compile_assets module_.key + |> Option.map (fun entry -> entry.Compile_assets.modified) + +let record_successful_compile ~compile_assets module_ ~cmt_path = + Compile_assets.refresh_cmt compile_assets ~key:module_.key ~path:cmt_path; + module_.last_compiled_cmt <- + Compile_assets.cmt compile_assets module_.key + |> Option.map (fun entry -> entry.Compile_assets.modified); + module_.compile_dirty <- false diff --git a/rewatch-ocaml/build_state.mli b/rewatch-ocaml/build_state.mli new file mode 100644 index 00000000000..f9988a20cbf --- /dev/null +++ b/rewatch-ocaml/build_state.mli @@ -0,0 +1,64 @@ +module String_set : Set.S with type elt = string + +(** Build state is the authoritative mutable dependency and freshness store. + Compile-asset indexes supply filesystem metadata, but publication updates + graph dirtiness here so every successful or partial CMI publication follows + the same invalidation path. *) +type module_kind = Source_module | Namespace_map + +type cmi_change = Cmi_changed | Cmi_unchanged | Cmi_change_unknown + +type module_ = { + key: string; + kind: module_kind; + mutable dependencies: string list; + mutable dependents: String_set.t; + mutable compile_dirty: bool; + mutable last_compiled_cmi: float option; + mutable last_compiled_cmt: float option; +} + +type t + +val create : int -> t + +val add : + t -> + key:string -> + kind:module_kind -> + last_compiled_cmi:float option -> + last_compiled_cmt:float option -> + unit + +val find : t -> string -> module_ option +val find_exn : t -> string -> module_ +val carry_forward_compile_dirty : + previous:t -> next:t -> same_source:(string -> bool) -> unit +val has_complete_compile_assets : module_ -> bool +val dependency_tree_compiled_after : + ?namespace_freshness:(string, float option) Hashtbl.t -> + t -> + module_ -> + module_ -> + bool +val set_dependencies : t -> key:string -> string list -> unit + +val mark_dependents_compile_dirty : + ?visited:(string, unit) Hashtbl.t -> t -> module_ -> unit +(** Marks the direct source dependents of [module_], looking through namespace + maps. Dependents further away are marked only when a dependent's own + recompilation publishes a changed CMI ({!record_published_cmi}), because a + byte-identical CMI cannot affect them. [visited] is shared across one + publication batch so each dependent is visited once. *) + +val record_published_cmi : + ?dirty_propagation:(string, unit) Hashtbl.t -> + t -> + compile_assets:Compile_assets.t -> + module_ -> + path:string -> + cmi_change -> + unit + +val record_successful_compile : + compile_assets:Compile_assets.t -> module_ -> cmt_path:string -> unit diff --git a/rewatch-ocaml/clean.ml b/rewatch-ocaml/clean.ml new file mode 100644 index 00000000000..3b766625bbf --- /dev/null +++ b/rewatch-ocaml/clean.ml @@ -0,0 +1,116 @@ +type package = { + name: string; + output_config: Config.t; + implementation_files: string list; +} + +(* The complete cleanup plan is validated before deletion starts so a malformed + dependency cannot leave only the packages visited before it partially + cleaned. The resulting order remains dependency-first for progress output. *) +let prepare ~(root_config : Config.t) ~(workspace_config : Config.t) ~resolution + ~seen ~prod ~is_local = + Package_diagnostics.validate_metadata root_config; + let packages = ref [] in + let rec visit (config : Config.t) ~is_local = + let root = config.root in + if not (Hashtbl.mem seen root) then ( + Hashtbl.add seen root (); + Package_diagnostics.report_missing_sources + ~is_root:(root = root_config.root) config; + let dependencies = Package_traversal.requests ~prod ~is_local config in + let resolved_dependencies = + List.map + (fun request -> + Package_traversal.resolve resolution ~package_root:root request) + dependencies + in + List.iter + (fun (resolved : Package_traversal.resolved) -> + visit resolved.dependency.config + ~is_local:resolved.dependency.is_local) + resolved_dependencies; + let implementation_files = + Source.discover_for_cleanup config ~prod:(prod || not is_local) + ~on_missing:(Package_diagnostics.report_missing_source_folder config) + in + let output_config = Config.with_root_options config workspace_config in + packages := + {name = config.name; output_config; implementation_files} :: !packages) + in + visit root_config ~is_local; + List.rev !packages + +let remove_compiler_assets packages ~on_clean = + List.iter + (fun package -> + on_clean package.name; + Compiler_info.clean_package package.output_config) + packages + +let remove_generated_outputs packages = + List.iter + (fun package -> + List.iter + (fun implementation -> + List.iter + (fun spec -> + let output = + Build_artifacts.generated_js_path package.output_config + implementation spec + in + File_util.remove_file output; + File_util.remove_file (output ^ ".map")) + package.output_config.package_specs) + package.implementation_files) + packages + +let run ~poll ~verbosity ~folder ~prod = + let root = Project_context.canonical_project_root folder in + let show_progress = verbosity >= 0 in + let interactive = Unix.isatty Unix.stdout && Unix.isatty Unix.stderr in + let colors = Output.colors_enabled ~interactive in + let print_cleaning ~step target = + if interactive && show_progress then + Printf.printf "%s%!" + (Output.cleaning_command_message ~color:colors ~step target) + in + let print_cleaned ~step ~target ~started_at = + if interactive && show_progress then + print_endline + (Output.cleaned_command_message ~color:colors ~step ~target + ~seconds:(Unix.gettimeofday () -. started_at)) + in + Build_lock.with_build ~poll (Project_context.workspace_lock_root root) + (fun ~release:_ -> + poll (); + let root_config = Config.load_root root in + let workspace_config = Project_context.workspace_config_for root_config in + let resolution = Package_resolution.create root_config in + let cleanup = + prepare ~root_config ~workspace_config ~resolution + ~seen:(Hashtbl.create 32) ~prod ~is_local:true + in + let compiler_assets = "compiler assets" in + let compiler_started = Unix.gettimeofday () in + remove_compiler_assets cleanup ~on_clean:(fun name -> + if show_progress then + if interactive then print_cleaning ~step:"1/2" name + else Printf.printf "Cleaning %s\n%!" name); + print_cleaned ~step:"1/2" ~target:compiler_assets + ~started_at:compiler_started; + poll (); + let suffixes = + workspace_config.package_specs + |> List.filter_map (fun (spec : Config.package_spec) -> + if spec.in_source then + Some (Config.package_spec_suffix workspace_config spec) + else None) + |> String.concat ", " + in + let generated_files = suffixes ^ " files" in + let generated_started = Unix.gettimeofday () in + print_cleaning ~step:"2/2" generated_files; + remove_generated_outputs cleanup; + poll (); + print_cleaned ~step:"2/2" ~target:generated_files + ~started_at:generated_started) diff --git a/rewatch-ocaml/clean.mli b/rewatch-ocaml/clean.mli new file mode 100644 index 00000000000..be5ef56c8cc --- /dev/null +++ b/rewatch-ocaml/clean.mli @@ -0,0 +1,2 @@ +val run : + poll:(unit -> unit) -> verbosity:int -> folder:string -> prod:bool -> unit diff --git a/rewatch-ocaml/cli.ml b/rewatch-ocaml/cli.ml new file mode 100644 index 00000000000..e5b148af3d9 --- /dev/null +++ b/rewatch-ocaml/cli.ml @@ -0,0 +1,420 @@ +type command = + | Build of build_options + | Clean of {verbosity: int; folder: string; prod: bool} + | Watch of build_options + | Format of format_input + | Compiler_args of {verbosity: int; path: string} + +and build_options = { + verbosity: int; + folder: string; + prod: bool; + features: string list option; + warn_error: string option; + after_build: string option; + filter: Source_filter.t option; + clear_screen: bool; + no_timing: bool; +} + +and format_input = + | Format_stdin of string + | Format_files of {verbosity: int; check: bool; paths: string list} + +open Cmdliner +open Cmdliner.Term.Syntax + +let verbosity = + let verbose = + Arg.( + value & flag_all + & info ["v"; "verbose"] + ~doc: + "Increase logging verbosity: $(b,-v) shows debug and $(b,-vv) also \ + trace output.") + in + let quiet = + Arg.( + value & flag_all + & info ["q"; "quiet"] + ~doc:"Decrease logging verbosity: hide progress and summary output.") + in + Term.term_result + (let+ verbose and+ quiet in + match (verbose, quiet) with + | _ :: _, _ :: _ -> + Error (`Msg "--verbose cannot be used together with --quiet") + | _ -> Ok (List.length verbose - List.length quiet)) + +let folder = + Arg.( + value & pos 0 string "." + & info [] ~docv:"FOLDER" + ~doc: + "Path to the project or subproject. This folder must contain a \ + rescript.json file.") + +let prod = + Arg.( + value & flag + & info ["prod"] + ~doc:"Skip dev-dependencies and dev sources (type: \"dev\").") + +let features = + let parse value = + let values = + String.split_on_char ',' value + |> List.map String.trim + |> List.filter (fun value -> value <> "") + in + if values = [] then + Error + (`Msg + "--features must not be empty. Omit the flag to build with all \ + features active.") + else Ok values + in + let print formatter values = + Stdlib.Format.pp_print_string formatter (String.concat "," values) + in + let converter = Arg.conv (parse, print) in + Arg.( + value + & opt (some converter) None + & info ["features"] ~docv:"FEATURES" + ~doc: + "Restrict the current package to a comma-separated set of features. \ + Only source directories tagged with one of these features (plus \ + untagged ones, and features they transitively imply through the \ + top-level $(b,features) map) are compiled. Omit the flag to build \ + with all features active. Example: $(b,--features \ + native,experimental)") + +let warn_error = + Arg.( + value + & opt (some string) None + & info ["warn-error"] ~docv:"WARNINGS" + ~doc: + "Override warning configuration from rescript.json. Example: \ + $(b,--warn-error \"+3+8+11+12+26+27+31+32+33+34+35+39+44+45+110\")") + +let after_build = + Arg.( + value + & opt (some string) None + & info ["a"; "after-build"] ~docv:"COMMAND" + ~doc: + "Run an additional command after a successful build. E.g., play a \ + sound or run a test suite when done compiling.") + +let filter = + let parse value = + match Source_filter.compile value with + | Ok filter -> Ok filter + | Error message -> Error (`Msg message) + in + let print formatter filter = + Stdlib.Format.pp_print_string formatter (Source_filter.pattern filter) + in + Arg.( + value + & opt (some (conv (parse, print))) None + & info ["f"; "filter"] ~docv:"REGEX" + ~doc: + "Filter source files by regular expression. E.g., filter out test \ + files for compilation while doing feature work.") + +let no_timing = + Arg.(value & flag & info ["n"; "no-timing"] ~doc:"Disable output timing.") + +let clear_screen = + Arg.( + value & flag + & info ["clear-screen"] + ~doc:"Clear the terminal before each interactive rebuild.") + +let build_term ~watch = + let no_timing = if watch then Term.const false else no_timing in + let clear_screen = if watch then clear_screen else Term.const false in + let+ verbosity + and+ folder + and+ prod + and+ features + and+ warn_error + and+ after_build + and+ filter + and+ no_timing + and+ clear_screen in + let options : build_options = + { + verbosity; + folder; + prod; + features; + warn_error; + after_build; + filter; + clear_screen; + no_timing; + } + in + if watch then Watch options else Build options + +let clean_term = + let+ verbosity and+ folder and+ prod in + Clean {verbosity; folder; prod} + +let format_term = + let extension = Arg.enum [(".res", ".res"); (".resi", ".resi")] in + let stdin = + Arg.( + value + & opt (some extension) None + & info ["s"; "stdin"] ~docv:"EXTENSION" + ~doc: + "Read the code from stdin and print the formatted code to stdout.") + in + let check = + Arg.( + value & flag + & info ["c"; "check"] + ~doc:"Check formatting status without applying changes.") + in + let files = + Arg.( + value & pos_all string [] + & info [] ~docv:"FILES" + ~doc: + "Files to format. If no files are provided, all files are \ + formatted.") + in + Term.term_result + (let+ verbosity = verbosity and+ check and+ stdin and+ files in + match (check, stdin, files) with + | true, Some _, _ -> Error (`Msg "--stdin conflicts with --check") + | _, Some _, _ :: _ -> Error (`Msg "files conflict with --stdin") + | _, Some extension, [] -> Ok (Format (Format_stdin extension)) + | _, None, paths -> Ok (Format (Format_files {verbosity; check; paths}))) + +let compiler_args_term = + let path = + Arg.( + required + & pos 0 (some string) None + & info [] ~docv:"PATH" ~doc:"ReScript source file (.res or .resi).") + in + let+ verbosity = verbosity and+ path in + Compiler_args {verbosity; path} + +let exits = + [ + Cmd.Exit.info 0 ~doc:"on success."; + Cmd.Exit.info 1 ~doc:"on build, configuration, or file system errors."; + Cmd.Exit.info 2 + ~doc:"on command-line usage errors and invalid package dependencies."; + Cmd.Exit.info 129 ~max:143 + ~doc:"when interrupted by a signal (128 plus the signal number)."; + ] + +let command_info name doc = Cmd.info name ~doc ~exits + +let root = + let build = + Cmd.make + (command_info "build" "Build the project (default command).") + (build_term ~watch:false) + in + let watch = + Cmd.make + (command_info "watch" "Build, then start a watcher.") + (build_term ~watch:true) + in + let clean = + Cmd.make (command_info "clean" "Clean the build artifacts.") clean_term + in + let format = + Cmd.make (command_info "format" "Format ReScript files.") format_term + in + let compiler_args = + Cmd.make + (command_info "compiler-args" + "Print the compiler arguments for a ReScript source file.") + compiler_args_term + in + let help = + let topic = + Arg.(value & pos 0 (some string) None & info [] ~docv:"COMMAND") + in + let help_term = + Term.ret + (let+ commands = Term.choice_names and+ topic in + match topic with + | None -> `Help (`Plain, None) + | Some command when List.mem command commands -> + `Help (`Plain, Some command) + | Some command -> + `Error (false, Printf.sprintf "unknown command %S" command)) + in + Cmd.make + (command_info "help" "Print this message or command help.") + help_term + in + let info = + let man = + [ + `S "NOTES"; + `P + "If no command is provided, the $(b,build) command is run by \ + default. See $(b,rescript help build) for more information."; + `P + "To create a new ReScript project, or to add ReScript to an existing \ + project, use https://github.com/rescript-lang/create-rescript-app."; + ] + in + Cmd.info "rescript" ~exits + ~version:("rescript " ^ Rewatch_version.version) + ~doc:"Fast, Simple, Fully Typed JavaScript from the Future" ~man + in + Cmd.group info ~default:(build_term ~watch:false) + [build; watch; clean; format; compiler_args; help] + +type evaluation = Run of command | Exit of int + +exception Parse_error of string +exception Help +exception Version + +(* Bare project folders must select the default build command, even though + Cmdliner otherwise treats them as unknown commands. Move global options + behind the selected command and expand short help/version clusters because + Cmdliner's standard display options only provide long names. A root display + request takes precedence over otherwise invalid implicit-build arguments. *) +let normalize_argv argv = + let is_short_global_cluster argument = + let length = String.length argument in + length > 1 + && argument.[0] = '-' + && argument.[1] <> '-' + && String.for_all + (function + | 'v' | 'q' | 'h' | 'V' -> true + | _ -> false) + (String.sub argument 1 (length - 1)) + in + let short_cluster_contains character argument = + is_short_global_cluster argument + && String.contains_from argument 1 character + in + let is_global = function + | "--verbose" | "--quiet" | "--help" | "--version" -> true + | argument -> + is_short_global_cluster argument + || String.starts_with ~prefix:"--help=" argument + in + let requests_help argument = + argument = "--help" + || String.starts_with ~prefix:"--help=" argument + || short_cluster_contains 'h' argument + in + let requests_version argument = + argument = "--version" || short_cluster_contains 'V' argument + in + let is_command = function + | "build" | "watch" | "clean" | "format" | "compiler-args" | "help" -> true + | _ -> false + in + let rec normalize_display_options = function + | [] -> [] + | "--" :: rest -> "--" :: rest + | argument :: rest when String.starts_with ~prefix:"--help=" argument -> + argument :: normalize_display_options rest + | argument :: rest when requests_help argument -> + "--help=plain" :: normalize_display_options rest + | argument :: rest when requests_version argument -> + "--version" :: normalize_display_options rest + | argument :: rest -> argument :: normalize_display_options rest + in + let explicit_command arguments = + let rec loop globals = function + | [] | "--" :: _ -> None + | argument :: rest when is_global argument -> + loop (argument :: globals) rest + | command :: rest when is_command command -> + Some (List.rev globals, command, rest) + | _ -> None + in + loop [] arguments + in + let partition_implicit arguments = + let rec loop globals others = function + | [] -> (List.rev globals, List.rev others) + | "--" :: rest -> (List.rev globals, List.rev_append others ("--" :: rest)) + | argument :: rest when is_global argument -> + loop (argument :: globals) others rest + | argument :: rest -> loop globals (argument :: others) rest + in + loop [] [] arguments + in + match Array.to_list argv with + | [] -> argv + | executable :: arguments -> + let routed = + match explicit_command arguments with + | Some (globals, command, rest) -> + executable :: command :: (globals @ rest) + | None -> + let globals, others = partition_implicit arguments in + if + List.exists + (fun argument -> + requests_help argument || requests_version argument) + globals + then executable :: globals + else executable :: "build" :: (globals @ others) + in + Array.of_list (normalize_display_options routed) + +(* Evaluates the command line and returns Cmdliner's result with the + diagnostics it wrote, or [Error] for arguments that are not UTF-8. Help is + written to [help] when given, otherwise to stdout. *) +let evaluate ?help argv = + if not (Array.for_all String.is_valid_utf_8 argv) then + Error "invalid UTF-8 in command-line argument" + else + let error_buffer = Buffer.create 256 in + let err = Stdlib.Format.formatter_of_buffer error_buffer in + let result = + Cmd.eval_value ~catch:false ?help ~err ~argv:(normalize_argv argv) root + in + Option.iter (fun help -> Stdlib.Format.pp_print_flush help ()) help; + Stdlib.Format.pp_print_flush err (); + Ok (result, Buffer.contents error_buffer) + +let eval argv = + match evaluate argv with + | Error message -> + prerr_endline message; + Exit 2 + | Ok (result, errors) -> ( + (* Cmdliner styles its diagnostics whenever TERM allows it, even when stderr + is redirected, and offers no way to override that choice. Capture them + and apply the color policy used for all other output. *) + prerr_string + (if Output.colors_enabled ~interactive:(Unix.isatty Unix.stderr) then + errors + else Output.strip_sgr errors); + flush stderr; + match result with + | Ok (`Ok command) -> Run command + | Ok `Help | Ok `Version -> Exit 0 + | Error _ -> Exit 2) + +let parse argv = + let help = Stdlib.Format.formatter_of_buffer (Buffer.create 256) in + match evaluate ~help argv with + | Error message -> raise (Parse_error message) + | Ok (Ok (`Ok command), _) -> command + | Ok (Ok `Help, _) -> raise Help + | Ok (Ok `Version, _) -> raise Version + | Ok (Error _, errors) -> raise (Parse_error errors) diff --git a/rewatch-ocaml/cli.mli b/rewatch-ocaml/cli.mli new file mode 100644 index 00000000000..ceb134500d5 --- /dev/null +++ b/rewatch-ocaml/cli.mli @@ -0,0 +1,31 @@ +type command = + | Build of build_options + | Clean of {verbosity: int; folder: string; prod: bool} + | Watch of build_options + | Format of format_input + | Compiler_args of {verbosity: int; path: string} + +and build_options = { + verbosity: int; + folder: string; + prod: bool; + features: string list option; + warn_error: string option; + after_build: string option; + filter: Source_filter.t option; + clear_screen: bool; + no_timing: bool; +} + +and format_input = + | Format_stdin of string + | Format_files of {verbosity: int; check: bool; paths: string list} + +type evaluation = Run of command | Exit of int + +exception Parse_error of string +exception Help +exception Version + +val eval : string array -> evaluation +val parse : string array -> command diff --git a/rewatch-ocaml/compile_assets.ml b/rewatch-ocaml/compile_assets.ml new file mode 100644 index 00000000000..20d8bc6c9ca --- /dev/null +++ b/rewatch-ocaml/compile_assets.ml @@ -0,0 +1,134 @@ +type entry = {path: string; modified: float} +type ast_source = {ast_path: string; source_path: string} + +type t = { + files_by_directory: (string, string list) Hashtbl.t; + ast_sources_by_directory: (string, ast_source list) Hashtbl.t; + ast_dependencies: (string, string list) Hashtbl.t; + ast_by_source: (string, entry) Hashtbl.t; + cmi_by_module: (string, entry) Hashtbl.t; + cmt_by_module: (string, entry) Hashtbl.t; +} + +let ast_header path = + try Some (Ast_header.read path) + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> None + +let cleanup_extensions = + [".cmi"; ".cmj"; ".cmt"; ".cmti"; ".ast"; ".iast"; ".res"; ".resi"; ".mlmap"] + +let is_managed_basename basename = + List.exists (Filename.check_suffix basename) cleanup_extensions + +let state_extension = function + | ".ast" | ".iast" | ".cmi" | ".cmt" -> true + | _ -> false + +let read_directory directory = + let names = + try File_util.directory_entries directory + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> [] + in + let files = + names + |> List.filter (fun name -> + List.mem (Filename.extension name) cleanup_extensions) + |> List.map (Filename.concat directory) + in + let state_entries = + names + |> List.filter_map (fun name -> + if not (state_extension (Filename.extension name)) then None + else + let path = Filename.concat directory name in + try + let metadata = Unix.stat path in + if metadata.Unix.st_kind = Unix.S_DIR then None + else Some ({path; modified = metadata.Unix.st_mtime}, name) + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> None) + in + (files, state_entries) + +let module_key name = + name |> Filename.remove_extension |> String.capitalize_ascii + +let source_key = Platform.normalize_path_for_comparison + +let add_module_artifact state (entry, name) = + match Filename.extension name with + | ".cmi" -> Hashtbl.replace state.cmi_by_module (module_key name) entry + | ".cmt" -> Hashtbl.replace state.cmt_by_module (module_key name) entry + | _ -> () + +let create directories = + let state = + { + files_by_directory = Hashtbl.create (List.length directories); + ast_sources_by_directory = Hashtbl.create (List.length directories); + ast_dependencies = Hashtbl.create 64; + ast_by_source = Hashtbl.create 64; + cmi_by_module = Hashtbl.create 64; + cmt_by_module = Hashtbl.create 64; + } + in + directories + |> List.sort_uniq String.compare + |> List.iter (fun directory -> + let files, state_entries = read_directory directory in + Hashtbl.replace state.files_by_directory directory files; + let ast_sources = + state_entries + |> List.filter_map (fun (entry, name) -> + match Filename.extension name with + | ".ast" | ".iast" -> ( + match ast_header entry.path with + | Some header -> + Option.map + (fun source -> (entry, source, header.dependencies)) + header.Ast_header.source + | None -> None) + | _ -> None) + in + Hashtbl.replace state.ast_sources_by_directory directory + (List.map + (fun (entry, source, _) -> + {ast_path = entry.path; source_path = source}) + ast_sources); + List.iter + (fun (entry, source, dependencies) -> + Hashtbl.replace state.ast_dependencies entry.path dependencies; + Hashtbl.replace state.ast_by_source (source_key source) entry) + ast_sources; + List.iter (add_module_artifact state) state_entries); + state + +let files state directory = + Hashtbl.find_opt state.files_by_directory directory + |> Option.value ~default:[] + +let ast_sources state directory = + Hashtbl.find_opt state.ast_sources_by_directory directory + |> Option.value ~default:[] + +let ast_dependencies state path = + Hashtbl.find_opt state.ast_dependencies path |> Option.value ~default:[] + +let ast state source = Hashtbl.find_opt state.ast_by_source (source_key source) + +let cmi state key = Hashtbl.find_opt state.cmi_by_module key +let cmt state key = Hashtbl.find_opt state.cmt_by_module key + +let replace_from_path table key path = + try + Hashtbl.replace table key {path; modified = (Unix.stat path).Unix.st_mtime} + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> + Hashtbl.remove table key + +let refresh_cmi state ~key ~path = + replace_from_path state.cmi_by_module key path + +let refresh_cmt state ~key ~path = + replace_from_path state.cmt_by_module key path + +let refresh_ast state ~source ~path = + replace_from_path state.ast_by_source (source_key source) path diff --git a/rewatch-ocaml/compile_assets.mli b/rewatch-ocaml/compile_assets.mli new file mode 100644 index 00000000000..53180ff4d62 --- /dev/null +++ b/rewatch-ocaml/compile_assets.mli @@ -0,0 +1,19 @@ +type entry = {path: string; modified: float} +(** This index avoids repeatedly scanning [lib/ocaml] while retaining the source + provenance embedded in AST headers. Mutating refresh operations must be + called whenever publication changes the corresponding filesystem entry. *) + +type ast_source = {ast_path: string; source_path: string} +type t + +val is_managed_basename : string -> bool +val create : string list -> t +val files : t -> string -> string list +val ast_sources : t -> string -> ast_source list +val ast_dependencies : t -> string -> string list +val ast : t -> string -> entry option +val cmi : t -> string -> entry option +val cmt : t -> string -> entry option +val refresh_cmi : t -> key:string -> path:string -> unit +val refresh_cmt : t -> key:string -> path:string -> unit +val refresh_ast : t -> source:string -> path:string -> unit diff --git a/rewatch-ocaml/compiler_args.ml b/rewatch-ocaml/compiler_args.ml new file mode 100644 index 00000000000..098bd5ccf28 --- /dev/null +++ b/rewatch-ocaml/compiler_args.ml @@ -0,0 +1,135 @@ +let source_triggered_ppxes = + [ + (["graphql-ppx"; "graphql_ppx"], "%graphql"); + (["spice"], "@spice"); + (["rescript-relay"], "%relay"); + (["re-formality"], "%form"); + (["rescript-schema-ppx"; "sury-ppx"], "@schema"); + ] + +let ppx_is_enabled ~bisect_enabled flag contents = + if String_util.contains flag "bisect" then bisect_enabled + else + List.for_all + (fun (names, marker) -> + (not (List.exists (fun name -> String_util.contains flag name) names)) + || String_util.contains contents marker) + source_triggered_ppxes + +let filter_ppx_flags ?bisect_enabled flags contents = + let bisect_enabled = + Option.value bisect_enabled + ~default:(Option.is_some (Sys.getenv_opt "BISECT_ENABLE")) + in + List.filter + (function + | [] -> false + | flag :: _ -> ppx_is_enabled ~bisect_enabled flag contents) + flags + +let source_map_args (config : Config.t) ~watch = + if config.source_map_dev && not watch then ["-bs-source-map"; "false"] + else config.source_map_args + +let parser_flags ?(ppx_flags = []) (config : Config.t) = + let ppx_args = + ppx_flags + |> List.concat_map (function + | [] -> [] + | flag :: arguments -> + let executable = + match Project_context.dependency_path config.root flag with + | Some path -> path + | None -> flag + in + ["-ppx"; String.concat " " (executable :: arguments)]) + in + ppx_args @ config.jsx_args @ config.experimental_args @ config.warning_flags + @ config.compiler_flags + +let compiler_flags ~watch (config : Config.t) = + config.jsx_args + @ source_map_args config ~watch + @ config.compiler_flags @ config.warning_flags @ config.gentype_args + @ config.experimental_args + +let with_local_warning_policy ~is_local (config : Config.t) = + if is_local then config else {config with warning_flags = []} + +let package_output (config : Config.t) path (spec : Config.package_spec) = + let output_dir = Build_artifacts.relative_output_directory path spec in + Printf.sprintf "%s:%s:%s" + (Config.module_format_name spec.module_format) + output_dir + (Config.package_spec_suffix config spec) + +let gentype_dependency_args_from_paths (config : Config.t) dependencies = + if config.gentype_args = [] then [] + else + let paths = Hashtbl.create (List.length dependencies) in + List.iter + (fun ((dependency : Config.dependency), path) -> + Hashtbl.replace paths dependency.name path) + dependencies; + config.dependencies + |> List.concat_map (fun (dependency : Config.dependency) -> + match Hashtbl.find_opt paths dependency.name with + | None -> [] + | Some path -> ["-bs-gentype-dep-path"; dependency.name ^ "=" ^ path]) + +let namespace_args (config : Config.t) module_name = + match config.namespace with + | Config.No_namespace -> [] + | Config.Namespace namespace -> ["-bs-ns"; namespace] + | Config.Namespace_with_entry {name; entry} -> + if entry = module_name then ["-open"; "@" ^ name] + else ["-bs-ns"; "@" ^ name] + +let parser_arguments ~(config : Config.t) ~contents ~path = + parser_flags ~ppx_flags:(filter_ppx_flags config.ppx_flags contents) config + @ [ + "-absname"; + "-bs-ast"; + "-o"; + Source.ast_path path; + Filename.concat + (Filename.concat Filename.parent_dir_name Filename.parent_dir_name) + path; + ] + +let compiler_common_arguments ~(config : Config.t) ~runtime ~dependency_dirs + ~watch ~gentype_dependency_args = + ["-I"; Filename.concat Filename.parent_dir_name "ocaml"] + @ ["-runtime-path"; runtime] + @ List.concat_map (fun directory -> ["-I"; directory]) dependency_dirs + @ compiler_flags ~watch config + @ gentype_dependency_args + @ ["-bs-package-name"; config.name; "-bs-project-root"; config.root] + +let compiler_arguments_with_common ~(config : Config.t) ~common_args + ~module_name ~source_kind ~has_interface ~path = + let interface_args = + match source_kind with + | Source.Implementation when has_interface -> ["-bs-read-cmi"] + | Source.Implementation | Source.Interface -> [] + in + let output_args = + match source_kind with + | Source.Interface -> [] + | Source.Implementation -> + List.concat_map + (fun spec -> ["-bs-package-output"; package_output config path spec]) + config.package_specs + in + namespace_args config module_name + @ interface_args @ common_args @ output_args + @ [Source.ast_path path] + +let compiler_arguments ~(config : Config.t) ~runtime ~dependency_dirs + ~module_name ~source_kind ~has_interface ~watch ~gentype_dependency_args + ~path = + compiler_arguments_with_common ~config + ~common_args: + (compiler_common_arguments ~config ~runtime ~dependency_dirs ~watch + ~gentype_dependency_args) + ~module_name ~source_kind ~has_interface ~path diff --git a/rewatch-ocaml/compiler_args.mli b/rewatch-ocaml/compiler_args.mli new file mode 100644 index 00000000000..52713918475 --- /dev/null +++ b/rewatch-ocaml/compiler_args.mli @@ -0,0 +1,46 @@ +val filter_ppx_flags : + ?bisect_enabled:bool -> string list list -> string -> string list list + +val source_map_args : Config.t -> watch:bool -> string list + +val parser_flags : ?ppx_flags:string list list -> Config.t -> string list +(** The flags of a parse, in the order Rust rewatch passes them. *) + +val compiler_flags : watch:bool -> Config.t -> string list +(** The configured flags of a compile, including source maps and genType. *) + +val with_local_warning_policy : is_local:bool -> Config.t -> Config.t +val gentype_dependency_args_from_paths : + Config.t -> (Config.dependency * string) list -> string list + +val parser_arguments : + config:Config.t -> contents:string -> path:string -> string list + +val compiler_arguments : + config:Config.t -> + runtime:string -> + dependency_dirs:string list -> + module_name:string -> + source_kind:Source.source_kind -> + has_interface:bool -> + watch:bool -> + gentype_dependency_args:string list -> + path:string -> + string list + +val compiler_common_arguments : + config:Config.t -> + runtime:string -> + dependency_dirs:string list -> + watch:bool -> + gentype_dependency_args:string list -> + string list + +val compiler_arguments_with_common : + config:Config.t -> + common_args:string list -> + module_name:string -> + source_kind:Source.source_kind -> + has_interface:bool -> + path:string -> + string list diff --git a/rewatch-ocaml/compiler_args_command.ml b/rewatch-ocaml/compiler_args_command.ml new file mode 100644 index 00000000000..49ce4385b3b --- /dev/null +++ b/rewatch-ocaml/compiler_args_command.ml @@ -0,0 +1,95 @@ +let error message = raise (Project_context.Error message) + +let runtime_path resolution package_root = + try + Toolchain.runtime + ~find_package: + (Package_resolution.dependency_path resolution ~package_root) + with Toolchain.Error message -> error message + +let source_error path message = + error (Printf.sprintf "Could not read source file %s: %s" path message) + +let run ~verbosity path = + let source = + try + Filename.concat + (Platform.canonicalize_path (Filename.dirname path)) + (Filename.basename path) + with + | Sys_error message -> source_error path message + | Unix.Unix_error (unix_error, _, _) -> + source_error path (Unix.error_message unix_error) + in + if + not + (Filename.check_suffix source ".res" + || Filename.check_suffix source ".resi") + then error "compiler-args expects a .res or .resi source file"; + let package_config = + match Project_context.nearest_config_path (Filename.dirname source) with + | Some path -> Config.load path + | None -> error "could not find a rescript.json parent" + in + let root_config = Project_context.workspace_config_for package_config in + Output.debug ~channel:stderr ~verbosity + (Project_context.describe package_config ~workspace:root_config); + let resolution = + Package_resolution.create + ~diagnostic_mode:Package_resolution.Suppress_diagnostics root_config + in + let config = Config.with_root_options package_config root_config in + let relative = Project_context.relative_to config.root source in + let contents = + try File_util.read_file source with + | Sys_error message -> source_error path message + | Unix.Unix_error (unix_error, _, _) -> + source_error path (Unix.error_message unix_error) + in + let parser_args = + Compiler_args.parser_arguments ~config ~contents ~path:relative + in + let source_kind = + if Filename.check_suffix source ".resi" then Source.Interface + else Source.Implementation + in + let has_interface = + match source_kind with + | Source.Implementation -> File_util.exists (source ^ "i") + | Source.Interface -> false + in + let dependencies = + (if Config.source_is_dev config relative then + List.map (fun dependency -> (false, dependency)) config.dev_dependencies + else []) + @ List.map (fun dependency -> (true, dependency)) config.dependencies + in + let dependency_dirs = + dependencies + |> List.filter_map (fun (required, (dependency : Config.dependency)) -> + match + Package_resolution.dependency_path resolution + ~package_root:config.root dependency.name + with + | Some directory -> Some (Build_artifacts.lib_path directory "ocaml") + | None when not required -> None + | None -> + error + (Printf.sprintf "Expected to find dependent package %s of %s" + dependency.name config.name)) + in + let runtime = runtime_path resolution config.root in + let compiler_args = + Compiler_args.compiler_arguments ~config ~runtime ~dependency_dirs + ~module_name:(Source.module_name source) + ~source_kind ~has_interface ~watch:false ~gentype_dependency_args:[] + ~path:relative + in + Yojson.Safe.pretty_to_string + (`Assoc + [ + ( "compiler_args", + `List (List.map (fun value -> `String value) compiler_args) ); + ( "parser_args", + `List (List.map (fun value -> `String value) parser_args) ); + ]) diff --git a/rewatch-ocaml/compiler_args_command.mli b/rewatch-ocaml/compiler_args_command.mli new file mode 100644 index 00000000000..6d485a8e99d --- /dev/null +++ b/rewatch-ocaml/compiler_args_command.mli @@ -0,0 +1 @@ +val run : verbosity:int -> string -> string diff --git a/rewatch-ocaml/compiler_info.ml b/rewatch-ocaml/compiler_info.ml new file mode 100644 index 00000000000..859f37ea1c8 --- /dev/null +++ b/rewatch-ocaml/compiler_info.ml @@ -0,0 +1,146 @@ +type context = { + bsc_path: string; + bsc_hash: string; + runtime_path: string; + source_map_args: string list; + inherited_compiler_args: string list; + package_output_specs: package_output_spec list; +} + +and package_output_spec = { + module_format: Config.module_format; + in_source: bool; + suffix: string; +} + +let format_version = "5" + +let package_output_specs (config : Config.t) = + List.map + (fun (spec : Config.package_spec) -> + { + module_format = spec.module_format; + in_source = spec.in_source; + suffix = Config.package_spec_suffix config spec; + }) + config.package_specs + +let make_context ~bsc_path ~runtime_path ~source_map_args + ~inherited_compiler_args ~package_output_specs = + { + bsc_path; + bsc_hash = Digest.file bsc_path |> Digest.to_hex; + runtime_path; + source_map_args; + inherited_compiler_args; + package_output_specs; + } + +let for_package context config = + {context with package_output_specs = package_output_specs config} + +let path root = File_util.path_of_parts root ["lib"; "bs"; "compiler-info.json"] + +let package_output_spec_json spec = + `Assoc + [ + ("module", `String (Config.module_format_name spec.module_format)); + ("in_source", `Bool spec.in_source); + ("suffix", `String spec.suffix); + ] + +let package_output_spec_of_json = function + | `Assoc fields -> ( + match + ( List.assoc_opt "module" fields, + List.assoc_opt "in_source" fields, + List.assoc_opt "suffix" fields ) + with + | ( Some (`String module_format), + Some (`Bool in_source), + Some (`String suffix) ) -> ( + match module_format with + | "esmodule" -> Some {module_format = Config.Esmodule; in_source; suffix} + | "commonjs" -> Some {module_format = Config.Commonjs; in_source; suffix} + | _ -> None) + | _ -> None) + | _ -> None + +let package_output_specs_of_json = function + | `Assoc fields -> ( + match List.assoc_opt "package_output_specs" fields with + | Some (`List values) -> + let specs = List.filter_map package_output_spec_of_json values in + if List.length specs = List.length values then Some specs else None + | _ -> None) + | _ -> None + +let read config = + try Some (Yojson.Safe.from_file (path config.Config.root)) + with Yojson.Json_error _ | Sys_error _ -> None + +let json context (config : Config.t) = + `Assoc + [ + ("version", `String format_version); + ("bsc_path", `String context.bsc_path); + ("bsc_hash", `String context.bsc_hash); + ("rescript_config_hash", `String config.file_hash); + ( "source_map_args", + `List (List.map (fun value -> `String value) context.source_map_args) ); + ( "inherited_compiler_args", + `List + (List.map + (fun value -> `String value) + context.inherited_compiler_args) ); + ( "package_output_specs", + `List (List.map package_output_spec_json context.package_output_specs) + ); + ("runtime_path", `String context.runtime_path); + ] + +let matches_json context config contents = contents = json context config + +let matches context config = + match read config with + | Some contents -> matches_json context config contents + | None -> false + +let changed_package_output_specs context config = + match read config with + | None -> None + | Some contents -> + Option.bind (package_output_specs_of_json contents) (fun previous -> + if previous = context.package_output_specs then None else Some previous) + +let config_with_package_output_specs (config : Config.t) specs = + let package_specs = + List.map + (fun spec : Config.package_spec -> + { + module_format = spec.module_format; + in_source = spec.in_source; + suffix = Some spec.suffix; + }) + specs + in + {config with package_specs} + +let previous_build_exists root = + File_util.exists + (File_util.path_of_parts root ["lib"; "ocaml"; ".compiler.log"]) + +let needs_clean context (config : Config.t) = + let info_path = path config.root in + if File_util.exists info_path then not (matches context config) + else previous_build_exists config.root + +let clean_package (config : Config.t) = + File_util.remove_tree (Build_artifacts.lib_path config.root "bs"); + File_util.remove_tree (Build_artifacts.lib_path config.root "ocaml") + +let write_package context (config : Config.t) = + if not (matches context config) then + let info_path = path config.root in + let contents = Yojson.Safe.pretty_to_string (json context config) ^ "\n" in + File_util.write_file_atomic info_path contents diff --git a/rewatch-ocaml/compiler_info.mli b/rewatch-ocaml/compiler_info.mli new file mode 100644 index 00000000000..a638f1059b5 --- /dev/null +++ b/rewatch-ocaml/compiler_info.mli @@ -0,0 +1,40 @@ +type context = { + bsc_path: string; + bsc_hash: string; + runtime_path: string; + source_map_args: string list; + inherited_compiler_args: string list; + package_output_specs: package_output_spec list; +} +(** Compiler information fingerprints effective inputs rather than only the + package's own JSON. Root-level JSX, experimental options, runtime identity, + and output layout can all change dependency output without changing a + dependency configuration file. *) + +and package_output_spec = { + module_format: Config.module_format; + in_source: bool; + suffix: string; +} + +val package_output_specs : Config.t -> package_output_spec list + +val make_context : + bsc_path:string -> + runtime_path:string -> + source_map_args:string list -> + inherited_compiler_args:string list -> + package_output_specs:package_output_spec list -> + context + +val for_package : context -> Config.t -> context + +val changed_package_output_specs : + context -> Config.t -> package_output_spec list option + +val config_with_package_output_specs : + Config.t -> package_output_spec list -> Config.t + +val needs_clean : context -> Config.t -> bool +val clean_package : Config.t -> unit +val write_package : context -> Config.t -> unit diff --git a/rewatch-ocaml/compiler_log.ml b/rewatch-ocaml/compiler_log.ml new file mode 100644 index 00000000000..1c2c9ba26b7 --- /dev/null +++ b/rewatch-ocaml/compiler_log.ml @@ -0,0 +1,38 @@ +let path root directory = + Filename.concat (Build_artifacts.lib_path root directory) ".compiler.log" + +let strip_ansi content = + let length = String.length content in + let output = Buffer.create length in + let rec skip_csi index = + if index >= length then index + else + let code = Char.code content.[index] in + if code >= 0x40 && code <= 0x7e then index + 1 else skip_csi (index + 1) + in + let rec loop index = + if index < length then + if + (content.[index] = '\027' || content.[index] = '\155') + && index + 1 < length + && content.[index + 1] = '[' + then loop (skip_csi (index + 2)) + else ( + Buffer.add_char output content.[index]; + loop (index + 1)) + in + loop 0; + Buffer.contents output + +let initialize root = + let path = path root "bs" in + File_util.ensure_dir (Filename.dirname path); + File_util.write_file path + (Printf.sprintf "#Start(%.6f)\n" (Unix.gettimeofday ())) + +let append root content = + File_util.append_file (path root "bs") (strip_ansi content) + +let finalize root = + append root (Printf.sprintf "#Done(%.6f)\n" (Unix.gettimeofday ())); + File_util.copy_existing_file (path root "bs") (path root "ocaml") diff --git a/rewatch-ocaml/compiler_log.mli b/rewatch-ocaml/compiler_log.mli new file mode 100644 index 00000000000..ab6bd3b51ca --- /dev/null +++ b/rewatch-ocaml/compiler_log.mli @@ -0,0 +1,6 @@ +val initialize : string -> unit +(** Compiler logs are finalized separately from artifact cleanup so one cleanup + failure cannot leave a successfully completed log in its temporary state. *) + +val append : string -> string -> unit +val finalize : string -> unit diff --git a/rewatch-ocaml/compiler_process.ml b/rewatch-ocaml/compiler_process.ml new file mode 100644 index 00000000000..82b07ec1050 --- /dev/null +++ b/rewatch-ocaml/compiler_process.ml @@ -0,0 +1,214 @@ +let retain_critical_external_warnings stderr = + let marker = "`(. ...)` uncurried syntax" in + if not (String_util.contains stderr marker) then "" + else + stderr + |> Str.global_replace (Str.regexp_string "\r\n") "\n" + |> Str.split_delim (Str.regexp_string "\n\n\n") + |> List.filter (fun block -> String_util.contains block marker) + |> String.concat "\n\n\n" + +let parse_job ~bsc ~build_dir ~(config : Config.t) path = + let ast = Source.ast_path path in + File_util.ensure_dir (Filename.concat build_dir (Filename.dirname ast)); + let contents = + if config.ppx_flags = [] then "" + else File_util.read_file (Filename.concat config.root path) + in + let args = Compiler_args.parser_arguments ~config ~contents ~path in + Process.{program = bsc; args; cwd = build_dir} + +let ast_dependencies ~build_dir ast = + (Ast_header.read (Filename.concat build_dir ast)).dependencies + +type compiler_artifact = Cmi | Required of string | Optional of string + +let publish_compiler_artifacts ~artifact_dir ~ocaml_dir ~basename artifacts = + let cmi_change = ref Compiler_scheduler.Cmi_change_unknown in + try + List.iter + (fun artifact -> + let extension = + match artifact with + | Cmi -> "cmi" + | Required name | Optional name -> name + in + let source = + Filename.concat artifact_dir (basename ^ "." ^ extension) + in + let destination = + Filename.concat ocaml_dir (basename ^ "." ^ extension) + in + match artifact with + | Cmi -> + cmi_change := + if File_util.copy_file_if_different source destination then + Compiler_scheduler.Cmi_changed + else Compiler_scheduler.Cmi_unchanged + | Required _ -> File_util.copy_existing_file source destination + | Optional _ -> File_util.copy_optional_existing_file source destination) + artifacts; + !cmi_change + with error -> + raise (Compiler_scheduler.Publication_failure (error, !cmi_change)) + +let namespace_task ~bsc ~runtime ~build_dir ~ocaml_dir ~entry ~package_dirty + ~force namespace modules = + let mlmap = Filename.concat build_dir (namespace ^ ".mlmap") in + let contents = + let buffer = Buffer.create 128 in + Buffer.add_string buffer "randjbuildsystem\n"; + Source.namespace_members ~entry modules + |> List.map (fun module_ -> module_.Source.name) + |> List.sort String.compare + |> List.iter (fun name -> + Buffer.add_string buffer name; + Buffer.add_char buffer '\n'); + Buffer.contents buffer + in + let previous_contents = + try Some (File_util.read_file mlmap) + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> None + in + let mlmap_changed = previous_contents <> Some contents in + if mlmap_changed then + File_util.write_file_atomic ~ensure_parent:false mlmap contents; + let outputs_exist = + ["cmi"; "cmj"; "cmt"; "mlmap"] + |> List.for_all (fun extension -> + File_util.is_regular_file + (Filename.concat ocaml_dir (namespace ^ "." ^ extension))) + in + let published_mlmap_matches = + try + File_util.read_file (Filename.concat ocaml_dir (namespace ^ ".mlmap")) + = contents + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> false + in + if + not + (force || package_dirty || mlmap_changed + || (not published_mlmap_matches) + || not outputs_exist) + then None + else + Some + Compiler_scheduler. + { + job = + Process. + { + program = bsc; + args = + [ + "-runtime-path"; + runtime; + "-w"; + "-49"; + "-color"; + "always"; + "-no-alias-deps"; + Filename.basename mlmap; + ]; + cwd = build_dir; + }; + publish = + (fun result -> + if not (Process.succeeded result) then + raise + (Compiler_scheduler.Build_failure + (result.Process.stderr ^ result.stdout)); + let cmi_change = + publish_compiler_artifacts ~artifact_dir:build_dir ~ocaml_dir + ~basename:namespace + [Cmi; Required "cmj"; Required "cmt"; Required "mlmap"] + in + Compiler_scheduler.{stderr = result.stderr; cmi_change}); + } + +let post_build_tasks (config : Config.t) path = + match config.js_post_build with + | None -> [] + | Some command -> + List.map + (fun spec -> + let output = Build_artifacts.generated_js_path config path spec in + let command = Platform.post_build_command ~command ~output in + Compiler_scheduler. + { + output; + task = + Process.task ?env:command.env + Process. + { + program = command.program; + args = command.args; + cwd = config.root; + }; + }) + config.package_specs + +let compile_job ~bsc ~build_dir ~(config : Config.t) ~common_args + (module_ : Source.module_) ~source_kind path = + let args = + Compiler_args.compiler_arguments_with_common ~config ~common_args + ~module_name:module_.name ~source_kind + ~has_interface:(Option.is_some module_.interface) + ~path + in + Process.{program = bsc; args; cwd = build_dir} + +let publish ~build_dir ~ocaml_dir ~is_local ~(config : Config.t) ~has_interface + ~source_kind path result = + let stderr = + if is_local then result.Process.stderr + else retain_critical_external_warnings result.stderr + in + let basename = Source.compiler_asset_basename config path in + let artifact_dir = Filename.concat build_dir (Filename.dirname path) in + let cmi_change = ref Compiler_scheduler.Cmi_change_unknown in + try + (cmi_change := + match source_kind with + | Source.Interface -> + publish_compiler_artifacts ~artifact_dir ~ocaml_dir ~basename + [Cmi; Optional "cmti"] + | Source.Implementation when has_interface -> + (* The implementation is compiled with -bs-read-cmi, so its .cmi is + the one already published after compiling the interface. *) + ignore + (publish_compiler_artifacts ~artifact_dir ~ocaml_dir ~basename + [Required "cmj"; Optional "cmt"]); + Compiler_scheduler.Cmi_unchanged + | Source.Implementation -> + publish_compiler_artifacts ~artifact_dir ~ocaml_dir ~basename + [Cmi; Required "cmj"; Optional "cmt"]); + let source = Filename.concat config.root path in + let build_source = Filename.concat build_dir path in + File_util.ensure_dir (Filename.dirname build_source); + File_util.copy_existing_file source build_source; + File_util.copy_existing_file source + (Filename.concat ocaml_dir (Filename.basename path)); + (match source_kind with + | Source.Interface -> () + | Source.Implementation -> + List.iter + (fun spec -> + if spec.Config.in_source then ( + let output = Build_artifacts.generated_js_path config path spec in + let build_output = + Build_artifacts.generated_build_js_path ~build_dir config path + spec + in + File_util.ensure_dir (Filename.dirname build_output); + if File_util.exists output then + File_util.copy_existing_file output build_output; + if File_util.exists (output ^ ".map") then + File_util.copy_existing_file (output ^ ".map") + (build_output ^ ".map") + else File_util.remove_file (build_output ^ ".map"))) + config.package_specs); + Compiler_scheduler.{stderr; cmi_change = !cmi_change} + with + | Compiler_scheduler.Publication_failure _ as error -> raise error + | error -> raise (Compiler_scheduler.Publication_failure (error, !cmi_change)) diff --git a/rewatch-ocaml/compiler_process.mli b/rewatch-ocaml/compiler_process.mli new file mode 100644 index 00000000000..38844006632 --- /dev/null +++ b/rewatch-ocaml/compiler_process.mli @@ -0,0 +1,40 @@ +val retain_critical_external_warnings : string -> string +val parse_job : + bsc:string -> build_dir:string -> config:Config.t -> string -> Process.job +val ast_dependencies : build_dir:string -> string -> string list + +val namespace_task : + bsc:string -> + runtime:string -> + build_dir:string -> + ocaml_dir:string -> + entry:string option -> + package_dirty:bool -> + force:bool -> + string -> + Source.module_ list -> + Compiler_scheduler.namespace_task option + +val compile_job : + bsc:string -> + build_dir:string -> + config:Config.t -> + common_args:string list -> + Source.module_ -> + source_kind:Source.source_kind -> + string -> + Process.job + +val post_build_tasks : + Config.t -> string -> Compiler_scheduler.post_build_task list + +val publish : + build_dir:string -> + ocaml_dir:string -> + is_local:bool -> + config:Config.t -> + has_interface:bool -> + source_kind:Source.source_kind -> + string -> + Process.result -> + Compiler_scheduler.publish_result diff --git a/rewatch-ocaml/compiler_scheduler.ml b/rewatch-ocaml/compiler_scheduler.ml new file mode 100644 index 00000000000..18cc1523de1 --- /dev/null +++ b/rewatch-ocaml/compiler_scheduler.ml @@ -0,0 +1,419 @@ +exception Build_failure of string +exception Module_failed +type cmi_change = Build_state.cmi_change = + | Cmi_changed + | Cmi_unchanged + | Cmi_change_unknown +exception Publication_failure of exn * cmi_change + +type publish_result = {stderr: string; cmi_change: cmi_change} +type namespace_task = { + job: Process.job; + publish: Process.result -> publish_result; +} +type post_build_task = {output: string; task: Process.task} + +type phase = + | Start + | Interface of string + | Implementation of string + | Post_build of {output: string; remaining: post_build_task list} + | Done + +type publication = + | Published of publish_result + | Failed_after_cmi_publication of {error: exn; cmi_change: cmi_change} + +type recorded_publication = + | No_publication + | Publication_succeeded of string + | Publication_failed of string + +let capture_publication publish = + try Published (publish ()) with + | Publication_failure (error, cmi_change) -> + Failed_after_cmi_publication {error; cmi_change} + | error -> + Failed_after_cmi_publication {error; cmi_change = Cmi_change_unknown} + +type scheduled_module = { + key: string; + dependencies: string list; + source: Source.module_; + state: Build_state.module_; + cmi_path: string; + publication: publication option Atomic.t; + prepare: unit -> unit; + compile: source_kind:Source.source_kind -> string -> Process.job; + publish: + source_kind:Source.source_kind -> string -> Process.result -> publish_result; + record_published_outputs: source_kind:Source.source_kind -> string -> unit; + post_build: string -> post_build_task list; + package_root: string; + is_local: bool; + mark_warning: string -> unit; + mutable messages: string list; + mutable phase: phase; +} + +type candidate = { + key: string; + state: Build_state.module_; + warning_paths: string list; + make: unit -> scheduled_module; +} + +type scheduled_item = Module of scheduled_module | Namespace_barrier + +let create ~key ~dependencies ~source ~state ~cmi_path ~prepare ~compile + ~publish ~record_published_outputs ~post_build ~package_root ~is_local + ~mark_warning = + { + key; + dependencies; + source; + state; + cmi_path; + publication = Atomic.make None; + prepare; + compile; + publish; + record_published_outputs; + post_build; + package_root; + is_local; + mark_warning; + messages = []; + phase = Start; + } + +let candidate ~key ~state ~warning_paths ~make = + {key; state; warning_paths; make} + +let candidate_requires_compile candidate = candidate.state.compile_dirty + +let run ~poll ~warning_state ~compile_assets ~build_state ~candidates + ~mark_compiled ~mark_had_warnings ~progress ~compile_step ~namespace_count + ~verbosity = + let dirty_propagation = Hashtbl.create 16 in + let refresh_published_cmi (scheduled : scheduled_module) cmi_change = + Build_state.record_published_cmi ~dirty_propagation build_state + ~compile_assets scheduled.state ~path:scheduled.cmi_path cmi_change + in + let finish_successful_compile (scheduled : scheduled_module) = + let cmt_path = Filename.remove_extension scheduled.cmi_path ^ ".cmt" in + Build_state.record_successful_compile ~compile_assets scheduled.state + ~cmt_path + in + let warning_paths = + candidates |> List.concat_map (fun candidate -> candidate.warning_paths) + in + Warning_state.retain_paths warning_state warning_paths; + if Output.trace_enabled verbosity then + candidates + |> List.filter candidate_requires_compile + |> List.sort (fun first second -> String.compare first.key second.key) + |> List.iter (fun candidate -> + Printf.printf "compile dirty: %s\n%!" candidate.key); + (* The scheduler only needs dirty modules and their transitive dependents. + Dependencies outside that universe already have usable artifacts, while + keeping every module in the subprocess graph makes small edits scale with + the whole project. *) + let candidate_by_key = Hashtbl.create (List.length candidates) in + List.iter + (fun candidate -> Hashtbl.replace candidate_by_key candidate.key candidate) + candidates; + let universe = Hashtbl.create (List.length candidates) in + let reached = Hashtbl.create (List.length candidates) in + let pending = Queue.create () in + let add_to_closure key = + if not (Hashtbl.mem reached key) then ( + Hashtbl.add reached key (); + if Hashtbl.mem candidate_by_key key then Hashtbl.add universe key (); + Queue.add key pending) + in + candidates + |> List.iter (fun candidate -> + if candidate.state.compile_dirty then add_to_closure candidate.key); + while not (Queue.is_empty pending) do + let key = Queue.take pending in + let state = Build_state.find_exn build_state key in + Build_state.String_set.iter add_to_closure state.dependents + done; + let scheduled_modules = + candidates + |> List.filter (fun candidate -> Hashtbl.mem universe candidate.key) + |> List.map (fun candidate -> candidate.make ()) + in + Output.Progress.start progress ~step:compile_step + ~symbol:Platform.build_symbol ~label:"Compiling" + ~total:(namespace_count + List.length scheduled_modules); + for _ = 1 to namespace_count do + Output.Progress.advance progress + done; + let completed_modules = ref 0 in + let scheduled_keys = Hashtbl.copy universe in + Hashtbl.iter + (fun key () -> + match Build_state.find build_state key with + | Some state when state.kind = Build_state.Namespace_map -> + Hashtbl.replace scheduled_keys key () + | Some _ | None -> ()) + reached; + let scheduled_dependencies dependencies = + List.filter (Hashtbl.mem scheduled_keys) dependencies + in + let module_works = + scheduled_modules + |> List.map (fun (scheduled : scheduled_module) -> + Process. + { + key = scheduled.key; + dependencies = scheduled_dependencies scheduled.dependencies; + value = Module scheduled; + }) + in + let namespace_works = + Hashtbl.to_seq_keys scheduled_keys + |> Seq.filter_map (fun key -> + match Build_state.find build_state key with + | Some state when state.kind = Build_state.Namespace_map -> + Some + Process. + { + key; + dependencies = scheduled_dependencies state.dependencies; + value = Namespace_barrier; + } + | Some _ | None -> None) + |> List.of_seq + in + let works = module_works @ namespace_works in + let record_publication (scheduled : scheduled_module) ~source_kind path = + let publication = Atomic.exchange scheduled.publication None in + match publication with + | Some (Published {stderr; cmi_change}) -> + refresh_published_cmi scheduled cmi_change; + scheduled.record_published_outputs ~source_kind path; + Publication_succeeded stderr + | Some (Failed_after_cmi_publication {error; cmi_change}) -> + refresh_published_cmi scheduled cmi_change; + scheduled.record_published_outputs ~source_kind path; + Publication_failed (Printexc.to_string error) + | None -> No_publication + in + let record_result (scheduled : scheduled_module) ~source_kind path result = + let result, publication_error = + match record_publication scheduled ~source_kind path with + | Publication_succeeded stderr -> ({result with Process.stderr}, None) + | Publication_failed message -> (result, Some message) + | No_publication -> (result, None) + in + let message = + match publication_error with + | Some message -> + Warning_state.remove warning_state ~package_root:scheduled.package_root + ~path; + Some message + | None -> + if Process.succeeded result then ( + match result.Process.stderr with + | "" -> + Warning_state.remove warning_state + ~package_root:scheduled.package_root ~path; + None + | warning -> + mark_had_warnings (); + Warning_state.set warning_state ~module_name:scheduled.key + ~package_root:scheduled.package_root ~path ~output:warning; + if scheduled.is_local then scheduled.mark_warning path; + None) + else ( + Warning_state.remove warning_state + ~package_root:scheduled.package_root ~path; + Some (result.Process.stderr ^ result.Process.stdout)) + in + Option.iter + (fun message -> scheduled.messages <- message :: scheduled.messages) + message; + Option.is_none message + in + let compilation_task (scheduled : scheduled_module) ~source_kind path = + let job = scheduled.compile ~source_kind path in + Atomic.set scheduled.publication None; + Process.task job ~on_result:(fun result -> + (if Process.succeeded result then + let publication = + capture_publication (fun () -> + scheduled.publish ~source_kind path result) + in + Atomic.set scheduled.publication (Some publication)); + result) + in + let record_post_build_result (scheduled : scheduled_module) output result = + if Process.succeeded result then ( + if result.Process.stdout <> "" then print_string result.stdout; + if result.stderr <> "" then prerr_string result.stderr; + true) + else + let captured = result.stderr ^ result.stdout in + let message = + Printf.sprintf "js-post-build command failed for %s%s" output + (if captured = "" then "" else "\n" ^ captured) + in + scheduled.messages <- message :: scheduled.messages; + false + in + let invalidate_persistent_freshness (scheduled : scheduled_module) = + let ocaml_dir = Filename.dirname scheduled.cmi_path in + scheduled.source.Source.implementation + :: Option.to_list scheduled.source.Source.interface + |> List.iter (fun source -> + let path = Build_artifacts.published_ast_path ~ocaml_dir source in + File_util.remove_file path; + Compile_assets.refresh_ast compile_assets + ~source:(Filename.concat scheduled.package_root source) + ~path) + in + let complete_module (scheduled : scheduled_module) = + scheduled.phase <- Done; + Output.Progress.advance progress; + if scheduled.messages <> [] then ( + invalidate_persistent_freshness scheduled; + raise Module_failed) + else ( + finish_successful_compile scheduled; + incr completed_modules) + in + let continue_post_build (scheduled : scheduled_module) tasks = + match tasks with + | [] -> + complete_module scheduled; + None + | {output; task} :: remaining -> + scheduled.phase <- Post_build {output; remaining}; + Some task + in + let reconcile_unconsumed_publications () = + List.iter + (fun (scheduled : scheduled_module) -> + let attempt_is_incomplete = + match scheduled.phase with + | Interface _ | Implementation _ | Post_build _ -> true + | Start | Done -> false + in + let source = + match scheduled.phase with + | Interface path -> Some (Source.Interface, path) + | Implementation path -> Some (Source.Implementation, path) + | Start | Post_build _ | Done -> None + in + Option.iter + (fun (source_kind, path) -> + match record_publication scheduled ~source_kind path with + | Publication_failed message -> + scheduled.messages <- message :: scheduled.messages + | No_publication | Publication_succeeded _ -> ()) + source; + if attempt_is_incomplete then invalidate_persistent_freshness scheduled) + scheduled_modules + in + let () = + try + Process.run_dependency_graph ?poll + works + (* Rust's parallel scheduler may already have independent work in + flight when a module fails. Finish all ready, independent work here + so the same diagnostics do not depend on the host's worker count; + dependents of the failed module remain blocked. *) + ~on_failure:(function + | Module_failed -> Process.Continue_independent_work + | _ -> Process.Abort_immediately) + ~next:(fun item result -> + match item with + | Namespace_barrier -> None + | Module scheduled -> ( + match (result, scheduled.phase) with + | None, Start -> + if scheduled.state.compile_dirty then ( + mark_compiled (); + scheduled.prepare (); + match scheduled.source.Source.interface with + | Some path -> + Output.Progress.debug progress ~verbosity + ("Compiling interface file: " ^ scheduled.key); + scheduled.phase <- Interface path; + Some + (compilation_task scheduled ~source_kind:Source.Interface + path) + | None -> + let path = scheduled.source.Source.implementation in + Output.Progress.debug progress ~verbosity + ("Compiling file: " ^ scheduled.key); + scheduled.phase <- Implementation path; + Some + (compilation_task scheduled + ~source_kind:Source.Implementation path)) + else ( + scheduled.phase <- Done; + incr completed_modules; + Output.Progress.advance progress; + None) + | Some result, Interface path -> + ignore + (record_result scheduled ~source_kind:Source.Interface path + result); + let path = scheduled.source.Source.implementation in + Output.Progress.debug progress ~verbosity + ("Compiling file: " ^ scheduled.key); + scheduled.phase <- Implementation path; + Some + (compilation_task scheduled ~source_kind:Source.Implementation + path) + | Some result, Implementation path -> + if + record_result scheduled ~source_kind:Source.Implementation path + result + then continue_post_build scheduled (scheduled.post_build path) + else ( + complete_module scheduled; + None) + | Some result, Post_build {output; remaining} -> + if record_post_build_result scheduled output result then + continue_post_build scheduled remaining + else ( + complete_module scheduled; + None) + | None, (Interface _ | Implementation _ | Post_build _ | Done) + | Some _, (Start | Done) -> + raise (Project_context.Error "invalid compiler scheduler state"))) + with exn -> ( + reconcile_unconsumed_publications (); + match exn with + | Module_failed -> () + | _ -> raise exn) + in + Output.Progress.finish progress; + Output.trace ~verbosity + (Printf.sprintf "Compiled %d out of %d in the universe" !completed_modules + (List.length scheduled_modules)); + let failures = + scheduled_modules + |> List.sort (fun (first : scheduled_module) second -> + String.compare first.key second.key) + |> List.concat_map (fun scheduled -> + scheduled.messages |> List.rev + |> List.map (fun output -> (scheduled, output))) + in + Warning_state.entries warning_state + |> List.iter (fun entry -> + Compiler_log.append entry.Warning_state.package_root entry.output); + List.iter + (fun ((scheduled : scheduled_module), output) -> + Compiler_log.append scheduled.package_root output) + failures; + match failures with + | [] -> () + | failures -> + failures |> List.map snd |> String.concat "" |> fun output -> + raise (Build_failure output) diff --git a/rewatch-ocaml/compiler_scheduler.mli b/rewatch-ocaml/compiler_scheduler.mli new file mode 100644 index 00000000000..2d3c31858fe --- /dev/null +++ b/rewatch-ocaml/compiler_scheduler.mli @@ -0,0 +1,73 @@ +exception Build_failure of string + +(* CMI change has an explicit unknown case because a later publication failure + must not erase the fact that an interface may already have become visible. + Unknown therefore invalidates conservatively instead of pretending that the + CMI was unchanged. *) +type cmi_change = Build_state.cmi_change = + | Cmi_changed + | Cmi_unchanged + | Cmi_change_unknown +exception Publication_failure of exn * cmi_change + +type publish_result = {stderr: string; cmi_change: cmi_change} +type namespace_task = { + job: Process.job; + publish: Process.result -> publish_result; +} +type post_build_task = {output: string; task: Process.task} + +(* Publication can fail after the CMI was copied. The partial outcome is kept + so dependents are still invalidated even though the module itself remains + dirty for retry. *) +type publication = + | Published of publish_result + | Failed_after_cmi_publication of {error: exn; cmi_change: cmi_change} + +val capture_publication : (unit -> publish_result) -> publication + +type scheduled_module +type candidate + +val create : + key:string -> + dependencies:string list -> + source:Source.module_ -> + state:Build_state.module_ -> + cmi_path:string -> + prepare:(unit -> unit) -> + compile:(source_kind:Source.source_kind -> string -> Process.job) -> + publish: + (source_kind:Source.source_kind -> + string -> + Process.result -> + publish_result) -> + record_published_outputs:(source_kind:Source.source_kind -> string -> unit) -> + post_build:(string -> post_build_task list) -> + package_root:string -> + is_local:bool -> + mark_warning:(string -> unit) -> + scheduled_module + +val candidate : + key:string -> + state:Build_state.module_ -> + warning_paths:string list -> + make:(unit -> scheduled_module) -> + candidate + +val candidate_requires_compile : candidate -> bool + +val run : + poll:(unit -> unit) option -> + warning_state:Warning_state.t -> + compile_assets:Compile_assets.t -> + build_state:Build_state.t -> + candidates:candidate list -> + mark_compiled:(unit -> unit) -> + mark_had_warnings:(unit -> unit) -> + progress:Output.Progress.t -> + compile_step:string -> + namespace_count:int -> + verbosity:int -> + unit diff --git a/rewatch-ocaml/config.ml b/rewatch-ocaml/config.ml new file mode 100644 index 00000000000..20b128c000f --- /dev/null +++ b/rewatch-ocaml/config.ml @@ -0,0 +1,432 @@ +include Config_types + +open Config_decode + +let namespace_name = function + | No_namespace -> None + | Namespace name | Namespace_with_entry {name; entry = _} -> Some name + +let namespace_entry = function + | Namespace_with_entry {name = _; entry} -> Some entry + | No_namespace | Namespace _ -> None + +let namespace_compiler_name = function + | No_namespace -> None + | Namespace name -> Some name + | Namespace_with_entry {name; entry = _} -> Some ("@" ^ name) + +let namespaced_module_name namespace module_name = + match namespace with + | No_namespace -> module_name + | Namespace name -> module_name ^ "-" ^ name + | Namespace_with_entry {name; entry} -> + if entry = module_name then module_name else module_name ^ "-@" ^ name + +let path_in_root root = + let current = Filename.concat root "rescript.json" in + if File_util.exists current then current + else Filename.concat root "bsconfig.json" + +let exists_in_root root = + File_util.exists (Filename.concat root "rescript.json") + || File_util.exists (Filename.concat root "bsconfig.json") + +let source_is_dev (config : t) relative_path = + let canonical path = + try Some (Platform.canonicalize_path path) + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> None + in + let source_parent = + Filename.concat config.root relative_path |> Filename.dirname |> canonical + in + match source_parent with + | None -> false + | Some source_parent -> + let comparable = Platform.normalize_path_for_comparison in + List.find_map + (fun (source : source) -> + match canonical (Filename.concat config.root source.dir) with + | None -> None + | Some directory -> + if + comparable source_parent = comparable directory + || source.recurse + && String.starts_with + ~prefix:(Filename.concat directory "" |> comparable) + (comparable source_parent) + then Some source.is_dev + else None) + config.sources + |> Option.value ~default:false + +(* Every package in one invocation must use the root project's effective + compiler options so dependencies expose outputs their consumers can use. *) +let with_root_options (config : t) (root_config : t) = + { + config with + package_specs = root_config.package_specs; + suffix = root_config.suffix; + jsx_args = root_config.jsx_args; + source_map_args = root_config.source_map_args; + source_map_dev = root_config.source_map_dev; + experimental_args = root_config.experimental_args; + gentype_args = + (if config.gentype_args = [] then [] + else + config.gentype_args + @ ["-bs-gentype-bsb-project-root"; root_config.root]); + } + +let with_read_errors path f = + try f () with + | Sys_error message -> fail_read path (String_util.strip_path path message) + | Unix.Unix_error (error, _, _) -> fail_read path (Unix.error_message error) + +let decode_package_specs path ~suffix fields = + let package_specs = + match optional_member "package-specs" fields with + | None -> + [{module_format = Esmodule; in_source = true; suffix = Some ".js"}] + | Some (`List values) -> List.map (parse_package_spec path) values + | Some value -> [parse_package_spec path value] + in + let seen_package_outputs = Hashtbl.create (List.length package_specs) in + List.iter + (fun (spec : package_spec) -> + let effective_suffix = Option.value spec.suffix ~default:suffix in + let key = (effective_suffix, spec.in_source) in + if Hashtbl.mem seen_package_outputs key then + fail path + (Printf.sprintf "Duplicate package-spec suffix %S is not allowed." + effective_suffix); + Hashtbl.add seen_package_outputs key ()) + package_specs; + package_specs + +let decode_namespace path ~name fields = + let namespace_entry = + optional_member "namespace-entry" fields + |> Option.map (string path "namespace-entry") + in + let namespace_name = + match optional_member "namespace" fields with + | None | Some (`Bool false) -> None + | Some (`Bool true) -> Some (namespace_from_package_name name) + | Some (`String "true") -> Some (namespace_from_package_name name) + | Some (`String value) when is_upper_flat_case value -> Some value + | Some (`String value) when Option.is_some namespace_entry -> + Some (pascal_case value) + | Some (`String value) -> Some (namespace_from_package_name value) + | Some _ -> fail path "field \"namespace\" must be a boolean or string" + in + match (namespace_entry, namespace_name) with + | None, None -> No_namespace + | None, Some name -> Namespace name + | Some _, None -> fail path "field \"namespace-entry\" requires a namespace" + | Some entry, Some name -> Namespace_with_entry {name; entry} + +let decode_warnings path fields = + match optional_member "warnings" fields with + | None -> [] + | Some (`Assoc warning_fields) -> + reject_duplicate_fields path "warnings" Config_decode.warning_fields + warning_fields; + let number = + match optional_member "number" warning_fields with + | None -> [] + | Some value -> ["-w"; string path "number" value] + in + let error = + match optional_member "error" warning_fields with + | Some (`Bool true) -> ["-warn-error"; "A"] + | Some (`String value) -> ["-warn-error"; value] + | None | Some (`Bool false) -> [] + | Some _ -> + fail path "field \"warnings.error\" must be a boolean or string" + in + number @ error + | Some _ -> fail path "field \"warnings\" must be an object" + +let decode_jsx path fields = + match optional_member "jsx" fields with + | None -> [] + | Some (`Assoc jsx) -> + reject_duplicate_fields path "jsx" jsx_fields jsx; + let version = + match optional_member "version" jsx with + | None -> [] + | Some (`Int 4) -> ["-bs-jsx"; "4"] + | Some _ -> fail path "field \"jsx.version\" must be 4" + in + let module_ = + match optional_member "module" jsx with + | None -> [] + | Some value -> ["-bs-jsx-module"; string path "jsx.module" value] + in + let preserve = + match optional_member "preserve" jsx with + | None | Some (`Bool false) -> [] + | Some (`Bool true) -> ["-bs-jsx-preserve"] + | Some _ -> fail path "field \"jsx.preserve\" must be a boolean" + in + version @ module_ @ preserve + | Some _ -> fail path "field \"jsx\" must be an object" + +(* Returns the compiler arguments and whether source maps are emitted only for + development builds. *) +let decode_source_map path fields = + match optional_member "sourceMap" fields with + | None -> ([], false) + | Some (`Bool false) -> (["-bs-source-map"; "false"], false) + | Some (`Bool true) -> + fail path + "sourceMap true is unsupported; use an object with enabled and mode \ + fields or false" + | Some (`Assoc options) -> + reject_duplicates path "sourceMap" options; + let mode = + match member "mode" options with + | Some (`String (("linked" | "inline" | "hidden") as value)) -> value + | None -> fail path "sourceMap is missing field \"mode\"" + | Some _ -> + fail path "sourceMap.mode must be one of linked, inline, hidden" + in + let dev_only = + match member "enabled" options with + | Some (`String "always") -> false + | Some (`String "dev") -> true + | None -> fail path "sourceMap is missing field \"enabled\"" + | Some _ -> fail path "sourceMap.enabled must be \"always\" or \"dev\"" + in + let content = + match optional_member "sourcesContent" options with + | None -> [] + | Some (`Bool value) -> + ["-bs-source-map-sources-content"; string_of_bool value] + | Some _ -> + fail path "field \"sourceMap.sourcesContent\" must be a boolean" + in + let root = + match optional_member "sourceRoot" options with + | None -> [] + | Some value -> + ["-bs-source-map-root"; string path "sourceMap.sourceRoot" value] + in + (["-bs-source-map"; mode] @ content @ root, dev_only) + | Some _ -> fail path "field \"sourceMap\" must be false or an object" + +let decode_experimental_features path fields = + match optional_member "experimental-features" fields with + | None -> [] + | Some (`Assoc features) -> + reject_duplicates path "experimental-features" features; + features + |> List.concat_map (fun (name, value) -> + if name <> "LetUnwrap" then + fail path + (Printf.sprintf + "Unknown experimental feature '%s'. Available features: \ + LetUnwrap" + name); + match value with + | `Bool true -> ["-enable-experimental"; name] + | `Bool false -> [] + | _ -> + fail path + "experimental-features: invalid type: feature values must be \ + booleans") + | Some _ -> + fail path + "Could not read rescript.json: experimental-features: invalid type: \ + expected an object" + +let decode_js_post_build path fields = + match optional_member "js-post-build" fields with + | None -> None + | Some (`Assoc fields) -> ( + reject_duplicate_fields path "js-post-build" js_post_build_fields fields; + match member "cmd" fields with + | Some value -> Some (string path "js-post-build.cmd" value) + | None -> fail path "field \"js-post-build\" is missing \"cmd\"") + | Some _ -> fail path "field \"js-post-build\" must be an object" + +let decode_features path fields = + match optional_member "features" fields with + | None -> [] + | Some (`Assoc values) -> + reject_duplicates path "features" values; + List.map (fun (name, value) -> (name, strings path "features" value)) values + | Some _ -> fail path "field \"features\" must be an object" + +let deprecation_diagnostics path ~name fields = + let deprecated = + (if Filename.basename path = "bsconfig.json" then + [" - filename 'bsconfig.json' — rename to 'rescript.json'"] + else []) + @ (deprecated_field_aliases + |> List.filter_map (fun (field, replacement) -> + if Option.is_some (member field fields) then + Some + (Printf.sprintf " - field '%s' — use '%s' instead" field + replacement) + else None)) + @ + match member "package-specs" fields with + | Some value -> + [ + ("cjs", " - module 'cjs' in package-specs — use 'commonjs' instead"); + ("es6", " - module 'es6' in package-specs — use 'esmodule' instead"); + ] + |> List.filter_map (fun (alias, message) -> + if package_specs_use_alias alias value then Some message else None) + | None -> [] + in + if deprecated = [] then [] + else + [ + Printf.sprintf + "\n\ + Package '%s' uses deprecated config (support will be removed in a \ + future version):\n\ + %s" + name + (String.concat "\n" deprecated); + ] + +let load path = + let root = + with_read_errors path (fun () -> + Platform.canonicalize_path (Filename.dirname path)) + in + let path = Filename.concat root (Filename.basename path) in + let contents = + with_read_errors path (fun () -> + if (Unix.stat path).Unix.st_kind = Unix.S_DIR then + fail_read path (Unix.error_message Unix.EISDIR); + File_util.read_file path) + in + (match Strict_json.check contents with + | Ok () -> () + | Error {line; column; message} -> + raise + (Error + (Printf.sprintf "%s:%d:%d: invalid JSON: %s" path line column message))); + let json = + try Yojson.Safe.from_string contents + with Yojson.Json_error message -> fail path ("invalid JSON: " ^ message) + in + let fields = + match json with + | `Assoc fields -> fields + | _ -> fail path "rescript.json must contain a JSON object" + in + reject_duplicate_fields path "configuration" configuration_fields fields; + let name = + match member "name" fields with + | Some value -> string path "name" value + | None -> fail path "missing required field \"name\"" + in + let configured_suffix = + optional_member "suffix" fields |> Option.map (string path "suffix") + in + let suffix = Option.value configured_suffix ~default:".js" in + let package_specs = decode_package_specs path ~suffix fields in + let namespace = decode_namespace path ~name fields in + let compiler_flags = + match (member "compiler-flags" fields, member "bsc-flags" fields) with + | Some _, Some _ -> + fail path "fields \"compiler-flags\" and \"bsc-flags\" cannot both be set" + | Some `Null, None | None, Some `Null -> [] + | Some value, None -> compiler_flags path "compiler-flags" value + | None, Some value -> compiler_flags path "bsc-flags" value + | None, None -> [] + in + let warning_flags = decode_warnings path fields in + let ppx_flags = + match optional_member "ppx-flags" fields with + | None -> [] + | Some (`List values) -> + List.map + (function + | `String value -> [value] + | `List values -> List.map (string path "ppx-flags") values + | _ -> + fail path "field \"ppx-flags\" entries must be strings or arrays") + values + | Some _ -> fail path "field \"ppx-flags\" must be an array" + in + let jsx_args = decode_jsx path fields in + let source_map_args, source_map_dev = decode_source_map path fields in + let experimental_args = decode_experimental_features path fields in + let sources_defined = Option.is_some (optional_member "sources" fields) in + let sources = parse_sources path fields in + let dependencies = + dependency_alias path "dependencies" "bs-dependencies" fields + in + let dev_dependencies = + dependency_alias path "dev-dependencies" "bs-dev-dependencies" fields + in + let gentype_args = + match optional_member "gentypeconfig" fields with + | None -> [] + | Some value -> + gentype_args path configured_suffix + (member "package-specs" fields) + dependencies value + in + let js_post_build = decode_js_post_build path fields in + let allowed_dependents = + optional_member "allowed-dependents" fields + |> Option.map (strings path "allowed-dependents") + in + let features = decode_features path fields in + let deprecation_diagnostics = deprecation_diagnostics path ~name fields in + let diagnostics = + deprecation_diagnostics + @ (Config_decode.unsupported_fields fields + |> List.map (fun field -> + Printf.sprintf + "The field '%s' found in the package config of '%s' is not \ + supported by ReScript 12's new build system." + field name)) + @ (unknown_fields fields + |> List.map (fun field -> + Printf.sprintf + "Unknown field '%s' found in the package config of '%s'. This \ + option will be ignored." + field name)) + in + { + path; + root; + file_hash = Digest.string contents |> Digest.to_hex; + name; + sources; + sources_defined; + dependencies; + dev_dependencies; + compiler_flags; + package_specs; + suffix; + namespace; + features; + warning_flags; + ppx_flags; + jsx_args; + source_map_args; + source_map_dev; + experimental_args; + gentype_args; + js_post_build; + allowed_dependents; + deprecation_diagnostics; + diagnostics; + } + +let load_root root = load (path_in_root root) + +let package_spec_suffix (config : t) (spec : package_spec) = + Option.value spec.suffix ~default:config.suffix +let module_format_name = function + | Esmodule -> "esmodule" + | Commonjs -> "commonjs" diff --git a/rewatch-ocaml/config.mli b/rewatch-ocaml/config.mli new file mode 100644 index 00000000000..36299039226 --- /dev/null +++ b/rewatch-ocaml/config.mli @@ -0,0 +1,14 @@ +include module type of Config_types + +val namespace_name : namespace -> string option +val namespace_entry : namespace -> string option +val namespace_compiler_name : namespace -> string option +val namespaced_module_name : namespace -> string -> string +val path_in_root : string -> string +val exists_in_root : string -> bool +val source_is_dev : t -> string -> bool +val with_root_options : t -> t -> t +val load : string -> t +val load_root : string -> t +val package_spec_suffix : t -> package_spec -> string +val module_format_name : module_format -> string diff --git a/rewatch-ocaml/config_decode.ml b/rewatch-ocaml/config_decode.ml new file mode 100644 index 00000000000..d8a7cdb601c --- /dev/null +++ b/rewatch-ocaml/config_decode.ml @@ -0,0 +1,495 @@ +open Config_types + +exception Error = Config_types.Error + +let fail path message = raise (Error (Printf.sprintf "%s: %s" path message)) + +let fail_read path message = + raise (Error (Printf.sprintf "Could not read '%s': %s" path message)) + +let member name fields = List.assoc_opt name fields + +let optional_member name fields = + match member name fields with + | None | Some `Null -> None + | value -> value + +type field_policy = {known: string list; duplicate_checked: string list} + +let reject_all_duplicates known = {known; duplicate_checked = known} + +(* Fields that take effect, unlike unsupported and no-op legacy fields, which + are accepted but ignored. *) +let supported_fields policy = policy.duplicate_checked + +(* Deprecated field names and the fields that replace them. *) +let deprecated_field_aliases = + [ + ("bs-dependencies", "dependencies"); + ("bs-dev-dependencies", "dev-dependencies"); + ("bsc-flags", "compiler-flags"); + ] + +let unsupported_configuration_fields = + [ + "ignored-dirs"; + "generators"; + "cut-generators"; + "pp-flags"; + "entries"; + "bs-external-includes"; + ] + +let configuration_duplicate_fields = + [ + "name"; + "sources"; + "package-specs"; + "warnings"; + "suffix"; + "dependencies"; + "bs-dependencies"; + "dev-dependencies"; + "bs-dev-dependencies"; + "features"; + "ppx-flags"; + "compiler-flags"; + "bsc-flags"; + "namespace"; + "jsx"; + "sourceMap"; + "experimental-features"; + "gentypeconfig"; + "js-post-build"; + "editor"; + "reanalyze"; + "namespace-entry"; + "allowed-dependents"; + ] + +let configuration_fields = + { + known = configuration_duplicate_fields @ unsupported_configuration_fields; + duplicate_checked = configuration_duplicate_fields; + } + +let warning_fields = reject_all_duplicates ["number"; "error"] + +(* Like Rust rewatch, jsx.mode and jsx.v3-dependencies no longer have any + effect: they are accepted with any value and not reported as unknown. *) +let jsx_fields = + { + known = ["version"; "module"; "preserve"; "mode"; "v3-dependencies"]; + duplicate_checked = ["version"; "module"; "preserve"]; + } + +let gentype_fields = + reject_all_duplicates + [ + "module"; + "moduleResolution"; + "exportInterfaces"; + "generatedFileExtension"; + "shims"; + "debug"; + ] + +let js_post_build_fields = reject_all_duplicates ["cmd"] +let dependency_fields = reject_all_duplicates ["name"; "features"] + +let source_fields = reject_all_duplicates ["dir"; "subdirs"; "type"; "feature"] + +let package_spec_fields = + reject_all_duplicates ["module"; "in-source"; "suffix"] + +(* Fails on the second occurrence of a field accepted by [checked]. *) +let reject_repeated ~checked path context fields = + let seen = Hashtbl.create (List.length fields) in + List.iter + (fun (name, _) -> + if checked name then + if Hashtbl.mem seen name then + fail path (Printf.sprintf "duplicate field %S in %s" name context) + else Hashtbl.add seen name ()) + fields + +let reject_duplicate_fields path context policy fields = + reject_repeated + ~checked:(fun name -> List.mem name policy.duplicate_checked) + path context fields + +let reject_duplicates path context fields = + reject_repeated ~checked:(fun _ -> true) path context fields + +let string path field = function + | `String value -> value + | _ -> fail path (Printf.sprintf "field %S must be a string" field) + +let bool path field = function + | `Bool value -> value + | _ -> fail path (Printf.sprintf "field %S must be a boolean" field) + +let strings path field = function + | `List values -> List.map (string path field) values + | _ -> fail path (Printf.sprintf "field %S must be an array of strings" field) + +let namespace_from_package_name name = + let buffer = Buffer.create (String.length name) in + let capitalize = ref true in + String.iter + (fun character -> + match character with + | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' -> + Buffer.add_char buffer + (if !capitalize then Char.uppercase_ascii character else character); + capitalize := false + | '/' | '-' -> capitalize := true + | _ -> ()) + name; + Buffer.contents buffer + +(* A string namespace combined with a namespace-entry is converted with the + Pascal case of Rust's convert_case crate (0.6), which rescript.json files + already depend on: "my_lib" names the namespace MyLib. Words split at + '-', '_' and ' ' (which are dropped), between a lower-case letter and an + upper-case letter or digit, between an upper-case letter and a digit, + between a digit and a letter, and before the last capital of an acronym + followed by a lower-case letter ("ABCdef" -> "AB", "Cdef"). Each word is + then capitalized and the rest lower-cased. Characters that are neither + letters nor digits, such as '.', stay inside their word. *) +let pascal_case_words value = + let is_upper = function + | 'A' .. 'Z' -> true + | _ -> false + in + let is_lower = function + | 'a' .. 'z' -> true + | _ -> false + in + let is_digit = function + | '0' .. '9' -> true + | _ -> false + in + let length = String.length value in + let words = ref [] in + let word = Buffer.create length in + let finish_word () = + if Buffer.length word > 0 then ( + words := Buffer.contents word :: !words; + Buffer.clear word) + in + String.iteri + (fun index character -> + match character with + | '-' | '_' | ' ' -> finish_word () + | _ -> + let splits_before = + index > 0 + && + let previous = value.[index - 1] in + (is_lower previous && (is_upper character || is_digit character)) + || (is_upper previous && is_digit character) + || (is_digit previous && (is_upper character || is_lower character)) + || index + 1 < length + && is_upper previous && is_upper character + && is_lower value.[index + 1] + in + if splits_before then finish_word (); + Buffer.add_char word character) + value; + finish_word (); + List.rev !words + +let pascal_case value = + pascal_case_words value + |> List.map (fun word -> + String.capitalize_ascii (String.lowercase_ascii word)) + |> String.concat "" + +(* convert_case's upper-flat case: a value that is already all capitals without + word separators is used as the namespace unchanged. *) +let is_upper_flat_case value = + String.concat "" (List.map String.uppercase_ascii (pascal_case_words value)) + = value + +let compiler_flags path field = function + | `List values -> + values + |> List.concat_map (function + | `String value -> + String.split_on_char ' ' value |> List.filter (( <> ) "") + | `List values -> + values + |> List.concat_map (fun value -> + string path field value |> String.split_on_char ' ' + |> List.filter (( <> ) "")) + | _ -> + fail path + (Printf.sprintf "field %S entries must be strings or arrays" field)) + | _ -> fail path (Printf.sprintf "field %S must be an array" field) + +let dependency_name path field = function + | `String value -> {name = value; features = None} + | `Assoc fields -> ( + reject_duplicate_fields path "dependency" dependency_fields fields; + match member "name" fields with + | Some value -> + let features = + match optional_member "features" fields with + | None -> None + | Some value -> Some (strings path "features" value) + in + {name = string path "name" value; features} + | None -> + fail path + (Printf.sprintf "an object in field %S is missing field \"name\"" field) + ) + | _ -> + fail path + (Printf.sprintf "entries of field %S must be strings or objects" field) + +let parse_dependencies path field fields = + match optional_member field fields with + | None -> [] + | Some (`List values) -> List.map (dependency_name path field) values + | Some _ -> fail path (Printf.sprintf "field %S must be an array" field) + +let dependency_alias path modern legacy fields = + match (member modern fields, member legacy fields) with + | Some _, Some _ -> + fail path + (Printf.sprintf "fields %S and %S cannot both be set" modern legacy) + | Some _, None -> parse_dependencies path modern fields + | None, Some _ -> parse_dependencies path legacy fields + | None, None -> [] + +let rec sources_of_json path inherited_dir forced_dev inherited_feature = + function + | `String dir -> + [ + { + dir = Filename.concat inherited_dir dir; + recurse = false; + is_dev = Option.value forced_dev ~default:false; + feature = inherited_feature; + }; + ] + | `Assoc fields -> + reject_duplicate_fields path "source" source_fields fields; + let dir = + match member "dir" fields with + | Some value -> Filename.concat inherited_dir (string path "dir" value) + | None -> + fail path "an object in field \"sources\" is missing field \"dir\"" + in + let declared_dev = + match optional_member "type" fields with + | None -> false + | Some (`String "dev") -> true + | Some (`String _) -> false + | Some _ -> fail path "field \"type\" in \"sources\" must be a string" + in + let is_dev = Option.value forced_dev ~default:declared_dev in + let feature = + match optional_member "feature" fields with + | None -> inherited_feature + | Some value -> Some (string path "feature" value) + in + let recurse, children = + match optional_member "subdirs" fields with + | None -> (false, []) + | Some (`Bool value) -> (value, []) + | Some (`List values) -> + ( false, + List.concat_map + (sources_of_json path dir (Some is_dev) feature) + values ) + | Some _ -> + fail path + "field \"subdirs\" in \"sources\" must be a boolean or an array" + in + {dir; recurse; is_dev; feature} :: children + | _ -> + fail path + "field \"sources\" must be a string, an object, or an array of them" + +let parse_sources path fields = + match optional_member "sources" fields with + | None -> [] + | Some (`List values) -> + List.concat_map (sources_of_json path "" None None) values + | Some value -> sources_of_json path "" None None value + +let nested_unknown_fields parent supported = function + | `Assoc fields -> + fields + |> List.filter_map (fun (name, _) -> + if List.mem name supported then None + else Some (Printf.sprintf "%s.?.%s" parent name)) + | _ -> [] + +let unknown_fields fields = + fields + |> List.concat_map (fun (name, value) -> + match name with + | "warnings" -> nested_unknown_fields name warning_fields.known value + | "jsx" -> nested_unknown_fields name jsx_fields.known value + | "gentypeconfig" -> nested_unknown_fields name gentype_fields.known value + | "js-post-build" -> + nested_unknown_fields name js_post_build_fields.known value + | _ -> if List.mem name configuration_fields.known then [] else [name]) + +let unsupported_fields fields = + unsupported_configuration_fields + |> List.filter (fun field -> Option.is_some (member field fields)) + +let parse_package_spec path = function + | `Assoc fields -> + reject_duplicate_fields path "package-specs entry" package_spec_fields + fields; + let module_format = + match member "module" fields with + | Some (`String ("esmodule" | "es6")) -> Esmodule + | Some (`String ("commonjs" | "cjs")) -> Commonjs + | None -> + fail path + "an object in field \"package-specs\" is missing field \"module\"" + | Some value -> + fail path + (Printf.sprintf + "unsupported module %s in field \"package-specs\"; expected \ + \"commonjs\" or \"esmodule\"" + (Yojson.Safe.to_string value)) + in + let in_source = + match member "in-source" fields with + | None -> true + | Some value -> bool path "in-source" value + in + let suffix = + match optional_member "suffix" fields with + | None -> None + | Some value -> Some (string path "suffix" value) + in + {module_format; in_source; suffix} + | _ -> + fail path "field \"package-specs\" must be an object or an array of objects" + +let package_specs_use_alias alias = function + | `Assoc fields -> member "module" fields = Some (`String alias) + | `List values -> + List.exists + (function + | `Assoc fields -> member "module" fields = Some (`String alias) + | _ -> false) + values + | _ -> false + +let gentype_args path configured_suffix package_specs_value dependencies = + function + | `Assoc fields -> + reject_duplicate_fields path "gentypeconfig" gentype_fields fields; + let module_ = + match optional_member "module" fields with + | None -> ( + match package_specs_value with + | Some (`Assoc package_spec) -> ( + match member "module" package_spec with + | Some (`String ("esmodule" | "es6")) -> + ["-bs-gentype-module"; "esmodule"] + | Some (`String ("commonjs" | "cjs")) -> + ["-bs-gentype-module"; "commonjs"] + | _ -> []) + | _ -> []) + | Some (`String (("esmodule" | "commonjs") as value)) -> + ["-bs-gentype-module"; value] + | Some _ -> + fail path + "field \"gentypeconfig.module\" must be \"esmodule\" or \"commonjs\"" + in + let module_resolution = + match optional_member "moduleResolution" fields with + | None -> [] + | Some (`String (("node" | "node16" | "bundler") as value)) -> + ["-bs-gentype-module-resolution"; value] + | Some _ -> + fail path + "field \"gentypeconfig.moduleResolution\" must be \"node\", \ + \"node16\", or \"bundler\"" + in + let export_interfaces = + match optional_member "exportInterfaces" fields with + | None | Some (`Bool false) -> [] + | Some (`Bool true) -> ["-bs-gentype-export-interfaces"] + | Some _ -> + fail path "field \"gentypeconfig.exportInterfaces\" must be a boolean" + in + let generated_extension = + match optional_member "generatedFileExtension" fields with + | None -> [] + | Some value -> + [ + "-bs-gentype-generated-extension"; + string path "gentypeconfig.generatedFileExtension" value; + ] + in + let shims = + let pairs = + match member "shims" fields with + | None -> [] + | Some (`Assoc values) -> + reject_duplicates path "gentypeconfig.shims" values; + List.map + (fun (from_, target) -> + (from_, string path "gentypeconfig.shims" target)) + values + | Some (`List values) -> + let pairs = + List.map + (fun value -> + let value = string path "gentypeconfig.shims" value in + match String.index_opt value '=' with + | Some separator -> + let from_ = String.sub value 0 separator |> String.trim in + let target = + String.sub value (separator + 1) + (String.length value - separator - 1) + |> String.trim + in + (from_, target) + | None -> fail path "gentypeconfig.shims entries must contain =") + values + in + reject_duplicates path "gentypeconfig.shims" pairs; + pairs + | Some _ -> + fail path "field \"gentypeconfig.shims\" must be an object or array" + in + pairs |> List.sort compare + |> List.concat_map (fun (from_, target) -> + ["-bs-gentype-shim"; from_ ^ "=" ^ target]) + in + let debug = + match member "debug" fields with + | None -> [] + | Some (`Assoc values) -> + reject_duplicates path "gentypeconfig.debug" values; + values |> List.sort compare + |> List.concat_map (fun (name, value) -> + match value with + | `Bool true -> ["-bs-gentype-debug"; name] + | `Bool false -> [] + | _ -> fail path "gentypeconfig.debug values must be booleans") + | Some _ -> fail path "field \"gentypeconfig.debug\" must be an object" + in + let suffix_args = + match configured_suffix with + | None -> [] + | Some suffix -> ["-bs-gentype-suffix"; suffix] + in + ["-bs-gentype"] @ module_ @ module_resolution @ export_interfaces + @ generated_extension @ suffix_args @ shims @ debug + @ List.concat_map + (fun (dependency : dependency) -> ["-bs-gentype-dep"; dependency.name]) + dependencies + | _ -> fail path "field \"gentypeconfig\" must be an object" diff --git a/rewatch-ocaml/config_decode.mli b/rewatch-ocaml/config_decode.mli new file mode 100644 index 00000000000..98465f9cc54 --- /dev/null +++ b/rewatch-ocaml/config_decode.mli @@ -0,0 +1,53 @@ +val fail : string -> string -> 'a +val fail_read : string -> string -> 'a +val member : string -> (string * 'a) list -> 'a option + +val optional_member : + string -> (string * Yojson.Safe.t) list -> Yojson.Safe.t option + +type field_policy + +val deprecated_field_aliases : (string * string) list +val supported_fields : field_policy -> string list +val configuration_fields : field_policy +val source_fields : field_policy +val dependency_fields : field_policy +val warning_fields : field_policy +val jsx_fields : field_policy +val js_post_build_fields : field_policy + +val reject_duplicate_fields : + string -> string -> field_policy -> (string * 'a) list -> unit + +val reject_duplicates : string -> string -> (string * 'a) list -> unit + +val string : string -> string -> Yojson.Safe.t -> string +val strings : string -> string -> Yojson.Safe.t -> string list + +val namespace_from_package_name : string -> string +val pascal_case : string -> string +val is_upper_flat_case : string -> bool +val compiler_flags : string -> string -> Yojson.Safe.t -> string list + +val dependency_alias : + string -> + string -> + string -> + (string * Yojson.Safe.t) list -> + Config_types.dependency list + +val parse_sources : + string -> (string * Yojson.Safe.t) list -> Config_types.source list + +val unknown_fields : (string * Yojson.Safe.t) list -> string list +val unsupported_fields : (string * 'a) list -> string list +val parse_package_spec : string -> Yojson.Safe.t -> Config_types.package_spec +val package_specs_use_alias : string -> Yojson.Safe.t -> bool + +val gentype_args : + string -> + string option -> + Yojson.Safe.t option -> + Config_types.dependency list -> + Yojson.Safe.t -> + string list diff --git a/rewatch-ocaml/config_types.ml b/rewatch-ocaml/config_types.ml new file mode 100644 index 00000000000..0f1d7edb86a --- /dev/null +++ b/rewatch-ocaml/config_types.ml @@ -0,0 +1,44 @@ +type module_format = Esmodule | Commonjs +type namespace = + | No_namespace + | Namespace of string + | Namespace_with_entry of {name: string; entry: string} + +type package_spec = { + module_format: module_format; + in_source: bool; + suffix: string option; +} + +type source = {dir: string; recurse: bool; is_dev: bool; feature: string option} + +type dependency = {name: string; features: string list option} + +type t = { + path: string; + root: string; + file_hash: string; + name: string; + sources: source list; + sources_defined: bool; + dependencies: dependency list; + dev_dependencies: dependency list; + compiler_flags: string list; + package_specs: package_spec list; + suffix: string; + namespace: namespace; + features: (string * string list) list; + warning_flags: string list; + ppx_flags: string list list; + jsx_args: string list; + source_map_args: string list; + source_map_dev: bool; + experimental_args: string list; + gentype_args: string list; + js_post_build: string option; + allowed_dependents: string list option; + deprecation_diagnostics: string list; + diagnostics: string list; +} + +exception Error of string diff --git a/rewatch-ocaml/dune b/rewatch-ocaml/dune new file mode 100644 index 00000000000..a2faebbeaf8 --- /dev/null +++ b/rewatch-ocaml/dune @@ -0,0 +1,87 @@ +(env + (static + (flags + (:standard -ccopt -static)))) + +(rule + (target platform.ml) + (enabled_if + (= %{os_type} Win32)) + (action + (copy platform_windows.ml platform.ml))) + +(rule + (target platform.ml) + (enabled_if + (<> %{os_type} Win32)) + (action + (copy platform_unix.ml platform.ml))) + +(library + (name rewatch_ocaml_lib) + (wrapped false) + (modules + rewatch_version + string_util + strict_json + source_filter + cli + config_types + config_decode + config + project_context + package_resolution + package_traversal + platform_common + platform + termination_signals + traversal_coverage + process_child + process + source + package_plan + graph + module_graph + package_diagnostics + package_graph + compiler_args + compiler_args_command + compiler_log + ast_header + compiler_process + compiler_scheduler + after_build + file_util + build_lock + build_artifacts + build_freshness + build_session + build_attempt + build_report + build_preparation + package_parse + package_compilation + package_build + clean + compile_assets + build_state + native_watcher + watch_scope + watch_snapshot + watcher + toolchain + compiler_info + source_dirs + warning_state + output + build + format) + (libraries unix threads yojson str spawn cmdliner luv re.perl) + (foreign_stubs + (language c) + (names windows_job_stubs))) + +(executable + (name rescript_ocaml) + (modules rescript_ocaml) + (libraries rewatch_ocaml_lib)) diff --git a/rewatch-ocaml/file_util.ml b/rewatch-ocaml/file_util.ml new file mode 100644 index 00000000000..3515a45d5e7 --- /dev/null +++ b/rewatch-ocaml/file_util.ml @@ -0,0 +1,244 @@ +let path_of_parts root parts = List.fold_left Filename.concat root parts + +let is_directory path = + match Unix.stat path with + | metadata -> metadata.Unix.st_kind = Unix.S_DIR + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> false + +let ensure_dir path = + (* OCaml's standard library has no recursive directory-creation primitive. + Another process may win a mkdir race, but EEXIST is success only when the + resulting path is a directory. Filename.dirname may return an unavailable + Windows volume root unchanged, so stop at that fixed point and let mkdir + surface the native filesystem error. *) + let mkdir path = + try Unix.mkdir path 0o755 + with Unix.Unix_error (Unix.EEXIST, _, _) as error -> + if not (is_directory path) then raise error + in + let rec loop path = + if path = "" || path = "." || is_directory path then () + else + let parent = Filename.dirname path in + if parent = path then mkdir path + else ( + loop parent; + mkdir path) + in + loop path + +let read_file path = + let descriptor = Unix.openfile path [Unix.O_RDONLY; Unix.O_CLOEXEC] 0 in + let channel = Unix.in_channel_of_descr descriptor in + Fun.protect + ~finally:(fun () -> close_in_noerr channel) + (fun () -> + let expected_size = (Unix.fstat descriptor).Unix.st_size in + let contents = Buffer.create (max 16 expected_size) in + (* A small initial chunk avoids allocating 64 KiB for tiny files such as + the watch lock. The loop still handles streams and files that grow + while they are being read. *) + let chunk = Bytes.create (max 1 (min 65536 (max 4096 expected_size))) in + let rec read () = + match input channel chunk 0 (Bytes.length chunk) with + | 0 -> Buffer.contents contents + | count -> + Buffer.add_subbytes contents chunk 0 count; + read () + in + read ()) + +let is_regular_file path = + match Unix.stat path with + | metadata -> metadata.Unix.st_kind = Unix.S_REG + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> false + +let digest_file path = + let descriptor = Unix.openfile path [Unix.O_RDONLY; Unix.O_CLOEXEC] 0 in + let channel = Unix.in_channel_of_descr descriptor in + Fun.protect + ~finally:(fun () -> close_in_noerr channel) + (fun () -> Digest.channel channel (-1)) + +let with_output_channel channel write = + try + let result = write channel in + close_out channel; + result + with exn -> + close_out_noerr channel; + raise exn + +let write_file path contents = + let channel = open_out_bin path in + with_output_channel channel (fun channel -> output_string channel contents) + +let append_file path contents = + let channel = + open_out_gen [Open_wronly; Open_append; Open_binary] 0o644 path + in + with_output_channel channel (fun channel -> output_string channel contents) + +let directory_entries path = + let directory = Unix.opendir path in + Fun.protect + ~finally:(fun () -> Unix.closedir directory) + (fun () -> + let rec read entries = + match Unix.readdir directory with + | "." | ".." -> read entries + | name -> read (name :: entries) + | exception End_of_file -> List.rev entries + in + read []) + +let write_file_atomic ?(ensure_parent = true) path contents = + if ensure_parent then ensure_dir (Filename.dirname path); + let candidate = + Filename.temp_file ~temp_dir:(Filename.dirname path) ".rewatch-write-" + ".tmp" + in + let published = ref false in + Fun.protect + ~finally:(fun () -> + if not !published then + try Sys.remove candidate with Sys_error _ | Unix.Unix_error _ -> ()) + (fun () -> + Unix.chmod candidate 0o644; + write_file candidate contents; + Sys.rename candidate path; + published := true) + +let copy_existing_file source destination = + let input_descriptor = + Unix.openfile source [Unix.O_RDONLY; Unix.O_CLOEXEC] 0 + in + let input_channel = Unix.in_channel_of_descr input_descriptor in + Fun.protect + ~finally:(fun () -> close_in_noerr input_channel) + (fun () -> + (* The copy writes in place, like Rust rewatch: replacing the file by a + rename would leave stale entries on case-insensitive virtiofs mounts + (Docker on macOS) for the compiler's lowercase .cmi lookups. A failed + copy removes its partial destination, so the next build publishes it + again instead of reading a truncated .cmi or .cmj. *) + let output_channel = open_out_bin destination in + try + with_output_channel output_channel (fun output_channel -> + let buffer = Bytes.create 65_536 in + let rec copy () = + let count = input input_channel buffer 0 (Bytes.length buffer) in + if count > 0 then ( + output output_channel buffer 0 count; + copy ()) + in + copy ()) + with error -> + let backtrace = Printexc.get_raw_backtrace () in + (try Unix.unlink destination with Unix.Unix_error _ -> ()); + Printexc.raise_with_backtrace error backtrace) + +let copy_optional_existing_file source destination = + try copy_existing_file source destination + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> ( + try Unix.unlink destination + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> ()) + +let stat_opt path = + try Some (Unix.stat path) + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> None + +let exists path = Option.is_some (stat_opt path) + +let files_equal first second = + match stat_opt first with + | None -> false + | Some first_stat -> ( + match stat_opt second with + | None -> false + | Some second_stat -> + first_stat.Unix.st_size = second_stat.Unix.st_size + && + let first_descriptor = + Unix.openfile first [Unix.O_RDONLY; Unix.O_CLOEXEC] 0 + in + let first_channel = Unix.in_channel_of_descr first_descriptor in + Fun.protect + ~finally:(fun () -> close_in_noerr first_channel) + (fun () -> + let second_descriptor = + Unix.openfile second [Unix.O_RDONLY; Unix.O_CLOEXEC] 0 + in + let second_channel = Unix.in_channel_of_descr second_descriptor in + Fun.protect + ~finally:(fun () -> close_in_noerr second_channel) + (fun () -> + let buffer_size = 65_536 in + let first_buffer = Bytes.create buffer_size in + let second_buffer = Bytes.create buffer_size in + let rec read_chunk channel buffer offset = + if offset = Bytes.length buffer then offset + else + match + input channel buffer offset (Bytes.length buffer - offset) + with + | 0 -> offset + | count -> read_chunk channel buffer (offset + count) + in + let equal_prefix length = + let index = ref 0 in + while + !index < length + && Bytes.get first_buffer !index + = Bytes.get second_buffer !index + do + incr index + done; + !index = length + in + let rec loop () = + let first_count = read_chunk first_channel first_buffer 0 in + let second_count = read_chunk second_channel second_buffer 0 in + first_count = second_count + && (first_count = 0 || (equal_prefix first_count && loop ())) + in + loop ()))) + +let copy_file_if_different source destination = + let changed = not (files_equal source destination) in + if changed then copy_existing_file source destination; + changed + +let modification_time path = + stat_opt path |> Option.map (fun metadata -> metadata.Unix.st_mtime) + +let remove_file path = + try Unix.unlink path + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> () + +let rec remove_tree path = + match (Unix.lstat path).Unix.st_kind with + | Unix.S_DIR -> + directory_entries path + |> List.iter (fun name -> remove_tree (Filename.concat path name)); + Unix.rmdir path + | _ -> Unix.unlink path + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> () + +let remove_file_best_effort path = + try remove_file path with Sys_error _ | Unix.Unix_error _ -> () + +let rec files_under directory = + match (Unix.lstat directory).Unix.st_kind with + | Unix.S_DIR -> + directory_entries directory + |> List.concat_map (fun name -> + files_under (Filename.concat directory name)) + (* Following links during recursion could leave the requested tree or enter + a cycle. Follow one only to omit dangling links from the result. *) + | Unix.S_LNK -> ( + match Unix.stat directory with + | _ -> [directory] + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> []) + | _ -> [directory] + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> [] diff --git a/rewatch-ocaml/file_util.mli b/rewatch-ocaml/file_util.mli new file mode 100644 index 00000000000..d53f60bfc20 --- /dev/null +++ b/rewatch-ocaml/file_util.mli @@ -0,0 +1,22 @@ +val path_of_parts : string -> string list -> string +val is_directory : string -> bool +val ensure_dir : string -> unit +val read_file : string -> string +val is_regular_file : string -> bool +val digest_file : string -> Digest.t +val write_file : string -> string -> unit +val append_file : string -> string -> unit +val directory_entries : string -> string list + +val write_file_atomic : ?ensure_parent:bool -> string -> string -> unit +val copy_existing_file : string -> string -> unit +val copy_optional_existing_file : string -> string -> unit + +val exists : string -> bool +val files_equal : string -> string -> bool +val copy_file_if_different : string -> string -> bool +val modification_time : string -> float option +val remove_file : string -> unit +val remove_tree : string -> unit +val remove_file_best_effort : string -> unit +val files_under : string -> string list diff --git a/rewatch-ocaml/format.ml b/rewatch-ocaml/format.ml new file mode 100644 index 00000000000..f63f9291bbd --- /dev/null +++ b/rewatch-ocaml/format.ml @@ -0,0 +1,215 @@ +exception Error of string + +let with_file_error ~action path f = + try f () with + | Sys_error message -> + raise + (Error + (Printf.sprintf "Could not %s %s: %s" action path + (String_util.strip_path path message))) + | Unix.Unix_error (error, _, _) -> + raise + (Error + (Printf.sprintf "Could not %s %s: %s" action path + (Unix.error_message error))) + +let read_file path = + with_file_error ~action:"read file" path (fun () -> File_util.read_file path) + +let write_file path contents = + with_file_error ~action:"write formatted file" path (fun () -> + (* Formatting changes the contents of a user-owned file. Writing through + its existing inode preserves symlinks, hard links, ownership, ACLs, and + extended attributes that replacing the directory entry could lose. *) + File_util.write_file path contents) + +let bsc () = + try Toolchain.bsc () with Toolchain.Error message -> raise (Error message) + +type discovered_package = {config: Config.t; files: string list} + +let package_sources (package : discovered_package) = + package.files |> List.map (Filename.concat package.config.root) + +(* Validate the complete package graph before selecting the local files that + format owns. Scan it with the effective feature selections so dependency + diagnostics and the eventual local file set cannot drift apart. The + resolution is returned so its package metadata diagnostics are reported + once. *) +let discover_package_graph (current : Config.t) = + let resolution = Package_resolution.create current in + let graph = + Package_traversal.discover ~root_config:current ~prod:false ~features:None + ~resolution + in + let packages = + graph.packages + |> List.map (fun (package : Package_traversal.package) -> + let config = package.config in + let is_local = package.is_local in + Package_diagnostics.report_missing_sources + ~is_root:(config.root = current.root) + config; + let features = + if config.root = current.root then None + else + match + Package_traversal.find_feature_selection graph config.root + with + | None | Some Package_traversal.All_features -> None + | Some (Package_traversal.Selected_features requested) -> + (try ignore (Source.resolve_active_features config requested) + with Source.Error message -> + raise + (Error + (Printf.sprintf "Invalid features for package '%s': %s" + config.name message))); + Some requested + in + let files = + Source.discover_files config + ~prod: + (Package_traversal.source_discovery_prod ~prod:false ~is_local) + ~features + ~on_missing: + (Package_diagnostics.report_missing_source_folder config) + in + {config; files}) + in + (resolution, packages) + +let files_in_scope ~verbosity = + let current_directory = Sys.getcwd () in + let current = + try Config.load_root current_directory + with Config.Error message -> + raise + (Error + (Printf.sprintf "Could not read rescript.json at %s: %s" + current_directory message)) + in + let workspace = Project_context.workspace_config_for current in + let listed_by_parent = workspace.root <> current.root in + Output.debug ~channel:stderr ~verbosity + (Project_context.describe current ~workspace); + let resolution, packages = discover_package_graph current in + let roots_in_scope = + if listed_by_parent then [current.root] + else + current.root + :: (Package_traversal.requests ~prod:false ~is_local:true current + |> List.map (fun request -> request.Package_traversal.declaration) + |> List.filter_map (fun (dependency : Config.dependency) -> + match + Package_resolution.dependency_path resolution + ~package_root:current.root dependency.name + with + | Some directory + when Package_resolution.is_local resolution directory -> + Some directory + | Some _ | None -> None)) + in + packages + |> List.filter (fun package -> + List.exists (( = ) package.config.root) roots_in_scope) + |> List.concat_map package_sources + |> List.sort_uniq String.compare + +let formatting_error target stderr = + Printf.sprintf "Error formatting %s: %s" target stderr + +let formatted ?poll ~bsc ~target path = + let result = Process.run ?poll ~cwd:(Sys.getcwd ()) bsc ["-format"; path] in + if not (Process.succeeded result) then + raise (Error (formatting_error target result.stderr)); + result.stdout + +let format_check_summary = function + | 1 -> "The file listed above needs formatting" + | count -> Printf.sprintf "The %d files listed above need formatting" count + +let format_files_with_bsc ?max_jobs ?poll ~bsc ~check files = + let cwd = Sys.getcwd () in + let incorrect = ref 0 in + let works = + files + |> List.mapi (fun index path -> + Process. + {key = Printf.sprintf "%08d" index; dependencies = []; value = path}) + in + let next path = function + | None -> + Some (Process.task Process.{program = bsc; args = ["-format"; path]; cwd}) + | Some result -> + if not (Process.succeeded result) then + raise (Error (formatting_error path result.stderr)); + let original = read_file path in + if original <> result.stdout then + if check then ( + incr incorrect; + prerr_endline ("[format check] " ^ path)) + else write_file path result.stdout; + None + in + Process.run_dependency_graph ?max_jobs ?poll works ~next; + if !incorrect > 0 then ( + prerr_endline (format_check_summary !incorrect); + raise (Error "Formatting check failed")) + +type stdin_read_result = Stdin_contents of string | Stdin_error of exn + +let read_stdin_interruptibly ?poll () = + let result = Atomic.make None in + let reader = + Thread.create + (fun () -> + let value = + try + let buffer = Buffer.create 4096 in + let bytes = Bytes.create 65536 in + let rec read () = + match input stdin bytes 0 (Bytes.length bytes) with + | 0 -> Stdin_contents (Buffer.contents buffer) + | count -> + Buffer.add_subbytes buffer bytes 0 count; + read () + in + read () + with exn -> Stdin_error exn + in + Atomic.set result (Some value)) + () + in + let rec await () = + Option.iter (fun poll -> poll ()) poll; + match Atomic.get result with + | Some value -> + Thread.join reader; + value + | None -> + Unix.sleepf 0.02; + await () + in + match await () with + | Stdin_contents contents -> contents + | Stdin_error exn -> raise exn + +let format_stdin ?poll extension = + if extension <> ".res" && extension <> ".resi" then + raise (Error "--stdin must be .res or .resi"); + let bsc = bsc () in + let path = Filename.temp_file "rescript-format-" extension in + Fun.protect + ~finally:(fun () -> try Sys.remove path with Sys_error _ -> ()) + (fun () -> + let contents = read_stdin_interruptibly ?poll () in + File_util.write_file path contents; + print_string (formatted ?poll ~bsc ~target:"stdin" path)) + +let run_files ?poll ~verbosity ~check paths = + let bsc = bsc () in + let files = if paths = [] then files_in_scope ~verbosity else paths in + List.iter + (fun file -> Output.trace ~channel:stderr ~verbosity ("Formatting " ^ file)) + files; + format_files_with_bsc ?poll ~bsc ~check files diff --git a/rewatch-ocaml/format.mli b/rewatch-ocaml/format.mli new file mode 100644 index 00000000000..95624e0c3f4 --- /dev/null +++ b/rewatch-ocaml/format.mli @@ -0,0 +1,17 @@ +exception Error of string + +val write_file : string -> string -> unit +val formatting_error : string -> string -> string +val format_check_summary : int -> string + +val format_files_with_bsc : + ?max_jobs:int -> + ?poll:(unit -> unit) -> + bsc:string -> + check:bool -> + string list -> + unit + +val format_stdin : ?poll:(unit -> unit) -> string -> unit +val run_files : + ?poll:(unit -> unit) -> verbosity:int -> check:bool -> string list -> unit diff --git a/rewatch-ocaml/graph.ml b/rewatch-ocaml/graph.ml new file mode 100644 index 00000000000..90655a6a610 --- /dev/null +++ b/rewatch-ocaml/graph.ml @@ -0,0 +1,246 @@ +type validation = + | Replace_duplicates_and_ignore_unknown + | Reject_invalid of { + duplicate_node: string -> exn; + unknown_dependency: node:string -> dependency:string -> exn; + } + +type 'a index = { + nodes_by_name: (string, 'a) Hashtbl.t; + dependencies_by_name: (string, string list) Hashtbl.t; + dependents_by_name: (string, string list) Hashtbl.t; +} + +let create_index nodes ~name ~deps ~validation = + let nodes_by_name = Hashtbl.create (List.length nodes) in + List.iter + (fun node -> + let node_name = name node in + match Hashtbl.find_opt nodes_by_name node_name with + | None -> Hashtbl.add nodes_by_name node_name node + | Some _ -> ( + match validation with + | Replace_duplicates_and_ignore_unknown -> + Hashtbl.replace nodes_by_name node_name node + | Reject_invalid {duplicate_node; unknown_dependency = _} -> + raise (duplicate_node node_name))) + nodes; + let dependencies_by_name = Hashtbl.create (Hashtbl.length nodes_by_name) in + let dependents_by_name = Hashtbl.create (Hashtbl.length nodes_by_name) in + Hashtbl.iter + (fun node_name node -> + let dependencies = + deps node + |> List.sort_uniq String.compare + |> List.filter (fun dependency -> + if Hashtbl.mem nodes_by_name dependency then true + else + match validation with + | Replace_duplicates_and_ignore_unknown -> false + | Reject_invalid {duplicate_node = _; unknown_dependency} -> + raise (unknown_dependency ~node:node_name ~dependency)) + in + Hashtbl.add dependencies_by_name node_name dependencies; + List.iter + (fun dependency -> + let dependents = + Hashtbl.find_opt dependents_by_name dependency + |> Option.value ~default:[] + in + Hashtbl.replace dependents_by_name dependency (node_name :: dependents)) + dependencies) + nodes_by_name; + {nodes_by_name; dependencies_by_name; dependents_by_name} + +let node_count index = Hashtbl.length index.nodes_by_name +let find_node index name = Hashtbl.find index.nodes_by_name name + +let dependencies index name = + Hashtbl.find_opt index.dependencies_by_name name |> Option.value ~default:[] + +let dependents index name = + Hashtbl.find_opt index.dependents_by_name name |> Option.value ~default:[] + +let dependency_count index name = List.length (dependencies index name) + +let cycle_blocked_nodes nodes ~name ~deps = + let index = + create_index nodes ~name ~deps + ~validation:Replace_duplicates_and_ignore_unknown + in + let pending = Hashtbl.create (node_count index) in + Hashtbl.iter + (fun node_name _ -> + Hashtbl.add pending node_name (dependency_count index node_name)) + index.nodes_by_name; + let ready = Queue.create () in + Hashtbl.iter (fun key count -> if count = 0 then Queue.add key ready) pending; + let removed = Hashtbl.create (node_count index) in + while not (Queue.is_empty ready) do + let key = Queue.take ready in + Hashtbl.replace removed key (); + dependents index key + |> List.iter (fun dependent -> + let count = Hashtbl.find pending dependent - 1 in + Hashtbl.replace pending dependent count; + if count = 0 then Queue.add dependent ready) + done; + List.filter (fun node -> not (Hashtbl.mem removed (name node))) nodes + +let canonical_cycle cycle = + let rec without_last = function + | [] | [_] -> [] + | value :: rest -> value :: without_last rest + in + let nodes = without_last cycle in + match nodes with + | [] -> cycle + | first :: rest -> + let smallest = List.fold_left min first rest in + let rec split prefix = function + | [] -> nodes + | head :: tail as suffix -> + if head = smallest then suffix @ List.rev prefix + else split (head :: prefix) tail + in + let canonical = split [] nodes in + canonical @ [smallest] + +let shortest_cycle_in_index index = + let names = + index.nodes_by_name |> Hashtbl.to_seq_keys |> List.of_seq + |> List.sort String.compare + in + let edges = Hashtbl.create (Hashtbl.length index.dependencies_by_name) in + List.iter + (fun name -> + List.iter + (fun dependency -> Hashtbl.replace edges (name, dependency) ()) + (dependencies index name)) + names; + match List.find_opt (fun name -> Hashtbl.mem edges (name, name)) names with + | Some name -> Some [name; name] + | None -> ( + let two_node_cycle = + names + |> List.find_map (fun name -> + dependencies index name + |> List.filter (fun dependency -> name < dependency) + |> List.sort String.compare + |> List.find_map (fun dependency -> + if Hashtbl.mem edges (dependency, name) then + Some [name; dependency; name] + else None)) + in + match two_node_cycle with + | Some _ as cycle -> cycle + | None -> + let next_index = ref 0 in + let indices = Hashtbl.create (List.length names) in + let lowlinks = Hashtbl.create (List.length names) in + let on_stack = Hashtbl.create (List.length names) in + let stack = Stack.create () in + let components = ref [] in + let rec visit name = + let index_value = !next_index in + incr next_index; + Hashtbl.add indices name index_value; + Hashtbl.add lowlinks name index_value; + Stack.push name stack; + Hashtbl.add on_stack name (); + dependencies index name + |> List.iter (fun dependency -> + match Hashtbl.find_opt indices dependency with + | None -> + visit dependency; + Hashtbl.replace lowlinks name + (min + (Hashtbl.find lowlinks name) + (Hashtbl.find lowlinks dependency)) + | Some dependency_index when Hashtbl.mem on_stack dependency -> + Hashtbl.replace lowlinks name + (min (Hashtbl.find lowlinks name) dependency_index) + | Some _ -> ()); + if Hashtbl.find lowlinks name = index_value then ( + let component = ref [] in + let complete = ref false in + while not !complete do + let member = Stack.pop stack in + Hashtbl.remove on_stack member; + component := member :: !component; + complete := member = name + done; + components := !component :: !components) + in + List.iter + (fun name -> if not (Hashtbl.mem indices name) then visit name) + names; + let component_by_name = Hashtbl.create (List.length names) in + !components + |> List.iteri (fun component_id component -> + if List.length component > 1 then + List.iter + (fun name -> Hashtbl.add component_by_name name component_id) + component); + let same_cyclic_component left right = + match + ( Hashtbl.find_opt component_by_name left, + Hashtbl.find_opt component_by_name right ) + with + | Some left, Some right -> left = right + | _ -> false + in + let best = ref None in + let best_length = ref max_int in + let consider cycle = + let cycle = canonical_cycle cycle in + match !best with + | None -> + best := Some cycle; + best_length := List.length cycle + | Some current -> + let cycle_length = List.length cycle in + if + cycle_length < !best_length + || (cycle_length = !best_length && cycle < current) + then ( + best := Some cycle; + best_length := cycle_length) + in + names + |> List.filter (Hashtbl.mem component_by_name) + |> List.iter (fun start -> + let queue = Queue.create () in + let parents = Hashtbl.create 16 in + let distances = Hashtbl.create 16 in + Hashtbl.add distances start 0; + Queue.add start queue; + let found = ref false in + while (not !found) && not (Queue.is_empty queue) do + let current = Queue.take queue in + let distance = Hashtbl.find distances current in + let can_improve = distance + 2 <= !best_length in + if can_improve then + dependencies index current + |> List.iter (fun dependency -> + if not (same_cyclic_component start dependency) then () + else if dependency = start then ( + let rec path_to_start acc node_name = + if node_name = start then start :: acc + else + path_to_start (node_name :: acc) + (Hashtbl.find parents node_name) + in + consider (path_to_start [] current @ [start]); + found := true) + else if not (Hashtbl.mem distances dependency) then ( + Hashtbl.add parents dependency current; + Hashtbl.add distances dependency (distance + 1); + Queue.add dependency queue)) + done); + !best) + +let shortest_cycle nodes ~name ~deps = + create_index nodes ~name ~deps + ~validation:Replace_duplicates_and_ignore_unknown + |> shortest_cycle_in_index diff --git a/rewatch-ocaml/graph.mli b/rewatch-ocaml/graph.mli new file mode 100644 index 00000000000..59b5005d2f1 --- /dev/null +++ b/rewatch-ocaml/graph.mli @@ -0,0 +1,33 @@ +(** Graph indexing is shared by cycle analysis and subprocess scheduling, but + their input contracts differ. The validation policy makes replacement or + rejection of duplicate and unknown nodes an explicit caller decision. *) +type validation = + | Replace_duplicates_and_ignore_unknown + | Reject_invalid of { + duplicate_node: string -> exn; + unknown_dependency: node:string -> dependency:string -> exn; + } + +type 'a index + +val create_index : + 'a list -> + name:('a -> string) -> + deps:('a -> string list) -> + validation:validation -> + 'a index + +val node_count : 'a index -> int +val find_node : 'a index -> string -> 'a +val dependencies : 'a index -> string -> string list +val dependents : 'a index -> string -> string list +val dependency_count : 'a index -> string -> int + +val cycle_blocked_nodes : + 'a list -> name:('a -> string) -> deps:('a -> string list) -> 'a list + +val shortest_cycle : + 'a list -> + name:('a -> string) -> + deps:('a -> string list) -> + string list option diff --git a/rewatch-ocaml/module_graph.ml b/rewatch-ocaml/module_graph.ml new file mode 100644 index 00000000000..f946363e61a --- /dev/null +++ b/rewatch-ocaml/module_graph.ml @@ -0,0 +1,382 @@ +type cycle_info = { + cycle: string list; + blocked: string list; + nodes_by_key: (string, cycle_node) Hashtbl.t; +} + +and cycle_node = { + key: string; + package_root: string; + source_path: string option; + display_name: string; +} + +type module_node = { + key: string; + package_name: string; + package_root: string; + source_path: string; + namespace: Config.namespace; + visible_packages: (string, unit) Hashtbl.t; + mutable raw_dependencies: string list; +} + +type namespace_map = { + key: string; + compiler_name: string; + namespace: string; + package_name: string; + package_root: string; + members: string list; +} + +let namespace_map_key package_root = "\000namespace:" ^ package_root + +let dependency_head dependency = + match String.split_on_char '.' dependency with + | head :: _ -> head + | [] -> dependency + +let compiler_namespace (config : Config.t) = + Config.namespace_compiler_name config.namespace + +let validate_visible_namespaces ~(root_config : Config.t) + (package_plans : Package_plan.t list) = + let by_root = Hashtbl.create (List.length package_plans) in + List.iter + (fun (package : Package_plan.t) -> + Hashtbl.replace by_root package.root package) + package_plans; + package_plans + |> List.sort (fun first second -> + String.compare first.Package_plan.root second.root) + |> List.iter (fun consumer -> + let visible = + consumer + :: (consumer.Package_plan.dependencies + |> List.filter_map (fun dependency -> + Hashtbl.find_opt by_root dependency.Package_plan.directory)) + in + let namespaces = Hashtbl.create (List.length visible) in + visible + |> List.sort (fun first second -> + String.compare first.Package_plan.root second.root) + |> List.iter (fun package -> + compiler_namespace package.Package_plan.compile_config + |> Option.iter (fun namespace -> + match Hashtbl.find_opt namespaces namespace with + | None -> Hashtbl.add namespaces namespace package + | Some previous when previous.Package_plan.root = package.root -> + () + | Some previous -> + let display package = + Printf.sprintf "%s (%s)" package.Package_plan.config.name + (Project_context.display_path ~root:root_config.root + package.root) + in + raise + (Project_context.Error + (Printf.sprintf + "Could not initialize build: Namespace %s is provided \ + by both %s and %s while building %s. Give the \ + packages distinct namespaces." + namespace (display previous) (display package) + (display consumer)))))) + +let resolve_dependency ~find_module ~find_namespace_maps (node : module_node) + dependency = + let raw_name = dependency_head dependency in + let local_name = + match + (Config.namespace_name node.namespace, String.split_on_char '.' dependency) + with + | Some namespace, first :: second :: _ when first = namespace -> second + | _ -> raw_name + in + let local_key = Config.namespaced_module_name node.namespace local_name in + let is_visible (dependency_node : module_node) = + Hashtbl.mem node.visible_packages dependency_node.package_name + in + match find_module local_key with + | Some dependency_node when is_visible dependency_node -> [local_key] + | _ when Config.namespace_name node.namespace = Some raw_name -> [] + | _ -> ( + match find_module raw_name with + | Some dependency_node when is_visible dependency_node -> [raw_name] + | _ -> ( + let explicit_namespaced_module = + match String.split_on_char '.' dependency with + | namespace :: module_name :: _ -> + [module_name ^ "-" ^ namespace; module_name ^ "-@" ^ namespace] + |> List.find_opt (fun key -> + match find_module key with + | Some dependency_node + when Config.namespace_name dependency_node.namespace + = Some namespace + && is_visible dependency_node -> + true + | Some _ | None -> false) + | _ -> None + in + match explicit_namespaced_module with + | Some key -> [key] + | None -> + find_namespace_maps raw_name + |> Option.value ~default:[] + |> List.filter_map (fun (namespace_map : namespace_map) -> + if Hashtbl.mem node.visible_packages namespace_map.package_name then + Some namespace_map.key + else None))) + +let resolved_dependencies ~find_module ~find_namespace_maps (node : module_node) + = + let parsed = + node.raw_dependencies + |> List.concat_map + (resolve_dependency ~find_module ~find_namespace_maps node) + in + let implicit_namespace_entry = + match node.namespace with + | Config.Namespace_with_entry {name = namespace; entry} + when Source.module_name node.source_path = entry -> + find_namespace_maps namespace + |> Option.value ~default:[] + |> List.find_map (fun (namespace_map : namespace_map) -> + if namespace_map.package_root = node.package_root then + Some namespace_map.key + else None) + |> Option.to_list + | Config.Namespace_with_entry _ | Config.Namespace _ | Config.No_namespace + -> + [] + in + parsed @ implicit_namespace_entry + |> List.filter (fun dependency -> dependency <> node.key) + |> List.sort_uniq String.compare + +let raw_dependencies ~build_dir ~parse_failed (module_ : Source.module_) = + let dependencies path = + if parse_failed path then [] + else Compiler_process.ast_dependencies ~build_dir (Source.ast_path path) + in + List.sort_uniq String.compare + (dependencies module_.implementation + @ + match module_.interface with + | None -> [] + | Some path -> dependencies path) + +type initialized = { + nodes: module_node list; + namespace_maps: namespace_map list; + build_state: Build_state.t; + use_existing_ast_paths: string list; +} + +let initialize ~(root_config : Config.t) ~package_plans ~compile_assets + ~failed_parse_paths = + let nodes = ref [] in + let use_existing_ast_paths = ref [] in + List.iter + (fun (package : Package_plan.t) -> + let visible_packages = + Hashtbl.create (List.length package.dependencies + 1) + in + Hashtbl.replace visible_packages package.name (); + List.iter + (fun (dependency : Package_plan.dependency) -> + Hashtbl.replace visible_packages dependency.declaration.name ()) + package.dependencies; + List.iter + (fun module_ -> + let raw_dependencies = + raw_dependencies ~build_dir:package.build_dir + ~parse_failed:(fun path -> + Hashtbl.mem failed_parse_paths + (Filename.concat package.root path)) + module_ + in + let compiler_base = + Source.compiler_basename package.compile_config module_.Source.name + in + if Option.is_none (Compile_assets.cmt compile_assets compiler_base) + then + use_existing_ast_paths := + Filename.concat package.root module_.Source.implementation + :: !use_existing_ast_paths; + nodes := + { + key = compiler_base; + package_name = package.name; + package_root = package.root; + source_path = module_.Source.implementation; + namespace = package.compile_config.namespace; + visible_packages; + raw_dependencies; + } + :: !nodes) + package.modules) + package_plans; + let nodes = + List.sort + (fun (first : module_node) second -> String.compare first.key second.key) + !nodes + in + let by_key : (string, module_node) Hashtbl.t = + Hashtbl.create (List.length nodes) + in + List.iter + (fun (node : module_node) -> + match Hashtbl.find_opt by_key node.key with + | None -> Hashtbl.add by_key node.key node + | Some previous -> + raise + (Source.duplicate_error ~display_root:root_config.root "" node.key + (Filename.concat previous.package_root previous.source_path) + (Filename.concat node.package_root node.source_path))) + nodes; + let namespace_maps = + package_plans + |> List.filter_map (fun (package : Package_plan.t) -> + let namespace = package.Package_plan.compile_config.namespace in + let namespace_details = + match namespace with + | Config.No_namespace -> None + | Config.Namespace name -> Some (name, name, None) + | Config.Namespace_with_entry {name; entry} -> + Some ("@" ^ name, name, Some entry) + in + namespace_details + |> Option.map (fun (compiler_name, name, namespace_entry) -> + let members = + Source.namespace_members ~entry:namespace_entry package.modules + |> List.map (fun module_ -> + Source.compiler_basename package.compile_config + module_.Source.name) + |> List.sort_uniq String.compare + in + { + key = namespace_map_key package.root; + compiler_name; + namespace = name; + package_name = package.name; + package_root = package.root; + members; + })) + in + let namespace_maps_by_name = Hashtbl.create (List.length namespace_maps) in + List.iter + (fun (namespace_map : namespace_map) -> + let existing = + Hashtbl.find_opt namespace_maps_by_name namespace_map.namespace + |> Option.value ~default:[] + in + Hashtbl.replace namespace_maps_by_name namespace_map.namespace + (namespace_map :: existing)) + namespace_maps; + let source_graph_nodes = + List.map + (fun (node : module_node) -> + ( node, + resolved_dependencies ~find_module:(Hashtbl.find_opt by_key) + ~find_namespace_maps:(Hashtbl.find_opt namespace_maps_by_name) + node )) + nodes + in + let build_state = + Build_state.create + (List.length source_graph_nodes + List.length namespace_maps) + in + let modified = Option.map (fun entry -> entry.Compile_assets.modified) in + List.iter + (fun ((node : module_node), _) -> + Build_state.add build_state ~key:node.key ~kind:Build_state.Source_module + ~last_compiled_cmi: + (Compile_assets.cmi compile_assets node.key |> modified) + ~last_compiled_cmt: + (Compile_assets.cmt compile_assets node.key |> modified)) + source_graph_nodes; + List.iter + (fun (namespace_map : namespace_map) -> + Build_state.add build_state ~key:namespace_map.key + ~kind:Build_state.Namespace_map + ~last_compiled_cmi: + (Compile_assets.cmi compile_assets namespace_map.compiler_name + |> modified) + ~last_compiled_cmt: + (Compile_assets.cmt compile_assets namespace_map.compiler_name + |> modified)) + namespace_maps; + List.iter + (fun ((node : module_node), dependencies) -> + Build_state.set_dependencies build_state ~key:node.key dependencies) + source_graph_nodes; + List.iter + (fun (namespace_map : namespace_map) -> + Build_state.set_dependencies build_state ~key:namespace_map.key + namespace_map.members) + namespace_maps; + { + nodes; + namespace_maps; + build_state; + use_existing_ast_paths = !use_existing_ast_paths; + } + +let find_cycle modules namespace_maps build_state = + let nodes_by_key = + Hashtbl.create (List.length modules + List.length namespace_maps) + in + List.iter + (fun (node : module_node) -> + let key = node.key in + let module_name = Source.module_name node.source_path in + let display_name = + match node.namespace with + | Config.Namespace_with_entry {name = namespace; entry} + when entry <> module_name -> + namespace ^ "." ^ module_name + | Config.Namespace namespace -> namespace ^ "." ^ module_name + | Config.Namespace_with_entry _ | Config.No_namespace -> module_name + in + Hashtbl.add nodes_by_key key + { + key; + package_root = node.package_root; + source_path = Some node.source_path; + display_name; + }) + modules; + List.iter + (fun (namespace_map : namespace_map) -> + let key = namespace_map.key in + Hashtbl.add nodes_by_key key + { + key; + package_root = namespace_map.package_root; + source_path = None; + display_name = namespace_map.compiler_name; + }) + namespace_maps; + let graph_nodes = + Hashtbl.to_seq_values nodes_by_key + |> List.of_seq + |> List.sort (fun (first : cycle_node) second -> + String.compare first.key second.key) + |> List.map (fun (node : cycle_node) -> + (node, (Build_state.find_exn build_state node.key).dependencies)) + in + let name ((node : cycle_node), _) = node.key in + let blocked_nodes = Graph.cycle_blocked_nodes graph_nodes ~name ~deps:snd in + match blocked_nodes with + | [] -> None + | _ -> + let cycle = + match Graph.shortest_cycle blocked_nodes ~name ~deps:snd with + | Some cycle -> cycle + | None -> + raise + (Project_context.Error + "cycle-blocked dependency graph contains no detectable cycle") + in + Some {cycle; blocked = List.map name blocked_nodes; nodes_by_key} diff --git a/rewatch-ocaml/module_graph.mli b/rewatch-ocaml/module_graph.mli new file mode 100644 index 00000000000..4c6406f4c3e --- /dev/null +++ b/rewatch-ocaml/module_graph.mli @@ -0,0 +1,72 @@ +(** Namespace maps are graph nodes because adding or removing a namespace + member can invalidate consumers even when no ordinary source dependency + name changes. The graph therefore contains both source modules and these + synthetic nodes. *) + +type cycle_info = { + cycle: string list; + blocked: string list; + nodes_by_key: (string, cycle_node) Hashtbl.t; +} + +and cycle_node = { + key: string; + package_root: string; + source_path: string option; + display_name: string; +} + +type module_node = { + key: string; + package_name: string; + package_root: string; + source_path: string; + namespace: Config.namespace; + visible_packages: (string, unit) Hashtbl.t; + mutable raw_dependencies: string list; +} + +type namespace_map = { + key: string; + compiler_name: string; + namespace: string; + package_name: string; + package_root: string; + members: string list; +} + +val namespace_map_key : string -> string + +val validate_visible_namespaces : + root_config:Config.t -> Package_plan.t list -> unit + +val resolved_dependencies : + find_module:(string -> module_node option) -> + find_namespace_maps:(string -> namespace_map list option) -> + module_node -> + string list + +val raw_dependencies : + build_dir:string -> + parse_failed:(string -> bool) -> + Source.module_ -> + string list +(** The sorted module names that a module's ASTs reference, skipping the + source paths whose parse failed. *) + +type initialized = { + nodes: module_node list; + namespace_maps: namespace_map list; + build_state: Build_state.t; + use_existing_ast_paths: string list; +} + +val initialize : + root_config:Config.t -> + package_plans:Package_plan.t list -> + compile_assets:Compile_assets.t -> + failed_parse_paths:(string, unit) Hashtbl.t -> + initialized + +val find_cycle : + module_node list -> namespace_map list -> Build_state.t -> cycle_info option diff --git a/rewatch-ocaml/native_watcher.ml b/rewatch-ocaml/native_watcher.ml new file mode 100644 index 00000000000..6f8b18ed70b --- /dev/null +++ b/rewatch-ocaml/native_watcher.ml @@ -0,0 +1,301 @@ +type change_kind = Content | Structural +type change = {path: string option; kind: change_kind} + +type wait_result = Changed of change list | Stopped | Failed of string + +type watch_path = {directory: string; recursive: bool} + +type watched_directory = { + directory: string; + identity: string; + handle: Luv.FS_event.t; +} + +type t = { + loop: Luv.Loop.t; + timer: Luv.Timer.t; + mutable handles: watched_directory list; + mutable changes: change list; + mutable stopped: bool; + mutable error: string option; +} + +let error_message error = + Printf.sprintf "%s: %s" (Luv.Error.err_name error) (Luv.Error.strerror error) + +let is_compiler_artifact_directory path = + let name = Filename.basename path in + (name = "bs" || name = "ocaml") + && Filename.basename (Filename.dirname path) = "lib" + +let directories_under paths = + let visited = Hashtbl.create 64 in + let rec walk acc directory = + match Platform.canonicalize_path directory with + | canonical -> ( + if Hashtbl.mem visited canonical then acc + else + let entries = + try Some (File_util.directory_entries canonical) + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> None + in + match entries with + | None -> acc + | Some entries -> + Hashtbl.add visited canonical (); + entries + |> List.fold_left + (fun acc name -> + let path = Filename.concat canonical name in + if is_compiler_artifact_directory path then acc + else + match Unix.stat path with + | stat -> + if stat.Unix.st_kind = Unix.S_DIR then walk acc path + else acc + | exception + Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> + acc) + (canonical :: acc)) + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> acc + in + paths + |> List.fold_left + (fun directories path -> + if path.recursive then walk directories path.directory + else + match Platform.canonicalize_path path.directory with + | canonical -> canonical :: directories + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> + directories) + [] + |> List.sort_uniq String.compare + +let close_fs_handles loop handles = + let pending = ref 0 in + List.iter + (fun handle -> + ignore (Luv.FS_event.stop handle); + if not (Luv.Handle.is_closing handle) then ( + incr pending; + Luv.Handle.close handle (fun () -> decr pending))) + handles; + while !pending > 0 do + ignore (Luv.Loop.run ~loop ~mode:`NOWAIT ()) + done + +let close_timer loop timer = + if not (Luv.Handle.is_closing timer) then ( + let closed = ref false in + Luv.Handle.close timer (fun () -> closed := true); + while not !closed do + ignore (Luv.Loop.run ~loop ~mode:`NOWAIT ()) + done) + +let remove_handles watcher = + close_fs_handles watcher.loop + (List.map (fun watched -> watched.handle) watcher.handles); + watcher.handles <- [] + +let close watcher = + remove_handles watcher; + ignore (Luv.Timer.stop watcher.timer); + close_timer watcher.loop watcher.timer; + ignore (Luv.Loop.close watcher.loop) + +let directory_identity directory = + try + let metadata = Unix.stat directory in + Ok (Platform.directory_identity ~path:directory metadata) + with (Sys_error _ | Unix.Unix_error _) as error -> + Error + (Printf.sprintf "could not identify watched directory %s: %s" directory + (Printexc.to_string error)) + +let identify_directories ~directory_identity directories = + let rec identify identified = function + | [] -> Ok (List.rev identified) + | directory :: rest -> ( + match directory_identity directory with + | Ok identity -> identify ((directory, identity) :: identified) rest + | Error _ as error -> error) + in + identify [] directories + +let install_handles watcher identified_directories = + let existing = Hashtbl.create (List.length watcher.handles) in + List.iter + (fun watched -> Hashtbl.add existing watched.directory ()) + watcher.handles; + let install (directory, identity) = + if not (Hashtbl.mem existing directory) then + match Luv.FS_event.init ~loop:watcher.loop () with + | Error error -> watcher.error <- Some (error_message error) + | Ok handle -> + watcher.handles <- {directory; identity; handle} :: watcher.handles; + Luv.FS_event.start handle directory (function + | Ok (filename, events) -> + let path = + match filename with + | None | Some "" -> None + | Some filename -> + Some + (if Filename.is_relative filename then + Filename.concat directory filename + else filename) + in + let kind = + if List.mem `CHANGE events && not (List.mem `RENAME events) then + Content + else Structural + in + watcher.changes <- {path; kind} :: watcher.changes; + Luv.Loop.stop watcher.loop + | Error error -> + watcher.error <- Some (error_message error); + Luv.Loop.stop watcher.loop) + in + List.iter install identified_directories; + match watcher.error with + | None -> Ok () + | Some message -> Error message + +let wait watcher ~keep_running = + watcher.stopped <- not (keep_running ()); + (* Events can arrive while refresh closes handles and pumps the libuv loop. + Consume the event that wakes this call, but never erase one already queued + by reconciliation before the next wait begins. A failed handle or an + external stop must take precedence because another reconciliation could + otherwise erase the condition that requires native watch to end. *) + let ready_result () = + match watcher.error with + | Some message -> Some (Failed message) + | None when watcher.stopped -> Some Stopped + | None when watcher.changes <> [] -> + let changes = List.rev watcher.changes in + watcher.changes <- []; + Some (Changed changes) + | None -> None + in + match ready_result () with + | Some result -> result + | None -> ( + let check_running () = + try + if not (keep_running ()) then ( + watcher.stopped <- true; + Luv.Loop.stop watcher.loop) + with error -> + watcher.error <- Some (Printexc.to_string error); + Luv.Loop.stop watcher.loop + in + (match Luv.Timer.start ~repeat:100 watcher.timer 100 check_running with + | Ok () -> () + | Error error -> watcher.error <- Some (error_message error)); + while + watcher.changes = [] && (not watcher.stopped) + && Option.is_none watcher.error + do + ignore (Luv.Loop.run ~loop:watcher.loop ~mode:`ONCE ()) + done; + ignore (Luv.Timer.stop watcher.timer); + match ready_result () with + | Some result -> result + | None -> Failed "native watcher loop stopped without a wakeup condition") + +let drain watcher = + (* The first callback stops the loop so the build can start promptly. Pump + already-ready callbacks after the debounce window to keep one editor save + together without waiting for another build cycle. *) + let rec pump remaining = + if remaining > 0 then ( + let changes = watcher.changes in + ignore (Luv.Loop.run ~loop:watcher.loop ~mode:`NOWAIT ()); + if watcher.changes != changes then pump (remaining - 1)) + in + pump 1024; + let changes = List.rev watcher.changes in + watcher.changes <- []; + changes + +let watches_directory watcher path = + List.exists (fun watched -> watched.directory = path) watcher.handles + +let refresh_with_directory_identity ~directory_identity watcher ~paths = + (* Only failures from work completed before this refresh are stale. Clear + them before pumping close callbacks so a newly reported handle failure is + preserved and makes the caller fall back to polling. *) + watcher.error <- None; + match + try Ok (directories_under paths) + with (Unix.Unix_error _ | Sys_error _) as error -> + Error (Printexc.to_string error) + with + | Error _ as error -> error + | Ok directories -> ( + match identify_directories ~directory_identity directories with + | Error _ as error -> error + | Ok identified_directories -> + let desired = Hashtbl.create (List.length directories) in + List.iter + (fun (directory, identity) -> Hashtbl.add desired directory identity) + identified_directories; + let kept, removed = + List.partition + (fun watched -> + Hashtbl.find_opt desired watched.directory = Some watched.identity) + watcher.handles + in + close_fs_handles watcher.loop + (List.map (fun watched -> watched.handle) removed); + watcher.handles <- kept; + install_handles watcher identified_directories) + +let refresh = refresh_with_directory_identity ~directory_identity + +(* Creating a watcher refreshes an empty one, so creation and later refreshes + install handles the same way. *) +let create_with_directory_identity ~directory_identity ~paths = + match Luv.Loop.init () with + | Error error -> Error (error_message error) + | Ok loop -> ( + match Luv.Timer.init ~loop () with + | Error error -> + ignore (Luv.Loop.close loop); + Error (error_message error) + | Ok timer -> ( + let watcher = + {loop; timer; handles = []; changes = []; stopped = false; error = None} + in + let fail message = + try + close watcher; + Error message + with cleanup_error -> + Error + (Printf.sprintf "%s (native watcher cleanup failed: %s)" message + (Printexc.to_string cleanup_error)) + in + match + try refresh_with_directory_identity ~directory_identity watcher ~paths + with error -> Error (Printexc.to_string error) + with + | Ok () -> Ok watcher + | Error message -> fail message)) + +let create = create_with_directory_identity ~directory_identity + +module For_test = struct + let create_with_directory_identity = create_with_directory_identity + let refresh_with_directory_identity = refresh_with_directory_identity + let handle_count watcher = List.length watcher.handles + let directory_identity watcher directory = + watcher.handles + |> List.find_opt (fun watched -> watched.directory = directory) + |> Option.map (fun watched -> watched.identity) + + let queue_change watcher = + watcher.changes <- {path = None; kind = Structural} :: watcher.changes + + let queue_error watcher message = watcher.error <- Some message +end diff --git a/rewatch-ocaml/native_watcher.mli b/rewatch-ocaml/native_watcher.mli new file mode 100644 index 00000000000..089a30fcb02 --- /dev/null +++ b/rewatch-ocaml/native_watcher.mli @@ -0,0 +1,37 @@ +type t +(** A native watcher is only a low-latency notification source. Callers must + reconcile notifications against {!Watch_snapshot}; operating systems may + merge, duplicate, reorder, or omit the pathname attached to an event. *) + +type change_kind = Content | Structural +type change = {path: string option; kind: change_kind} + +type watch_path = {directory: string; recursive: bool} + +type wait_result = Changed of change list | Stopped | Failed of string + +val create : paths:watch_path list -> (t, string) result +val is_compiler_artifact_directory : string -> bool +val wait : t -> keep_running:(unit -> bool) -> wait_result +val drain : t -> change list +val watches_directory : t -> string -> bool +val refresh : t -> paths:watch_path list -> (unit, string) result +val close : t -> unit + +module For_test : sig + val create_with_directory_identity : + directory_identity:(string -> (string, string) result) -> + paths:watch_path list -> + (t, string) result + + val refresh_with_directory_identity : + directory_identity:(string -> (string, string) result) -> + t -> + paths:watch_path list -> + (unit, string) result + + val handle_count : t -> int + val directory_identity : t -> string -> string option + val queue_change : t -> unit + val queue_error : t -> string -> unit +end diff --git a/rewatch-ocaml/output.ml b/rewatch-ocaml/output.ml new file mode 100644 index 00000000000..3dff6a84c00 --- /dev/null +++ b/rewatch-ocaml/output.ml @@ -0,0 +1,204 @@ +let line_clear = "\027[2K\r" + +(* Like Rust rewatch, logs go to stdout by default. Commands whose stdout is + machine-readable output (compiler-args, format) log to stderr instead. *) +let log ?(channel = stdout) ~minimum ~verbosity ~label message = + if verbosity >= minimum then + Printf.fprintf channel "%s:\n%s\n%!" label message + +let debug ?channel ~verbosity message = + log ?channel ~minimum:1 ~verbosity ~label:"DEBUG" message + +let trace ?channel ~verbosity message = + log ?channel ~minimum:2 ~verbosity ~label:"TRACE" message +let trace_enabled verbosity = verbosity >= 2 + +let format_step ~color step = + if color then Printf.sprintf "\027[1m\027[2m[%s]\027[0m" step + else Printf.sprintf "[%s]" step + +module Progress = struct + type phase = { + step: string; + symbol: string; + label: string; + total: int; + mutable position: int; + } + + type t = { + enabled: bool; + color: bool; + mutable phase: phase option; + mutable frame: int; + mutable next_draw: float; + } + + let frames = [|"⠁"; "⠂"; "⠄"; "⡀"; "⢀"; "⠠"; "⠐"; "⠈"|] + let create ~enabled ~color = + {enabled; color; phase = None; frame = 0; next_draw = 0.} + + let draw ?(force = false) progress = + if progress.enabled then + match progress.phase with + | None -> () + | Some phase -> + let now = Unix.gettimeofday () in + if force || now >= progress.next_draw then ( + let spinner = frames.(progress.frame mod Array.length frames) in + progress.frame <- progress.frame + 1; + progress.next_draw <- now +. 0.08; + Printf.printf "%s%s %s%s... %s %d/%d %!" line_clear + (format_step ~color:progress.color phase.step) + phase.symbol phase.label spinner phase.position phase.total) + + let start progress ~step ~symbol ~label ~total = + progress.phase <- Some {step; symbol; label; total; position = 0}; + progress.frame <- 0; + progress.next_draw <- 0.; + draw ~force:true progress + + let advance progress = + Option.iter + (fun phase -> + if phase.position < phase.total then + phase.position <- phase.position + 1) + progress.phase; + draw progress + + let tick progress = draw progress + let finish progress = progress.phase <- None + + let debug progress ~verbosity message = + if verbosity >= 1 then ( + let redraw = progress.enabled && Option.is_some progress.phase in + if redraw then Printf.printf "%s%!" line_clear; + log ~minimum:1 ~verbosity ~label:"DEBUG" message; + if redraw then draw ~force:true progress) + + let start_grouped progress ~step ~symbol ~label groups = + let remaining = Hashtbl.create (List.length groups) in + List.iter + (fun group -> + let count = + Hashtbl.find_opt remaining group |> Option.value ~default:0 + in + Hashtbl.replace remaining group (count + 1)) + groups; + start progress ~step ~symbol ~label ~total:(Hashtbl.length remaining); + let groups = Array.of_list groups in + fun index -> + let group = groups.(index) in + let count = Hashtbl.find remaining group - 1 in + Hashtbl.replace remaining group count; + if count = 0 then advance progress +end + +let yellow text = + if String.starts_with ~prefix:"\n" text then + "\n\027[33m" ^ String.sub text 1 (String.length text - 1) ^ "\027[0m" + else "\027[33m" ^ text ^ "\027[0m" + +let colors_enabled_with ~getenv ~win32 ~interactive = + let nonzero name default = + match getenv name with + | None -> default + | Some value -> value <> "0" + in + let terminal_supports_color = + interactive + && + if win32 then true + else + Option.is_none (getenv "NO_COLOR") + && + match getenv "TERM" with + | Some term -> term <> "dumb" + | None -> false + in + (terminal_supports_color && nonzero "CLICOLOR" true) + || nonzero "CLICOLOR_FORCE" false + +(* Removes SGR sequences (ESC [ parameters m), the only escapes Cmdliner + writes into its diagnostics. *) +let strip_sgr text = + let length = String.length text in + let buffer = Buffer.create length in + let rec sequence_end index = + if index >= length then None + else + match text.[index] with + | '0' .. '9' | ';' -> sequence_end (index + 1) + | 'm' -> Some (index + 1) + | _ -> None + in + let rec copy index = + if index < length then + if text.[index] = '\027' && index + 1 < length && text.[index + 1] = '[' + then ( + match sequence_end (index + 2) with + | Some next -> copy next + | None -> + Buffer.add_char buffer text.[index]; + copy (index + 1)) + else ( + Buffer.add_char buffer text.[index]; + copy (index + 1)) + in + copy 0; + Buffer.contents buffer + +let colors_enabled ~interactive = + colors_enabled_with ~getenv:Sys.getenv_opt + ~win32:Platform.terminal_supports_color_without_term ~interactive + +let cleanup_message ~color ~step ~cleaned ~total ~seconds = + Printf.sprintf "%s%s %sCleaned %d/%d in %.2fs" line_clear + (format_step ~color step) Platform.clean_symbol cleaned total seconds + +let compiler_cleanup_message ~color ~step = + Printf.sprintf "%s%s %sCleaned previous build due to compiler update" + line_clear (format_step ~color step) Platform.clean_symbol + +let cleaning_command_message ~color ~step target = + Printf.sprintf "%s%s %sCleaning %s..." line_clear (format_step ~color step) + Platform.clean_symbol target + +let cleaned_command_message ~color ~step ~target ~seconds = + Printf.sprintf "%s%s %sCleaned %s in %.2fs" line_clear + (format_step ~color step) Platform.clean_symbol target seconds + +let parsing_message ~color ~step ~count ~seconds = + Printf.sprintf "%s%s %sParsed %d source files in %.2fs" line_clear + (format_step ~color step) Platform.parse_symbol count seconds + +let parsing_failed_message ~color ~step ~seconds = + Printf.sprintf "%s%s %sError parsing source files in %.2fs" line_clear + (format_step ~color step) Platform.error_symbol seconds + +let compiling_message ~color ~step ~count ~seconds = + Printf.sprintf "%s%s %sCompiled %d modules in %.2fs" line_clear + (format_step ~color step) Platform.build_symbol count seconds + +let compilation_failed_message ~color ~step ~count ~seconds = + Printf.sprintf "%s%s %sCompiled %d modules in %.2fs" line_clear + (format_step ~color step) Platform.error_symbol count seconds + +type compilation_label = Standard | Initial | Incremental + +let finished_compilation_message ~label ~warnings ~seconds = + let status = + if warnings then Platform.warning_symbol else Platform.success_symbol + in + let kind = + match label with + | Standard -> "" + | Initial -> "initial " + | Incremental -> "incremental " + in + let warning_suffix = if warnings then " with warnings" else "" in + Printf.sprintf "%s%sFinished %scompilation%s in %.2fs" line_clear status kind + warning_suffix seconds + +let should_clear_screen ~clear_screen ~show_progress ~interactive = + clear_screen && show_progress && interactive diff --git a/rewatch-ocaml/output.mli b/rewatch-ocaml/output.mli new file mode 100644 index 00000000000..5613e1c3210 --- /dev/null +++ b/rewatch-ocaml/output.mli @@ -0,0 +1,62 @@ +val debug : ?channel:out_channel -> verbosity:int -> string -> unit +val trace : ?channel:out_channel -> verbosity:int -> string -> unit +val trace_enabled : int -> bool + +module Progress : sig + type t + + val create : enabled:bool -> color:bool -> t + + val start : + t -> step:string -> symbol:string -> label:string -> total:int -> unit + + val advance : t -> unit + val tick : t -> unit + val finish : t -> unit + val debug : t -> verbosity:int -> string -> unit + + val start_grouped : + t -> step:string -> symbol:string -> label:string -> 'a list -> int -> unit +end + +val yellow : string -> string + +val colors_enabled_with : + getenv:(string -> string option) -> win32:bool -> interactive:bool -> bool + +val colors_enabled : interactive:bool -> bool +val strip_sgr : string -> string + +val cleanup_message : + color:bool -> + step:string -> + cleaned:int -> + total:int -> + seconds:float -> + string + +val compiler_cleanup_message : color:bool -> step:string -> string +val cleaning_command_message : color:bool -> step:string -> string -> string + +val cleaned_command_message : + color:bool -> step:string -> target:string -> seconds:float -> string + +val parsing_message : + color:bool -> step:string -> count:int -> seconds:float -> string + +val parsing_failed_message : + color:bool -> step:string -> seconds:float -> string + +val compiling_message : + color:bool -> step:string -> count:int -> seconds:float -> string + +val compilation_failed_message : + color:bool -> step:string -> count:int -> seconds:float -> string + +type compilation_label = Standard | Initial | Incremental + +val finished_compilation_message : + label:compilation_label -> warnings:bool -> seconds:float -> string + +val should_clear_screen : + clear_screen:bool -> show_progress:bool -> interactive:bool -> bool diff --git a/rewatch-ocaml/package_build.ml b/rewatch-ocaml/package_build.ml new file mode 100644 index 00000000000..f6c515b49ac --- /dev/null +++ b/rewatch-ocaml/package_build.ml @@ -0,0 +1,44 @@ +exception Error = Project_context.Error + +let rec prepare_tree ~seen ~(package : Package_plan.t) ~prepared ~watch + ~(attempt : Build_attempt.t) = + let root = package.root in + Hashtbl.replace seen root (); + attempt.diagnostics <- + List.rev_append + (Package_diagnostics.for_package ~is_local:package.is_local package.config) + attempt.diagnostics; + List.iter + (fun (dependency : Package_plan.dependency) -> + let root = dependency.directory in + if not (Hashtbl.mem seen root) then + match Build_session.find_package_plan attempt.session root with + | None -> () + | Some dependency_package -> + prepare_tree ~seen ~package:dependency_package ~prepared ~watch + ~attempt) + package.dependencies; + File_util.ensure_dir package.build_dir; + File_util.ensure_dir package.ocaml_dir; + Compiler_log.initialize root; + Build_attempt.mark_log_initialized attempt root; + let prepared_package = + match Hashtbl.find_opt prepared.Build_session.packages root with + | Some package -> package + | None -> + raise (Error ("Package build was not prepared for " ^ package.root)) + in + let present_public_outputs = + match Build_session.find_public_outputs attempt.session root with + | Some outputs -> outputs + | None -> raise (Error ("Package cleanup was not prepared for " ^ root)) + in + let removed_module_names = Hashtbl.create 8 in + Build_attempt.removed_package_modules attempt root + |> List.iter (fun module_name -> + Hashtbl.replace removed_module_names module_name ()); + let parse_dirty_modules = + Package_parse.run ~package ~prepared ~attempt ~removed_module_names + in + Package_compilation.prepare ~package ~prepared ~prepared_package ~attempt + ~watch ~present_public_outputs ~removed_module_names ~parse_dirty_modules diff --git a/rewatch-ocaml/package_build.mli b/rewatch-ocaml/package_build.mli new file mode 100644 index 00000000000..bcdbc8f8635 --- /dev/null +++ b/rewatch-ocaml/package_build.mli @@ -0,0 +1,11 @@ +val prepare_tree : + seen:(string, unit) Hashtbl.t -> + package:Package_plan.t -> + prepared:Build_session.prepared -> + watch:bool -> + attempt:Build_attempt.t -> + unit +(** Package preparation remains recursive because dependencies must register + their compiler work before a consumer can be scheduled. [seen] prevents a + package graph cycle or duplicate dependency edge from preparing a package + twice within the attempt. *) diff --git a/rewatch-ocaml/package_compilation.ml b/rewatch-ocaml/package_compilation.ml new file mode 100644 index 00000000000..9ac565e481b --- /dev/null +++ b/rewatch-ocaml/package_compilation.ml @@ -0,0 +1,199 @@ +let prepare ~(package : Package_plan.t) ~(prepared : Build_session.prepared) + ~(prepared_package : Package_plan.compilation) ~(attempt : Build_attempt.t) + ~watch ~present_public_outputs ~removed_module_names ~parse_dirty_modules = + let root = package.root in + let is_local = package.is_local in + let config = package.compile_config in + let build_state = prepared.build_state in + let compile_assets = prepared.compile_assets in + let build_dir = package.build_dir in + let ocaml_dir = package.ocaml_dir in + let modules = package.modules in + let module_is_dirty module_ (state : Build_state.module_) = + let global_key = Source.compiler_basename config module_.Source.name in + let module_name = Source.module_name module_.Source.implementation in + let source_artifact_is_pending path = + let source = Filename.concat root path in + match + (Compile_assets.ast compile_assets source, state.last_compiled_cmt) + with + | Some ast, Some cmt_time -> ast.modified >= cmt_time + | Some _, None -> true + | None, _ -> false + in + let outputs_exist = + List.for_all + (fun spec -> + Hashtbl.mem present_public_outputs + (Build_artifacts.generated_js_path config + module_.Source.implementation spec)) + config.package_specs + in + let raw_dependencies = + match Build_session.find_global_module attempt.session global_key with + | Some node -> node.raw_dependencies + | None -> + raise + (Project_context.Error + ("Build module was not prepared for " ^ global_key)) + in + let dependency_is_newer dependency = + let dependency_state = Build_state.find_exn build_state dependency in + Build_state.dependency_tree_compiled_after + ~namespace_freshness:attempt.namespace_freshness build_state state + dependency_state + in + Hashtbl.mem parse_dirty_modules module_.Source.name + || Hashtbl.mem removed_module_names module_name + || List.exists source_artifact_is_pending + (module_.Source.implementation + :: Option.to_list module_.Source.interface) + || (not (Build_state.has_complete_compile_assets state)) + || (not outputs_exist) + || List.exists + (fun dependency -> Hashtbl.mem attempt.removed_modules dependency) + raw_dependencies + || List.exists dependency_is_newer state.dependencies + in + if attempt.freshness_mode = Build_attempt.Initialize_freshness then + List.iter + (fun module_ -> + let key = Source.compiler_basename config module_.Source.name in + let state = Build_state.find_exn build_state key in + state.compile_dirty <- + state.compile_dirty || module_is_dirty module_ state) + modules; + if not (Build_attempt.has_parse_error attempt.parse_messages) then ( + attempt.parsed <- attempt.parsed + Hashtbl.length parse_dirty_modules; + let compile_warning_paths = Hashtbl.create 8 in + let prepare_outputs module_ = + let path = module_.Source.implementation in + List.iter + (fun spec -> + let output = Build_artifacts.generated_js_path config path spec in + File_util.ensure_dir (Filename.dirname output)) + config.package_specs + in + let compile_process module_ ~source_kind path = + Compiler_process.compile_job ~bsc:prepared.compiler_context.bsc_path + ~build_dir ~config + ~common_args: + (if module_.Source.is_dev then + prepared_package.development_common_args + else prepared_package.regular_common_args) + module_ ~source_kind path + in + let record_published_outputs ~source_kind path = + match source_kind with + | Source.Interface -> () + | Source.Implementation -> + List.iter + (fun spec -> + let output = Build_artifacts.generated_js_path config path spec in + [output; output ^ ".map"] + |> List.iter (fun path -> + if File_util.is_regular_file path then + Hashtbl.replace present_public_outputs path ())) + config.package_specs + in + let candidates = + List.filter_map + (fun module_ -> + let key = Source.compiler_basename config module_.Source.name in + let state = Build_state.find_exn build_state key in + if Hashtbl.mem attempt.blocked_modules key then None + else + let cmi_path = + Filename.concat ocaml_dir + (Source.compiler_asset_basename config + module_.Source.implementation + ^ ".cmi") + in + let warning_paths = + module_.Source.implementation + :: Option.to_list module_.Source.interface + |> List.map (Filename.concat config.root) + in + let make () = + Compiler_scheduler.create ~key ~dependencies:state.dependencies + ~source:module_ ~state ~cmi_path + ~prepare:(fun () -> prepare_outputs module_) + ~compile:(fun ~source_kind path -> + compile_process module_ ~source_kind path) + ~publish:(fun ~source_kind path result -> + Compiler_process.publish ~build_dir ~ocaml_dir ~is_local + ~config + ~has_interface:(Option.is_some module_.Source.interface) + ~source_kind path result) + ~record_published_outputs + ~post_build:(Compiler_process.post_build_tasks config) + ~package_root:config.root ~is_local + ~mark_warning:(fun _path -> + module_.Source.implementation + :: Option.to_list module_.Source.interface + |> List.iter (fun path -> + Hashtbl.replace compile_warning_paths + (Build_artifacts.published_ast_path ~ocaml_dir path) + ())) + in + Some (Compiler_scheduler.candidate ~key ~state ~warning_paths ~make)) + modules + in + Config.namespace_compiler_name config.namespace + |> Option.iter (fun compiler_name -> + let namespace_map = + Build_session.find_namespace_map attempt.session + (Module_graph.namespace_map_key root) + in + let namespace_state = + Build_state.find_exn build_state namespace_map.key + in + let package_dirty = + List.exists Compiler_scheduler.candidate_requires_compile candidates + in + if + package_dirty || namespace_state.compile_dirty + || attempt.freshness_mode = Build_attempt.Initialize_freshness + then + Compiler_process.namespace_task + ~bsc:prepared.compiler_context.bsc_path + ~runtime:prepared.compiler_context.runtime_path ~build_dir + ~ocaml_dir + ~entry:(Config.namespace_entry config.namespace) + ~package_dirty ~force:namespace_state.compile_dirty compiler_name + modules + |> Option.iter (fun namespace_task -> + namespace_state.compile_dirty <- true; + let cmi_path = + Filename.concat ocaml_dir (compiler_name ^ ".cmi") + in + let finish result = + if not (Process.succeeded result) then + ignore (namespace_task.Compiler_scheduler.publish result) + else + match + Compiler_scheduler.capture_publication (fun () -> + namespace_task.Compiler_scheduler.publish result) + with + | Compiler_scheduler.Published {cmi_change; _} -> + Build_state.record_published_cmi build_state ~compile_assets + namespace_state ~path:cmi_path cmi_change; + let cmt_path = + Filename.concat ocaml_dir (compiler_name ^ ".cmt") + in + Build_state.record_successful_compile ~compile_assets + namespace_state ~cmt_path + | Compiler_scheduler.Failed_after_cmi_publication + {error; cmi_change} -> + Build_state.record_published_cmi build_state ~compile_assets + namespace_state ~path:cmi_path cmi_change; + raise error + in + Build_attempt.add_namespace_job attempt + Build_attempt.{job = namespace_task.job; finish})); + Build_attempt.add_compile_candidates attempt candidates; + Build_attempt.register_cleanup attempt (fun () -> + if not watch then + Hashtbl.iter + (fun path () -> File_util.remove_file path) + compile_warning_paths)) diff --git a/rewatch-ocaml/package_compilation.mli b/rewatch-ocaml/package_compilation.mli new file mode 100644 index 00000000000..6f0fb22fa20 --- /dev/null +++ b/rewatch-ocaml/package_compilation.mli @@ -0,0 +1,14 @@ +val prepare : + package:Package_plan.t -> + prepared:Build_session.prepared -> + prepared_package:Package_plan.compilation -> + attempt:Build_attempt.t -> + watch:bool -> + present_public_outputs:(string, unit) Hashtbl.t -> + removed_module_names:(string, unit) Hashtbl.t -> + parse_dirty_modules:(string, unit) Hashtbl.t -> + unit +(** Compilation preparation turns one stable package plan into the parse, + namespace, and compiler work owned by the current attempt. It records + pending work separately from scheduler eligibility so cycle-blocked modules + remain dirty for a later recovery build. *) diff --git a/rewatch-ocaml/package_diagnostics.ml b/rewatch-ocaml/package_diagnostics.ml new file mode 100644 index 00000000000..ffb71567d47 --- /dev/null +++ b/rewatch-ocaml/package_diagnostics.ml @@ -0,0 +1,125 @@ +let member name = function + | `Assoc fields -> List.assoc_opt name fields + | _ -> None + +let last_member name = function + | `Assoc fields -> List.assoc_opt name (List.rev fields) + | _ -> None + +let package_name package_root = + let path = Filename.concat package_root "package.json" in + try + if not (File_util.exists path) then Ok None + else + let json = Yojson.Safe.from_file path in + match last_member "name" json with + | Some (`String name) -> Ok (Some name) + | Some _ | None -> Ok None + with + | Sys_error message -> Error ("Could not read package.json: " ^ message) + | Unix.Unix_error (error, _, _) -> + Error ("Could not read package.json: " ^ Unix.error_message error) + | Yojson.Json_error message -> + Error ("Could not parse package.json: " ^ message) + +let url_value = function + | `String value -> Some value + | `Assoc fields -> ( + match List.assoc_opt "url" fields with + | Some (`String value) -> Some value + | _ -> None) + | _ -> None + +let remove_prefix prefix value = + if String.starts_with ~prefix value then + String.sub value (String.length prefix) + (String.length value - String.length prefix) + else value + +let remove_suffix suffix value = + if String.ends_with ~suffix value then + String.sub value 0 (String.length value - String.length suffix) + else value + +let issues_url_from_repository repository = + let cleaned = repository |> remove_prefix "git+" |> remove_suffix ".git" in + if + (not (String.contains cleaned '@')) + && not (String_util.contains cleaned "://") + then + let path = remove_prefix "github:" cleaned in + "https://github.com/" ^ path ^ "/issues" + else cleaned ^ "/issues" + +let issue_tracker_url package_root = + let path = Filename.concat package_root "package.json" in + try + let json = Yojson.Safe.from_file path in + match Option.bind (member "bugs" json) url_value with + | Some url -> Some url + | None -> + Option.bind (member "repository" json) url_value + |> Option.map issues_url_from_repository + with Sys_error _ | Yojson.Json_error _ -> None + +let for_package ~is_local (config : Config.t) = + if is_local then config.diagnostics + else if config.deprecation_diagnostics = [] then [] + else + let report_suffix = + issue_tracker_url config.root + |> Option.map (fun url -> + "\nPlease report this to the package maintainer: " ^ url) + |> Option.value ~default:"" + in + List.map + (fun diagnostic -> diagnostic ^ report_suffix) + config.deprecation_diagnostics + +let report_missing_source_folder (config : Config.t) path = + let prefix = Filename.concat config.root "" in + let relative = + if String.starts_with ~prefix path then + String.sub path (String.length prefix) + (String.length path - String.length prefix) + else path + in + Printf.eprintf + "ERROR:\n\ + Could not read folder: %S. Specified in dependency: %s, located %S...\n\ + %!" + relative config.name config.root + +let report_missing_sources ~is_root (config : Config.t) = + if (not is_root) && not config.sources_defined then + Printf.eprintf + "WARN:\n\ + Package '%s' has not defined any sources, but is not the root package. \ + This is likely a mistake. It is located: %s\n\ + %!" + config.name config.root + +let package_identity ~report_diagnostics (config : Config.t) = + match package_name config.root with + | Error message -> + raise (Project_context.Error ("Could not initialize build: " ^ message)) + | Ok (Some package_name) when package_name <> config.name -> + if report_diagnostics then + Printf.eprintf + "WARN:\n\n\ + Package name mismatch for %s:\n\ + The package.json name is %S, while the rescript.json name is %S\n\ + This inconsistency will cause issues with package resolution.\n\n\ + %!" + config.root package_name config.name; + package_name + | Ok (Some package_name) -> package_name + | Ok None -> config.name + +let validate_metadata config = + ignore (package_identity ~report_diagnostics:true config) + +module For_test = struct + let package_name = package_name + let issue_tracker_url = issue_tracker_url +end diff --git a/rewatch-ocaml/package_diagnostics.mli b/rewatch-ocaml/package_diagnostics.mli new file mode 100644 index 00000000000..8bcccf0057f --- /dev/null +++ b/rewatch-ocaml/package_diagnostics.mli @@ -0,0 +1,10 @@ +val for_package : is_local:bool -> Config.t -> string list +val report_missing_source_folder : Config.t -> string -> unit +val report_missing_sources : is_root:bool -> Config.t -> unit +val package_identity : report_diagnostics:bool -> Config.t -> string +val validate_metadata : Config.t -> unit + +module For_test : sig + val package_name : string -> (string option, string) result + val issue_tracker_url : string -> string option +end diff --git a/rewatch-ocaml/package_graph.ml b/rewatch-ocaml/package_graph.ml new file mode 100644 index 00000000000..b49dc26b1b5 --- /dev/null +++ b/rewatch-ocaml/package_graph.ml @@ -0,0 +1,169 @@ +exception Error = Project_context.Error + +let with_gentype_source_dirs directories (config : Config.t) = + if config.gentype_args = [] then config + else + { + config with + gentype_args = + config.gentype_args + @ List.concat_map + (fun directory -> ["-bs-gentype-source-dir"; directory]) + directories; + } + +let dependent_is_allowed allowed_dependents dependent = + Option.fold ~none:true + ~some:(fun allowed -> List.mem dependent allowed) + allowed_dependents + +let discover ~(root_config : Config.t) ~(workspace_config : Config.t) ~prod + ~features ~warn_error ~filter ~(attempt : Build_attempt.t) = + let resolution = Package_resolution.create root_config in + let unallowed_dependencies = ref [] in + let discovered = + Package_traversal.discover ~root_config ~prod ~features ~resolution + in + List.iter + (fun (package : Package_traversal.package) -> + Output.debug ~verbosity:attempt.verbosity + ("Parsing package: " ^ package.config.name); + List.iter + (fun (resolved : Package_traversal.resolved) -> + let dependency = resolved.dependency in + if + not + (dependent_is_allowed dependency.config.allowed_dependents + package.config.name) + then + unallowed_dependencies := + ( package.config.name, + Package_traversal.dependency_kind_name resolved.request.kind, + dependency.config.name ) + :: !unallowed_dependencies) + package.dependencies) + discovered.packages; + (if !unallowed_dependencies <> [] then + let details = + !unallowed_dependencies |> List.sort_uniq compare + |> List.map (fun (dependent, kind, dependency) -> + Printf.sprintf "%s %s: %s" dependent kind dependency) + |> String.concat "\n" + in + raise + (Error + ("The following packages use dependencies that do not allow them:\n" + ^ details + ^ "\nUpdate allowed-dependents in the dependency rescript.json files." + ))); + let packages_by_root = Hashtbl.create (List.length discovered.packages) in + List.iter + (fun (package : Package_traversal.package) -> + Hashtbl.add packages_by_root package.config.root package) + discovered.packages; + let visited = Hashtbl.create 32 in + let package_plans = ref [] in + let rec visit root = + if not (Hashtbl.mem visited root) then ( + Hashtbl.add visited root (); + let discovered_package = Hashtbl.find packages_by_root root in + let is_local = discovered_package.Package_traversal.is_local in + let features = + match Package_traversal.find_feature_selection discovered root with + | Some features -> + Package_traversal.feature_selection_to_option features + | None -> None + in + let config = discovered_package.config in + Package_diagnostics.report_missing_sources + ~is_root:(root = root_config.root) config; + let config = + match warn_error with + | None -> config + | Some value -> {config with warning_flags = ["-warn-error"; value]} + in + let dependencies = + List.map + (fun (resolved : Package_traversal.resolved) -> + let request = resolved.request in + Package_plan. + { + declaration = request.declaration; + directory = resolved.dependency.directory; + kind = request.kind; + }) + discovered_package.dependencies + in + List.iter + (fun (dependency : Package_plan.dependency) -> + visit dependency.directory) + dependencies; + let discovery = + Output.debug ~verbosity:attempt.verbosity + ("Building source file-tree for package: " ^ config.name); + Source.discover_with_inventory config + ~prod:(Package_traversal.source_discovery_prod ~prod ~is_local) + ~features + ~filter:(if root = root_config.root then filter else None) + ~on_missing:(Package_diagnostics.report_missing_source_folder config) + ~on_orphan:(fun path -> + Printf.eprintf + "\027[2K\r No implementation file found for interface file \ + (skipping): %s\n\ + %!" + path) + ~display_root:root_config.root + in + let modules = discovery.modules in + let compile_config = + let config = with_gentype_source_dirs discovery.gentype_dirs config in + Config.with_root_options config workspace_config + |> Compiler_args.with_local_warning_policy ~is_local + in + let build_dir = Build_artifacts.lib_path root "bs" in + let ocaml_dir = Build_artifacts.lib_path root "ocaml" in + let source_mtimes = + Hashtbl.create (List.length discovery.source_mtimes) + in + List.iter + (fun (path, modified) -> Hashtbl.replace source_mtimes path modified) + discovery.source_mtimes; + let package : Package_plan.t = + Package_plan. + { + name = discovered_package.name; + root; + is_local; + config; + compile_config; + build_dir; + ocaml_dir; + dependencies; + gentype_dependency_args = + Compiler_args.gentype_dependency_args_from_paths compile_config + (List.map + (fun (dependency : Package_plan.dependency) -> + (dependency.declaration, dependency.directory)) + dependencies); + modules; + source_mtimes; + source_files = discovery.inventory_files; + present_source_files = discovery.present_files; + } + in + Build_session.add_package_plan attempt.session package; + List.iter + (fun module_ -> + module_.Source.implementation + :: Option.to_list module_.Source.interface + |> List.iter (fun relative_path -> + let absolute_path = Filename.concat root relative_path in + Build_session.add_source_reference attempt.session + (Platform.normalize_path_for_comparison absolute_path) + Build_session. + {package_root = root; module_; relative_path; absolute_path})) + modules; + package_plans := package :: !package_plans) + in + visit root_config.root; + !package_plans diff --git a/rewatch-ocaml/package_graph.mli b/rewatch-ocaml/package_graph.mli new file mode 100644 index 00000000000..4aa537ffb4e --- /dev/null +++ b/rewatch-ocaml/package_graph.mli @@ -0,0 +1,13 @@ +val discover : + root_config:Config.t -> + workspace_config:Config.t -> + prod:bool -> + features:string list option -> + warn_error:string option -> + filter:Source_filter.t option -> + attempt:Build_attempt.t -> + Package_plan.t list +(** Package discovery resolves each dependency edge once, aggregates feature + requests across all incoming edges, and then constructs stable package + plans. Commands that need a different file projection reuse the lower-level + {!Package_traversal} graph. *) diff --git a/rewatch-ocaml/package_parse.ml b/rewatch-ocaml/package_parse.ml new file mode 100644 index 00000000000..424b1fed46d --- /dev/null +++ b/rewatch-ocaml/package_parse.ml @@ -0,0 +1,114 @@ +let run ~(package : Package_plan.t) ~(prepared : Build_session.prepared) + ~(attempt : Build_attempt.t) ~removed_module_names = + let root = package.root in + let is_local = package.is_local in + let config = package.compile_config in + let build_state = prepared.build_state in + let compile_assets = prepared.compile_assets in + let build_dir = package.build_dir in + let ocaml_dir = package.ocaml_dir in + let dirty_parse_paths = + package.modules + |> List.concat_map (fun (module_ : Source.module_) -> + module_.implementation :: Option.to_list module_.interface) + |> List.filter (fun path -> + let forced = + Hashtbl.mem attempt.preliminary_parses (Filename.concat root path) + in + match attempt.freshness_mode with + | Build_attempt.Reuse_freshness -> forced + | Build_attempt.Initialize_freshness -> + Hashtbl.mem removed_module_names (Source.module_name path) + || forced + || Build_freshness.source_is_not_older_than_ast compile_assets ~root + ~source_mtimes:package.source_mtimes path) + in + let dirty_parse_path_set = Hashtbl.create (List.length dirty_parse_paths) in + List.iter + (fun path -> Hashtbl.replace dirty_parse_path_set path ()) + dirty_parse_paths; + List.iter + (fun path -> + Filename.concat root path |> Platform.normalize_path_for_comparison + |> Build_session.mark_parse_pending attempt.session) + dirty_parse_paths; + let dirty_modules = Hashtbl.create (List.length package.modules) in + List.iter + (fun module_ -> + let paths = + module_.Source.implementation :: Option.to_list module_.Source.interface + in + if List.exists (Hashtbl.mem dirty_parse_path_set) paths then ( + Hashtbl.replace dirty_modules module_.Source.name (); + let key = Source.compiler_basename config module_.Source.name in + (Build_state.find_exn build_state key).compile_dirty <- true)) + package.modules; + let parse_paths_to_run = + dirty_parse_paths + |> List.filter (fun path -> + not (Hashtbl.mem attempt.preliminary_parses (Filename.concat root path))) + in + let parsed = + List.map2 + (fun path result -> (path, Build_attempt.preliminary_parse result)) + parse_paths_to_run + (Process.run_parallel_map ?poll:attempt.process_poll parse_paths_to_run + ~job: + (Compiler_process.parse_job ~bsc:prepared.compiler_context.bsc_path + ~build_dir ~config)) + @ (dirty_parse_paths + |> List.filter_map (fun path -> + Hashtbl.find_opt attempt.preliminary_parses + (Filename.concat root path) + |> Option.map (fun result -> (path, result)))) + in + List.iter + (fun (path, result) -> + let absolute_path = Filename.concat root path in + let pending_path = Platform.normalize_path_for_comparison absolute_path in + let publish_successful_parse stderr = + let stderr = + if is_local then stderr + else Compiler_process.retain_critical_external_warnings stderr + in + if stderr <> "" then ( + attempt.had_warnings <- true; + Compiler_log.append root stderr; + attempt.parse_messages <- + Build_attempt.Parse_warning stderr :: attempt.parse_messages); + let ast = Source.ast_path path in + if is_local && stderr <> "" then + Build_attempt.register_cleanup attempt (fun () -> + let path = Filename.concat ocaml_dir (Filename.basename ast) in + File_util.remove_file path; + Compile_assets.refresh_ast compile_assets ~source:absolute_path + ~path); + let published_ast = + Build_artifacts.published_ast_path ~ocaml_dir path + in + File_util.copy_existing_file + (Filename.concat build_dir ast) + published_ast; + Compile_assets.refresh_ast compile_assets ~source:absolute_path + ~path:published_ast; + File_util.copy_existing_file + (Filename.concat config.root path) + (Filename.concat ocaml_dir (Filename.basename path)); + if is_local && stderr <> "" then + Build_session.mark_parse_pending attempt.session pending_path + else Build_session.clear_parse_pending attempt.session pending_path + in + match result with + | Build_attempt.Parse_failed {stdout; stderr} -> + Build_session.mark_parse_pending attempt.session pending_path; + let output = + Printf.sprintf "Error in %s:\n%s%s" config.name stderr stdout + in + Compiler_log.append root output; + attempt.parse_messages <- + Build_attempt.Parse_error output :: attempt.parse_messages + | Build_attempt.Parsed_successfully {stderr} -> + publish_successful_parse stderr + | Build_attempt.Use_existing_ast -> publish_successful_parse "") + parsed; + dirty_modules diff --git a/rewatch-ocaml/package_parse.mli b/rewatch-ocaml/package_parse.mli new file mode 100644 index 00000000000..3a5bb6913a5 --- /dev/null +++ b/rewatch-ocaml/package_parse.mli @@ -0,0 +1,10 @@ +val run : + package:Package_plan.t -> + prepared:Build_session.prepared -> + attempt:Build_attempt.t -> + removed_module_names:(string, unit) Hashtbl.t -> + (string, unit) Hashtbl.t +(** Parsing returns the modules whose dependency information changed or whose + compilation is pending. Failed and warning-bearing source paths are also + retained in the session so later watch attempts cannot silently reuse an + older AST. *) diff --git a/rewatch-ocaml/package_plan.ml b/rewatch-ocaml/package_plan.ml new file mode 100644 index 00000000000..fcecad4a377 --- /dev/null +++ b/rewatch-ocaml/package_plan.ml @@ -0,0 +1,26 @@ +type dependency = { + declaration: Config.dependency; + directory: string; + kind: Package_traversal.dependency_kind; +} + +type t = { + name: string; + root: string; + is_local: bool; + config: Config.t; + compile_config: Config.t; + build_dir: string; + ocaml_dir: string; + dependencies: dependency list; + gentype_dependency_args: string list; + modules: Source.module_ list; + source_mtimes: (string, float) Hashtbl.t; + source_files: string list; + present_source_files: string list; +} + +type compilation = { + regular_common_args: string list; + development_common_args: string list; +} diff --git a/rewatch-ocaml/package_plan.mli b/rewatch-ocaml/package_plan.mli new file mode 100644 index 00000000000..7d67df7ad16 --- /dev/null +++ b/rewatch-ocaml/package_plan.mli @@ -0,0 +1,31 @@ +(** A package plan holds the discovery and configuration decisions for one + package, and [compilation] the compiler arguments that build preparation + derives from it. Both live as long as the session that prepared them, so + retained watch attempts reuse them without rediscovery. *) + +type dependency = { + declaration: Config.dependency; + directory: string; + kind: Package_traversal.dependency_kind; +} + +type t = { + name: string; + root: string; + is_local: bool; + config: Config.t; + compile_config: Config.t; + build_dir: string; + ocaml_dir: string; + dependencies: dependency list; + gentype_dependency_args: string list; + modules: Source.module_ list; + source_mtimes: (string, float) Hashtbl.t; + source_files: string list; + present_source_files: string list; +} + +type compilation = { + regular_common_args: string list; + development_common_args: string list; +} diff --git a/rewatch-ocaml/package_resolution.ml b/rewatch-ocaml/package_resolution.ml new file mode 100644 index 00000000000..d61a0d9c957 --- /dev/null +++ b/rewatch-ocaml/package_resolution.ml @@ -0,0 +1,121 @@ +type dependency = { + name: string; + directory: string; + config: Config.t; + is_local: bool; +} + +type diagnostic_mode = Report_diagnostics | Suppress_diagnostics + +type t = { + root_config: Config.t; + context: Project_context.dependency_context; + loaded: (string, Config.t) Hashtbl.t; + edges: (string * string, dependency) Hashtbl.t; + selected: (string, dependency) Hashtbl.t; + reported_duplicates: (string * string, unit) Hashtbl.t; + diagnostic_mode: diagnostic_mode; + root_package_name: string; +} + +let create ?(diagnostic_mode = Report_diagnostics) root_config = + let loaded = Hashtbl.create 32 in + Hashtbl.add loaded root_config.Config.root root_config; + { + root_config; + context = Project_context.dependency_context root_config; + loaded; + edges = Hashtbl.create 32; + selected = Hashtbl.create 32; + reported_duplicates = Hashtbl.create 8; + diagnostic_mode; + root_package_name = + Package_diagnostics.package_identity + ~report_diagnostics:(diagnostic_mode = Report_diagnostics) + root_config; + } + +let load_config resolution root = + match Hashtbl.find_opt resolution.loaded root with + | Some config -> config + | None -> + let config = Config.load_root root in + Hashtbl.add resolution.loaded root config; + config + +let is_local resolution directory = + Project_context.dependency_is_local_canonical resolution.context directory + +let dependency_path resolution ~package_root name = + Project_context.dependency_path_in resolution.context package_root name + +let dependency_candidates resolution ~package_root name = + Project_context.dependency_candidates_in resolution.context package_root name + +let root_package_name resolution = resolution.root_package_name + +let resolve resolution ~package_root (declaration : Config.dependency) = + let edge_key = (package_root, declaration.name) in + match Hashtbl.find_opt resolution.edges edge_key with + | Some identity -> identity + | None -> + let candidate = + Project_context.require_dependency_directory ~context:resolution.context + package_root declaration + in + let dependency = + match Hashtbl.find_opt resolution.selected declaration.name with + | Some selected -> + (if selected.directory <> candidate then + let key = (declaration.name, candidate) in + if + resolution.diagnostic_mode = Report_diagnostics + && not (Hashtbl.mem resolution.reported_duplicates key) + then ( + Hashtbl.add resolution.reported_duplicates key (); + Printf.eprintf "Duplicated package: %s %s (chosen) vs %s in %s\n%!" + declaration.name + (Project_context.display_path ~root:resolution.root_config.root + selected.directory) + (Project_context.display_path ~root:resolution.root_config.root + candidate) + (Project_context.display_path ~root:resolution.root_config.root + package_root))); + selected + | None -> + let config = + try load_config resolution candidate + with Config.Error message -> + raise + (Project_context.Package_error + (Printf.sprintf + "Could not build package tree for '%s' at path '%s'. \ + Error: %s" + declaration.name resolution.root_config.root message)) + in + let name = + Package_diagnostics.package_identity + ~report_diagnostics:(resolution.diagnostic_mode = Report_diagnostics) + config + in + if name <> declaration.name then + raise + (Project_context.Package_error + (Printf.sprintf + "Could not build package tree reading dependency '%s' at \ + path '%s'. Error: resolved package identity '%s' does not \ + match the requested dependency name" + declaration.name candidate name)); + let identity = + { + name; + directory = candidate; + config; + is_local = is_local resolution candidate; + } + in + Hashtbl.add resolution.selected declaration.name identity; + identity + in + Hashtbl.add resolution.edges edge_key dependency; + dependency diff --git a/rewatch-ocaml/package_resolution.mli b/rewatch-ocaml/package_resolution.mli new file mode 100644 index 00000000000..71f0d30bc04 --- /dev/null +++ b/rewatch-ocaml/package_resolution.mli @@ -0,0 +1,20 @@ +type t +(** Resolution caches package identity, not declaration-specific feature + requests. The same installed package may be reached through multiple edges + whose requested features must remain distinct for later aggregation. *) + +type dependency = { + name: string; + directory: string; + config: Config.t; + is_local: bool; +} + +type diagnostic_mode = Report_diagnostics | Suppress_diagnostics + +val create : ?diagnostic_mode:diagnostic_mode -> Config.t -> t +val resolve : t -> package_root:string -> Config.dependency -> dependency +val dependency_path : t -> package_root:string -> string -> string option +val dependency_candidates : t -> package_root:string -> string -> string list +val root_package_name : t -> string +val is_local : t -> string -> bool diff --git a/rewatch-ocaml/package_traversal.ml b/rewatch-ocaml/package_traversal.ml new file mode 100644 index 00000000000..afd39f396a3 --- /dev/null +++ b/rewatch-ocaml/package_traversal.ml @@ -0,0 +1,100 @@ +type dependency_kind = Regular | Development + +let source_discovery_prod ~prod ~is_local = prod || not is_local + +type request = {kind: dependency_kind; declaration: Config.dependency} + +type resolved = {request: request; dependency: Package_resolution.dependency} + +type package = { + name: string; + config: Config.t; + is_local: bool; + dependencies: resolved list; +} + +type feature_selection = All_features | Selected_features of string list +module String_set = Set.Make (String) + +type accumulated_features = All_requested | Selected_requested of String_set.t + +type feature_requests = (string, accumulated_features) Hashtbl.t +type graph = {packages: package list; feature_requests: feature_requests} + +let add_feature_request requests root request = + match (Hashtbl.find_opt requests root, request) with + | None, None -> Hashtbl.add requests root All_requested + | None, Some requested -> + Hashtbl.add requests root + (Selected_requested (String_set.of_list requested)) + | Some All_requested, _ | Some _, None -> + Hashtbl.replace requests root All_requested + | Some (Selected_requested current), Some requested -> + Hashtbl.replace requests root + (Selected_requested + (List.fold_left + (fun features feature -> String_set.add feature features) + current requested)) + +let find_feature_selection graph root = + Hashtbl.find_opt graph.feature_requests root + |> Option.map (function + | All_requested -> All_features + | Selected_requested features -> + Selected_features (String_set.elements features)) + +let feature_selection_to_option = function + | All_features -> None + | Selected_features features -> Some features + +let dependency_kind_name = function + | Regular -> "dependencies" + | Development -> "dev-dependencies" + +let requests ~prod ~is_local (config : Config.t) = + List.map + (fun declaration -> {kind = Regular; declaration}) + config.dependencies + @ + if source_discovery_prod ~prod ~is_local then [] + else + List.map + (fun declaration -> {kind = Development; declaration}) + config.dev_dependencies + +let resolve resolution ~package_root request = + { + request; + dependency = + Package_resolution.resolve resolution ~package_root request.declaration; + } + +let traverse ~root_config ~root_name ~prod ~features ~resolve = + let visited = Hashtbl.create 32 in + let feature_requests = Hashtbl.create 32 in + let packages = ref [] in + let rec visit ~name ~is_local ~features (config : Config.t) = + add_feature_request feature_requests config.root features; + if not (Hashtbl.mem visited config.root) then ( + Hashtbl.add visited config.root (); + let dependencies = + requests ~prod ~is_local config + |> List.filter_map (fun request -> resolve config request) + in + List.iter + (fun resolved -> + visit ~is_local:resolved.dependency.is_local + ~name:resolved.dependency.name + ~features:resolved.request.declaration.features + resolved.dependency.config) + dependencies; + packages := {name; config; is_local; dependencies} :: !packages) + in + visit ~name:root_name ~is_local:true ~features root_config; + {packages = !packages; feature_requests} + +let discover ~root_config ~prod ~features ~resolution = + traverse ~root_config + ~root_name:(Package_resolution.root_package_name resolution) ~prod ~features + ~resolve:(fun config request -> + Some (resolve resolution ~package_root:config.root request)) diff --git a/rewatch-ocaml/package_traversal.mli b/rewatch-ocaml/package_traversal.mli new file mode 100644 index 00000000000..054d033df83 --- /dev/null +++ b/rewatch-ocaml/package_traversal.mli @@ -0,0 +1,45 @@ +(** Traversal centralizes dependency admission and feature aggregation while + leaving command-specific failure policy to its [resolve] callback. This is + why build, watch, and format can share graph semantics without sharing all + recovery behavior. *) +type dependency_kind = Regular | Development + +val source_discovery_prod : prod:bool -> is_local:bool -> bool + +type request = {kind: dependency_kind; declaration: Config.dependency} + +type resolved = {request: request; dependency: Package_resolution.dependency} + +type package = { + name: string; + config: Config.t; + is_local: bool; + dependencies: resolved list; +} + +type feature_selection = All_features | Selected_features of string list +type feature_requests +type graph = {packages: package list; feature_requests: feature_requests} + +val find_feature_selection : graph -> string -> feature_selection option +val feature_selection_to_option : feature_selection -> string list option + +val dependency_kind_name : dependency_kind -> string +val requests : prod:bool -> is_local:bool -> Config.t -> request list + +val resolve : Package_resolution.t -> package_root:string -> request -> resolved + +val traverse : + root_config:Config.t -> + root_name:string -> + prod:bool -> + features:string list option -> + resolve:(Config.t -> request -> resolved option) -> + graph + +val discover : + root_config:Config.t -> + prod:bool -> + features:string list option -> + resolution:Package_resolution.t -> + graph diff --git a/rewatch-ocaml/platform.mli b/rewatch-ocaml/platform.mli new file mode 100644 index 00000000000..18c66de50df --- /dev/null +++ b/rewatch-ocaml/platform.mli @@ -0,0 +1,53 @@ +(** Platform-specific filesystem and process operations live behind this + interface because path identity, command-line quoting, handle inheritance, + and process-tree termination have materially different Unix and Windows + contracts. Higher layers should not infer those rules from path strings. *) + +val normalize_path_for_comparison : string -> string +val directory_identity : path:string -> Unix.stats -> string +val canonicalize_path : string -> string +val resolve_program : cwd:string -> string -> string +val terminal_supports_color_without_term : bool +val inherit_streaming_terminal_stdin : bool +val configure_standard_streams : unit -> unit +val clean_symbol : string +val parse_symbol : string +val build_symbol : string +val success_symbol : string +val warning_symbol : string +val error_symbol : string + +type command = {env: Spawn.Env.t option; program: string; args: string list} + +val post_build_command : command:string -> output:string -> command + +type process + +val spawn : + env:Spawn.Env.t option -> + cwd:string -> + program:string -> + args:string list -> + stdin:Unix.file_descr -> + stdout:Unix.file_descr -> + stderr:Unix.file_descr -> + process + +val null_device : string + +val current_process_id : unit -> int +val process_id : process -> int +val release_process : process -> unit + +val signal_process_tree : process -> int -> (unit, string) result + +val termination_signals : int list +(** Signals that request a clean shutdown: killing children, releasing locks, + and removing temporary outputs before exiting. *) + +val escalate_process_groups : bool + +val process_is_active : + run:(string -> string list -> (Unix.process_status * string) option) -> + string -> + bool diff --git a/rewatch-ocaml/platform_common.ml b/rewatch-ocaml/platform_common.ml new file mode 100644 index 00000000000..00defb3fc38 --- /dev/null +++ b/rewatch-ocaml/platform_common.ml @@ -0,0 +1,63 @@ +(* Like Rust's std::process::Command, the current directory is not searched: a + project file named like a tool (cmd.exe, node) must not run in its place. A + program in the current directory needs an explicit path. *) +let resolve_program ~path_separator ~executable_extensions ~normalize_directory + ~executable_is_usable ~cwd program = + if (not (Filename.is_implicit program)) || Filename.dirname program <> "." + then program + else + let path_directories = + Sys.getenv_opt "PATH" |> Option.value ~default:"" + |> String.split_on_char path_separator + in + path_directories + |> List.find_map (fun directory -> + let directory = normalize_directory directory in + let directory = + if directory = "" then cwd + else if Filename.is_relative directory then + Filename.concat cwd directory + else directory + in + executable_extensions ~program + |> List.find_map (fun extension -> + let candidate = Filename.concat directory (program ^ extension) in + if executable_is_usable candidate then Some candidate else None)) + |> Option.value ~default:program + +(* A lock records the PID of the rescript process that owns it. A PID that has + since been reused by an unrelated process must not keep the lock alive, so + only the names of the build-system executables count: the packaged OCaml + and Rust implementations and the dune development executable. Linux + truncates process names to 15 bytes, so a truncated name also matches. *) +let lock_owner_names = ["rescript"; "rescript-rust"; "rescript_ocaml"] + +let is_lock_owner_name name = + let name = String.lowercase_ascii name in + let without_extension = + if Filename.check_suffix name ".exe" then Filename.chop_suffix name ".exe" + else name + in + List.mem without_extension lock_owner_names + || String.length name >= 15 + && List.exists + (fun owner -> String.starts_with ~prefix:name (owner ^ ".exe")) + lock_owner_names + +let process_is_active ~probe value = + try + let pid = int_of_string value in + (* PID zero names a process group on Unix and is not a usable child-process + identity on Windows, so it can never prove ownership of a build lock. *) + if pid = 0 then false else probe pid + with + | Failure _ | Unix.Unix_error (Unix.ESRCH, _, _) -> false + | Unix.Unix_error (Unix.EPERM, _, _) -> true + +let create_capture_pipes () = + let stdout = Spawn.safe_pipe () in + try (stdout, Spawn.safe_pipe ()) + with exn -> + Unix.close (fst stdout); + Unix.close (snd stdout); + raise exn diff --git a/rewatch-ocaml/platform_common.mli b/rewatch-ocaml/platform_common.mli new file mode 100644 index 00000000000..96cf840e22b --- /dev/null +++ b/rewatch-ocaml/platform_common.mli @@ -0,0 +1,14 @@ +val resolve_program : + path_separator:char -> + executable_extensions:(program:string -> string list) -> + normalize_directory:(string -> string) -> + executable_is_usable:(string -> bool) -> + cwd:string -> + string -> + string + +val is_lock_owner_name : string -> bool +val process_is_active : probe:(int -> bool) -> string -> bool +val create_capture_pipes : + unit -> + (Unix.file_descr * Unix.file_descr) * (Unix.file_descr * Unix.file_descr) diff --git a/rewatch-ocaml/platform_unix.ml b/rewatch-ocaml/platform_unix.ml new file mode 100644 index 00000000000..b0fca3df641 --- /dev/null +++ b/rewatch-ocaml/platform_unix.ml @@ -0,0 +1,100 @@ +let path_separator = ':' +let terminal_supports_color_without_term = false +let inherit_streaming_terminal_stdin = false +let configure_standard_streams () = () +let clean_symbol = "🧹 " +let parse_symbol = "🧱 " +let build_symbol = "🤺 " +let success_symbol = "✅ " +let warning_symbol = "⚠️ " +let error_symbol = "❌ " +let normalize_path_for_comparison value = value +let directory_identity ~path:_ metadata = + Printf.sprintf "%d:%d" metadata.Unix.st_dev metadata.Unix.st_ino + +let canonicalize_path = Unix.realpath +let executable_extensions ~program:_ = [""] + +let executable_is_usable candidate = + try + (Unix.stat candidate).Unix.st_kind = Unix.S_REG + && + try + Unix.access candidate [Unix.X_OK]; + true + with Unix.Unix_error _ -> false + with Unix.Unix_error _ -> false + +let resolve_program = + Platform_common.resolve_program ~path_separator ~executable_extensions + ~normalize_directory:Fun.id ~executable_is_usable + +type command = {env: Spawn.Env.t option; program: string; args: string list} + +let post_build_command ~command ~output = + { + env = None; + program = "/bin/sh"; + args = ["-c"; command ^ " " ^ Filename.quote output]; + } + +type process = int + +let spawn ~env ~cwd ~program ~args ~stdin ~stdout ~stderr = + let program = resolve_program ~cwd program in + Spawn.spawn ?env ~cwd:(Spawn.Working_dir.Path cwd) ~prog:program + ~argv:(program :: args) ~stdin ~stdout ~stderr + ~setpgid:Spawn.Pgid.new_process_group () + +let null_device = "/dev/null" + +let current_process_id = Unix.getpid +let process_id process = process +let release_process _process = () + +let signal_process_tree process signal = + try + Unix.kill (-process) signal; + Ok () + with + (* A missing group is already in the requested terminal state. Other errors + must prevent the caller from waiting indefinitely for an undelivered + signal. *) + | Unix.Unix_error (Unix.ESRCH, _, _) -> Ok () + | Unix.Unix_error (error, operation, _) -> + Error + (Printf.sprintf "%s while sending signal %d to process group %d: %s" + operation signal process (Unix.error_message error)) + +(* Children run in their own process groups, so a closing terminal's SIGHUP + and a SIGQUIT reach only rescript. Handling them like SIGTERM keeps those + children from outliving the build and leaving its lock behind. *) +let termination_signals = [Sys.sigint; Sys.sigterm; Sys.sighup; Sys.sigquit] + +let escalate_process_groups = true + +let process_name_from_ps ~run pid = + match run "/bin/ps" ["-p"; string_of_int pid; "-o"; "comm="] with + | Some (Unix.WEXITED 0, output) -> + output |> String.trim |> Filename.basename + |> Platform_common.is_lock_owner_name + | Some (Unix.WEXITED _, _) -> false + | Some (Unix.WSIGNALED _, _) | Some (Unix.WSTOPPED _, _) | None -> true + +let probe_process ~run pid = + Unix.kill pid 0; + let executable = Printf.sprintf "/proc/%d/exe" pid in + if Sys.file_exists executable then + try + Unix.realpath executable |> Filename.basename + |> Platform_common.is_lock_owner_name + with Unix.Unix_error _ -> true + else + (* macOS has no procfs. `ps` supplies the same executable-name check so a + reused PID from an abandoned lock is not mistaken for this tool. A + failed probe remains conservative because stealing a live build's lock + is worse than asking the user to remove an inconclusive stale lock. *) + process_name_from_ps ~run pid + +let process_is_active ~run value = + Platform_common.process_is_active ~probe:(probe_process ~run) value diff --git a/rewatch-ocaml/platform_windows.ml b/rewatch-ocaml/platform_windows.ml new file mode 100644 index 00000000000..f9f4f45b834 --- /dev/null +++ b/rewatch-ocaml/platform_windows.ml @@ -0,0 +1,239 @@ +let path_separator = ';' +let terminal_supports_color_without_term = true +let inherit_streaming_terminal_stdin = true + +external enable_virtual_terminal_processing : unit -> unit + = "rewatch_windows_enable_virtual_terminal_processing" + +let configure_standard_streams () = + set_binary_mode_in stdin true; + set_binary_mode_out stdout true; + set_binary_mode_out stderr true; + enable_virtual_terminal_processing () +let clean_symbol = "[clean] " +let parse_symbol = "[parse] " +let build_symbol = "[build] " +let success_symbol = "[ok] " +let warning_symbol = "[warn] " +let error_symbol = "[error] " +let normalize_path_for_comparison path = + path |> String.lowercase_ascii + |> String.map (function + | '/' -> '\\' + | character -> character) + +let strip_verbatim_prefix path = + if String.starts_with ~prefix:"\\\\?\\UNC\\" path then + "\\\\" ^ String.sub path 8 (String.length path - 8) + else if String.starts_with ~prefix:"\\\\?\\" path then + String.sub path 4 (String.length path - 4) + else path + +let canonicalize_path path = Unix.realpath path |> strip_verbatim_prefix + +external directory_file_identity : string -> string + = "rewatch_windows_directory_identity" + +let directory_identity ~path _metadata = directory_file_identity path + +let executable_extensions ~program = + if Filename.extension program <> "" then [""] + else + Sys.getenv_opt "PATHEXT" + |> Option.value ~default:".COM;.EXE;.BAT;.CMD" + |> String.split_on_char ';' + +let executable_is_usable candidate = + try (Unix.stat candidate).Unix.st_kind = Unix.S_REG + with Unix.Unix_error _ -> false + +let normalize_path_directory directory = + let directory = String.trim directory in + let length = String.length directory in + if length >= 2 && directory.[0] = '"' && directory.[length - 1] = '"' then + String.sub directory 1 (length - 2) + else directory + +let resolve_program = + Platform_common.resolve_program ~path_separator ~executable_extensions + ~normalize_directory:normalize_path_directory ~executable_is_usable + +type command = {env: Spawn.Env.t option; program: string; args: string list} + +let post_build_command ~command ~output = + let variable = "REWATCH_JS_POST_BUILD_FILE" in + let prefix = String.lowercase_ascii (variable ^ "=") in + let environment = + Unix.environment () |> Array.to_list + |> List.filter (fun entry -> + not (String.starts_with ~prefix (String.lowercase_ascii entry))) + |> List.cons (variable ^ "=" ^ output) + |> Spawn.Env.of_list + in + { + env = Some environment; + program = "cmd.exe"; + args = ["/D"; "/V:OFF"; "/S"; "/C"; command ^ " \"%" ^ variable ^ "%\""]; + } + +let is_batch_file program = + List.mem + (Filename.extension program |> String.lowercase_ascii) + [".bat"; ".cmd"] + +type process_job + +type process = {wait_id: int; job: process_job} + +external spawn_owned : + env:Spawn.Env.t option -> + cwd:string -> + program:string -> + command_line:string -> + stdin:Unix.file_descr -> + stdout:Unix.file_descr -> + stderr:Unix.file_descr -> + process = "rewatch_windows_spawn_owned_byte" "rewatch_windows_spawn_owned" + +external terminate_process_job : process_job -> bool + = "rewatch_windows_terminate_process_job" + +external close_process_job : process_job -> unit + = "rewatch_windows_close_process_job" + +let quote_argument argument = + if + argument = "" + || String.contains argument ' ' + || String.contains argument '\t' + || String.contains argument '"' + then Filename.quote argument + else argument + +let ensure_no_null label value = + if String.contains value '\x00' then + invalid_arg (Printf.sprintf "%s contains a NUL byte" label) + +let program_for_working_directory ~cwd program = + if Filename.is_relative program then Filename.concat cwd program else program + +let serialize_command_line ~shell_command_is_quoted ~program ~args = + match args with + | ["/D"; "/V:OFF"; "/S"; "/C"; command] -> + let command = + if shell_command_is_quoted then command else "\"" ^ command ^ "\"" + in + String.concat " " [quote_argument program; "/D"; "/V:OFF"; "/S"; "/C"] + ^ " " ^ command + | _ -> program :: args |> List.map quote_argument |> String.concat " " + +let spawn ~env ~cwd ~program ~args ~stdin ~stdout ~stderr = + let program = resolve_program ~cwd program in + ensure_no_null "working directory" cwd; + ensure_no_null "program" program; + List.iter (ensure_no_null "argument") args; + let program, args, shell_command_is_quoted = + if is_batch_file program then + let command = Filename.quote_command program args in + ( resolve_program ~cwd "cmd.exe", + ["/D"; "/V:OFF"; "/S"; "/C"; command], + true ) + else (program, args, false) + in + let command_line = + serialize_command_line ~shell_command_is_quoted ~program ~args + in + let program = program_for_working_directory ~cwd program in + (* Starting suspended closes the only interval in which a child could create + descendants before the job owns its process tree. *) + spawn_owned ~env ~cwd ~program ~command_line ~stdin ~stdout ~stderr + +let null_device = "NUL" + +external current_process_id : unit -> int = "rewatch_windows_current_process_id" + +let process_id process = process.wait_id +let release_process process = close_process_job process.job + +let signal_process_tree process _signal = + if terminate_process_job process.job then Ok () + else Error "TerminateJobObject failed" + +(* OCaml supports only these two signals on Windows. *) +let termination_signals = [Sys.sigint; Sys.sigterm] + +let escalate_process_groups = false + +let parse_tasklist_csv_line line = + let length = String.length line in + let rec parse_field fields index = + if index >= length || line.[index] <> '"' then None + else + let buffer = Buffer.create 32 in + let rec parse_char index = + if index >= length then None + else + match line.[index] with + | '"' when index + 1 < length && line.[index + 1] = '"' -> + Buffer.add_char buffer '"'; + parse_char (index + 2) + | '"' -> + let fields = Buffer.contents buffer :: fields in + let next = index + 1 in + if next = length then Some (List.rev fields) + else if line.[next] = ',' then parse_field fields (next + 1) + else None + | character -> + Buffer.add_char buffer character; + parse_char (index + 1) + in + parse_char (index + 1) + in + if length = 0 then None else parse_field [] 0 + +type tasklist_probe = Process_found | Process_absent | Malformed_output + +(* The probe filters by PID. When nothing matches, tasklist prints a localized + informational message instead of CSV rows, so only quoted lines are rows. *) +let tasklist_probe ~pid output = + let lines = + output |> String.trim |> String.split_on_char '\n' |> List.map String.trim + |> List.filter (String.starts_with ~prefix:"\"") + in + let rows = List.map parse_tasklist_csv_line lines in + let valid_row = function + | Some [_image; row_pid; _session; _session_number; _memory] -> + Option.is_some (int_of_string_opt row_pid) + | Some _ | None -> false + in + if lines = [] then Process_absent + else if not (List.for_all valid_row rows) then Malformed_output + else if + List.exists + (function + | Some [image; row_pid; _session; _session_number; _memory] -> + Platform_common.is_lock_owner_name image + && row_pid = string_of_int pid + | Some _ | None -> false) + rows + then Process_found + else Process_absent + +let probe_process ~run pid = + let tasklist = + match Sys.getenv_opt "SystemRoot" with + | Some root -> + Filename.concat (Filename.concat root "System32") "tasklist.exe" + | None -> "tasklist.exe" + in + match + run tasklist ["/FI"; Printf.sprintf "PID eq %d" pid; "/FO"; "CSV"; "/NH"] + with + | Some (Unix.WEXITED 0, stdout) -> ( + match tasklist_probe ~pid stdout with + | Process_found | Malformed_output -> true + | Process_absent -> false) + | Some _ | None -> true + +let process_is_active ~run value = + Platform_common.process_is_active ~probe:(probe_process ~run) value diff --git a/rewatch-ocaml/process.ml b/rewatch-ocaml/process.ml new file mode 100644 index 00000000000..0559efea75d --- /dev/null +++ b/rewatch-ocaml/process.ml @@ -0,0 +1,506 @@ +module Child = Process_child + +type result = Child.result = { + status: Unix.process_status; + stdout: string; + stderr: string; +} + +type job = Child.job = {program: string; args: string list; cwd: string} +type task = {job: job; env: Spawn.Env.t option; on_result: result -> result} + +exception Error = Child.Error +exception Interrupted of int + +let succeeded = Child.succeeded +let status_string = Child.status_string + +(* Reader threads are needed because a child can block when either output pipe + fills, and Windows cannot use select to drain anonymous pipes concurrently. + The threads perform only blocking I/O; dependency scheduling stays on the + calling thread. *) +let default_max_jobs = min 32 (max 1 (Domain.recommended_domain_count ())) + +let with_completion_notifier ~poll action = + match poll with + | Some poll -> + Child.with_completion_notifier ~ticker_enabled:true (action ~poll) + | None -> + Child.with_completion_notifier ~ticker_enabled:false + (action ~poll:(fun () -> ())) + +let task ?env ?(on_result = fun result -> result) job = {job; env; on_result} + +let run_parallel_map_with_notifier ~max_jobs ~poll ~on_complete notifier values + ~job = + let indexed = List.mapi (fun index value -> (index, value)) values in + let results = Array.make (List.length values) None in + let active = ref [] in + let launch_indexed (index, value) = + active := Child.launch ~notifier index (job value) :: !active + in + let rec fill slots queued = + if slots = 0 then queued + else + match queued with + | [] -> [] + | job :: rest -> + launch_indexed job; + fill (slots - 1) rest + in + let rec schedule queued = + let queued = fill (max_jobs - List.length !active) queued in + match !active with + | [] -> () + | _ -> + let child, result = Child.wait_for_running ~poll notifier !active in + active := List.filter (fun running -> running != child) !active; + Child.release_running child; + results.(Child.payload child) <- Some result; + on_complete (Child.payload child); + schedule queued + in + try + schedule indexed; + Array.to_list results |> List.map Option.get + with exn -> + Child.terminate_running !active; + raise exn + +let run_parallel_map ?(max_jobs = default_max_jobs) ?poll + ?(on_complete = fun _ -> ()) values ~job = + if max_jobs < 1 then raise (Error "max_jobs must be at least one"); + match values with + | [] -> [] + | _ -> + with_completion_notifier ~poll (fun ~poll notifier -> + run_parallel_map_with_notifier ~max_jobs ~poll ~on_complete notifier + values ~job) + +let run_parallel ?max_jobs ?poll ?on_complete jobs = + run_parallel_map ?max_jobs ?poll ?on_complete jobs ~job:Fun.id + +type 'a work = {key: string; dependencies: string list; value: 'a} +type failure_action = + | Abort_immediately + | Stop_new_work + | Continue_independent_work + +module Work_ready = Set.Make (struct + type t = int * string + + let compare (first_priority, first_key) (second_priority, second_key) = + let by_priority = compare second_priority first_priority in + if by_priority <> 0 then by_priority + else String.compare first_key second_key +end) + +type cancellation_state = + | Cancellation_not_requested + | Cancellation_requested + | Cancellation_failed of exn + +type termination_state = + | Termination_confirmed + | Termination_unconfirmed of exn + +type pool_active = { + id: int; + child: unit Child.running; + mutable cancellation: cancellation_state; +} + +let cancellation_was_requested = function + | Cancellation_not_requested -> false + | Cancellation_requested | Cancellation_failed _ -> true + +type 'a pool_completion = + | Task_completed of 'a * result + | Task_failed of 'a * exn + +type 'a worker_pool = { + notifier: Child.completion_notifier; + mutex: Mutex.t; + work_available: Condition.t; + cancellation_finished: Condition.t; + queued: ('a * task) Queue.t; + completed_tasks: 'a pool_completion Queue.t; + mutable active_children: pool_active list; + mutable next_active_id: int; + mutable stopping: bool; + mutable signalling_cancellation: bool; + mutable workers: unit Domain.t list; +} + +let remove_active pool active = + Child.with_lock pool.mutex (fun () -> + while + pool.signalling_cancellation + && cancellation_was_requested active.cancellation + do + Condition.wait pool.cancellation_finished pool.mutex + done; + pool.active_children <- + List.filter + (fun current -> current.id <> active.id) + pool.active_children) + +let complete_pool_task pool completion = + Child.with_lock pool.mutex (fun () -> + Queue.add completion pool.completed_tasks); + Child.notify_completion pool.notifier + +let run_pool_task pool payload task = + match + try Ok (Child.launch ?env:task.env ~notifier:pool.notifier () task.job) + with exn -> Error exn + with + | Error exn -> complete_pool_task pool (Task_failed (payload, exn)) + | Ok child -> + let active, cancel_after_launch = + Child.with_lock pool.mutex (fun () -> + let active = + { + id = pool.next_active_id; + child; + cancellation = + (if pool.stopping then Cancellation_requested + else Cancellation_not_requested); + } + in + pool.next_active_id <- pool.next_active_id + 1; + pool.active_children <- active :: pool.active_children; + (active, cancellation_was_requested active.cancellation)) + in + let wait_result = + try + if cancel_after_launch then Child.signal_running [child]; + Ok + (Child.wait_for_running + ~poll:(fun () -> + match + Child.with_lock pool.mutex (fun () -> active.cancellation) + with + | Cancellation_failed exn -> raise exn + | Cancellation_not_requested | Cancellation_requested -> ()) + pool.notifier [child]) + with exn -> Error exn + in + let completion = + match wait_result with + | Ok (_, result) -> ( + remove_active pool active; + try + Child.release_running child; + Task_completed (payload, task.on_result result) + with exn -> Task_failed (payload, exn)) + | Error exn -> ( + let termination = + try + Child.signal_running [child]; + Termination_confirmed + with cancellation_exn -> Termination_unconfirmed cancellation_exn + in + match termination with + | Termination_confirmed -> ( + remove_active pool active; + try + Child.release_running child; + Task_failed (payload, exn) + with release_exn -> Task_failed (payload, release_exn)) + | Termination_unconfirmed cancellation_exn -> + remove_active pool active; + Child.release_after_completion child; + Task_failed (payload, cancellation_exn)) + in + complete_pool_task pool completion + +let rec worker_loop pool = + let queued = + Child.with_lock pool.mutex (fun () -> + while Queue.is_empty pool.queued && not pool.stopping do + Condition.wait pool.work_available pool.mutex + done; + if Queue.is_empty pool.queued then None + else Some (Queue.take pool.queued)) + in + match queued with + | None -> () + | Some (payload, task) -> + run_pool_task pool payload task; + worker_loop pool + +let create_worker_pool ~max_jobs notifier = + let pool = + { + notifier; + mutex = Mutex.create (); + work_available = Condition.create (); + cancellation_finished = Condition.create (); + queued = Queue.create (); + completed_tasks = Queue.create (); + active_children = []; + next_active_id = 0; + stopping = false; + signalling_cancellation = false; + workers = []; + } + in + let rec start_workers remaining = + if remaining > 0 then ( + let worker = Domain.spawn (fun () -> worker_loop pool) in + pool.workers <- worker :: pool.workers; + start_workers (remaining - 1)) + in + try + start_workers max_jobs; + pool + with exn -> + Child.with_lock pool.mutex (fun () -> + pool.stopping <- true; + Condition.broadcast pool.work_available); + List.iter Domain.join pool.workers; + raise exn + +let submit_pool_task pool payload task = + Child.with_lock pool.mutex (fun () -> + Queue.add (payload, task) pool.queued; + Condition.signal pool.work_available) + +let await_pool_completion ~poll pool = + let rec wait generation = + match + Child.with_lock pool.mutex (fun () -> + if Queue.is_empty pool.completed_tasks then None + else Some (Queue.take pool.completed_tasks)) + with + | Some completion -> completion + | None -> + poll (); + Child.await_notification pool.notifier generation |> wait + in + Child.notifier_generation pool.notifier |> wait + +let stop_worker_pool ~cancel pool = + let active = + Child.with_lock pool.mutex (fun () -> + pool.stopping <- true; + Queue.clear pool.queued; + Condition.broadcast pool.work_available; + if cancel then ( + pool.signalling_cancellation <- true; + pool.active_children + |> List.filter_map (fun active -> + match active.cancellation with + | Cancellation_requested | Cancellation_failed _ -> None + | Cancellation_not_requested -> + active.cancellation <- Cancellation_requested; + Some active.child)) + else []) + in + let signal_error = + try + Child.signal_running active; + None + with exn -> Some exn + in + Child.with_lock pool.mutex (fun () -> + Option.iter + (fun exn -> + List.iter + (fun active -> + match active.cancellation with + | Cancellation_requested -> + active.cancellation <- Cancellation_failed exn + | Cancellation_not_requested | Cancellation_failed _ -> ()) + pool.active_children) + signal_error; + pool.signalling_cancellation <- false; + Condition.broadcast pool.cancellation_finished); + Option.iter (fun _ -> Child.notify_completion pool.notifier) signal_error; + List.iter Domain.join pool.workers; + Option.iter raise signal_error + +let with_worker_pool ~max_jobs notifier action = + let pool = create_worker_pool ~max_jobs notifier in + match action pool with + | result -> + stop_worker_pool ~cancel:false pool; + result + | exception exn -> + let exn = + try + stop_worker_pool ~cancel:true pool; + exn + with cancellation_exn -> cancellation_exn + in + raise exn + +let run_dependency_graph_with_notifier ~max_jobs ~on_failure ~poll notifier + works ~next = + let graph = + Graph.create_index works + ~name:(fun work -> work.key) + ~deps:(fun work -> work.dependencies) + ~validation: + (Graph.Reject_invalid + { + duplicate_node = + (fun key -> Error ("duplicate subprocess work key: " ^ key)); + unknown_dependency = + (fun ~node ~dependency -> + Error + (Printf.sprintf + "unknown dependency %s for subprocess work %s" dependency + node)); + }) + in + let count = Graph.node_count graph in + let pending = Hashtbl.create count in + List.iter + (fun work -> + Hashtbl.add pending work.key (Graph.dependency_count graph work.key)) + works; + let priorities = Hashtbl.create count in + let remaining_dependents = Hashtbl.create count in + let leaves = Queue.create () in + List.iter + (fun work -> + let dependent_count = List.length (Graph.dependents graph work.key) in + Hashtbl.add remaining_dependents work.key dependent_count; + if dependent_count = 0 then ( + Hashtbl.add priorities work.key 1; + Queue.add work.key leaves)) + works; + while not (Queue.is_empty leaves) do + let key = Queue.take leaves in + let key_priority = Hashtbl.find priorities key in + Graph.dependencies graph key + |> List.iter (fun dependency -> + let candidate = key_priority + 1 in + let current = + Hashtbl.find_opt priorities dependency |> Option.value ~default:1 + in + if candidate > current then + Hashtbl.replace priorities dependency candidate; + let remaining = Hashtbl.find remaining_dependents dependency - 1 in + Hashtbl.replace remaining_dependents dependency remaining; + if remaining = 0 then Queue.add dependency leaves) + done; + let ready = ref Work_ready.empty in + let add_ready work = + ready := Work_ready.add (Hashtbl.find priorities work.key, work.key) !ready + in + List.iter + (fun work -> if Hashtbl.find pending work.key = 0 then add_ready work) + works; + let in_flight = ref 0 in + let stopped = ref false in + let errors = ref [] in + let record_error work exn = + match on_failure exn with + | Abort_immediately -> raise exn + | Stop_new_work -> + stopped := true; + errors := (work.key, exn) :: !errors + | Continue_independent_work -> errors := (work.key, exn) :: !errors + in + let complete work = + Graph.dependents graph work.key + |> List.iter (fun dependent_key -> + let remaining = Hashtbl.find pending dependent_key - 1 in + Hashtbl.replace pending dependent_key remaining; + if remaining = 0 then add_ready (Graph.find_node graph dependent_key)) + in + let rec fill pool = + if (not !stopped) && !in_flight < max_jobs then + match Work_ready.min_elt_opt !ready with + | None -> () + | Some ((_, key) as ready_key) -> + ready := Work_ready.remove ready_key !ready; + let work = Graph.find_node graph key in + (try + match next work.value None with + | None -> complete work + | Some task -> + submit_pool_task pool work task; + incr in_flight + with exn -> record_error work exn); + fill pool + in + let rec schedule pool = + fill pool; + if !in_flight = 0 then + match + !errors + |> List.sort (fun (first, _) (second, _) -> String.compare first second) + with + | (_, exn) :: _ -> raise exn + | [] -> + (* Without errors, only a cycle leaves a node waiting on dependencies. *) + if + Hashtbl.fold + (fun _ count blocked -> blocked || count > 0) + pending false + then invalid_arg "dependency graph contains a cycle" + else () + else + let completion = await_pool_completion ~poll pool in + decr in_flight; + (match completion with + | Task_failed (work, exn) -> record_error work exn + | Task_completed (work, result) -> ( + try + match next work.value (Some result) with + | Some task -> + submit_pool_task pool work task; + incr in_flight + | None -> complete work + with exn -> record_error work exn)); + schedule pool + in + with_worker_pool ~max_jobs:(min max_jobs count) notifier schedule + +let run_dependency_graph ?(max_jobs = default_max_jobs) + ?(on_failure = + function + | Interrupted _ -> Abort_immediately + | _ -> Stop_new_work) ?poll works ~next = + if max_jobs < 1 then raise (Error "max_jobs must be at least one"); + match works with + | [] -> () + | _ -> + with_completion_notifier ~poll (fun ~poll notifier -> + run_dependency_graph_with_notifier ~max_jobs ~on_failure ~poll notifier + works ~next) + +let run_one ?poll ?stdout_chunk ?stderr_chunk ?stdin ~cwd program args = + with_completion_notifier ~poll (fun ~poll notifier -> + let child = + Child.launch ?stdout_chunk ?stderr_chunk ?stdin ~notifier () + {program; args; cwd} + in + let completion_received = ref false in + try + let _, result = Child.wait_for_running ~poll notifier [child] in + completion_received := true; + Child.release_running child; + result + with exn -> + if not !completion_received then Child.terminate_running [child]; + raise exn) + +let run ?poll ~cwd program args = run_one ?poll ~cwd program args + +let run_streaming ?poll ~cwd program args = + let write channel bytes count = + output channel bytes 0 count; + flush channel + in + let stdin = + if Platform.inherit_streaming_terminal_stdin || not (Unix.isatty Unix.stdin) + then Child.Inherit_stdin + else Child.Null_stdin + in + run_one ?poll ~stdout_chunk:(write stdout) ~stderr_chunk:(write stderr) ~stdin + ~cwd program args diff --git a/rewatch-ocaml/process.mli b/rewatch-ocaml/process.mli new file mode 100644 index 00000000000..a611081869b --- /dev/null +++ b/rewatch-ocaml/process.mli @@ -0,0 +1,56 @@ +(** Process scheduling has two policies but one child-lifecycle owner. Parallel + lists stop immediately on interruption; dependency graphs can stop admitting + new work while already-started children drain. {!Process_child} owns the + operating-system resources in both cases. *) + +type result = {status: Unix.process_status; stdout: string; stderr: string} +type job = {program: string; args: string list; cwd: string} +type task + +exception Error of string +exception Interrupted of int + +val succeeded : result -> bool +val status_string : Unix.process_status -> string +val default_max_jobs : int + +val task : ?env:Spawn.Env.t -> ?on_result:(result -> result) -> job -> task + +val run_parallel : + ?max_jobs:int -> + ?poll:(unit -> unit) -> + ?on_complete:(int -> unit) -> + job list -> + result list + +val run_parallel_map : + ?max_jobs:int -> + ?poll:(unit -> unit) -> + ?on_complete:(int -> unit) -> + 'a list -> + job:('a -> job) -> + result list + +type 'a work = {key: string; dependencies: string list; value: 'a} + +(* [Stop_new_work] preserves results from children that already started while + ensuring no newly ready dependency is launched after a build failure. + [Continue_independent_work] also drains work that was already ready, while + failed prerequisites continue to block their dependents. *) +type failure_action = + | Abort_immediately + | Stop_new_work + | Continue_independent_work + +val run_dependency_graph : + ?max_jobs:int -> + ?on_failure:(exn -> failure_action) -> + ?poll:(unit -> unit) -> + 'a work list -> + next:('a -> result option -> task option) -> + unit + +val run : ?poll:(unit -> unit) -> cwd:string -> string -> string list -> result + +val run_streaming : + ?poll:(unit -> unit) -> cwd:string -> string -> string list -> result diff --git a/rewatch-ocaml/process_child.ml b/rewatch-ocaml/process_child.ml new file mode 100644 index 00000000000..8eda49a2ab0 --- /dev/null +++ b/rewatch-ocaml/process_child.ml @@ -0,0 +1,394 @@ +type result = {status: Unix.process_status; stdout: string; stderr: string} +type job = {program: string; args: string list; cwd: string} +type stdin_policy = Inherit_stdin | Null_stdin + +exception Error of string + +let decode_utf8_lossy value = + if String.is_valid_utf_8 value then value + else + let output = Buffer.create (String.length value) in + let rec loop index = + if index < String.length value then ( + let decoded = String.get_utf_8_uchar value index in + let length = max 1 (Uchar.utf_decode_length decoded) in + if Uchar.utf_decode_is_valid decoded then + Buffer.add_substring output value index length + else Buffer.add_utf_8_uchar output Uchar.rep; + loop (index + length)) + in + loop 0; + Buffer.contents output + +let succeeded result = result.status = Unix.WEXITED 0 + +let status_string = function + | Unix.WEXITED code -> Printf.sprintf "exit code %d" code + | Unix.WSIGNALED signal -> Printf.sprintf "signal %d" signal + | Unix.WSTOPPED signal -> Printf.sprintf "stopped by signal %d" signal + +type capture = { + thread: Thread.t; + outcome: (string, exn) Stdlib.result option ref; +} + +type child_wait = { + thread: Thread.t; + direct_outcome: (Unix.process_status, exn) Stdlib.result option Atomic.t; + outcome: (result, exn) Stdlib.result option Atomic.t; +} + +type 'a running = { + payload: 'a; + process: Platform.process; + child_wait: child_wait; +} + +type launch_ownership = { + mutable stdin: Unix.file_descr option; + mutable stdout_read: Unix.file_descr option; + mutable stdout_write: Unix.file_descr option; + mutable stderr_read: Unix.file_descr option; + mutable stderr_write: Unix.file_descr option; + mutable stdout_capture: capture option; + mutable stderr_capture: capture option; + mutable process: Platform.process option; +} + +let empty_launch_ownership () = + { + stdin = None; + stdout_read = None; + stdout_write = None; + stderr_read = None; + stderr_write = None; + stdout_capture = None; + stderr_capture = None; + process = None; + } + +type completion_notifier = { + mutex: Mutex.t; + condition: Condition.t; + mutable generation: int; + mutable stopped: bool; +} + +(* Mutex.protect needs OCaml 5.1; the minimum supported version is 5.0. *) +let with_lock mutex action = + Mutex.lock mutex; + Fun.protect ~finally:(fun () -> Mutex.unlock mutex) action + +let create_completion_notifier () = + { + mutex = Mutex.create (); + condition = Condition.create (); + generation = 0; + stopped = false; + } + +let notify_completion notifier = + with_lock notifier.mutex (fun () -> + if not notifier.stopped then ( + notifier.generation <- notifier.generation + 1; + Condition.broadcast notifier.condition)) + +let notifier_generation notifier = + with_lock notifier.mutex (fun () -> notifier.generation) + +let await_notification notifier generation = + with_lock notifier.mutex (fun () -> + while notifier.generation = generation && not notifier.stopped do + Condition.wait notifier.condition notifier.mutex + done; + notifier.generation) + +let with_completion_notifier ~ticker_enabled action = + (* The scheduler needs immediate child completion without repeatedly asking + the operating system about every running PID. A condition variable wakes + it when status and captured output are both ready; one ticker also wakes a + supplied watch poll callback every five milliseconds while children are + busy. *) + let notifier = create_completion_notifier () in + let rec send_tick () = + Thread.delay 0.005; + let continue = + with_lock notifier.mutex (fun () -> + if notifier.stopped then false + else ( + notifier.generation <- notifier.generation + 1; + Condition.broadcast notifier.condition; + true)) + in + if continue then send_tick () + in + let ticker = + if ticker_enabled then Some (Thread.create send_tick ()) else None + in + let stop () = + with_lock notifier.mutex (fun () -> + notifier.stopped <- true; + Condition.broadcast notifier.condition); + Option.iter Thread.join ticker + in + Fun.protect ~finally:stop (fun () -> action notifier) + +let close_noerr descriptor = + try Unix.close descriptor with Unix.Unix_error _ -> () + +let start_capture ?on_chunk descriptor : capture = + let outcome = ref None in + let thread = + Thread.create + (fun () -> + outcome := + Some + (try + Fun.protect + ~finally:(fun () -> close_noerr descriptor) + (fun () -> + let output = Buffer.create 4096 in + let bytes = Bytes.create 65536 in + let rec read () = + try + match + Unix.read descriptor bytes 0 (Bytes.length bytes) + with + | 0 -> () + | count -> + (match on_chunk with + | Some on_chunk -> on_chunk bytes count + | None -> Buffer.add_subbytes output bytes 0 count); + read () + with Unix.Unix_error (Unix.EINTR, _, _) -> read () + in + read (); + Ok + (match on_chunk with + | Some _ -> "" + | None -> Buffer.contents output |> decode_utf8_lossy)) + with exn -> Error exn)) + () + in + {thread; outcome} + +let capture_outcome (capture : capture) = + Thread.join capture.thread; + match !(capture.outcome) with + | Some outcome -> outcome + | None -> Error (Failure "subprocess output reader did not finish") + +let capture_error exn = + Error ("failed to capture subprocess output: " ^ Printexc.to_string exn) + +let start_child_wait pid notifier stdout_capture stderr_capture : child_wait = + let direct_outcome = Atomic.make None in + let outcome = Atomic.make None in + let rec wait () = + try + let _, status = Unix.waitpid [] pid in + status + with Unix.Unix_error (Unix.EINTR, _, _) -> wait () + in + let thread = + Thread.create + (fun () -> + let status = try Ok (wait ()) with exn -> Error exn in + Atomic.set direct_outcome (Some status); + let stdout = capture_outcome stdout_capture in + let stderr = capture_outcome stderr_capture in + let result = + match (status, stdout, stderr) with + | Ok status, Ok stdout, Ok stderr -> Ok {status; stdout; stderr} + | Error exn, _, _ -> Error exn + | _, Error exn, _ | _, _, Error exn -> Error (capture_error exn) + in + Atomic.set outcome (Some result); + notify_completion notifier) + () + in + {thread; direct_outcome; outcome} + +let fail_launch ownership launch_error = + let termination_error = + match ownership.process with + | None -> None + | Some process -> ( + match Platform.signal_process_tree process Sys.sigkill with + | Ok () -> + (try ignore (Unix.waitpid [] (Platform.process_id process)) + with Unix.Unix_error _ -> ()); + None + | Error message -> Some message) + in + List.iter + (fun descriptor -> Option.iter close_noerr descriptor) + [ + ownership.stdout_write; + ownership.stderr_write; + ownership.stdout_read; + ownership.stderr_read; + ownership.stdin; + ]; + if Option.is_none termination_error && Option.is_some ownership.process then ( + Option.iter + (fun (capture : capture) -> Thread.join capture.thread) + ownership.stdout_capture; + Option.iter + (fun (capture : capture) -> Thread.join capture.thread) + ownership.stderr_capture); + let release_error = + try + Option.iter Platform.release_process ownership.process; + None + with release_exn -> Some release_exn + in + let error = + match termination_error with + | Some message -> + Error + ("Could not terminate a partially launched subprocess tree: " ^ message) + | None -> Option.value release_error ~default:launch_error + in + raise error + +let launch ?env ?stdout_chunk ?stderr_chunk ?(stdin = Null_stdin) ~notifier + payload job = + let ownership = empty_launch_ownership () in + try + let pipes = Platform_common.create_capture_pipes () in + let (stdout_read, stdout_write), (stderr_read, stderr_write) = pipes in + ownership.stdout_read <- Some stdout_read; + ownership.stdout_write <- Some stdout_write; + ownership.stderr_read <- Some stderr_read; + ownership.stderr_write <- Some stderr_write; + let stdout = start_capture ?on_chunk:stdout_chunk stdout_read in + ownership.stdout_read <- None; + ownership.stdout_capture <- Some stdout; + let stderr = start_capture ?on_chunk:stderr_chunk stderr_read in + ownership.stderr_read <- None; + ownership.stderr_capture <- Some stderr; + let stdin = + match stdin with + | Inherit_stdin -> Unix.stdin + | Null_stdin -> + let descriptor = + Unix.openfile Platform.null_device [Unix.O_RDONLY; Unix.O_CLOEXEC] 0 + in + ownership.stdin <- Some descriptor; + descriptor + in + let process = + Platform.spawn ~env ~cwd:job.cwd ~program:job.program ~args:job.args + ~stdin ~stdout:stdout_write ~stderr:stderr_write + in + ownership.process <- Some process; + let pid = Platform.process_id process in + Option.iter close_noerr ownership.stdin; + ownership.stdin <- None; + ownership.stdout_write <- None; + close_noerr stdout_write; + ownership.stderr_write <- None; + close_noerr stderr_write; + let child_wait = start_child_wait pid notifier stdout stderr in + {payload; process; child_wait} + with exn -> fail_launch ownership exn + +let wait_for_running ~poll notifier active = + let rec find_completed = function + | [] -> None + | (child : _ running) :: rest -> ( + match Atomic.get child.child_wait.outcome with + | Some outcome -> Some (child, outcome) + | None -> find_completed rest) + in + let rec wait generation = + match find_completed active with + | Some (child, Ok result) -> (child, result) + | Some (_, Error exn) -> raise exn + | None -> + poll (); + await_notification notifier generation |> wait + in + notifier_generation notifier |> wait + +let signal_running (children : _ running list) = + if children <> [] then ( + let completion_ready (child : _ running) = + Option.is_some (Atomic.get child.child_wait.outcome) + in + let root_identity_lost (child : _ running) = + Option.is_some (Atomic.get child.child_wait.direct_outcome) + in + let signal_all signal = + List.fold_left + (fun errors child -> + if completion_ready child then errors + else + match Platform.signal_process_tree child.process signal with + | Ok () -> errors + | Error message -> (child, message) :: errors) + [] children + in + let graceful_errors = signal_all Sys.sigterm in + let deadline = Unix.gettimeofday () +. 0.25 in + let rec wait_until_deadline children = + let remaining = + List.filter (fun child -> not (root_identity_lost child)) children + in + if remaining <> [] && Unix.gettimeofday () < deadline then ( + ignore (Unix.select [] [] [] 0.01); + wait_until_deadline remaining) + else remaining + in + ignore (wait_until_deadline children); + (* Every original process group needs escalation because a direct child can + exit while a PPX or helper in its group remains alive. Children whose + result is published are skipped. A group whose direct child was reaped + but whose result is not yet published could in theory have had its ID + reused by an unrelated new group in that instant; with sequential PIDs + and a window of microseconds this is not a practical concern. *) + let termination_errors = + if Platform.escalate_process_groups then signal_all Sys.sigkill + else graceful_errors + in + (* On Darwin, signalling a group containing only zombies returns EPERM. + Pipe closure and waiter publication happen on separate threads, so the + process result can become ready just after that harmless failure. A + bounded wait distinguishes this race from a live tree that the platform + genuinely could not terminate. *) + let completion_deadline = Unix.gettimeofday () +. 0.25 in + let rec unresolved errors = + let errors = + List.filter (fun (child, _) -> not (completion_ready child)) errors + in + if errors <> [] && Unix.gettimeofday () < completion_deadline then ( + ignore (Unix.select [] [] [] 0.01); + unresolved errors) + else errors + in + match unresolved termination_errors |> List.rev with + | [] -> () + | errors -> + raise + (Error + ("Could not terminate a subprocess tree: " + ^ String.concat "; " (List.map snd errors)))) + +let payload (child : _ running) = child.payload + +let release_running (child : _ running) = + Thread.join child.child_wait.thread; + Platform.release_process child.process + +let release_after_completion child = + ignore (Thread.create release_running child) + +let terminate_running (children : _ running list) = + if children <> [] then ( + try + signal_running children; + List.iter release_running children + with exn -> + List.iter release_after_completion children; + raise exn) diff --git a/rewatch-ocaml/process_child.mli b/rewatch-ocaml/process_child.mli new file mode 100644 index 00000000000..8ddd8964589 --- /dev/null +++ b/rewatch-ocaml/process_child.mli @@ -0,0 +1,47 @@ +(** A running child is abstract so descriptors, reader threads, the waiter, and + the platform process handle always have one cleanup owner. Callers may wait, + cancel, or release it, but cannot reconstruct a partially owned child. *) + +type result = {status: Unix.process_status; stdout: string; stderr: string} +type job = {program: string; args: string list; cwd: string} +type stdin_policy = Inherit_stdin | Null_stdin + +exception Error of string + +val succeeded : result -> bool +val status_string : Unix.process_status -> string + +type completion_notifier +type 'a running + +val with_lock : Mutex.t -> (unit -> 'a) -> 'a +(** Runs the action holding the mutex and releases it on exceptions too. *) + +val with_completion_notifier : + ticker_enabled:bool -> (completion_notifier -> 'a) -> 'a + +val notify_completion : completion_notifier -> unit +val notifier_generation : completion_notifier -> int +val await_notification : completion_notifier -> int -> int + +val launch : + ?env:Spawn.Env.t -> + ?stdout_chunk:(bytes -> int -> unit) -> + ?stderr_chunk:(bytes -> int -> unit) -> + ?stdin:stdin_policy -> + notifier:completion_notifier -> + 'a -> + job -> + 'a running + +val wait_for_running : + poll:(unit -> unit) -> + completion_notifier -> + 'a running list -> + 'a running * result + +val payload : 'a running -> 'a +val signal_running : 'a running list -> unit +val release_after_completion : 'a running -> unit +val terminate_running : 'a running list -> unit +val release_running : 'a running -> unit diff --git a/rewatch-ocaml/project_context.ml b/rewatch-ocaml/project_context.ml new file mode 100644 index 00000000000..da994f0f8e9 --- /dev/null +++ b/rewatch-ocaml/project_context.ml @@ -0,0 +1,206 @@ +exception Error of string +exception Package_error of string + +let canonical_project_root folder = + if not (File_util.exists folder) then + raise + (Error + ("Could not start Rescript build: Could not write lockfile because \ + the specified project folder does not exist: " ^ folder)); + Platform.canonicalize_path folder + +type dependency_context = { + current_root: string; + workspace_root: string; + allow_upward_search: bool; + include_workspace_dependencies: bool; +} + +let path_is_within_canonical ~root path = + let normalize = Platform.normalize_path_for_comparison in + let root = normalize root in + let path = normalize path in + path = root || String.starts_with ~prefix:(Filename.concat root "") path + +let rec nearest_config_path directory = + if Config.exists_in_root directory then Some (Config.path_in_root directory) + else + let parent = Filename.dirname directory in + if parent = directory then None else nearest_config_path parent + +(* Graph roots and resolved dependency paths are already canonical. Keeping this + predicate pure avoids repeating realpath calls throughout package traversal. *) +let is_local_dependency_canonical ~workspace path = + let equal_component left right = + Platform.normalize_path_for_comparison left + = Platform.normalize_path_for_comparison right + in + let rec contains_component path component = + if equal_component (Filename.basename path) component then true + else + let parent = Filename.dirname path in + parent <> path && contains_component parent component + in + path_is_within_canonical ~root:workspace path + && not (contains_component path "node_modules") + +(* A package listed by the nearest parent rescript.json is a monorepo member. + The parent then supplies the settings that every package of a build shares + (package-specs, suffix, JSX, ...), even when the build starts in the + member, so a member build produces the same outputs as a workspace build. *) +let workspace_config_for (current : Config.t) = + match nearest_config_path (Filename.dirname current.root) with + | Some path -> ( + match Config.load path with + | parent + when List.exists + (fun (dependency : Config.dependency) -> + dependency.name = current.name) + (parent.dependencies @ parent.dev_dependencies) -> + parent + | _ -> current) + | None -> current + +let workspace_lock_root_for current = (workspace_config_for current).root + +(* The same wording as Rust rewatch's debug output, which tests compare. *) +let describe (config : Config.t) ~(workspace : Config.t) = + if workspace.root = config.root then + Printf.sprintf "Created project context for \"%s\" at \"%s\"" config.name + config.path + else + Printf.sprintf + "Created project context for \"%s\" at \"%s\" with parent workspace \ + \"%s\" at \"%s\"" + config.name config.path workspace.name workspace.path + +let workspace_lock_root folder = + workspace_lock_root_for (Config.load_root folder) + +let dependency_context (current : Config.t) = + let workspace_root = workspace_lock_root_for current in + let has_local_dependency (dependency : Config.dependency) = + let candidate = + Filename.concat + (Filename.concat current.root "node_modules") + dependency.name + in + File_util.exists candidate + && is_local_dependency_canonical ~workspace:current.root + (Platform.canonicalize_path candidate) + in + let is_monorepo_root = + List.exists has_local_dependency + (current.dependencies @ current.dev_dependencies) + in + { + current_root = current.root; + workspace_root; + allow_upward_search = workspace_root = current.root && not is_monorepo_root; + include_workspace_dependencies = workspace_root = current.root; + } + +let dependency_is_local_canonical context path = + (* A command run from one package listed by a parent workspace owns only that + package. Sibling packages still resolve through the workspace, but treating + them as local would also include their development sources, clean their + outputs, and watch their source trees. *) + context.include_workspace_dependencies + && is_local_dependency_canonical ~workspace:context.workspace_root path + +let dependency_candidates_in context package_root name = + let candidate root = + Filename.concat (Filename.concat root "node_modules") name + in + let rec in_ancestors directory acc = + let candidate = + Filename.concat (Filename.concat directory "node_modules") name + in + let parent = Filename.dirname directory in + if parent = directory then List.rev (candidate :: acc) + else in_ancestors parent (candidate :: acc) + in + let deduplicate values = + let seen = Hashtbl.create (List.length values) in + List.fold_left + (fun unique value -> + if Hashtbl.mem seen value then unique + else ( + Hashtbl.add seen value (); + value :: unique)) + [] values + |> List.rev + in + let direct = + [ + candidate package_root; + candidate context.current_root; + candidate context.workspace_root; + ] + |> deduplicate + in + if context.allow_upward_search then + deduplicate (direct @ in_ancestors (Filename.dirname package_root) []) + else direct + +let dependency_path_in context package_root name = + let existing_realpath path = + if File_util.exists path then Some (Platform.canonicalize_path path) + else None + in + dependency_candidates_in context package_root name + |> List.find_map existing_realpath + +let standalone_dependency_context root = + { + current_root = root; + workspace_root = root; + allow_upward_search = true; + include_workspace_dependencies = true; + } + +let dependency_path root name = + dependency_path_in (standalone_dependency_context root) root name + +let require_dependency_directory ~context package_root + (dependency : Config.dependency) = + match dependency_path_in context package_root dependency.name with + | None -> + raise + (Package_error + (Printf.sprintf + "Could not build package tree reading dependency '%s' at path \ + '%s'. Error: Could not resolve dependency %s" + dependency.name context.current_root dependency.name)) + | Some directory when not (Config.exists_in_root directory) -> + raise + (Package_error + (Printf.sprintf + "Could not build package tree for '%s' at path '%s'. Error: no \ + rescript.json or bsconfig.json in %s" + dependency.name context.current_root directory)) + | Some directory -> directory + +let relative_to_opt root path = + let prefix = Filename.concat root "" in + let comparable = Platform.normalize_path_for_comparison in + if comparable path = comparable root then Some "." + else if String.starts_with ~prefix:(comparable prefix) (comparable path) then + Some + (String.sub path (String.length prefix) + (String.length path - String.length prefix)) + else None + +let relative_to root path = + match relative_to_opt root path with + | Some relative -> relative + | None -> raise (Error (path ^ " is not inside " ^ root)) + +let relative_or_absolute ~root path = + Option.value (relative_to_opt root path) ~default:path + +let display_path ~root path = + match relative_or_absolute ~root path with + | "." -> "." + | relative when path_is_within_canonical ~root path -> "./" ^ relative + | absolute -> absolute diff --git a/rewatch-ocaml/project_context.mli b/rewatch-ocaml/project_context.mli new file mode 100644 index 00000000000..c54e1c80cc0 --- /dev/null +++ b/rewatch-ocaml/project_context.mli @@ -0,0 +1,30 @@ +exception Error of string +exception Package_error of string + +type dependency_context + +val canonical_project_root : string -> string + +val nearest_config_path : string -> string option + +val workspace_config_for : Config.t -> Config.t +val describe : Config.t -> workspace:Config.t -> string +val workspace_lock_root : string -> string +val dependency_context : Config.t -> dependency_context +val dependency_is_local_canonical : dependency_context -> string -> bool + +val dependency_candidates_in : + dependency_context -> string -> string -> string list + +val dependency_path_in : dependency_context -> string -> string -> string option + +val dependency_path : string -> string -> string option + +val require_dependency_directory : + context:dependency_context -> string -> Config.dependency -> string + +val relative_to : string -> string -> string +val relative_to_opt : string -> string -> string option +val relative_or_absolute : root:string -> string -> string +val display_path : root:string -> string -> string +val path_is_within_canonical : root:string -> string -> bool diff --git a/rewatch-ocaml/rescript_ocaml.ml b/rewatch-ocaml/rescript_ocaml.ml new file mode 100644 index 00000000000..5814ffdfb40 --- /dev/null +++ b/rewatch-ocaml/rescript_ocaml.ml @@ -0,0 +1,94 @@ +(* Signal handlers can run on any domain, including between spawning a child + and registering its cleanup owner. Recording the request and raising from + the command's poll point keeps unwinding on the domain that owns scheduler, + lock, and temporary-output cleanup. *) +let with_termination_handlers action = + let requested_exit = Atomic.make 0 in + let interrupt signal = + (* Shells report a process killed by signal n as exit status 128 + n. *) + let exit_code = + if signal = Sys.sigint then 130 + else if signal = Sys.sigterm then 143 + else if signal = Sys.sighup then 129 + else if signal = Sys.sigquit then 131 + else 1 + in + ignore (Atomic.compare_and_set requested_exit 0 exit_code) + in + let poll () = + let exit_code = Atomic.get requested_exit in + if exit_code <> 0 then raise (Process.Interrupted exit_code) + in + let result = + Termination_signals.with_handlers interrupt (fun () -> action ~poll) + in + poll (); + result + +let run_command ~poll = function + | Cli.Build + { + verbosity; + folder; + prod; + features; + warn_error; + after_build; + filter; + clear_screen; + no_timing; + } -> + ignore clear_screen; + Build.run ~poll ~verbosity ~folder ~prod ~features ~warn_error ~after_build + ~filter ~no_timing + | Cli.Watch + { + verbosity; + folder; + prod; + features; + warn_error; + after_build; + filter; + clear_screen; + no_timing; + } -> + ignore no_timing; + Build.watch ~verbosity ~folder ~prod ~features ~warn_error ~after_build + ~filter ~clear_screen + | Cli.Format (Cli.Format_stdin extension) -> + Format.format_stdin ~poll extension + | Cli.Format (Cli.Format_files {verbosity; check; paths}) -> + Format.run_files ~poll ~verbosity ~check paths + | Cli.Compiler_args {verbosity; path} -> + print_endline (Compiler_args_command.run ~verbosity path) + | Cli.Clean {verbosity; folder; prod} -> + Clean.run ~poll ~verbosity ~folder ~prod + +let run = function + | Cli.Watch _ as command -> run_command ~poll:(fun () -> ()) command + | command -> + with_termination_handlers (fun ~poll -> run_command ~poll command) + +let () = + Platform.configure_standard_streams (); + try + match Cli.eval Sys.argv with + | Cli.Run command -> run command + | Cli.Exit code -> exit code + with + | Project_context.Package_error message -> + prerr_endline message; + exit 2 + | Config.Error message + | Source.Error message + | Project_context.Error message + | Process.Error message + | Format.Error message -> + prerr_endline message; + exit 1 + | Watcher.Stop -> exit 0 + | Process.Interrupted exit_code -> exit exit_code + | (Sys_error _ as exn) | (Unix.Unix_error _ as exn) -> + prerr_endline (Printexc.to_string exn); + exit 1 diff --git a/rewatch-ocaml/rewatch_version.ml b/rewatch-ocaml/rewatch_version.ml new file mode 100644 index 00000000000..5b5705ae522 --- /dev/null +++ b/rewatch-ocaml/rewatch_version.ml @@ -0,0 +1 @@ +let version = "13.0.0-alpha.7" diff --git a/rewatch-ocaml/rewatch_version.mli b/rewatch-ocaml/rewatch_version.mli new file mode 100644 index 00000000000..8579193c227 --- /dev/null +++ b/rewatch-ocaml/rewatch_version.mli @@ -0,0 +1 @@ +val version : string diff --git a/rewatch-ocaml/source.ml b/rewatch-ocaml/source.ml new file mode 100644 index 00000000000..750f8a838d5 --- /dev/null +++ b/rewatch-ocaml/source.ml @@ -0,0 +1,428 @@ +type module_ = { + name: string; + implementation: string; + interface: string option; + is_dev: bool; +} + +type discovery = { + modules: module_ list; + source_mtimes: (string * float) list; + inventory_files: string list; + present_files: string list; + gentype_dirs: string list; +} + +type discovered_file = {path: string; modified: float} +type source_kind = Implementation | Interface + +type scanned_file = {file: discovered_file; kind: source_kind; is_dev: bool} + +type scanned_sources = { + files: scanned_file list; + inventory_files: string list; + present_files: string list; + gentype_dirs: string list; +} + +exception Error of string + +let source_kind path = + match Filename.extension path with + | ".res" -> Some Implementation + | ".resi" -> Some Interface + | _ -> None + +let module_name path = + path |> Filename.basename |> Filename.remove_extension + |> String.capitalize_ascii + +let is_non_exotic_module_name name = + let is_ascii_uppercase = function + | 'A' .. 'Z' -> true + | _ -> false + in + let is_ascii_alphanumeric = function + | 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' -> true + | _ -> false + in + let rec valid_tail index = + if index = String.length name then true + else + let character = name.[index] in + (is_ascii_alphanumeric character || character = '_') + && valid_tail (index + 1) + in + String.length name > 0 && is_ascii_uppercase name.[0] && valid_tail 1 + +let display_path ~display_root root path = + let absolute = + if Filename.is_relative path then Filename.concat root path else path + in + let display_root = Platform.canonicalize_path display_root in + Project_context.relative_or_absolute ~root:display_root absolute + +let duplicate_error ~display_root root name first second = + let first, second = + let first = display_path ~display_root root first in + let second = display_path ~display_root root second in + if String.compare first second <= 0 then (first, second) else (second, first) + in + Error + (Printf.sprintf + "Could not initialize build: Duplicate module name: %s. Found in %s and \ + %s. Rename one of these files." + name first second) + +let interface_mismatch_error implementation interface = + Error + (Printf.sprintf + "Could not initialize build: Implementation and interface have \ + different path names or different cases: `%s` vs `%s`" + implementation interface) + +(* A package source tree has three consumers with deliberately different + recursion rules. Compilation follows directory links and honors source + activation/subdirs; cleanup inventories every real descendant but treats + links as leaves; GenType records every configured directory that its + subdirs setting reaches. Keeping the views in one walk gives every consumer + the same filesystem snapshot without weakening stale-output cleanup. *) +let scan_source ~root (source : Config.source) ~discover_modules ~on_missing + ~visited_dirs ~visited_inventory_dirs ~collect_inventory ~collect_gentype + ~visited_gentype_dirs candidates inventory_files present_files gentype_dirs + = + let rec scan_directory ~relative ~collect_inventory ~discover_requested + ~collect_gentype ~identity = + let absolute = Filename.concat root relative in + let coverage table requested = + if requested then + Traversal_coverage.admit table identity ~recursive:source.recurse + else Traversal_coverage.Skip + in + let discovery = coverage visited_dirs discover_requested in + let gentype = coverage visited_gentype_dirs collect_gentype in + let inventory = + if collect_inventory then + Traversal_coverage.admit visited_inventory_dirs identity ~recursive:true + else Traversal_coverage.Skip + in + let discover_here = Traversal_coverage.visits_current discovery in + let discover_children = Traversal_coverage.visits_descendants discovery in + let inventory_here = Traversal_coverage.visits_current inventory in + let inventory_children = Traversal_coverage.visits_descendants inventory in + let gentype_here = Traversal_coverage.visits_current gentype in + let gentype_children = Traversal_coverage.visits_descendants gentype in + if gentype_here then gentype_dirs := relative :: !gentype_dirs; + if + inventory <> Traversal_coverage.Skip + || discovery <> Traversal_coverage.Skip + || gentype <> Traversal_coverage.Skip + then + let entries = + try File_util.directory_entries absolute |> List.sort String.compare + with Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> + if discover_here || discover_children then on_missing absolute; + [] + in + let record_candidate relative_path absolute_path metadata = + present_files := absolute_path :: !present_files; + if inventory_here then + inventory_files := absolute_path :: !inventory_files; + if discover_here && metadata.Unix.st_kind = Unix.S_REG then + match source_kind relative_path with + | None -> () + | Some kind -> + candidates := + { + file = {path = relative_path; modified = metadata.Unix.st_mtime}; + kind; + is_dev = source.is_dev; + } + :: !candidates + in + List.iter + (fun name -> + let relative_path = Filename.concat relative name in + let absolute_path = Filename.concat root relative_path in + match Unix.lstat absolute_path with + | metadata -> ( + match metadata.Unix.st_kind with + | Unix.S_DIR -> + if inventory_children || discover_children || gentype_children + then + let identity = + Platform.directory_identity ~path:absolute_path metadata + in + scan_directory ~relative:relative_path + ~collect_inventory:inventory_children + ~discover_requested:discover_children + ~collect_gentype:gentype_children ~identity + | Unix.S_LNK -> ( + match Unix.stat absolute_path with + | target_metadata -> ( + match target_metadata.Unix.st_kind with + | Unix.S_DIR -> + if inventory_here then + inventory_files := absolute_path :: !inventory_files; + if discover_children || gentype_children then + let identity = + Platform.directory_identity ~path:absolute_path + target_metadata + in + scan_directory ~relative:relative_path + ~collect_inventory:false + ~discover_requested:discover_children + ~collect_gentype:gentype_children ~identity + | _ -> + record_candidate relative_path absolute_path target_metadata) + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) + -> + ()) + | _ -> record_candidate relative_path absolute_path metadata) + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> ()) + entries + in + let relative = source.dir in + let absolute = Filename.concat root relative in + match Unix.lstat absolute with + | metadata -> ( + match metadata.Unix.st_kind with + | Unix.S_DIR -> + let identity = Platform.directory_identity ~path:absolute metadata in + scan_directory ~relative ~collect_inventory + ~discover_requested:discover_modules ~collect_gentype ~identity + | Unix.S_LNK -> ( + match Unix.stat absolute with + | target_metadata -> ( + match target_metadata.Unix.st_kind with + | Unix.S_DIR -> + inventory_files := absolute :: !inventory_files; + let identity = + Platform.directory_identity ~path:absolute target_metadata + in + scan_directory ~relative ~collect_inventory:false + ~discover_requested:discover_modules ~collect_gentype ~identity + | _ -> + present_files := absolute :: !present_files; + inventory_files := absolute :: !inventory_files; + if discover_modules then on_missing absolute) + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> + if discover_modules then on_missing absolute) + | _ -> + present_files := absolute :: !present_files; + inventory_files := absolute :: !inventory_files; + if discover_modules then on_missing absolute) + | exception Unix.Unix_error ((Unix.ENOENT | Unix.ENOTDIR), _, _) -> + if discover_modules then on_missing absolute + +let resolve_active_features (config : Config.t) requested = + let active_features = Hashtbl.create 16 in + let visiting_features = Hashtbl.create 16 in + let features = Hashtbl.create (List.length config.features) in + List.iter + (fun (name, implied) -> Hashtbl.replace features name implied) + config.features; + let raise_feature_cycle feature visiting = + let chain = List.rev (feature :: visiting) |> String.concat " -> " in + raise (Error ("Cycle detected in `features` map: " ^ chain)) + in + let rec activate feature visiting = + if Hashtbl.mem visiting_features feature then + raise_feature_cycle feature visiting; + if not (Hashtbl.mem active_features feature) then ( + Hashtbl.add visiting_features feature (); + let implied = + Hashtbl.find_opt features feature |> Option.value ~default:[] + in + List.iter (fun name -> activate name (feature :: visiting)) implied; + Hashtbl.remove visiting_features feature; + Hashtbl.add active_features feature ()) + in + List.iter (fun feature -> activate feature []) requested; + active_features + +let feature_enabled ~all_features ~active_features (source : Config.source) = + all_features + || Option.fold ~none:true + ~some:(fun feature -> Hashtbl.mem active_features feature) + source.feature + +let source_is_active ~prod ~all_features ~active_features + (source : Config.source) = + (not (prod && source.is_dev)) + && feature_enabled ~all_features ~active_features source + +let active_sources (config : Config.t) ~prod ~features = + let active_features = + resolve_active_features config (Option.value features ~default:[]) + in + let all_features = Option.is_none features in + List.filter + (source_is_active ~prod ~all_features ~active_features) + config.sources + +let namespace_members ~entry modules = + modules + |> List.filter (fun module_ -> Some module_.name <> entry) + |> List.filter (fun module_ -> is_non_exotic_module_name module_.name) + +let scan_sources ~on_missing (config : Config.t) ~prod ~features + ~collect_inventory ~collect_gentype = + let active_features = + resolve_active_features config (Option.value features ~default:[]) + in + let all_features = features = None in + let visited_dirs = Hashtbl.create 32 in + let visited_inventory_dirs = Hashtbl.create 32 in + let visited_gentype_dirs = Hashtbl.create 32 in + let files = ref [] in + let inventory_files = ref [] in + let present_files = ref [] in + let gentype_dirs = ref [] in + config.sources + |> List.iter (fun (source : Config.source) -> + let discover_modules = + source_is_active ~prod ~all_features ~active_features source + in + scan_source ~root:config.root source ~discover_modules ~on_missing + ~visited_dirs ~visited_inventory_dirs ~collect_inventory + ~collect_gentype: + (collect_gentype + && feature_enabled ~all_features ~active_features source) + ~visited_gentype_dirs files inventory_files present_files gentype_dirs); + { + files = !files; + inventory_files = List.sort_uniq String.compare !inventory_files; + present_files = List.sort_uniq String.compare !present_files; + gentype_dirs = List.sort_uniq String.compare !gentype_dirs; + } + +let discover_for_cleanup ~on_missing (config : Config.t) ~prod = + let scanned = + scan_sources ~on_missing config ~prod ~features:None + ~collect_inventory:false ~collect_gentype:false + in + let implementations = + scanned.files + |> List.filter_map (fun source -> + match source.kind with + | Interface -> None + | Implementation -> Some source.file.path) + |> List.sort_uniq String.compare + in + implementations + +let discover_files ~on_missing (config : Config.t) ~prod ~features = + let scanned = + scan_sources ~on_missing config ~prod ~features ~collect_inventory:false + ~collect_gentype:false + in + scanned.files + |> List.map (fun source -> source.file.path) + |> List.sort_uniq String.compare + +let discover_with_inventory ?(on_orphan = fun _ -> ()) ~on_missing + ?(display_root = Sys.getcwd ()) (config : Config.t) ~prod ~features ~filter + = + let matches_filter = + match filter with + | None -> fun _ -> true + | Some filter -> Source_filter.matches_basename filter + in + let scanned = + scan_sources ~on_missing config ~prod ~features ~collect_inventory:true + ~collect_gentype:(config.gentype_args <> []) + in + let files = scanned.files in + let table = Hashtbl.create (List.length files) in + List.iter + (fun source -> + let file = source.file in + let is_dev = source.is_dev in + let name = module_name file.path in + let implementation, interface, old_dev = + match Hashtbl.find_opt table name with + | None -> (None, None, is_dev) + | Some values -> values + in + match source.kind with + | Interface -> ( + match interface with + | Some previous -> + raise + (duplicate_error ~display_root config.root name previous.path + file.path) + | None -> + Hashtbl.replace table name + (implementation, Some file, old_dev || is_dev)) + | Implementation -> ( + match implementation with + | Some previous -> + raise + (duplicate_error ~display_root config.root name previous.path + file.path) + | None -> + Hashtbl.replace table name (Some file, interface, old_dev || is_dev))) + (List.filter (fun source -> matches_filter source.file.path) files); + Hashtbl.iter + (fun _ (implementation, interface, _) -> + match (implementation, interface) with + | Some implementation, Some interface + when Filename.remove_extension implementation.path + <> Filename.remove_extension interface.path -> + raise (interface_mismatch_error implementation.path interface.path) + | _ -> ()) + table; + Hashtbl.to_seq table + |> Seq.filter_map (fun (_, (implementation, interface, _)) -> + match (implementation, interface) with + | None, Some interface -> Some interface.path + | _ -> None) + |> List.of_seq |> List.sort String.compare |> List.iter on_orphan; + let modules = + Hashtbl.to_seq table + |> Seq.filter_map (fun (name, (implementation, interface, is_dev)) -> + match implementation with + | None -> None + | Some implementation -> + Some + { + name; + implementation = implementation.path; + interface = Option.map (fun file -> file.path) interface; + is_dev; + }) + |> List.of_seq + |> List.sort (fun a b -> String.compare a.name b.name) + in + let source_mtimes = + Hashtbl.to_seq_values table + |> Seq.flat_map (fun (implementation, interface, _) -> + List.to_seq (Option.to_list implementation @ Option.to_list interface)) + |> Seq.map (fun file -> (file.path, file.modified)) + |> List.of_seq + in + { + modules; + source_mtimes; + inventory_files = scanned.inventory_files; + present_files = scanned.present_files; + gentype_dirs = scanned.gentype_dirs; + } + +let ast_path path = + Filename.remove_extension path + ^ if Filename.extension path = ".resi" then ".iast" else ".ast" + +let compiler_basename config module_name = + Config.namespaced_module_name config.Config.namespace module_name + +(* Compiler artifacts preserve the source filename's case, while dependency + graph module names are capitalized. Keep those two names distinct. *) +let compiler_asset_basename config path = + let basename = path |> Filename.basename |> Filename.remove_extension in + match config.Config.namespace with + | Config.No_namespace -> basename + | Config.Namespace namespace -> basename ^ "-" ^ namespace + | Config.Namespace_with_entry {name; entry} -> + if entry = module_name path then basename else basename ^ "-@" ^ name diff --git a/rewatch-ocaml/source.mli b/rewatch-ocaml/source.mli new file mode 100644 index 00000000000..aca9f6f8df8 --- /dev/null +++ b/rewatch-ocaml/source.mli @@ -0,0 +1,59 @@ +(** Discovery keeps filesystem files separate from compilable modules. Commands + such as formatting can operate on orphan interfaces and duplicate basenames, + while compilation uses [module_] after pairing and duplicate validation. *) + +type module_ = { + name: string; + implementation: string; + interface: string option; + is_dev: bool; +} + +type discovery = { + modules: module_ list; + source_mtimes: (string * float) list; + inventory_files: string list; + present_files: string list; + gentype_dirs: string list; +} + +exception Error of string + +type source_kind = Implementation | Interface + +val source_kind : string -> source_kind option +val module_name : string -> string +val namespace_members : entry:string option -> module_ list -> module_ list + +val duplicate_error : + display_root:string -> string -> string -> string -> string -> exn + +val resolve_active_features : + Config.t -> string list -> (string, unit) Hashtbl.t + +val active_sources : + Config.t -> prod:bool -> features:string list option -> Config.source list + +val discover_for_cleanup : + on_missing:(string -> unit) -> Config.t -> prod:bool -> string list + +val discover_files : + on_missing:(string -> unit) -> + Config.t -> + prod:bool -> + features:string list option -> + string list + +val discover_with_inventory : + ?on_orphan:(string -> unit) -> + on_missing:(string -> unit) -> + ?display_root:string -> + Config.t -> + prod:bool -> + features:string list option -> + filter:Source_filter.t option -> + discovery + +val ast_path : string -> string +val compiler_basename : Config.t -> string -> string +val compiler_asset_basename : Config.t -> string -> string diff --git a/rewatch-ocaml/source_dirs.ml b/rewatch-ocaml/source_dirs.ml new file mode 100644 index 00000000000..b92834e8481 --- /dev/null +++ b/rewatch-ocaml/source_dirs.ml @@ -0,0 +1,91 @@ +type scan = {build_root: string; scan_dirs: string list} + +(* Every scan includes its build root, as in Rust's .sourcedirs.json. *) +let scan_json scan = + `Assoc + [ + ("also_scan_build_root", `Bool true); + ("build_root", `String scan.build_root); + ("scan_dirs", `List (List.map (fun path -> `String path) scan.scan_dirs)); + ] + +let write ~root ~dirs ~packages ~scans = + let path = File_util.path_of_parts root ["lib"; "bs"; ".sourcedirs.json"] in + File_util.ensure_dir (Filename.dirname path); + let json = + `Assoc + [ + ("cmt_scan", `List (List.map scan_json scans)); + ("dirs", `List (List.map (fun path -> `String path) dirs)); + ("generated", `List []); + ( "pkgs", + `List + (List.map + (fun (name, path) -> `List [`String name; `String path]) + packages) ); + ("version", `Int 2); + ] + in + File_util.write_file_atomic ~ensure_parent:false path + (Yojson.Safe.to_string json) + +let write_build ~(root_config : Config.t) session = + let packages = + Build_session.package_plan_values session + |> List.of_seq + |> List.sort (fun (left : Package_plan.t) right -> + String.compare left.root right.root) + in + packages + |> List.iter (fun package -> + if package.Package_plan.root <> root_config.root then + File_util.remove_file + (File_util.path_of_parts package.root + ["lib"; "bs"; ".sourcedirs.json"])); + let local_packages = + List.filter (fun package -> package.Package_plan.is_local) packages + in + let source_directories package = + package.Package_plan.modules + |> List.map (fun module_ -> Filename.dirname module_.Source.implementation) + |> List.sort_uniq String.compare + in + let relative_package_root package = + if package.Package_plan.root = root_config.root then "" + else Project_context.relative_to root_config.root package.root + in + let dirs = + local_packages + |> List.concat_map (fun package -> + let relative_root = relative_package_root package in + source_directories package + |> List.map (fun directory -> + if relative_root = "" then directory + else Filename.concat relative_root directory)) + |> List.sort_uniq String.compare + in + let package_roots = Hashtbl.create 16 in + local_packages + |> List.iter (fun package -> + package.Package_plan.dependencies + |> List.iter (fun dependency -> + Hashtbl.replace package_roots dependency.Package_plan.declaration.name + dependency.directory)); + let package_roots = + Hashtbl.to_seq package_roots + |> List.of_seq + |> List.sort (fun (left, _) (right, _) -> String.compare left right) + in + let scans = + local_packages + |> List.map (fun package -> + let relative_root = relative_package_root package in + let build_root = + if relative_root = "" then File_util.path_of_parts "" ["lib"; "bs"] + else File_util.path_of_parts relative_root ["lib"; "bs"] + in + {build_root; scan_dirs = source_directories package}) + |> List.sort (fun (left : scan) right -> + String.compare left.build_root right.build_root) + in + write ~root:root_config.root ~dirs ~packages:package_roots ~scans diff --git a/rewatch-ocaml/source_dirs.mli b/rewatch-ocaml/source_dirs.mli new file mode 100644 index 00000000000..95f6c90978a --- /dev/null +++ b/rewatch-ocaml/source_dirs.mli @@ -0,0 +1 @@ +val write_build : root_config:Config.t -> Build_session.t -> unit diff --git a/rewatch-ocaml/source_filter.ml b/rewatch-ocaml/source_filter.ml new file mode 100644 index 00000000000..bf864d8db6d --- /dev/null +++ b/rewatch-ocaml/source_filter.ml @@ -0,0 +1,60 @@ +type t = {pattern: string; regex: Re.re} + +let unsupported = Error "unsupported regular expression" + +(* A filter that compiles with different semantics can silently select the + wrong source set. Keep the accepted grammar to the CLI's shared safe subset; + the regex parser below rejects unsupported syntax outside this check. *) +let validate_compatibility pattern = + let length = String.length pattern in + let rec loop ~in_class ~class_start index = + if index >= length then Ok () + else + match pattern.[index] with + | '\\' when index + 1 < length -> ( + let escaped = pattern.[index + 1] in + match escaped with + | '0' .. '9' | 'Q' | 'E' | 'G' | 'Z' | 'e' | 'o' -> unsupported + | ('b' | 'W') when in_class -> unsupported + | _ -> loop ~in_class ~class_start (index + 2)) + | '(' + when (not in_class) + && index + 2 < length + && pattern.[index + 1] = '?' + && pattern.[index + 2] = '#' -> + unsupported + | '[' when not in_class -> + loop ~in_class:true ~class_start:(index + 1) (index + 1) + | '[' when index + 1 >= length || pattern.[index + 1] <> ':' -> + unsupported + | ']' when in_class && index > class_start -> + loop ~in_class:false ~class_start:0 (index + 1) + | ('&' | '-' | '~') as operator + when in_class && index + 1 < length && pattern.[index + 1] = operator -> + unsupported + | '-' + when in_class && index > class_start + && index + 1 < length + && pattern.[index + 1] <> ']' -> + let left = pattern.[index - 1] in + let right = pattern.[index + 1] in + let escaped_left = index >= 2 && pattern.[index - 2] = '\\' in + if escaped_left || left = '\\' || right = '\\' || left > right then + unsupported + else loop ~in_class ~class_start (index + 1) + | _ -> loop ~in_class ~class_start (index + 1) + in + loop ~in_class:false ~class_start:0 0 + +let compile pattern = + match validate_compatibility pattern with + | Error _ as error -> error + | Ok () -> ( + match Re.Perl.re_result pattern with + | Ok regex -> Ok {pattern; regex = Re.compile regex} + | Error `Parse_error -> Error "invalid regular expression" + | Error `Not_supported -> unsupported) + +let pattern filter = filter.pattern +let matches_basename filter path = + Re.execp filter.regex (Filename.basename path) diff --git a/rewatch-ocaml/source_filter.mli b/rewatch-ocaml/source_filter.mli new file mode 100644 index 00000000000..2b533c9dc5a --- /dev/null +++ b/rewatch-ocaml/source_filter.mli @@ -0,0 +1,5 @@ +type t + +val compile : string -> (t, string) result +val pattern : t -> string +val matches_basename : t -> string -> bool diff --git a/rewatch-ocaml/strict_json.ml b/rewatch-ocaml/strict_json.ml new file mode 100644 index 00000000000..e930cb03275 --- /dev/null +++ b/rewatch-ocaml/strict_json.ml @@ -0,0 +1,149 @@ +(* Yojson also accepts comments, unquoted keys, NaN, and Infinity. Other tools + that read rescript.json, such as the editor extension, use standard JSON + parsers, so a configuration the build accepted would fail there. This + validator rejects anything outside RFC 8259 before Yojson parses it. *) + +type error = {line: int; column: int; message: string} + +exception Invalid of int * string + +let error_at contents index message = + let line = ref 1 and column = ref 1 in + for position = 0 to min index (String.length contents) - 1 do + match contents.[position] with + | '\n' -> + incr line; + column := 1 + (* Count characters rather than bytes: skip UTF-8 continuation bytes. *) + | character when Char.code character land 0xC0 = 0x80 -> () + | _ -> incr column + done; + {line = !line; column = !column; message} + +let check contents = + let length = String.length contents in + let fail index message = raise (Invalid (index, message)) in + let peek index = if index < length then Some contents.[index] else None in + let rec skip_whitespace index = + match peek index with + | Some (' ' | '\t' | '\n' | '\r') -> skip_whitespace (index + 1) + | Some '/' -> fail index "comments are not allowed in JSON" + | Some _ | None -> index + in + let expect_literal index literal = + let literal_length = String.length literal in + if + index + literal_length <= length + && String.sub contents index literal_length = literal + then index + literal_length + else fail index "expected a value" + in + let is_digit = function + | '0' .. '9' -> true + | _ -> false + in + let rec digits index = + match peek index with + | Some character when is_digit character -> digits (index + 1) + | Some _ | None -> index + in + let one_or_more_digits index = + match peek index with + | Some character when is_digit character -> digits index + | Some _ | None -> fail index "invalid number" + in + let number index = + let index = if peek index = Some '-' then index + 1 else index in + let index = + match peek index with + | Some '0' -> index + 1 + | Some '1' .. '9' -> digits index + | Some _ | None -> fail index "invalid number" + in + let index = + if peek index = Some '.' then one_or_more_digits (index + 1) else index + in + match peek index with + | Some ('e' | 'E') -> + let index = index + 1 in + let index = + match peek index with + | Some ('+' | '-') -> index + 1 + | Some _ | None -> index + in + one_or_more_digits index + | Some _ | None -> index + in + let is_hex = function + | '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' -> true + | _ -> false + in + let rec string_body index = + match peek index with + | None -> fail index "unterminated string" + | Some '"' -> index + 1 + | Some '\\' -> ( + match peek (index + 1) with + | Some ('"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't') -> + string_body (index + 2) + | Some 'u' -> + for offset = 2 to 5 do + match peek (index + offset) with + | Some character when is_hex character -> () + | Some _ | None -> fail index "invalid \\u escape" + done; + string_body (index + 6) + | Some _ | None -> fail index "invalid escape in string") + | Some character when Char.code character < 0x20 -> + fail index "control characters must be escaped in strings" + | Some _ -> string_body (index + 1) + in + let string index = + match peek index with + | Some '"' -> string_body (index + 1) + | Some _ | None -> fail index "expected a string key" + in + let rec value index = + let index = skip_whitespace index in + match peek index with + | Some '{' -> members (index + 1) ~first:true + | Some '[' -> elements (index + 1) ~first:true + | Some '"' -> string_body (index + 1) + | Some ('-' | '0' .. '9') -> number index + | Some 't' -> expect_literal index "true" + | Some 'f' -> expect_literal index "false" + | Some 'n' -> expect_literal index "null" + | Some _ | None -> fail index "expected a value" + and members index ~first = + let index = skip_whitespace index in + match peek index with + | Some '}' when first -> index + 1 + | Some '}' -> fail index "trailing comma" + | Some _ | None -> ( + let index = skip_whitespace (string index) in + if peek index <> Some ':' then fail index "expected ':'"; + let index = skip_whitespace (value (index + 1)) in + match peek index with + | Some ',' -> members (index + 1) ~first:false + | Some '}' -> index + 1 + | Some _ | None -> fail index "expected ',' or '}'") + and elements index ~first = + let index = skip_whitespace index in + match peek index with + | Some ']' when first -> index + 1 + | Some ']' -> fail index "trailing comma" + | Some _ | None -> ( + let index = skip_whitespace (value index) in + match peek index with + | Some ',' -> elements (index + 1) ~first:false + | Some ']' -> index + 1 + | Some _ | None -> fail index "expected ',' or ']'") + in + try + if not (String.is_valid_utf_8 contents) then fail 0 "invalid UTF-8"; + if String.starts_with ~prefix:"\xEF\xBB\xBF" contents then + fail 0 "byte order mark is not allowed"; + let index = skip_whitespace (value 0) in + if index < length then fail index "unexpected content after the value"; + Ok () + with Invalid (index, message) -> Error (error_at contents index message) diff --git a/rewatch-ocaml/strict_json.mli b/rewatch-ocaml/strict_json.mli new file mode 100644 index 00000000000..12d985db58f --- /dev/null +++ b/rewatch-ocaml/strict_json.mli @@ -0,0 +1,6 @@ +type error = {line: int; column: int; message: string} + +val check : string -> (unit, error) result +(** Checks that the text is standard JSON (RFC 8259), reporting the first + violation, such as a comment or trailing comma, with its 1-based line and + column (in characters). *) diff --git a/rewatch-ocaml/string_util.ml b/rewatch-ocaml/string_util.ml new file mode 100644 index 00000000000..35900a6a8ea --- /dev/null +++ b/rewatch-ocaml/string_util.ml @@ -0,0 +1,24 @@ +(* OCaml 5.5 provides [String.includes], but Rewatch also supports OCaml 5.0. + The affixes checked here are short markers, so this allocation-free scan + keeps the compatibility implementation simpler than a general-purpose + substring-search algorithm. *) +let contains value substring = + let substring_length = String.length substring in + let last_start = String.length value - substring_length in + let rec matches_at start offset = + offset = substring_length + || String.get value (start + offset) = String.get substring offset + && matches_at start (offset + 1) + in + let rec search start = + start <= last_start && (matches_at start 0 || search (start + 1)) + in + search 0 + +let strip_prefix ~prefix value = + if String.starts_with ~prefix value then + String.sub value (String.length prefix) + (String.length value - String.length prefix) + else value + +let strip_path path message = strip_prefix ~prefix:(path ^ ": ") message diff --git a/rewatch-ocaml/string_util.mli b/rewatch-ocaml/string_util.mli new file mode 100644 index 00000000000..31a1ef074bf --- /dev/null +++ b/rewatch-ocaml/string_util.mli @@ -0,0 +1,6 @@ +val contains : string -> string -> bool +val strip_prefix : prefix:string -> string -> string + +val strip_path : string -> string -> string +(** Removes the ["path: "] prefix that [Sys_error] messages carry, so callers + can report the path in their own wording. *) diff --git a/rewatch-ocaml/termination_signals.ml b/rewatch-ocaml/termination_signals.ml new file mode 100644 index 00000000000..ae69a1940e9 --- /dev/null +++ b/rewatch-ocaml/termination_signals.ml @@ -0,0 +1,10 @@ +let with_handlers handler action = + let rec install = function + | [] -> action () + | signal :: signals -> + let previous = Sys.signal signal (Sys.Signal_handle handler) in + Fun.protect + (fun () -> install signals) + ~finally:(fun () -> ignore (Sys.signal signal previous)) + in + install Platform.termination_signals diff --git a/rewatch-ocaml/termination_signals.mli b/rewatch-ocaml/termination_signals.mli new file mode 100644 index 00000000000..77cfe608acb --- /dev/null +++ b/rewatch-ocaml/termination_signals.mli @@ -0,0 +1,4 @@ +val with_handlers : (int -> unit) -> (unit -> 'a) -> 'a +(** Runs the action with the handler installed for every + {!Platform.termination_signals} entry, restoring the previous handlers + afterwards. *) diff --git a/rewatch-ocaml/tests/basic/rescript.json b/rewatch-ocaml/tests/basic/rescript.json new file mode 100644 index 00000000000..6abd6654a34 --- /dev/null +++ b/rewatch-ocaml/tests/basic/rescript.json @@ -0,0 +1,6 @@ +{ + "name": "rewatch-ocaml-basic", + "sources": {"dir": "src", "subdirs": true}, + "package-specs": {"module": "esmodule", "in-source": true}, + "suffix": ".mjs" +} diff --git a/rewatch-ocaml/tests/basic/src/A.res b/rewatch-ocaml/tests/basic/src/A.res new file mode 100644 index 00000000000..5f5aa16a1ae --- /dev/null +++ b/rewatch-ocaml/tests/basic/src/A.res @@ -0,0 +1 @@ +let value = 41 diff --git a/rewatch-ocaml/tests/basic/src/Authored.js b/rewatch-ocaml/tests/basic/src/Authored.js new file mode 100644 index 00000000000..e65eaf2a3a6 --- /dev/null +++ b/rewatch-ocaml/tests/basic/src/Authored.js @@ -0,0 +1 @@ +authored same-stem JavaScript diff --git a/rewatch-ocaml/tests/basic/src/Authored.res b/rewatch-ocaml/tests/basic/src/Authored.res new file mode 100644 index 00000000000..3c37c33b59a --- /dev/null +++ b/rewatch-ocaml/tests/basic/src/Authored.res @@ -0,0 +1 @@ +let value = 1 diff --git a/rewatch-ocaml/tests/basic/src/B.res b/rewatch-ocaml/tests/basic/src/B.res new file mode 100644 index 00000000000..f12af2ffc7d --- /dev/null +++ b/rewatch-ocaml/tests/basic/src/B.res @@ -0,0 +1 @@ +let answer = A.value + 1 diff --git a/rewatch-ocaml/tests/basic/src/WithInterface.res b/rewatch-ocaml/tests/basic/src/WithInterface.res new file mode 100644 index 00000000000..ec69b5dd4a5 --- /dev/null +++ b/rewatch-ocaml/tests/basic/src/WithInterface.res @@ -0,0 +1 @@ +let value = B.answer diff --git a/rewatch-ocaml/tests/basic/src/WithInterface.resi b/rewatch-ocaml/tests/basic/src/WithInterface.resi new file mode 100644 index 00000000000..14829e3b698 --- /dev/null +++ b/rewatch-ocaml/tests/basic/src/WithInterface.resi @@ -0,0 +1 @@ +let value: int diff --git a/rewatch-ocaml/tests/check_canonical_test_coverage.sh b/rewatch-ocaml/tests/check_canonical_test_coverage.sh new file mode 100755 index 00000000000..db93f31a404 --- /dev/null +++ b/rewatch-ocaml/tests/check_canonical_test_coverage.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +root=$(cd "$(dirname "$0")/../.." && pwd) +tests="$root/rewatch/tests" +inventory=$(mktemp) +referenced=$(mktemp) +cleanup() { + rm -f "$inventory" "$referenced" +} +trap cleanup EXIT + +for file in "$tests"/*/*.sh; do + relative=${file#"$tests/"} + printf './%s\n' "$relative" +done | sort >"$inventory" + +sed -n 's/^\(\.\/[^ ]*\.sh\).*$/\1/p' "$tests/suite.sh" | sort \ + >"$referenced" + +duplicates=$(uniq -d "$referenced") +missing=$(comm -23 "$inventory" "$referenced") +stale=$(comm -13 "$inventory" "$referenced") +if [[ -n "$duplicates" || -n "$missing" || -n "$stale" ]]; then + [[ -z "$duplicates" ]] \ + || printf 'Canonical tests referenced more than once:\n%s\n' "$duplicates" >&2 + [[ -z "$missing" ]] \ + || printf 'Canonical tests omitted from suite.sh:\n%s\n' "$missing" >&2 + [[ -z "$stale" ]] \ + || printf 'Stale canonical test references in suite.sh:\n%s\n' "$stale" >&2 + exit 1 +fi + +total=$(wc -l <"$inventory" | tr -d ' ') +printf 'Canonical integration tests: %s; all referenced exactly once\n' "$total" diff --git a/rewatch-ocaml/tests/check_command_validation.sh b/rewatch-ocaml/tests/check_command_validation.sh new file mode 100755 index 00000000000..872fc4f7444 --- /dev/null +++ b/rewatch-ocaml/tests/check_command_validation.sh @@ -0,0 +1,1885 @@ +#!/bin/bash +set -eu + +root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd) +rust=${1:-$root/rewatch/target/debug/rescript} +ocaml=${2:-$root/_build/default/rewatch-ocaml/rescript_ocaml.exe} +rust=$(realpath "$rust") +ocaml=$(realpath "$ocaml") +bsc_test_proxy="$root/_build/default/tests/rewatch_ounit_tests/rewatch_bsc_test_proxy.exe" +work=$(mktemp -d "${TMPDIR:-/tmp}/rewatch-command-validation-XXXXXX") +# Compiler diagnostics contain canonical paths. Resolve platform aliases such +# as macOS's /var -> /private/var before deriving paths used for comparison. +work=$(realpath "$work") +native_work=$work +native_short_work=$work +windows_posix_shell=false +case $(uname -s) in + MINGW*|MSYS*) + windows_posix_shell=true + native_work=$(cd "$work" && pwd -W) + native_user=$(cygpath -w "$USERPROFILE" | tr '\\' '/') + native_short_user=$(cygpath -w -s "$USERPROFILE" | tr '\\' '/') + native_short_work=${native_work/"$native_user"/"$native_short_user"} + bsc_test_proxy=$(cygpath -aw \ + "$root/_build/default/tests/rewatch_ounit_tests/rewatch_bsc_test_proxy.exe") + ;; +esac +delete_source_bsc=$bsc_test_proxy +delete_parse_sources_bsc=$bsc_test_proxy +delete_ast_bsc=$bsc_test_proxy +lock_owner_pid() { + local shell_pid=$1 + if $windows_posix_shell; then + # MSYS assigns a synthetic PID to native Windows children. Lock files are + # consumed by native executables and therefore must contain the WINPID. + ps -p "$shell_pid" -l | awk 'NR == 2 { print $4 }' + else + printf '%s\n' "$shell_pid" + fi +} +directory_link() { + local target=$1 + local link=$2 + if $windows_posix_shell; then + LINK_PATH=$(cygpath -aw "$link") TARGET_PATH=$(cygpath -aw "$target") \ + powershell.exe -NoProfile -NonInteractive -Command \ + '$ErrorActionPreference = "Stop"; $null = New-Item -ItemType Junction -Path $env:LINK_PATH -Target $env:TARGET_PATH' + else + ln -s "$target" "$link" + fi +} +file_link_if_supported() { + local target=$1 + local link=$2 + if $windows_posix_shell; then + LINK_PATH=$(cygpath -aw "$link") TARGET_PATH=$(cygpath -aw "$target") \ + powershell.exe -NoProfile -NonInteractive -Command \ + '$ErrorActionPreference = "Stop"; $null = New-Item -ItemType SymbolicLink -Path $env:LINK_PATH -Target $env:TARGET_PATH' \ + >/dev/null 2>&1 + else + ln -s "$target" "$link" + fi +} +command_work=$native_work +command_path() { + case $1 in + "$work"*) printf '%s\n' "$command_work${1#"$work"}" ;; + *) printf '%s\n' "$1" ;; + esac +} +terminate_and_wait() { + local pid=$1 + local label=$2 + kill -TERM "$pid" + set +e + wait "$pid" + local status=$? + set -e + if [ "$status" -ne 0 ] && \ + { ! $windows_posix_shell || [ "$status" -ne 143 ]; }; then + printf '%s exited with status %s after shutdown\n' "$label" "$status" >&2 + return 1 + fi +} +background_pids="" +cleanup() { + for pid in $background_pids; do + kill -TERM "$pid" 2>/dev/null || true + wait "$pid" 2>/dev/null || true + done + rm -rf "$work" +} +trap cleanup EXIT + +project="$work/project" +mkdir -p "$project/src" "$work/orphan" "$work/empty" "$work/malformed" +mkdir -p "$work/malformed-parent/child/src" "$work/config-directory/rescript.json" +mkdir -p "$work/missing-dependency/src" +mkdir -p "$work/malformed-lock/src" "$work/malformed-lock/lib" +mkdir -p "$work/watch-lock-order/src" "$work/watch-lock-order/lib" +mkdir -p "$work/signal-lock/src" "$work/signal-lock/lib" +mkdir -p "$work/signal-lock-owner/src" +mkdir -p "$work/interface-mismatch/src" +mkdir -p "$work/exotic-module-rust/src" "$work/exotic-module-ocaml/src" +mkdir -p "$work/filter-basename-rust/src/nested" \ + "$work/filter-basename-ocaml/src/nested" +mkdir -p "$work/external-dev-source/src" \ + "$work/external-dev-source/node_modules/dep/src" \ + "$work/external-dev-source/node_modules/dep/test" +mkdir -p "$work/external-dev-permission/src" \ + "$work/external-dev-permission/node_modules/a" \ + "$work/external-dev-permission/node_modules/b" +mkdir -p "$work/active-permission/node_modules/a" \ + "$work/active-permission/node_modules/b" +mkdir -p "$work/source-path-file" +mkdir -p "$work/missing-runtime-package" +mkdir -p "$work/clean-missing-bsc/src" "$work/clean-missing-bsc/lib/bs" +mkdir -p "$work/clean-missing-runtime/src" \ + "$work/clean-missing-runtime/lib/bs" +for implementation in rust ocaml; do + mkdir -p "$work/clean-duplicate-$implementation/src/one" \ + "$work/clean-duplicate-$implementation/src/two" \ + "$work/clean-duplicate-$implementation/lib/bs" +done +mkdir -p "$work/missing-source-folder/src" \ + "$work/missing-source-folder/node_modules/dep" +mkdir -p "$work/dependency-without-sources/src" \ + "$work/dependency-without-sources/node_modules/dep" +mkdir -p "$work/default-feature-cycle/src" +mkdir -p "$work/format-feature-cycle/src" \ + "$work/format-feature-cycle/node_modules/dep/src" +mkdir -p "$work/format-source-selection/src" \ + "$work/format-source-selection/node_modules/installed" \ + "$work/format-source-selection/packages/local/base" \ + "$work/format-source-selection/packages/local/native" \ + "$work/format-source-selection/packages/local/other" +mkdir -p "$work/package-name-mismatch/src" "$work/malformed-package-json/src" +mkdir -p "$work/failed-js-post-build/src" +mkdir -p "$work/mismatched-dependency/src" \ + "$work/mismatched-dependency/node_modules/dep/src" +mkdir -p "$work/configless-dependency/src" \ + "$work/configless-dependency/node_modules/no-config" +mkdir -p "$work/malformed-dependency/src" \ + "$work/malformed-dependency/node_modules/bad-config" +mkdir -p "$work/duplicate-dependency/src" \ + "$work/duplicate-dependency/node_modules/a/src" \ + "$work/duplicate-dependency/node_modules/shared/src" \ + "$work/duplicate-dependency/node_modules/a/node_modules/shared/src" +mkdir -p "$work/publication-race-rust/src" \ + "$work/publication-race-ocaml/src" +mkdir -p "$work/ast-race-rust/src" "$work/ast-race-ocaml/src" +mkdir -p "$work/parse-source-race-rust/src" \ + "$work/parse-source-race-ocaml/src" +mkdir -p "$work/watch-config-rust/src" "$work/watch-config-ocaml/src" +mkdir -p "$work/watch-retained-graph/src" +mkdir -p "$work/watch-dependency-recovery/src" \ + "$work/watch-dependency-recovery/node_modules" \ + "$work/watch-dependency-recovery/packages/dep/src" +mkdir -p "$work/watch-dependency-install/src" \ + "$work/watch-dependency-install/node_modules" +mkdir -p "$work/watch-dependency-fallback/src" \ + "$work/watch-dependency-fallback/node_modules/dep" \ + "$work/watch-dependency-fallback/packages/dep/src" \ + "$work/node_modules" +mkdir -p "$work/watch-symlink-target/src" "$work/watch-symlink-external/sub" +mkdir -p "$work/watch-feature-scope/src" "$work/watch-feature-scope/inactive" +mkdir -p "$work/watch-filter-rust/src" "$work/watch-filter-rust/inactive" \ + "$work/watch-filter-ocaml/src" "$work/watch-filter-ocaml/inactive" +mkdir -p "$work/quiet-watch-rust/src" "$work/quiet-watch-ocaml/src" +printf '{"name":"command-validation","sources":["src"]}\n' \ + >"$project/rescript.json" +printf 'let value = 1\n' >"$project/src/A.res" +printf 'not a ReScript source\n' >"$project/src/A.txt" +printf '{"name":"signal-lock","sources":["src"]}\n' \ + >"$work/signal-lock/rescript.json" +printf 'let value = 1\n' >"$work/signal-lock/src/A.res" +printf '{"name":"signal-lock-owner","sources":["src"]}\n' \ + >"$work/signal-lock-owner/rescript.json" +printf 'let value = 1\n' >"$work/signal-lock-owner/src/A.res" +printf '{"name":"watch-lock-order","sources":["src"]}\n' \ + >"$work/watch-lock-order/rescript.json" +printf 'let value = 1\n' >"$work/watch-lock-order/src/A.res" +mkdir -p "$work/redirected-parse-fixture/src" +mkdir -p "$work/multiple-parse-errors/src" +mkdir -p "$work/redirected-config-diagnostics/src" +printf '{"name":"parse-output","sources":["src"]}\n' \ + >"$work/redirected-parse-fixture/rescript.json" +printf 'let value =\n' >"$work/redirected-parse-fixture/src/A.res" +printf '{"name":"multiple-parse-errors","sources":["src"]}\n' \ + >"$work/multiple-parse-errors/rescript.json" +printf 'let value =\n' >"$work/multiple-parse-errors/src/A.res" +printf 'let other =\n' >"$work/multiple-parse-errors/src/B.res" +printf '%s\n' \ + '{"name":"config-diagnostics","sources":["src"],"bsc-flags":[],"ignored-dirs":[],"future-field":true}' \ + >"$work/redirected-config-diagnostics/rescript.json" +printf 'let value = 1\n' >"$work/redirected-config-diagnostics/src/A.res" +printf 'process.stderr.write("hook failed\\n"); process.exit(7)\n' \ + >"$work/failing-after-build.js" +printf 'let value = 1\n' >"$work/orphan/A.res" +printf '{ invalid json\n' >"$work/malformed/rescript.json" +printf '{ invalid json\n' >"$work/malformed-parent/rescript.json" +printf '{"name":"child","sources":["src"]}\n' \ + >"$work/malformed-parent/child/rescript.json" +printf 'let value = 1\n' >"$work/malformed-parent/child/src/A.res" +printf '{"name":"missing-dependency","sources":["src"],"dependencies":["absent"]}\n' \ + >"$work/missing-dependency/rescript.json" +printf 'let value = 1\n' >"$work/missing-dependency/src/A.res" +printf '{"name":"malformed-lock","sources":["src"]}\n' \ + >"$work/malformed-lock/rescript.json" +printf 'let value = 1\n' >"$work/malformed-lock/src/A.res" +printf '{"name":"interface-mismatch","sources":["src"]}\n' \ + >"$work/interface-mismatch/rescript.json" +printf 'let value = 1\n' >"$work/interface-mismatch/src/lower.res" +printf 'let value: int\n' >"$work/interface-mismatch/src/Lower.resi" +for implementation in rust ocaml; do + printf '{"name":"exotic-module","namespace":"Ns","sources":["src"]}\n' \ + >"$work/exotic-module-$implementation/rescript.json" + printf 'let value = 1\n' \ + >"$work/exotic-module-$implementation/src/Main.res" + printf 'let value = 2\n' \ + >"$work/exotic-module-$implementation/src/foo-bar.res" + printf '{"name":"filter-basename","sources":[{"dir":"src","subdirs":true}]}\n' \ + >"$work/filter-basename-$implementation/rescript.json" + printf 'let value = 1\n' \ + >"$work/filter-basename-$implementation/src/nested/A.res" + printf 'let value = 2\n' \ + >"$work/filter-basename-$implementation/src/nested/B2.res" +done +printf '{"name":"external-dev-source","sources":["src"],"dependencies":["dep"]}\n' \ + >"$work/external-dev-source/rescript.json" +printf 'let value = DepPublic.value\n' \ + >"$work/external-dev-source/src/App.res" +printf '{"name":"dep","sources":["src",{"dir":"test","type":"dev"}]}\n' \ + >"$work/external-dev-source/node_modules/dep/rescript.json" +printf 'let value = 1\n' \ + >"$work/external-dev-source/node_modules/dep/src/DepPublic.res" +printf 'this is deliberately invalid ReScript\n' \ + >"$work/external-dev-source/node_modules/dep/test/DevOnly.res" +printf '{"name":"root","sources":["src"],"dependencies":["a","b"]}\n' \ + >"$work/external-dev-permission/rescript.json" +printf '{"name":"a","sources":[],"dev-dependencies":["b"]}\n' \ + >"$work/external-dev-permission/node_modules/a/rescript.json" +printf '{"name":"b","sources":[],"allowed-dependents":["root"]}\n' \ + >"$work/external-dev-permission/node_modules/b/rescript.json" +printf '{"name":"root","sources":[],"dependencies":["a","b"]}\n' \ + >"$work/active-permission/rescript.json" +printf '{"name":"a","sources":[],"allowed-dependents":["someone-else"]}\n' \ + >"$work/active-permission/node_modules/a/rescript.json" +printf '{"name":"b","sources":[],"allowed-dependents":["someone-else"]}\n' \ + >"$work/active-permission/node_modules/b/rescript.json" +printf '{"name":"source-path-file","sources":["src"]}\n' \ + >"$work/source-path-file/rescript.json" +printf 'not a directory\n' >"$work/source-path-file/src" +printf '{"name":"missing-runtime-package","sources":[]}\n' \ + >"$work/missing-runtime-package/rescript.json" +for clean_project in clean-missing-bsc clean-missing-runtime; do + printf '{"name":"%s","sources":["src"]}\n' "$clean_project" \ + >"$work/$clean_project/rescript.json" + printf 'let value = 1\n' >"$work/$clean_project/src/A.res" + printf 'owned compiler artifact\n' >"$work/$clean_project/lib/bs/marker" +done +for implementation in rust ocaml; do + duplicate_clean="$work/clean-duplicate-$implementation" + printf '%s\n' \ + '{"name":"duplicate-clean","sources":{"dir":"src","subdirs":true},"package-specs":{"module":"esmodule","in-source":true}}' \ + >"$duplicate_clean/rescript.json" + printf 'let value = 1\n' >"$duplicate_clean/src/one/A.res" + printf 'let value = 2\n' >"$duplicate_clean/src/two/A.res" + printf 'generated\n' >"$duplicate_clean/src/one/A.js" + printf 'generated\n' >"$duplicate_clean/src/two/A.js" + printf 'owned compiler artifact\n' >"$duplicate_clean/lib/bs/marker" +done +printf '{"name":"missing-source-folder","sources":["src"],"dependencies":["dep"]}\n' \ + >"$work/missing-source-folder/rescript.json" +printf 'let value = 1\n' >"$work/missing-source-folder/src/App.res" +printf '{"name":"dep","sources":["missing"]}\n' \ + >"$work/missing-source-folder/node_modules/dep/rescript.json" +printf '{"name":"dependency-without-sources","sources":["src"],"dependencies":["dep"]}\n' \ + >"$work/dependency-without-sources/rescript.json" +printf 'let value = 1\n' >"$work/dependency-without-sources/src/App.res" +printf '{"name":"dep"}\n' \ + >"$work/dependency-without-sources/node_modules/dep/rescript.json" +printf '{"name":"dep"}\n' \ + >"$work/dependency-without-sources/node_modules/dep/package.json" +printf '{"name":"default-feature-cycle","sources":["src"],"features":{"a":["b"],"b":["a"]}}\n' \ + >"$work/default-feature-cycle/rescript.json" +printf 'let value = 1\n' >"$work/default-feature-cycle/src/App.res" +printf '{"name":"format-feature-cycle","sources":["src"],"dependencies":[{"name":"dep","features":["a"]}]}\n' \ + >"$work/format-feature-cycle/rescript.json" +printf 'let value = 1\n' >"$work/format-feature-cycle/src/App.res" +printf '{"name":"dep","sources":["src"],"features":{"a":["b"],"b":["a"]}}\n' \ + >"$work/format-feature-cycle/node_modules/dep/rescript.json" +printf '{"name":"dep"}\n' \ + >"$work/format-feature-cycle/node_modules/dep/package.json" +printf 'let value = 1\n' \ + >"$work/format-feature-cycle/node_modules/dep/src/Dep.res" +printf '{"name":"format-source-selection","sources":["src"],"dependencies":["installed",{"name":"local","features":["native"]}]}\n' \ + >"$work/format-source-selection/rescript.json" +printf '{"name":"installed","sources":["missing"]}\n' \ + >"$work/format-source-selection/node_modules/installed/rescript.json" +printf '{"name":"local","sources":["base",{"dir":"native","feature":"native"},{"dir":"other","feature":"other"}]}\n' \ + >"$work/format-source-selection/packages/local/rescript.json" +printf 'let value=1\n' \ + >"$work/format-source-selection/packages/local/base/Base.res" +printf 'let value=2\n' \ + >"$work/format-source-selection/packages/local/native/Native.res" +printf 'let value=3\n' \ + >"$work/format-source-selection/packages/local/other/Other.res" +directory_link "$work/format-source-selection/packages/local" \ + "$work/format-source-selection/node_modules/local" +printf '{"name":"config-name","sources":["src"]}\n' \ + >"$work/package-name-mismatch/rescript.json" +printf '{"name":"package-name"}\n' >"$work/package-name-mismatch/package.json" +printf 'let value = 1\n' >"$work/package-name-mismatch/src/A.res" +printf '{"name":"malformed-package-json","sources":["src"]}\n' \ + >"$work/malformed-package-json/rescript.json" +printf '{invalid\n' >"$work/malformed-package-json/package.json" +printf 'let value = 1\n' >"$work/malformed-package-json/src/A.res" +printf '{"name":"failed-js-post-build","sources":["src"],"js-post-build":{"cmd":"exit 7"}}\n' \ + >"$work/failed-js-post-build/rescript.json" +printf 'let value = 1\n' >"$work/failed-js-post-build/src/A.res" +printf '{"name":"mismatched-dependency","sources":["src"],"dependencies":["dep"]}\n' \ + >"$work/mismatched-dependency/rescript.json" +printf 'let value = Dep.value\n' >"$work/mismatched-dependency/src/A.res" +printf '{"name":"dep","sources":["src"]}\n' \ + >"$work/mismatched-dependency/node_modules/dep/rescript.json" +printf '{"name":"different-name"}\n' \ + >"$work/mismatched-dependency/node_modules/dep/package.json" +printf 'let value = 1\n' \ + >"$work/mismatched-dependency/node_modules/dep/src/Dep.res" +printf '{"name":"configless-dependency","sources":["src"],"dependencies":["no-config"]}\n' \ + >"$work/configless-dependency/rescript.json" +printf 'let value = 1\n' >"$work/configless-dependency/src/A.res" +printf '{"name":"malformed-dependency","sources":["src"],"dependencies":["bad-config"]}\n' \ + >"$work/malformed-dependency/rescript.json" +printf 'let value = 1\n' >"$work/malformed-dependency/src/A.res" +printf '{ invalid json\n' \ + >"$work/malformed-dependency/node_modules/bad-config/rescript.json" +printf '{"name":"duplicate-dependency","sources":["src"],"dependencies":["a","shared"]}\n' \ + >"$work/duplicate-dependency/rescript.json" +printf 'let value = Shared.value + A.value\n' \ + >"$work/duplicate-dependency/src/Main.res" +printf '{"name":"a","sources":["src"],"dependencies":["shared"]}\n' \ + >"$work/duplicate-dependency/node_modules/a/rescript.json" +printf 'let value = Shared.value\n' \ + >"$work/duplicate-dependency/node_modules/a/src/A.res" +printf '{"name":"shared","sources":["src"]}\n' \ + >"$work/duplicate-dependency/node_modules/shared/rescript.json" +printf 'let value = 1\n' \ + >"$work/duplicate-dependency/node_modules/shared/src/Shared.res" +printf '{"name":"shared","sources":["src"]}\n' \ + >"$work/duplicate-dependency/node_modules/a/node_modules/shared/rescript.json" +printf 'let value = 2\n' \ + >"$work/duplicate-dependency/node_modules/a/node_modules/shared/src/Shared.res" +printf '{"name":"publication-race","sources":["src"]}\n' \ + >"$work/publication-race-rust/rescript.json" +cp "$work/publication-race-rust/rescript.json" \ + "$work/publication-race-ocaml/rescript.json" +printf 'let value = 1\n' >"$work/publication-race-rust/src/A.res" +cp "$work/publication-race-rust/src/A.res" \ + "$work/publication-race-ocaml/src/A.res" +printf '{"name":"ast-race","sources":["src"]}\n' \ + >"$work/ast-race-rust/rescript.json" +cp "$work/ast-race-rust/rescript.json" "$work/ast-race-ocaml/rescript.json" +printf 'let value = 1\n' >"$work/ast-race-rust/src/A.res" +cp "$work/ast-race-rust/src/A.res" "$work/ast-race-ocaml/src/A.res" +printf '{"name":"parse-source-race","sources":["src"]}\n' \ + >"$work/parse-source-race-rust/rescript.json" +cp "$work/parse-source-race-rust/rescript.json" \ + "$work/parse-source-race-ocaml/rescript.json" +for implementation in rust ocaml; do + printf 'let value = 1\n' \ + >"$work/parse-source-race-$implementation/src/A.res" + printf 'let value = 2\n' \ + >"$work/parse-source-race-$implementation/src/B.res" +done +printf '{"name":"watch-config","sources":["src"]}\n' \ + >"$work/watch-config-rust/rescript.json" +cp "$work/watch-config-rust/rescript.json" \ + "$work/watch-config-ocaml/rescript.json" +printf 'let value = 1\n' >"$work/watch-config-rust/src/A.res" +cp "$work/watch-config-rust/src/A.res" "$work/watch-config-ocaml/src/A.res" +printf '{"name":"watch-retained-graph","sources":["src"]}\n' \ + >"$work/watch-retained-graph/rescript.json" +printf 'let value = 1\n' >"$work/watch-retained-graph/src/A.res" +printf 'let oldValue = 1\n' >"$work/watch-retained-graph/src/C.res" +printf 'let value = A.value\n' >"$work/watch-retained-graph/src/B.res" +printf '{"name":"watch-dependency-recovery","sources":["src"],"dependencies":["dep"]}\n' \ + >"$work/watch-dependency-recovery/rescript.json" +printf 'let value = 1\n' >"$work/watch-dependency-recovery/src/A.res" +printf '{ invalid json\n' \ + >"$work/watch-dependency-recovery/packages/dep/rescript.json" +printf 'let dependency = 1\n' \ + >"$work/watch-dependency-recovery/packages/dep/src/Dep.res" +directory_link "$work/watch-dependency-recovery/packages/dep" \ + "$work/watch-dependency-recovery/node_modules/dep" +printf '{"name":"watch-dependency-install","sources":["src"],"dependencies":["@scope/dep"]}\n' \ + >"$work/watch-dependency-install/rescript.json" +printf 'let value = 1\n' >"$work/watch-dependency-install/src/A.res" +printf '{"name":"watch-feature-scope","sources":["src",{"dir":"inactive","feature":"inactive"}]}\n' \ + >"$work/watch-feature-scope/rescript.json" +printf 'let value = 1\n' >"$work/watch-feature-scope/src/A.res" +printf 'let inactive = 1\n' >"$work/watch-feature-scope/inactive/Inactive.res" +printf '{"name":"watch-dependency-fallback","sources":["src"],"dependencies":["dep"]}\n' \ + >"$work/watch-dependency-fallback/rescript.json" +printf 'let value = 1\n' >"$work/watch-dependency-fallback/src/A.res" +printf '{"name":"dep","sources":["src"]}\n' \ + >"$work/watch-dependency-fallback/packages/dep/rescript.json" +printf 'let dependency = 1\n' \ + >"$work/watch-dependency-fallback/packages/dep/src/Dep.res" +printf '{"name":"watch-symlink-target","sources":["src"]}\n' \ + >"$work/watch-symlink-target/rescript.json" +printf 'let linked = 1\n' >"$work/watch-symlink-external/sub/Linked.res" +file_symlinks_supported=true +if ! file_link_if_supported "$work/watch-symlink-external/sub/Linked.res" \ + "$work/watch-symlink-target/src/Linked.res"; then + file_symlinks_supported=false +fi +for implementation in rust ocaml; do + printf '{"name":"watch-filter","sources":["src",{"dir":"inactive","feature":"inactive"}]}\n' \ + >"$work/watch-filter-$implementation/rescript.json" + printf 'let value = 1\n' \ + >"$work/watch-filter-$implementation/src/Include.res" + printf 'let value = 10\n' \ + >"$work/watch-filter-$implementation/src/Exclude.res" + printf 'let value = 20\n' \ + >"$work/watch-filter-$implementation/inactive/Inactive.res" + printf '{"name":"quiet-watch","sources":["src"]}\n' \ + >"$work/quiet-watch-$implementation/rescript.json" + printf 'let value = 1\n' \ + >"$work/quiet-watch-$implementation/src/A.res" +done +printf 'require("fs").appendFileSync(process.env.REWATCH_WATCH_FILTER_MARKER, "done\\n")\n' \ + >"$work/watch-filter-marker.js" +printf '%s\n' \ + '#!/bin/sh' \ + 'if [ -f "$REWATCH_SCOPE_BLOCK_REQUEST" ] && [ ! -f "$REWATCH_SCOPE_BLOCK_STARTED" ]; then' \ + ' : >"$REWATCH_SCOPE_BLOCK_STARTED"' \ + ' attempts=0' \ + ' while [ ! -f "$REWATCH_SCOPE_BLOCK_RELEASE" ] && [ "$attempts" -lt 200 ]; do' \ + ' attempts=$((attempts + 1))' \ + ' sleep 0.05' \ + ' done' \ + 'fi' \ + 'exec "$REWATCH_SCOPE_REAL_BSC" "$@"' \ + >"$work/watch-scope-bsc.sh" +chmod +x "$work/watch-scope-bsc.sh" +watch_scope_bsc="$work/watch-scope-bsc.sh" +if $windows_posix_shell; then + watch_scope_bsc=$bsc_test_proxy +fi + +default_bsc=$root/_build/default/compiler/bsc/rescript_compiler_main.exe +default_runtime=$root/packages/@rescript/runtime +case $(uname -s) in + MINGW*|MSYS*) + default_bsc=$(cygpath -w "$default_bsc") + default_runtime=$(cygpath -w "$default_runtime") + ;; +esac +export RESCRIPT_BSC_EXE=${RESCRIPT_BSC_EXE:-$default_bsc} +export RESCRIPT_RUNTIME=${RESCRIPT_RUNTIME:-$default_runtime} + +classify() { + case "$1" in + 0) printf accept ;; + 101) printf panic ;; + 2) printf exit2 ;; + *) printf reject ;; + esac +} + +strip_ansi() { + LC_ALL=C sed $'s/\033\\[[0-9;]*m//g' "$1" +} + +normalize_project_path() { + local input=$1 + local output=$2 + local project=$3 + local native_project=$project + local native_short_project=$project + case $(uname -s) in + MINGW*|MSYS*) + native_project=$(cd "$project" && pwd -W) + native_short_project=${native_project/"$native_user"/"$native_short_user"} + ;; + esac + PROJECT_PATH=$project PROJECT_NATIVE_PATH=$native_project \ + PROJECT_SHORT_PATH=$native_short_project node -e ' + const fs = require("fs"); + let text = fs.readFileSync(process.argv[1], "utf8"); + for (const project of [process.env.PROJECT_PATH, process.env.PROJECT_NATIVE_PATH, process.env.PROJECT_SHORT_PATH]) { + for (const spelling of [project, project.replaceAll("/", "\\")]) { + text = text.split(spelling).join(""); + } + } + text = text.replaceAll("\\", "/"); + text = text.replaceAll(".//", "./"); + fs.writeFileSync(process.argv[2], text); + ' "$input" "$output" +} + +dump_both() { + printf '%s\n' '--- Rust output ---' >&2 + cat "$work/rust.out" "$work/rust.err" >&2 + printf '%s\n' '--- OCaml output ---' >&2 + cat "$work/ocaml.out" "$work/ocaml.err" >&2 +} + +# run_both [--cwd DIR] [--unset VAR] ARGS... +# Runs Rust and then OCaml with ARGS, writing $work/{rust,ocaml}.{out,err} and +# setting rust_status and ocaml_status. A literal {impl} in an argument becomes +# "rust" or "ocaml", for cases that use a separate fixture copy per +# implementation. +run_both() { + local cwd="" unset_variable="" implementation executable argument status + local -a arguments command + while :; do + case $1 in + --cwd) cwd=$2; shift 2 ;; + --unset) unset_variable=$2; shift 2 ;; + *) break ;; + esac + done + for implementation in rust ocaml; do + if [ "$implementation" = rust ]; then executable=$rust; else executable=$ocaml; fi + arguments=() + for argument in "$@"; do + arguments+=("${argument//"{impl}"/$implementation}") + done + command=("$executable" "${arguments[@]}") + if [ -n "$unset_variable" ]; then + command=(env -u "$unset_variable" "${command[@]}") + fi + set +e + if [ -n "$cwd" ]; then + (cd "$cwd" && "${command[@]}") \ + >"$work/$implementation.out" 2>"$work/$implementation.err" + else + "${command[@]}" >"$work/$implementation.out" 2>"$work/$implementation.err" + fi + status=$? + set -e + if [ "$implementation" = rust ]; then + rust_status=$status + else + ocaml_status=$status + fi + done +} + +checked=0 +# run_case [--cwd DIR] NAME RUST_EXPECTED OCAML_EXPECTED ARGS... +run_case() { + local -a options=() + if [ "$1" = --cwd ]; then + options=(--cwd "$2") + shift 2 + fi + name=$1 + rust_expected=$2 + ocaml_expected=$3 + shift 3 + run_both ${options[@]+"${options[@]}"} "$@" + rust_actual=$(classify "$rust_status") + ocaml_actual=$(classify "$ocaml_status") + if [ "$rust_actual" != "$rust_expected" ] || \ + [ "$ocaml_actual" != "$ocaml_expected" ]; then + printf '%s: expected Rust=%s/OCaml=%s, got Rust=%s/OCaml=%s\n' \ + "$name" "$rust_expected" "$ocaml_expected" \ + "$rust_status" "$ocaml_status" >&2 + dump_both + exit 1 + fi + checked=$((checked + 1)) +} + +require_same_output() { + name=$1 + if ! cmp -s "$work/rust.out" "$work/ocaml.out" || \ + ! cmp -s "$work/rust.err" "$work/ocaml.err"; then + echo "$name: Rust and OCaml output differ" >&2 + dump_both + # Invisible differences such as line endings only show up byte by byte. + for stream in out err; do + if ! cmp "$work/rust.$stream" "$work/ocaml.$stream" >&2; then + printf -- '--- first bytes of std%s (Rust, then OCaml) ---\n' "$stream" >&2 + head -c 160 "$work/rust.$stream" | od -c >&2 + head -c 160 "$work/ocaml.$stream" | od -c >&2 + fi + done + exit 1 + fi +} + +require_both_errors_contain() { + local name=$1 + local fragment=$2 + local native_fragment=${fragment/"$work"/"$native_work"} + local native_short_fragment=${fragment/"$work"/"$native_short_work"} + if ! { grep -F "$fragment" "$work/rust.err" >/dev/null || \ + tr '\\' '/' <"$work/rust.err" | grep -F "$native_fragment" >/dev/null || \ + tr '\\' '/' <"$work/rust.err" | grep -F "$native_short_fragment" >/dev/null; } || \ + ! { grep -F "$fragment" "$work/ocaml.err" >/dev/null || \ + tr '\\' '/' <"$work/ocaml.err" | grep -F "$native_fragment" >/dev/null || \ + tr '\\' '/' <"$work/ocaml.err" | grep -F "$native_short_fragment" >/dev/null; }; then + printf '%s: expected both errors to contain %s\n' "$name" "$fragment" >&2 + dump_both + exit 1 + fi +} + +run_missing_bsc_case() { + name=$1 + shift + RESCRIPT_BSC_EXE="$work/missing-bsc" run_both "$@" + if [ "$(classify "$rust_status")" != panic ] || \ + [ "$(classify "$ocaml_status")" != reject ]; then + printf '%s: expected Rust=panic/OCaml=reject, got Rust=%s/OCaml=%s\n' \ + "$name" "$rust_status" "$ocaml_status" >&2 + dump_both + exit 1 + fi + if ! grep -F 'RESCRIPT_BSC_EXE points to missing path' \ + "$work/ocaml.err" >/dev/null; then + echo "$name: OCaml did not report the stale compiler path" >&2 + cat "$work/ocaml.out" "$work/ocaml.err" >&2 + exit 1 + fi + checked=$((checked + 1)) +} + +run_build_output_case() { + name=$1 + expected_status=$2 + fixture=$3 + mode=$4 + rust_project="$work/$name-rust" + ocaml_project="$work/$name-ocaml" + cp -R "$fixture" "$rust_project" + cp -R "$fixture" "$ocaml_project" + if [ "$mode" = quiet ]; then + run_both -q build "$work/$name-{impl}" + elif [ "$mode" = forced-color ]; then + CLICOLOR_FORCE=1 run_both build "$work/$name-{impl}" + else + run_both build "$work/$name-{impl}" + fi + normalize_project_path "$work/rust.out" "$work/rust.out.norm" "$rust_project" + normalize_project_path "$work/rust.err" "$work/rust.err.norm" "$rust_project" + normalize_project_path "$work/ocaml.out" "$work/ocaml.out.norm" "$ocaml_project" + normalize_project_path "$work/ocaml.err" "$work/ocaml.err.norm" "$ocaml_project" + if [ "$rust_status" -ne "$expected_status" ] || \ + [ "$ocaml_status" -ne "$expected_status" ] || \ + ! cmp -s "$work/rust.out.norm" "$work/ocaml.out.norm" || \ + ! cmp -s "$work/rust.err.norm" "$work/ocaml.err.norm"; then + echo "$name: $mode build output differs" >&2 + printf '%s\n' \ + "statuses: expected=$expected_status Rust=$rust_status OCaml=$ocaml_status" \ + >&2 + printf '%s\n' '--- Rust stdout ---' >&2 + cat "$work/rust.out.norm" >&2 + printf '%s\n' '--- OCaml stdout ---' >&2 + cat "$work/ocaml.out.norm" >&2 + printf '%s\n' '--- Rust stderr ---' >&2 + cat "$work/rust.err.norm" >&2 + printf '%s\n' '--- OCaml stderr ---' >&2 + cat "$work/ocaml.err.norm" >&2 + for stream in out err; do + if ! cmp -s "$work/rust.$stream.norm" "$work/ocaml.$stream.norm"; then + printf '%s\n' "--- $stream byte counts ---" >&2 + wc -c "$work/rust.$stream.norm" "$work/ocaml.$stream.norm" >&2 + printf '%s\n' "--- first differing $stream bytes ---" >&2 + cmp -l "$work/rust.$stream.norm" "$work/ocaml.$stream.norm" \ + | head -n 20 >&2 || true + printf '%s\n' "--- Rust $stream tail bytes ---" >&2 + tail -c 64 "$work/rust.$stream.norm" | od -An -tx1c >&2 + printf '%s\n' "--- OCaml $stream tail bytes ---" >&2 + tail -c 64 "$work/ocaml.$stream.norm" | od -An -tx1c >&2 + fi + done + exit 1 + fi + checked=$((checked + 1)) +} + +run_multiple_parse_errors_case() { + rust_project="$work/multiple-parse-errors-rust" + ocaml_project="$work/multiple-parse-errors-ocaml" + cp -R "$work/multiple-parse-errors" "$rust_project" + cp -R "$work/multiple-parse-errors" "$ocaml_project" + run_both build "$work/multiple-parse-errors-{impl}" + if [ "$rust_status" -ne 1 ] || [ "$ocaml_status" -ne 1 ]; then + printf 'multiple-parse-errors: expected status 1, got Rust=%s OCaml=%s\n' \ + "$rust_status" "$ocaml_status" >&2 + exit 1 + fi + for implementation in rust ocaml; do + error="$work/$implementation.err" + if [ "$(grep -cF 'Error in multiple-parse-errors:' "$error")" -ne 2 ] || \ + ! grep -E '[/\\]src[/\\]A\.res' "$error" >/dev/null || \ + ! grep -E '[/\\]src[/\\]B\.res' "$error" >/dev/null; then + echo "$implementation did not retain every independent parse error" >&2 + cat "$error" >&2 + exit 1 + fi + done + checked=$((checked + 1)) +} + +wait_for_file() { + path=$1 + attempts=0 + while [ "$attempts" -lt 150 ] && [ ! -f "$path" ]; do + attempts=$((attempts + 1)) + sleep 0.1 + done + if [ -f "$path" ]; then + return 0 + fi + printf 'Timed out waiting for file %s (requested at line %s)\n' \ + "$path" "${BASH_LINENO[0]:-unknown}" >&2 + return 1 +} + +# Waits until a -v watcher logs a watch handle for a path ending in the given +# extended regular expression. Paths use native separators; trailing space +# tolerates CRLF output on Windows. +wait_for_watch() { + path=$1 + suffix=$2 + attempts=0 + while [ "$attempts" -lt 150 ]; do + if grep -Eq "watching \((non-)?recursive\): .*$suffix[[:space:]]*\$" \ + "$path" 2>/dev/null; then + return 0 + fi + attempts=$((attempts + 1)) + sleep 0.1 + done + printf 'Timed out waiting for a watch on %s in %s\n' "$suffix" "$path" >&2 + if [ -f "$path" ]; then + cat "$path" >&2 + fi + return 1 +} + +wait_for_text() { + path=$1 + pattern=$2 + attempts=0 + while [ "$attempts" -lt 150 ] && \ + ! grep -F "$pattern" "$path" >/dev/null 2>&1; do + attempts=$((attempts + 1)) + sleep 0.1 + done + if grep -F "$pattern" "$path" >/dev/null 2>&1; then + return 0 + fi + printf 'Timed out waiting for %s in %s\n' "$pattern" "$path" >&2 + if [ -f "$path" ]; then + printf '%s\n' '--- observed contents ---' >&2 + cat "$path" >&2 + else + printf '%s\n' '--- file does not exist ---' >&2 + fi + return 1 +} + +wait_for_exit() { + pid=$1 + attempts=0 + while [ "$attempts" -lt 150 ] && kill -0 "$pid" 2>/dev/null; do + attempts=$((attempts + 1)) + sleep 0.1 + done + ! kill -0 "$pid" 2>/dev/null +} + +wait_for_line_count() { + path=$1 + expected=$2 + attempts=0 + while [ "$attempts" -lt 150 ]; do + actual=0 + if [ -f "$path" ]; then + actual=$(wc -l <"$path" | tr -d ' ') + fi + if [ "$actual" -ge "$expected" ]; then + return 0 + fi + attempts=$((attempts + 1)) + sleep 0.1 + done + return 1 +} + +line_count_stays() { + path=$1 + expected=$2 + attempts=0 + while [ "$attempts" -lt 20 ]; do + actual=0 + if [ -f "$path" ]; then + actual=$(wc -l <"$path" | tr -d ' ') + fi + if [ "$actual" -ne "$expected" ]; then + return 1 + fi + attempts=$((attempts + 1)) + sleep 0.1 + done +} + +run_build_output_case redirected-success 0 \ + "$root/rewatch-ocaml/tests/basic" redirected +run_build_output_case redirected-compile-error 1 \ + "$root/rewatch-ocaml/tests/failure" redirected +run_build_output_case redirected-parse-error 1 \ + "$work/redirected-parse-fixture" redirected +run_multiple_parse_errors_case +run_build_output_case redirected-warning 0 \ + "$root/rewatch-ocaml/tests/warning-replay" redirected +run_build_output_case redirected-config-diagnostics 0 \ + "$work/redirected-config-diagnostics" redirected +run_build_output_case forced-color-config-diagnostics 0 \ + "$work/redirected-config-diagnostics" forced-color + +run_build_output_case quiet-success 0 "$project" quiet +if [ -s "$work/rust.out" ] || [ -s "$work/rust.err" ] || \ + [ -s "$work/ocaml.out" ] || [ -s "$work/ocaml.err" ]; then + echo "quiet-success: a clean build emitted output" >&2 + for implementation in rust ocaml; do + printf '%s\n' "--- $implementation stdout ---" >&2 + cat "$work/$implementation.out" >&2 + printf '%s\n' "--- $implementation stderr ---" >&2 + cat "$work/$implementation.err" >&2 + done + exit 1 +fi +run_build_output_case quiet-compile-error 1 \ + "$root/rewatch-ocaml/tests/failure" quiet +run_build_output_case quiet-parse-error 1 "$work/redirected-parse-fixture" quiet +run_build_output_case quiet-warning 0 \ + "$root/rewatch-ocaml/tests/warning-replay" quiet + +run_case build-subcommand-version exit2 accept build --version +run_case clustered-global-version accept accept -vV build +run_case clustered-global-verbosity accept accept -vvvvv build "$project" +run_case clustered-global-version-before-help accept accept -Vh build +run_case clustered-global-help-before-version accept accept -hV build +run_case clustered-subcommand-help-before-version accept accept build -hV +run_case clustered-subcommand-version-before-help exit2 accept build -Vh +"$ocaml" build --help=groff >"$work/ocaml-help-groff.out" +if ! grep -F '.\" Pipe this output to groff' \ + "$work/ocaml-help-groff.out" >/dev/null; then + echo "formatted-help: OCaml did not preserve the requested groff format" >&2 + cat "$work/ocaml-help-groff.out" >&2 + exit 1 +fi +checked=$((checked + 1)) +run_case implicit-conflicting-verbosity exit2 exit2 -v -q +run_case build-conflicting-verbosity exit2 exit2 build --verbose --quiet +run_case filter-perl-quoting exit2 exit2 build --filter '\QFoo.res\E' "$project" +run_case filter-comment-group exit2 exit2 build --filter '(?#note)Foo' "$project" +run_case filter-octal-escape exit2 exit2 build --filter '\123' "$project" +run_case filter-braced-octal-escape exit2 exit2 build --filter '\o{123}' "$project" +run_case filter-perl-control-escape-e exit2 exit2 build --filter '\e' "$project" +run_case filter-perl-anchor-g exit2 exit2 build --filter '\G' "$project" +run_case filter-perl-anchor-z exit2 exit2 build --filter '\Z' "$project" +run_case filter-descending-range exit2 exit2 build --filter '[z-a]' "$project" +run_case filter-escaped-range-start exit2 exit2 build --filter '[\d-z]' "$project" +run_case filter-in-class-nonword accept exit2 build --filter \ + '^[\W]+\.res$' "$project" +run_case filter-collating-element accept exit2 build --filter '[[.a.]]' "$project" +run_case filter-class-algebra accept exit2 build --filter \ + '[a-z&&[^aeiou]]' "$project" +run_case build-no-timing-preserves-folder exit2 accept build --no-timing "$project" +run_case compiler-args-source accept accept compiler-args "$project/src/A.res" +run_case compiler-args-extension accept reject compiler-args "$project/src/A.txt" +run_case compiler-args-missing panic reject compiler-args "$project/src/Missing.res" +run_case compiler-args-no-project panic reject compiler-args "$work/orphan/A.res" + +run_missing_bsc_case build-missing-bsc build "$project" +run_missing_bsc_case format-missing-bsc format "$project/src/A.res" +RESCRIPT_BSC_EXE="$work/missing-bsc" run_both clean "$work/clean-missing-bsc" +if [ "$(classify "$rust_status")" != panic ] || [ "$ocaml_status" -ne 0 ] || \ + [ -e "$work/clean-missing-bsc/lib/bs/marker" ]; then + echo "clean-missing-bsc: expected Rust panic and successful OCaml cleanup" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_both --unset RESCRIPT_RUNTIME clean "$work/clean-missing-runtime" +if [ "$(classify "$rust_status")" != reject ] || [ "$ocaml_status" -ne 0 ] || \ + [ -e "$work/clean-missing-runtime/lib/bs/marker" ]; then + echo "clean-missing-runtime: expected Rust rejection and successful OCaml cleanup" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_both --unset RESCRIPT_RUNTIME build "$work/missing-runtime-package" +if [ "$rust_status" -eq 0 ] || [ "$ocaml_status" -eq 0 ]; then + echo "build-missing-runtime-package: expected both builds to reject" >&2 + exit 1 +fi +require_both_errors_contain build-missing-runtime-package \ + 'The rescript runtime package could not be found.' +require_both_errors_contain build-missing-runtime-package \ + 'Please set RESCRIPT_RUNTIME environment variable' +checked=$((checked + 1)) +RESCRIPT_RUNTIME="$work/missing-runtime" run_both build "$project" +if [ "$rust_status" -eq 0 ] || [ "$ocaml_status" -eq 0 ] || \ + ! grep -F "RESCRIPT_RUNTIME points to missing path" \ + "$work/ocaml.err" >/dev/null || \ + ! grep -F "missing-runtime" "$work/ocaml.err" >/dev/null || \ + ! grep -F "The module or file Pervasives can't be found." \ + "$work/rust.err" >/dev/null; then + echo "build-stale-runtime: expected contextual OCaml preflight rejection" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_case format-missing-file reject reject format "$project/src/Missing.res" +require_same_output format-missing-file +run_case format-directory reject reject format "$project/src" +require_same_output format-directory +run_case format-unsupported-extension reject reject format "$project/src/A.txt" +require_same_output format-unsupported-extension +run_case --cwd "$work/empty" format-no-config reject reject format +require_both_errors_contain format-no-config \ + "Could not read rescript.json at $work/empty:" +require_both_errors_contain format-no-config "$work/empty/bsconfig.json" +run_case --cwd "$work/malformed" format-malformed-config reject reject format +require_both_errors_contain format-malformed-config \ + "Could not read rescript.json at $work/malformed:" +if ! grep -F 'Failed to parse rescript.json' "$work/rust.err" >/dev/null || \ + ! grep -F 'invalid JSON' "$work/ocaml.err" >/dev/null; then + echo "format-malformed-config: JSON parser context was lost" >&2 + dump_both + exit 1 +fi +run_case --cwd "$work/config-directory" \ + format-config-directory reject reject format +require_both_errors_contain format-config-directory \ + "$work/config-directory/rescript.json" +if ! grep -E 'Is a directory|Access is denied' "$work/rust.err" >/dev/null || \ + ! grep -F 'Is a directory' "$work/ocaml.err" >/dev/null; then + echo "format-config-directory: file-kind diagnostic was lost" >&2 + exit 1 +fi +set +e +printf 'let value =\n' | "$rust" format --stdin .res \ + >"$work/rust.out" 2>"$work/rust.err" +rust_status=$? +printf 'let value =\n' | "$ocaml" format --stdin .res \ + >"$work/ocaml.out" 2>"$work/ocaml.err" +ocaml_status=$? +set -e +if [ "$rust_status" -eq 0 ] || [ "$ocaml_status" -eq 0 ] || \ + [ -s "$work/rust.out" ] || [ -s "$work/ocaml.out" ]; then + echo "format-invalid-stdin: expected both formatters to reject" >&2 + exit 1 +fi +require_both_errors_contain format-invalid-stdin 'Error formatting stdin:' +require_both_errors_contain format-invalid-stdin \ + 'This let-binding misses an expression' +checked=$((checked + 1)) +mkdir -p "$work/format-write-rust" "$work/format-write-ocaml" +printf 'let value=1\n' >"$work/format-write-rust/A.res" +printf 'let value=1\n' >"$work/format-write-ocaml/A.res" +chmod 0444 "$work/format-write-rust/A.res" "$work/format-write-ocaml/A.res" +if [ ! -w "$work/format-write-rust/A.res" ] && \ + [ ! -w "$work/format-write-ocaml/A.res" ]; then + run_both format "$work/format-write-{impl}/A.res" + if [ "$rust_status" -eq 0 ] || [ "$ocaml_status" -eq 0 ] || \ + ! grep -E 'Permission denied|Access is denied' "$work/rust.err" >/dev/null || \ + ! grep -F "Could not write formatted file" "$work/ocaml.err" >/dev/null || \ + ! grep -F "format-write-ocaml/A.res" \ + < <(tr '\\' '/' <"$work/ocaml.err") >/dev/null; then + echo "format-write-failure: formatter write failures lost context" >&2 + dump_both + exit 1 + fi + checked=$((checked + 1)) +fi +chmod 0644 "$work/format-write-rust/A.res" "$work/format-write-ocaml/A.res" + +run_case build-missing-folder reject reject build "$work/missing" +run_case build-existing-folder-without-config reject reject build "$work/empty" +require_both_errors_contain build-existing-folder-without-config "$work/empty" +run_case build-malformed-config reject reject build "$work/malformed" +require_both_errors_contain build-malformed-config \ + "$work/malformed" +run_case build-malformed-parent reject reject build "$work/malformed-parent/child" +require_both_errors_contain build-malformed-parent \ + "$work/malformed-parent" +run_case build-config-path-is-directory reject reject build "$work/config-directory" +require_both_errors_contain build-config-path-is-directory \ + "$work/config-directory" +run_case after-build-nonzero-is-not-ignored accept reject build --after-build \ + "node $command_work/failing-after-build.js" "$project" +if ! grep -F 'hook failed' "$work/rust.err" >/dev/null || \ + ! grep -F -- '--after-build command failed with exit code 7' \ + "$work/ocaml.err" >/dev/null || \ + ! grep -F 'hook failed' "$work/ocaml.err" >/dev/null; then + echo "Nonzero --after-build handling differs from its recorded outcomes" >&2 + dump_both + exit 1 +fi +run_case after-build-empty panic reject build --after-build '' "$project" +if ! grep -F -- '--after-build command cannot be empty' \ + "$work/ocaml.err" >/dev/null; then + echo "Empty --after-build did not produce a contextual OCaml error" >&2 + cat "$work/ocaml.out" "$work/ocaml.err" >&2 + exit 1 +fi +run_case after-build-missing-program panic reject build --after-build \ + rewatch-command-that-does-not-exist "$project" +if ! grep -F 'Could not run --after-build command' \ + "$work/ocaml.err" >/dev/null || \ + ! grep -F 'rewatch-command-that-does-not-exist' \ + "$work/ocaml.err" >/dev/null; then + echo "Missing --after-build program did not produce a contextual OCaml error" >&2 + cat "$work/ocaml.out" "$work/ocaml.err" >&2 + exit 1 +fi +run_case js-post-build-nonzero reject reject build "$work/failed-js-post-build" +js_post_build_error="js-post-build command failed for $work/failed-js-post-build/src/A.js" +require_both_errors_contain js-post-build-nonzero "$js_post_build_error" +printf 'not-a-pid' >"$work/malformed-lock/lib/build.lock" +run_case build-malformed-lock reject reject build "$work/malformed-lock" +if [ "$(cat "$work/malformed-lock/lib/build.lock")" != not-a-pid ]; then + echo "OCaml replaced a malformed build lock with unknown ownership" >&2 + exit 1 +fi +if [ -n "$(find "$work/malformed-lock/lib" -maxdepth 1 \ + -name '.build-lock-*.tmp' -print -quit)" ]; then + echo "OCaml left a build-lock candidate after acquisition failed" >&2 + exit 1 +fi +# Use the real executable as the lock owner. Copying an MSYS utility to a +# rescript-prefixed name does not change the image name reported by tasklist, +# while both implementations deliberately reject locks owned by unrelated +# executables to protect against PID reuse. +"$ocaml" watch "$work/signal-lock-owner" \ + >"$work/signal-lock-owner.out" 2>"$work/signal-lock-owner.err" & +signal_lock_owner_pid=$! +background_pids="$background_pids $signal_lock_owner_pid" +wait_for_text "$work/signal-lock-owner.out" "Finished initial compilation" +printf '%s' "$(lock_owner_pid "$signal_lock_owner_pid")" \ + >"$work/signal-lock/lib/build.lock" +"$ocaml" watch "$work/signal-lock" \ + >"$work/signal-lock.out" 2>"$work/signal-lock.err" & +signal_lock_watch_pid=$! +background_pids="$background_pids $signal_lock_watch_pid" +wait_for_text "$work/signal-lock.out" "Waiting for other build to finish" +kill -TERM "$signal_lock_watch_pid" +set +e +wait "$signal_lock_watch_pid" +signal_lock_status=$? +set -e +if ! $windows_posix_shell && [ "$signal_lock_status" -ne 0 ]; then + echo "Signal during build-lock wait exited with $signal_lock_status" >&2 + exit 1 +fi +# MSYS implements kill for native processes by terminating them externally, +# so no Windows console control event reaches OCaml and the status is nonzero. +# The native Windows unit tests cover deferred signal dispatch; this integration +# case still proves that terminating a waiter cannot emit a spurious diagnostic. +if [ -s "$work/signal-lock.err" ]; then + echo "Signal during build-lock wait emitted a diagnostic" >&2 + cat "$work/signal-lock.err" >&2 + exit 1 +fi +kill -TERM "$signal_lock_owner_pid" +wait "$signal_lock_owner_pid" 2>/dev/null || true +checked=$((checked + 1)) +printf 'not-a-pid' >"$work/malformed-lock/lib/watch.lock" +run_case watch-malformed-lock reject reject watch "$work/malformed-lock" +if [ "$(cat "$work/malformed-lock/lib/watch.lock")" != not-a-pid ]; then + echo "OCaml replaced a malformed watch lock with unknown ownership" >&2 + exit 1 +fi +if [ -n "$(find "$work/malformed-lock/lib" -maxdepth 1 \ + -name '.watch-lock-*.tmp' -print -quit)" ]; then + echo "OCaml left a watch-lock candidate after acquisition failed" >&2 + exit 1 +fi +printf '{ invalid json\n' >"$work/watch-lock-order/rescript.json" +# A copied MSYS utility keeps its original Windows image name and is therefore +# rejected as an unrelated lock owner. Run the implementation under test as a +# real watcher so both process identity and the native PID match production. +for implementation in rust ocaml; do + case "$implementation" in + rust) executable=$rust ;; + ocaml) executable=$ocaml ;; + esac + owner_dir="$work/watch-lock-owner-$implementation" + mkdir -p "$owner_dir/src" + printf '{"name":"watch-lock-owner-%s","sources":["src"]}\n' \ + "$implementation" >"$owner_dir/rescript.json" + printf 'let value = 1\n' >"$owner_dir/src/A.res" + "$executable" watch "$owner_dir" \ + >"$owner_dir/watch.out" 2>"$owner_dir/watch.err" & + watch_lock_owner_pid=$! + background_pids="$background_pids $watch_lock_owner_pid" + wait_for_text "$owner_dir/watch.out" "Finished initial compilation" + native_owner_pid=$(lock_owner_pid "$watch_lock_owner_pid") + if [ -z "$native_owner_pid" ]; then + echo "watch-lock-before-config: could not resolve $implementation owner PID" >&2 + exit 1 + fi + printf '%s' "$native_owner_pid" \ + >"$work/watch-lock-order/lib/watch.lock" + set +e + "$executable" watch "$work/watch-lock-order" \ + >"$work/$implementation.out" 2>"$work/$implementation.err" + status=$? + set -e + if [ "$(classify "$status")" != reject ] || \ + ! grep -F 'A ReScript build is already running' \ + "$work/$implementation.err" >/dev/null || \ + grep -F 'invalid JSON' "$work/$implementation.err" >/dev/null; then + echo "watch-lock-before-config: $implementation lock acquisition did not precede config parsing" >&2 + cat "$work/$implementation.out" "$work/$implementation.err" >&2 + exit 1 + fi + kill -TERM "$watch_lock_owner_pid" + wait "$watch_lock_owner_pid" 2>/dev/null || true +done +checked=$((checked + 1)) +run_case build-interface-path-mismatch reject reject build \ + "$work/interface-mismatch" +if ! cmp -s "$work/rust.err" "$work/ocaml.err"; then + echo "Implementation/interface mismatch diagnostics differ" >&2 + dump_both + exit 1 +fi +run_both build "$work/exotic-module-{impl}" +rust_mlmap="$work/exotic-module-rust/lib/bs/Ns.mlmap" +ocaml_mlmap="$work/exotic-module-ocaml/lib/bs/Ns.mlmap" +if [ "$(classify "$rust_status")" != accept ] || \ + [ "$(classify "$ocaml_status")" != accept ] || \ + ! cmp -s "$rust_mlmap" "$ocaml_mlmap" || \ + ! grep -Fx Main "$ocaml_mlmap" >/dev/null || \ + grep -F 'Foo-bar' "$ocaml_mlmap" >/dev/null; then + printf 'namespace-exotic-module: expected matching successful builds, got Rust=%s/OCaml=%s\n' \ + "$rust_status" "$ocaml_status" >&2 + printf '%s\n' '--- Rust output / namespace map ---' >&2 + cat "$work/rust.out" "$work/rust.err" "$rust_mlmap" >&2 + printf '%s\n' '--- OCaml output / namespace map ---' >&2 + cat "$work/ocaml.out" "$work/ocaml.err" "$ocaml_mlmap" >&2 + exit 1 +fi +checked=$((checked + 1)) +run_both build --filter nested "$work/filter-basename-{impl}" +if [ "$(classify "$rust_status")" != accept ] || \ + [ "$(classify "$ocaml_status")" != accept ] || \ + [ -e "$work/filter-basename-rust/src/nested/A.js" ] || \ + [ -e "$work/filter-basename-ocaml/src/nested/A.js" ]; then + echo "Source filters did not consistently ignore directory-only matches" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_both build --filter 'A\.res$' "$work/filter-basename-{impl}" +if [ "$(classify "$rust_status")" != accept ] || \ + [ "$(classify "$ocaml_status")" != accept ] || \ + [ ! -e "$work/filter-basename-rust/src/nested/A.js" ] || \ + [ ! -e "$work/filter-basename-ocaml/src/nested/A.js" ]; then + echo "Source filters did not consistently include a basename match" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_both build --filter '(?:A|B\d)\.res$' "$work/filter-basename-{impl}" +if [ "$(classify "$rust_status")" != accept ] || \ + [ "$(classify "$ocaml_status")" != accept ] || \ + [ ! -e "$work/filter-basename-rust/src/nested/B2.js" ] || \ + [ ! -e "$work/filter-basename-ocaml/src/nested/B2.js" ]; then + echo "Source filters did not consistently support Rust-style regex syntax" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_case build-excludes-external-dev-source accept accept build \ + "$work/external-dev-source" +run_case build-ignores-dormant-external-dev-permission reject accept build \ + "$work/external-dev-permission" +strip_ansi "$work/rust.out" >"$work/rust.out.plain" +strip_ansi "$work/rust.err" >"$work/rust.err.plain" +if ! grep -F 'a has the following unallowed dependencies' \ + "$work/rust.err.plain" >/dev/null; then + echo "Rust dormant external dev-dependency rejection was not reproduced" >&2 + cat "$work/rust.out" "$work/rust.err" >&2 + exit 1 +fi +run_case build-reports-all-active-permission-failures reject reject build \ + "$work/active-permission" +strip_ansi "$work/rust.out" >"$work/rust.out.plain" +strip_ansi "$work/rust.err" >"$work/rust.err.plain" +strip_ansi "$work/ocaml.out" >"$work/ocaml.out.plain" +strip_ansi "$work/ocaml.err" >"$work/ocaml.err.plain" +rust_permission_details=$(grep -Ec '^dependencies dependencies: (a|b)$' \ + "$work/rust.out.plain" || true) +if [ "$rust_permission_details" -ne 1 ] || \ + ! grep -Fx 'root dependencies: a' "$work/ocaml.err.plain" >/dev/null || \ + ! grep -Fx 'root dependencies: b' "$work/ocaml.err.plain" >/dev/null || \ + ! grep -F 'allowed-dependents' "$work/rust.err.plain" >/dev/null || \ + ! grep -F 'rescript.json' "$work/rust.err.plain" >/dev/null || \ + ! grep -F 'Update allowed-dependents in the dependency rescript.json files.' \ + "$work/ocaml.err.plain" >/dev/null || [ -s "$work/ocaml.out.plain" ]; then + echo "Active dependency-permission diagnostics changed unexpectedly" >&2 + dump_both + exit 1 +fi +run_case build-source-path-is-file accept accept build "$work/source-path-file" +if ! cmp -s "$work/rust.err" "$work/ocaml.err" || \ + ! grep -F 'Could not read folder: "src"' "$work/ocaml.err" >/dev/null; then + echo "Non-directory source diagnostics differ" >&2 + dump_both + exit 1 +fi +run_case build-missing-source-folder accept accept build \ + "$work/missing-source-folder" +if ! cmp -s "$work/rust.err" "$work/ocaml.err"; then + echo "Missing source-folder diagnostics differ" >&2 + dump_both + exit 1 +fi +run_case build-dependency-without-sources accept accept build \ + "$work/dependency-without-sources" +if ! cmp -s "$work/rust.err" "$work/ocaml.err"; then + echo "Dependency-without-sources diagnostics differ" >&2 + dump_both + exit 1 +fi +run_case build-default-feature-cycle accept accept build \ + "$work/default-feature-cycle" +run_case --cwd "$work/format-feature-cycle" \ + format-requested-feature-cycle reject reject format +if ! cmp -s "$work/rust.err" "$work/ocaml.err"; then + echo "Requested format feature-cycle diagnostics differ" >&2 + dump_both + exit 1 +fi +run_case --cwd "$work/format-source-selection" \ + format-scans-graph-with-effective-features reject reject format --check +normalize_project_path "$work/rust.err" "$work/rust.err.norm" \ + "$work/format-source-selection" +normalize_project_path "$work/ocaml.err" "$work/ocaml.err.norm" \ + "$work/format-source-selection" +missing_folder='Could not read folder: "missing". Specified in dependency: installed' +base_file='[format check] /packages/local/base/Base.res' +native_file='[format check] /packages/local/native/Native.res' +other_file='/packages/local/other/Other.res' +if ! grep -F "$missing_folder" "$work/rust.err.norm" >/dev/null || \ + ! grep -F "$missing_folder" "$work/ocaml.err.norm" >/dev/null || \ + ! grep -F "$base_file" "$work/rust.err.norm" >/dev/null || \ + ! grep -F "$base_file" "$work/ocaml.err.norm" >/dev/null || \ + ! grep -F "$native_file" "$work/rust.err.norm" >/dev/null || \ + ! grep -F "$native_file" "$work/ocaml.err.norm" >/dev/null || \ + grep -F "$other_file" "$work/rust.err.norm" >/dev/null || \ + grep -F "$other_file" "$work/ocaml.err.norm" >/dev/null || \ + ! grep -F 'The 2 files listed above need formatting' "$work/rust.err.norm" >/dev/null || \ + ! grep -F 'The 2 files listed above need formatting' "$work/ocaml.err.norm" >/dev/null; then + echo "Implicit format package scanning or feature selection differs" >&2 + dump_both + exit 1 +fi +run_case clean-dependency-without-sources accept accept clean \ + "$work/dependency-without-sources" +if ! cmp -s "$work/rust.err" "$work/ocaml.err"; then + echo "Clean dependency-without-sources diagnostics differ" >&2 + dump_both + exit 1 +fi +run_both clean "$project" +if [ "$rust_status" -ne 0 ] || [ "$ocaml_status" -ne 0 ] || \ + ! cmp -s "$work/rust.out" "$work/ocaml.out" || \ + ! cmp -s "$work/rust.err" "$work/ocaml.err" || \ + ! grep -Fx 'Cleaning command-validation' "$work/ocaml.out" >/dev/null; then + echo "Redirected clean progress differs" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_both -q clean "$project" +if [ "$rust_status" -ne 0 ] || [ "$ocaml_status" -ne 0 ] || \ + [ -s "$work/rust.out" ] || [ -s "$work/rust.err" ] || \ + [ -s "$work/ocaml.out" ] || [ -s "$work/ocaml.err" ]; then + echo "Quiet redirected clean emitted output" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +run_case --cwd "$work/dependency-without-sources" \ + format-dependency-without-sources accept accept format +if ! cmp -s "$work/rust.err" "$work/ocaml.err"; then + echo "Format dependency-without-sources diagnostics differ" >&2 + dump_both + exit 1 +fi +run_case build-package-name-mismatch accept accept build \ + "$work/package-name-mismatch" +normalize_project_path "$work/rust.err" "$work/rust.err.norm" \ + "$work/package-name-mismatch" +normalize_project_path "$work/ocaml.err" "$work/ocaml.err.norm" \ + "$work/package-name-mismatch" +if ! cmp -s "$work/rust.err.norm" "$work/ocaml.err.norm"; then + echo "Package-name mismatch diagnostics differ" >&2 + dump_both + exit 1 +fi +run_case build-malformed-package-json reject reject build \ + "$work/malformed-package-json" +require_both_errors_contain build-malformed-package-json \ + 'Could not initialize build: Could not parse package.json:' +run_case build-mismatched-dependency-name panic exit2 build \ + "$work/mismatched-dependency" +strip_ansi "$work/ocaml.err" >"$work/ocaml.err.plain" +if ! grep -F \ + "resolved package identity 'different-name' does not match the requested dependency name" \ + "$work/ocaml.err.plain" >/dev/null; then + echo "build-mismatched-dependency-name: OCaml did not reject the conflicting identity" >&2 + cat "$work/ocaml.out" "$work/ocaml.err" >&2 + exit 1 +fi +run_case build-missing-dependency exit2 exit2 build "$work/missing-dependency" +require_both_errors_contain build-missing-dependency \ + "Could not build package tree reading dependency 'absent' at path '$work/missing-dependency'. Error:" +run_case build-configless-dependency exit2 exit2 build "$work/configless-dependency" +require_both_errors_contain build-configless-dependency \ + "Could not build package tree for 'no-config' at path '$work/configless-dependency'. Error:" +run_case build-malformed-dependency exit2 exit2 build "$work/malformed-dependency" +require_both_errors_contain build-malformed-dependency \ + "Could not build package tree for 'bad-config' at path '$work/malformed-dependency'. Error:" +run_case build-duplicate-dependency accept accept build "$work/duplicate-dependency" +duplicate_warning='Duplicated package: shared ./node_modules/shared (chosen) vs ./node_modules/a/node_modules/shared in ./node_modules/a' +normalize_project_path "$work/rust.err" "$work/rust.err.norm" \ + "$work/duplicate-dependency" +normalize_project_path "$work/ocaml.err" "$work/ocaml.err.norm" \ + "$work/duplicate-dependency" +if ! grep -F "$duplicate_warning" "$work/rust.err.norm" >/dev/null || \ + ! grep -F "$duplicate_warning" "$work/ocaml.err.norm" >/dev/null; then + echo "Duplicate dependency warning was not emitted by both implementations" >&2 + dump_both + exit 1 +fi +run_case --cwd "$work/duplicate-dependency" \ + format-duplicate-dependency accept accept format +normalize_project_path "$work/rust.err" "$work/rust.err.norm" \ + "$work/duplicate-dependency" +normalize_project_path "$work/ocaml.err" "$work/ocaml.err.norm" \ + "$work/duplicate-dependency" +if ! grep -F "$duplicate_warning" "$work/rust.err.norm" >/dev/null || \ + ! grep -F "$duplicate_warning" "$work/ocaml.err.norm" >/dev/null; then + echo "Format duplicate dependency warning was not emitted by both implementations" >&2 + dump_both + exit 1 +fi + +set +e +REWATCH_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_BSC_PROXY_MODE=delete-source \ +REWATCH_SOURCE_TO_DELETE="$(command_path "$work/publication-race-rust/src/A.res")" \ +REWATCH_SOURCE_DELETED="$(command_path "$work/publication-race-rust/source-deleted")" \ +RESCRIPT_BSC_EXE="$delete_source_bsc" \ + "$rust" build "$work/publication-race-rust" \ + >"$work/rust.out" 2>"$work/rust.err" & +rust_pid=$! +attempts=0 +while kill -0 "$rust_pid" 2>/dev/null && [ "$attempts" -lt 150 ]; do + attempts=$((attempts + 1)) + sleep 0.1 +done +if kill -0 "$rust_pid" 2>/dev/null; then + kill -TERM "$rust_pid" 2>/dev/null + wait "$rust_pid" 2>/dev/null + rust_status=124 +else + wait "$rust_pid" + rust_status=$? +fi +REWATCH_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_BSC_PROXY_MODE=delete-source \ +REWATCH_SOURCE_TO_DELETE="$(command_path "$work/publication-race-ocaml/src/A.res")" \ +REWATCH_SOURCE_DELETED="$(command_path "$work/publication-race-ocaml/source-deleted")" \ +RESCRIPT_BSC_EXE="$delete_source_bsc" \ + "$ocaml" build "$work/publication-race-ocaml" \ + >"$work/ocaml.out" 2>"$work/ocaml.err" +ocaml_status=$? +set -e +if [ "$rust_status" -ne 124 ] || \ + ! grep -F "copying source file failed" "$work/rust.err" >/dev/null || \ + [ "$(classify "$ocaml_status")" != reject ] || \ + ! grep -F "A.res" "$work/ocaml.err" >/dev/null; then + printf 'build-source-disappears-during-publication: expected Rust=worker-panic/timeout and OCaml=path-bearing rejection, got Rust=%s/OCaml=%s\n' \ + "$rust_status" "$ocaml_status" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) + +set +e +RAYON_NUM_THREADS=1 \ +REWATCH_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_BSC_PROXY_MODE=delete-parse-sources \ +REWATCH_SOURCE_A="$(command_path "$work/parse-source-race-rust/src/A.res")" \ +REWATCH_SOURCE_B="$(command_path "$work/parse-source-race-rust/src/B.res")" \ +REWATCH_SOURCES_DELETED="$(command_path "$work/parse-source-race-rust/sources-deleted")" \ +RESCRIPT_BSC_EXE="$delete_parse_sources_bsc" \ + "$rust" build "$work/parse-source-race-rust" \ + >"$work/rust.out" 2>"$work/rust.err" +rust_status=$? +REWATCH_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_BSC_PROXY_MODE=delete-parse-sources \ +REWATCH_SOURCE_A="$(command_path "$work/parse-source-race-ocaml/src/A.res")" \ +REWATCH_SOURCE_B="$(command_path "$work/parse-source-race-ocaml/src/B.res")" \ +REWATCH_SOURCES_DELETED="$(command_path "$work/parse-source-race-ocaml/sources-deleted")" \ +RESCRIPT_BSC_EXE="$delete_parse_sources_bsc" \ + "$ocaml" build "$work/parse-source-race-ocaml" \ + >"$work/ocaml.out" 2>"$work/ocaml.err" +ocaml_status=$? +set -e +if [ "$rust_status" -ne 101 ] || \ + ! grep -F "file not found" "$work/rust.err" >/dev/null || \ + [ "$(classify "$ocaml_status")" != reject ] || \ + ! grep -F "parse-source-race" "$work/ocaml.err" >/dev/null || \ + ! grep -E 'A\.(res|ast)' "$work/ocaml.err" >/dev/null; then + printf 'build-source-disappears-before-parse-read: expected Rust=panic and OCaml=path-bearing rejection, got Rust=%s/OCaml=%s\n' \ + "$rust_status" "$ocaml_status" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) + +set +e +REWATCH_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_BSC_PROXY_MODE=delete-ast \ +REWATCH_AST_DELETED="$(command_path "$work/ast-race-rust/ast-deleted")" \ +RESCRIPT_BSC_EXE="$delete_ast_bsc" \ + "$rust" build "$work/ast-race-rust" \ + >"$work/rust.out" 2>"$work/rust.err" +rust_status=$? +REWATCH_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_BSC_PROXY_MODE=delete-ast \ +REWATCH_AST_DELETED="$(command_path "$work/ast-race-ocaml/ast-deleted")" \ +RESCRIPT_BSC_EXE="$delete_ast_bsc" \ + "$ocaml" build "$work/ast-race-ocaml" \ + >"$work/ocaml.out" 2>"$work/ocaml.err" +ocaml_status=$? +set -e +if [ "$rust_status" -ne 101 ] || \ + ! grep -F "Could not read file" "$work/rust.err" >/dev/null || \ + [ "$(classify "$ocaml_status")" != reject ] || \ + ! grep -F "A.ast" "$work/ocaml.err" >/dev/null; then + printf 'build-ast-disappears-before-dependency-read: expected Rust=panic and OCaml=path-bearing rejection, got Rust=%s/OCaml=%s\n' \ + "$rust_status" "$ocaml_status" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) + +"$rust" watch "$work/watch-config-rust" \ + >"$work/watch-rust.out" 2>"$work/watch-rust.err" & +rust_watch_pid=$! +background_pids="$background_pids $rust_watch_pid" +wait_for_file "$work/watch-config-rust/src/A.js" +wait_for_text "$work/watch-config-rust/lib/ocaml/.compiler.log" "#Done(" +printf '{ invalid json\n' >"$work/watch-config-rust/rescript.json" +wait_for_text "$work/watch-rust.err" "Could not initialize build" +wait_for_exit "$rust_watch_pid" +set +e +wait "$rust_watch_pid" +rust_watch_status=$? +set -e +if [ "$rust_watch_status" -ne 101 ]; then + printf 'watch-invalid-config-rebuild: expected Rust panic exit 101, got %s\n' \ + "$rust_watch_status" >&2 + cat "$work/watch-rust.out" "$work/watch-rust.err" >&2 + exit 1 +fi + +"$ocaml" watch "$work/watch-config-ocaml" \ + >"$work/watch-ocaml.out" 2>"$work/watch-ocaml.err" & +ocaml_watch_pid=$! +background_pids="$background_pids $ocaml_watch_pid" +wait_for_file "$work/watch-config-ocaml/src/A.js" +wait_for_text "$work/watch-config-ocaml/lib/ocaml/.compiler.log" "#Done(" +printf '{ invalid json\n' >"$work/watch-config-ocaml/rescript.json" +wait_for_text "$work/watch-ocaml.err" "invalid JSON" +if ! kill -0 "$ocaml_watch_pid" 2>/dev/null; then + echo "OCaml watcher exited after a recoverable config error" >&2 + cat "$work/watch-ocaml.out" "$work/watch-ocaml.err" >&2 + exit 1 +fi +printf '{"name":"watch-config","sources":["src"],"dependencies":["definitely-missing-dep"]}\n' \ + >"$work/watch-config-ocaml/rescript.json" +wait_for_text "$work/watch-ocaml.err" "definitely-missing-dep" +if ! kill -0 "$ocaml_watch_pid" 2>/dev/null; then + echo "OCaml watcher exited after a recoverable dependency error" >&2 + cat "$work/watch-ocaml.out" "$work/watch-ocaml.err" >&2 + exit 1 +fi +printf '{"name":"watch-config","sources":["src"],"package-specs":{"module":"esmodule","in-source":true,"suffix":".mjs"}}\n' \ + >"$work/watch-config-ocaml/rescript.json" +wait_for_file "$work/watch-config-ocaml/src/A.mjs" +wait_for_file "$work/watch-config-ocaml/lib/bs/build.ninja" +if ! terminate_and_wait "$ocaml_watch_pid" "recoverable-config watcher"; then + cat "$work/watch-ocaml.out" "$work/watch-ocaml.err" >&2 + exit 1 +fi +checked=$((checked + 1)) + +retained_graph_marker="$work/watch-retained-graph/after-build.log" +REWATCH_WATCH_FILTER_MARKER="$retained_graph_marker" \ + "$ocaml" watch --after-build "node $command_work/watch-filter-marker.js" \ + "$work/watch-retained-graph" \ + >"$work/watch-retained-graph.out" \ + 2>"$work/watch-retained-graph.err" & +retained_graph_pid=$! +background_pids="$background_pids $retained_graph_pid" +wait_for_line_count "$retained_graph_marker" 1 +printf 'let newValue = 2\n' >"$work/watch-retained-graph/src/C.res" +printf 'let value = C.newValue\n' >"$work/watch-retained-graph/src/B.res" +wait_for_line_count "$retained_graph_marker" 2 +wait_for_text "$work/watch-retained-graph/src/B.js" "C.newValue" +printf 'let value = C.newValue\n' >"$work/watch-retained-graph/src/B.res" +printf 'let newValue = B.value\n' >"$work/watch-retained-graph/src/C.res" +wait_for_text "$work/watch-retained-graph.err" \ + "Found a circular dependency in your code" +if ! kill -0 "$retained_graph_pid" 2>/dev/null; then + echo "OCaml watcher exited after an incremental dependency cycle" >&2 + exit 1 +fi +printf 'let newValue = 3\n' >"$work/watch-retained-graph/src/C.res" +wait_for_line_count "$retained_graph_marker" 3 +terminate_and_wait "$retained_graph_pid" "retained-graph watcher" +checked=$((checked + 1)) + +"$ocaml" watch "$work/watch-dependency-recovery" \ + >"$work/watch-dependency-recovery.out" \ + 2>"$work/watch-dependency-recovery.err" & +dependency_recovery_pid=$! +background_pids="$background_pids $dependency_recovery_pid" +wait_for_text "$work/watch-dependency-recovery.err" \ + "Could not build package tree for 'dep'" +if ! kill -0 "$dependency_recovery_pid" 2>/dev/null; then + echo "OCaml watcher exited after a malformed dependency config" >&2 + exit 1 +fi +printf '{"name":"dep","sources":["src"]}\n' \ + >"$work/watch-dependency-recovery/packages/dep/rescript.json" +wait_for_file "$work/watch-dependency-recovery/src/A.js" +terminate_and_wait "$dependency_recovery_pid" "dependency-recovery watcher" +checked=$((checked + 1)) + +"$ocaml" -v watch "$work/watch-dependency-install" \ + >"$work/watch-dependency-install.out" \ + 2>"$work/watch-dependency-install.err" & +dependency_install_pid=$! +background_pids="$background_pids $dependency_install_pid" +if ! wait_for_text "$work/watch-dependency-install.err" \ + "Could not resolve dependency @scope/dep"; then + printf '%s\n' '--- watcher stdout ---' >&2 + cat "$work/watch-dependency-install.out" >&2 + exit 1 +fi +if ! kill -0 "$dependency_install_pid" 2>/dev/null; then + echo "OCaml watcher exited while waiting for a missing dependency" >&2 + exit 1 +fi +mkdir "$work/watch-dependency-install/node_modules/@scope" +wait_for_watch "$work/watch-dependency-install.out" '[/\\]@scope' +mkdir -p "$work/watch-dependency-install/node_modules/@scope/dep/src" +printf '{"name":"@scope/dep","sources":["src"]}\n' \ + >"$work/watch-dependency-install/node_modules/@scope/dep/rescript.json" +printf 'let dependency = 1\n' \ + >"$work/watch-dependency-install/node_modules/@scope/dep/src/Dep.res" +wait_for_file "$work/watch-dependency-install/src/A.js" +terminate_and_wait "$dependency_install_pid" "dependency-install watcher" +checked=$((checked + 1)) + +directory_link "$work/watch-dependency-fallback/packages/dep" \ + "$work/node_modules/dep" +"$ocaml" -v watch "$work/watch-dependency-fallback" \ + >"$work/watch-dependency-fallback.out" \ + 2>"$work/watch-dependency-fallback.err" & +dependency_fallback_pid=$! +background_pids="$background_pids $dependency_fallback_pid" +wait_for_text "$work/watch-dependency-fallback.err" \ + "no rescript.json or bsconfig.json" +mv "$work/watch-dependency-fallback/node_modules/dep" \ + "$work/watch-dependency-fallback/node_modules/dep-disabled" +if ! wait_for_file "$work/watch-dependency-fallback/src/A.js"; then + printf '%s\n' '--- watcher stdout ---' >&2 + cat "$work/watch-dependency-fallback.out" >&2 + printf '%s\n' '--- watcher stderr ---' >&2 + cat "$work/watch-dependency-fallback.err" >&2 + exit 1 +fi +terminate_and_wait "$dependency_fallback_pid" "dependency-fallback watcher" +checked=$((checked + 1)) + +if $file_symlinks_supported; then + symlink_target_marker="$work/watch-symlink-target/after-build.log" + REWATCH_WATCH_FILTER_MARKER="$symlink_target_marker" \ + "$ocaml" watch --after-build "node $command_work/watch-filter-marker.js" \ + "$work/watch-symlink-target" \ + >"$work/watch-symlink-target.out" 2>"$work/watch-symlink-target.err" & + symlink_target_pid=$! + background_pids="$background_pids $symlink_target_pid" + wait_for_file "$work/watch-symlink-target/src/Linked.js" + wait_for_line_count "$symlink_target_marker" 1 + printf 'let linked = 9876\n' \ + >"$work/watch-symlink-external/sub/Linked.res.next" + mv "$work/watch-symlink-external/sub/Linked.res.next" \ + "$work/watch-symlink-external/sub/Linked.res" + wait_for_text "$work/watch-symlink-target/src/Linked.js" "9876" + wait_for_line_count "$symlink_target_marker" 2 + mv "$work/watch-symlink-external/sub/Linked.res" \ + "$work/watch-symlink-external/sub/Linked.res.removed" + wait_for_line_count "$symlink_target_marker" 3 + if [ -e "$work/watch-symlink-target/src/Linked.js" ]; then + echo "OCaml watcher retained output for a dangling source symlink" >&2 + exit 1 + fi + mv "$work/watch-symlink-external/sub/Linked.res.removed" \ + "$work/watch-symlink-external/sub/Linked.res" + wait_for_file "$work/watch-symlink-target/src/Linked.js" + wait_for_line_count "$symlink_target_marker" 4 + mv "$work/watch-symlink-external/sub" \ + "$work/watch-symlink-external/sub.removed" + wait_for_line_count "$symlink_target_marker" 5 + if [ -e "$work/watch-symlink-target/src/Linked.js" ]; then + echo "OCaml watcher retained output after a symlink target parent moved" >&2 + exit 1 + fi + mv "$work/watch-symlink-external/sub.removed" \ + "$work/watch-symlink-external/sub" + wait_for_file "$work/watch-symlink-target/src/Linked.js" + wait_for_line_count "$symlink_target_marker" 6 + terminate_and_wait "$symlink_target_pid" "symlink-target watcher" + checked=$((checked + 1)) +fi + +feature_scope_marker="$work/watch-feature-scope/after-build.log" +scope_block_request="$work/watch-feature-scope/block-request" +scope_block_started="$work/watch-feature-scope/block-started" +scope_block_release="$work/watch-feature-scope/block-release" +REWATCH_SCOPE_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_REAL_BSC="$RESCRIPT_BSC_EXE" \ +REWATCH_BSC_PROXY_MODE=scope-block \ +REWATCH_SCOPE_BLOCK_REQUEST="$(command_path "$scope_block_request")" \ +REWATCH_SCOPE_BLOCK_STARTED="$(command_path "$scope_block_started")" \ +REWATCH_SCOPE_BLOCK_RELEASE="$(command_path "$scope_block_release")" \ +RESCRIPT_BSC_EXE="$watch_scope_bsc" \ +REWATCH_WATCH_FILTER_MARKER="$feature_scope_marker" \ + "$ocaml" watch --features other \ + --after-build "node $command_work/watch-filter-marker.js" \ + "$work/watch-feature-scope" \ + >"$work/watch-feature-scope.out" 2>"$work/watch-feature-scope.err" & +feature_scope_pid=$! +background_pids="$background_pids $feature_scope_pid" +if ! wait_for_line_count "$feature_scope_marker" 1; then + echo "OCaml feature-scope watcher did not finish its initial build" >&2 + cat "$work/watch-feature-scope.out" "$work/watch-feature-scope.err" >&2 + exit 1 +fi +: >"$scope_block_request" +printf '{"name":"watch-feature-scope","sources":["src",{"dir":"inactive","feature":"inactive"}],"features":{"other":["inactive"]}}\n' \ + >"$work/watch-feature-scope/rescript.json" +wait_for_file "$scope_block_started" +printf 'let createdDuringBuild = 2\n' \ + >"$work/watch-feature-scope/inactive/CreatedDuringBuild.res" +: >"$scope_block_release" +wait_for_file "$work/watch-feature-scope/inactive/Inactive.js" +wait_for_file "$work/watch-feature-scope/inactive/CreatedDuringBuild.js" +wait_for_line_count "$feature_scope_marker" 3 +if ! line_count_stays "$feature_scope_marker" 3; then + echo "OCaml watcher lost or duplicated an edit during a source-scope transition" >&2 + cat "$work/watch-feature-scope.out" "$work/watch-feature-scope.err" >&2 + exit 1 +fi +terminate_and_wait "$feature_scope_pid" "feature-scope watcher" +checked=$((checked + 1)) + +rust_filter_marker="$work/watch-filter-rust/after-build.log" +REWATCH_WATCH_FILTER_MARKER="$rust_filter_marker" \ + "$rust" watch --features other --filter 'Include\.res$' \ + --after-build "node $command_work/watch-filter-marker.js" \ + "$work/watch-filter-rust" \ + >"$work/watch-filter-rust.out" 2>"$work/watch-filter-rust.err" & +rust_filter_pid=$! +background_pids="$background_pids $rust_filter_pid" +wait_for_file "$work/watch-filter-rust/src/Include.js" +wait_for_line_count "$rust_filter_marker" 1 +if [ -e "$work/watch-filter-rust/src/Exclude.js" ]; then + echo "Rust filter unexpectedly compiled the excluded source initially" >&2 + exit 1 +fi +cp "$work/watch-filter-rust/src/Include.js" "$work/watch-filter-rust-initial.js" +printf 'let value = 2\n' >"$work/watch-filter-rust/src/Include.res" +printf 'let value = 11\n' >"$work/watch-filter-rust/src/Exclude.res" +wait_for_line_count "$rust_filter_marker" 2 +# A canary for the documented difference: Rust's event filter is inverted, so +# the excluded edit triggers the rebuild and the included edit is missed. It +# only warns, because file event backends such as macOS FSEvents can deliver +# both edits in one batch, and Rust then rebuilds the included source anyway. +if ! cmp -s "$work/watch-filter-rust-initial.js" \ + "$work/watch-filter-rust/src/Include.js"; then + echo "Notice: Rust did not reproduce the inverted watch-filter event behavior" >&2 + echo "this time; if this persists, Rust fixed it and the difference is stale." >&2 +fi +terminate_and_wait "$rust_filter_pid" "Rust filter watcher" + +ocaml_filter_marker="$work/watch-filter-ocaml/after-build.log" +REWATCH_WATCH_FILTER_MARKER="$ocaml_filter_marker" \ + "$ocaml" watch --features other --filter 'Include\.res$' \ + --after-build "node $command_work/watch-filter-marker.js" \ + "$work/watch-filter-ocaml" \ + >"$work/watch-filter-ocaml.out" 2>"$work/watch-filter-ocaml.err" & +ocaml_filter_pid=$! +background_pids="$background_pids $ocaml_filter_pid" +wait_for_file "$work/watch-filter-ocaml/src/Include.js" +wait_for_line_count "$ocaml_filter_marker" 1 +if [ -e "$work/watch-filter-ocaml/src/Exclude.js" ]; then + echo "OCaml filter unexpectedly compiled the excluded source initially" >&2 + exit 1 +fi +cp "$work/watch-filter-ocaml/src/Include.js" "$work/watch-filter-ocaml-initial.js" +printf 'let value = 2\n' >"$work/watch-filter-ocaml/src/Include.res" +wait_for_line_count "$ocaml_filter_marker" 2 +if cmp -s "$work/watch-filter-ocaml-initial.js" \ + "$work/watch-filter-ocaml/src/Include.js" || \ + ! grep -F '2' "$work/watch-filter-ocaml/src/Include.js" >/dev/null; then + echo "OCaml watch filter did not rebuild its included source" >&2 + cat "$work/watch-filter-ocaml.out" "$work/watch-filter-ocaml.err" >&2 + exit 1 +fi +printf 'let value = 11\n' >"$work/watch-filter-ocaml/src/Exclude.res" +if ! line_count_stays "$ocaml_filter_marker" 2; then + echo "OCaml watch filter rebuilt for an excluded-only edit" >&2 + cat "$work/watch-filter-ocaml.out" "$work/watch-filter-ocaml.err" >&2 + exit 1 +fi +printf 'let value = 21\n' \ + >"$work/watch-filter-ocaml/inactive/Inactive.res" +if ! line_count_stays "$ocaml_filter_marker" 2; then + echo "OCaml watcher rebuilt for a feature-disabled source edit" >&2 + cat "$work/watch-filter-ocaml.out" "$work/watch-filter-ocaml.err" >&2 + exit 1 +fi +terminate_and_wait "$ocaml_filter_pid" "OCaml filter watcher" +checked=$((checked + 1)) + +for implementation in rust ocaml; do + if [ "$implementation" = rust ]; then + executable=$rust + else + executable=$ocaml + fi + quiet_watch_project="$work/quiet-watch-$implementation" + quiet_watch_marker="$quiet_watch_project/after-build.log" + REWATCH_WATCH_FILTER_MARKER="$quiet_watch_marker" \ + "$executable" -q watch \ + --after-build "node $command_work/watch-filter-marker.js" \ + "$quiet_watch_project" \ + >"$work/quiet-watch-$implementation.out" \ + 2>"$work/quiet-watch-$implementation.err" & + quiet_watch_pid=$! + background_pids="$background_pids $quiet_watch_pid" + wait_for_line_count "$quiet_watch_marker" 1 + printf 'let value = 2\n' >"$quiet_watch_project/src/A.res" + wait_for_line_count "$quiet_watch_marker" 2 + printf 'let value =\n' >"$quiet_watch_project/src/A.res" + wait_for_text "$work/quiet-watch-$implementation.err" \ + "This let-binding misses an expression" + if ! kill -0 "$quiet_watch_pid" 2>/dev/null; then + echo "quiet-watch-$implementation: watcher exited after a parse error" >&2 + exit 1 + fi + printf 'let value = 3\n' >"$quiet_watch_project/src/A.res" + wait_for_line_count "$quiet_watch_marker" 3 + rm "$quiet_watch_project/lib/watch.lock" + wait_for_exit "$quiet_watch_pid" + wait "$quiet_watch_pid" + if [ -s "$work/quiet-watch-$implementation.out" ] || \ + grep -F "Incremental build failed" \ + "$work/quiet-watch-$implementation.err" >/dev/null; then + echo "quiet-watch-$implementation: quiet watch emitted progress or a duplicate failure summary" >&2 + cat "$work/quiet-watch-$implementation.out" \ + "$work/quiet-watch-$implementation.err" >&2 + exit 1 + fi + normalize_project_path "$work/quiet-watch-$implementation.err" \ + "$work/quiet-watch-$implementation.err.norm" "$quiet_watch_project" +done +if ! cmp -s "$work/quiet-watch-rust.err.norm" \ + "$work/quiet-watch-ocaml.err.norm"; then + echo "Quiet watch failure diagnostics differ" >&2 + printf '%s\n' '--- Rust stderr ---' >&2 + cat "$work/quiet-watch-rust.err.norm" >&2 + printf '%s\n' '--- OCaml stderr ---' >&2 + cat "$work/quiet-watch-ocaml.err.norm" >&2 + exit 1 +fi +checked=$((checked + 1)) + +run_case clean-missing-dependency exit2 exit2 clean "$work/missing-dependency" +run_case clean-configless-dependency exit2 exit2 clean "$work/configless-dependency" +run_case clean-malformed-dependency exit2 exit2 clean "$work/malformed-dependency" +run_both clean "$work/clean-duplicate-{impl}" +if [ "$(classify "$rust_status")" != reject ] || [ "$ocaml_status" -ne 0 ] || \ + [ ! -e "$work/clean-duplicate-rust/src/one/A.js" ] || \ + [ ! -e "$work/clean-duplicate-rust/src/two/A.js" ] || \ + [ -e "$work/clean-duplicate-rust/lib/bs/marker" ] || \ + [ -e "$work/clean-duplicate-ocaml/src/one/A.js" ] || \ + [ -e "$work/clean-duplicate-ocaml/src/two/A.js" ] || \ + [ -e "$work/clean-duplicate-ocaml/lib/bs/marker" ]; then + echo "clean-duplicate-modules: cleanup behavior differs unexpectedly" >&2 + dump_both + exit 1 +fi +checked=$((checked + 1)) +set +e +"$rust" watch "$work/missing-dependency" >"$work/rust.out" 2>"$work/rust.err" +rust_status=$? +set -e +if [ "$rust_status" -ne 2 ]; then + echo "watch-missing-dependency: expected Rust exit 2, got $rust_status" >&2 + cat "$work/rust.out" "$work/rust.err" >&2 + exit 1 +fi +"$ocaml" watch "$work/missing-dependency" \ + >"$work/ocaml.out" 2>"$work/ocaml.err" & +missing_dependency_watch_pid=$! +background_pids="$background_pids $missing_dependency_watch_pid" +wait_for_text "$work/ocaml.err" "Could not resolve dependency absent" +if ! kill -0 "$missing_dependency_watch_pid" 2>/dev/null; then + echo "OCaml watcher exited after its initial dependency error" >&2 + cat "$work/ocaml.out" "$work/ocaml.err" >&2 + exit 1 +fi +printf '{"name":"missing-dependency","sources":["src"]}\n' \ + >"$work/missing-dependency/rescript.json" +wait_for_file "$work/missing-dependency/src/A.js" +terminate_and_wait "$missing_dependency_watch_pid" \ + "missing-dependency watcher" +if $windows_posix_shell; then + # MSYS cannot deliver the graceful console event that lets a native watcher + # remove its locks. Its external termination intentionally leaves a stale + # watch lock, and a build lock if the rebuild was still finishing, so remove + # those harness artifacts before checking failure paths. + rm -f "$work/missing-dependency/lib/watch.lock" \ + "$work/missing-dependency/lib/build.lock" +fi +printf '{"name":"missing-dependency","sources":["src"],"dependencies":["absent"]}\n' \ + >"$work/missing-dependency/rescript.json" +checked=$((checked + 1)) +run_case --cwd "$work/missing-dependency" \ + format-missing-dependency exit2 exit2 format +run_case --cwd "$work/configless-dependency" \ + format-configless-dependency exit2 exit2 format +run_case --cwd "$work/malformed-dependency" \ + format-malformed-dependency exit2 exit2 format +if [ -e "$work/missing-dependency/lib/build.lock" ] || \ + [ -e "$work/missing-dependency/lib/watch.lock" ]; then + echo "OCaml dependency failures left a build or watch lock behind" >&2 + exit 1 +fi + +run_both --cwd "$project/src" format --check +if [ "$(classify "$rust_status")" != reject ] || \ + [ "$(classify "$ocaml_status")" != reject ]; then + printf 'format-nested: expected both implementations to reject, got Rust=%s/OCaml=%s\n' \ + "$rust_status" "$ocaml_status" >&2 + exit 1 +fi +checked=$((checked + 1)) + +printf 'Command validation cases: %d; expected outcomes matched\n' "$checked" diff --git a/rewatch-ocaml/tests/check_config_acceptance.sh b/rewatch-ocaml/tests/check_config_acceptance.sh new file mode 100755 index 00000000000..c414fcb1083 --- /dev/null +++ b/rewatch-ocaml/tests/check_config_acceptance.sh @@ -0,0 +1,112 @@ +#!/bin/bash +set -eu + +root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd) +rust=${1:-$root/rewatch/target/debug/rescript} +ocaml=${2:-$root/_build/default/rewatch-ocaml/rescript_ocaml.exe} +cases=$root/rewatch-ocaml/tests/config_acceptance_cases.tsv + +rust=$(realpath "$rust") +ocaml=$(realpath "$ocaml") +mkdir -p "$root/tmp" +work=$(mktemp -d "$root/tmp/rewatch-config-acceptance-XXXXXX") +trap 'rm -rf "$work"' EXIT +mkdir -p "$work/src" "$work/node_modules/dep/lib/ocaml" "$work/node_modules/ppx" +printf 'let value = 1\n' >"$work/src/A.res" + +default_bsc=$root/_build/default/compiler/bsc/rescript_compiler_main.exe +default_runtime=$root/packages/@rescript/runtime +case $(uname -s) in + MINGW*|MSYS*) + default_bsc=$(cygpath -w "$default_bsc") + default_runtime=$(cygpath -w "$default_runtime") + ;; +esac +export RESCRIPT_BSC_EXE=${RESCRIPT_BSC_EXE:-$default_bsc} +export RESCRIPT_RUNTIME=${RESCRIPT_RUNTIME:-$default_runtime} + +checked=0 +divergences=0 +diagnostic_checks=0 +while IFS=$'\t' read -r area name expected json; do + if [[ -z "$area" || "$area" == \#* ]]; then + continue + fi + printf '%s\n' "$json" >"$work/rescript.json" + set +e + "$rust" compiler-args "$work/src/A.res" >"$work/rust.out" 2>"$work/rust.err" + rust_status=$? + "$ocaml" compiler-args "$work/src/A.res" >"$work/ocaml.out" 2>"$work/ocaml.err" + ocaml_status=$? + set -e + + if [[ "$rust_status" -eq 0 ]]; then + rust_actual=accept + elif [[ "$rust_status" -eq 101 ]]; then + rust_actual=panic + else + rust_actual=reject + fi + if [[ "$ocaml_status" -eq 0 ]]; then + ocaml_actual=accept + else + ocaml_actual=reject + fi + rust_expected=${expected%%/*} + if [[ "$expected" == */* ]]; then + ocaml_expected=${expected#*/} + compare_arguments=false + divergences=$((divergences + 1)) + else + ocaml_expected=$expected + compare_arguments=true + fi + if [[ "$rust_actual" != "$rust_expected" || "$ocaml_actual" != "$ocaml_expected" ]]; then + printf 'Config case %s/%s: expected Rust=%s/OCaml=%s, got Rust=%s/OCaml=%s\n' \ + "$area" "$name" "$rust_expected" "$ocaml_expected" \ + "$rust_status" "$ocaml_status" >&2 + printf '%s\n' '--- Rust output ---' >&2 + cat "$work/rust.out" >&2 + cat "$work/rust.err" >&2 + printf '%s\n' '--- OCaml output ---' >&2 + cat "$work/ocaml.out" >&2 + cat "$work/ocaml.err" >&2 + exit 1 + fi + diagnostic_fragment= + case "$area" in + jsx) diagnostic_fragment=jsx ;; + source-map) diagnostic_fragment=sourceMap ;; + esac + if [[ -n "$diagnostic_fragment" && "$rust_expected" != accept ]]; then + if ! grep -Fi "$diagnostic_fragment" "$work/rust.err" >/dev/null || + ! grep -Fi "$diagnostic_fragment" "$work/ocaml.err" >/dev/null; then + printf 'Config case %s/%s lost the %s diagnostic context\n' \ + "$area" "$name" "$diagnostic_fragment" >&2 + printf '%s\n' '--- Rust output ---' >&2 + cat "$work/rust.out" "$work/rust.err" >&2 + printf '%s\n' '--- OCaml output ---' >&2 + cat "$work/ocaml.out" "$work/ocaml.err" >&2 + exit 1 + fi + diagnostic_checks=$((diagnostic_checks + 1)) + fi + if [[ "$compare_arguments" == true && "$rust_expected" == accept ]] && + ! node -e ' + const fs = require("fs"); + const assert = require("assert"); + assert.deepStrictEqual( + JSON.parse(fs.readFileSync(process.argv[1], "utf8")), + JSON.parse(fs.readFileSync(process.argv[2], "utf8")), + ); + ' "$work/rust.out" "$work/ocaml.out"; then + printf 'Config case %s/%s produced different compiler arguments\n' \ + "$area" "$name" >&2 + diff -u "$work/rust.out" "$work/ocaml.out" >&2 || true + exit 1 + fi + checked=$((checked + 1)) +done <"$cases" + +printf 'Configuration cases: %d (%d documented divergences, %d JSX/source-map diagnostic checks); Rust/OCaml expectations and parity arguments matched\n' \ + "$checked" "$divergences" "$diagnostic_checks" diff --git a/rewatch-ocaml/tests/check_interactive_output.sh b/rewatch-ocaml/tests/check_interactive_output.sh new file mode 100755 index 00000000000..1f599c3e87b --- /dev/null +++ b/rewatch-ocaml/tests/check_interactive_output.sh @@ -0,0 +1,790 @@ +#!/bin/bash +set -eu + +root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd) +rust=${1:-$root/rewatch/target/debug/rescript} +ocaml=${2:-$root/_build/default/rewatch-ocaml/rescript_ocaml.exe} +rust=$(realpath "$rust") +ocaml=$(realpath "$ocaml") +work=$(mktemp -d "${TMPDIR:-/tmp}/rewatch-interactive-output-XXXXXX") +windows_posix_shell=false +compare_rust_watch_output=true +case $(uname -s) in + CYGWIN*|MINGW*|MSYS*) windows_posix_shell=true ;; + # Rust's macOS watcher can classify an ordinary source write as one or more + # structural events and legitimately perform full rebuilds. Linux provides + # the stable event classification needed for exact incremental comparison; + # macOS still exercises the OCaml watch presentation and recovery paths. + Darwin) compare_rust_watch_output=false ;; +esac + +if $windows_posix_shell; then + echo "Skipping interactive output gate: a POSIX pseudo-terminal does not exercise the native Windows console" + exit 0 +fi + +command_path() { + if $windows_posix_shell; then + cygpath -am "$1" + else + printf '%s\n' "$1" + fi +} +active_script_pid="" +active_watch_project="" +active_watch_transcript="" +wait_for_pid_gone() { + pid=$1 + attempts=${2:-200} + while [ "$attempts" -gt 0 ]; do + if ! kill -0 "$pid" 2>/dev/null; then return 0; fi + attempts=$((attempts - 1)) + sleep 0.1 + done + return 1 +} +cleanup() { + if [ -n "$active_script_pid" ]; then + if [ -n "$active_watch_project" ]; then + rm -f "$active_watch_project/lib/watch.lock" + fi + if ! wait_for_pid_gone "$active_script_pid" 50; then + kill -TERM "$active_script_pid" 2>/dev/null || true + fi + if ! wait_for_pid_gone "$active_script_pid" 50; then + kill -KILL "$active_script_pid" 2>/dev/null || true + fi + wait "$active_script_pid" 2>/dev/null || true + fi + rm -rf "$work" +} +trap cleanup EXIT + +if ! command -v script >/dev/null 2>&1; then + echo "Interactive output gate requires the util-linux script command" >&2 + exit 1 +fi + +# macOS buffers typescript files for up to 30 seconds unless -F is used. The +# watcher checks below must observe each message as soon as it is written. + +normalize_output() { + sed -E $'s/\033\\[[0-9;]*[[:alpha:]]//g' \ + | sed -e 's/\[clean\]/🧹/g' -e 's/\[parse\]/🧱/g' \ + -e 's/\[build\]/🤺/g' -e 's/\[ok\]/✅/g' \ + -e 's/\[warn\]/⚠️/g' -e 's/\[error\]/❌/g' +} + +for implementation in rust ocaml; do + mkdir -p "$work/$implementation/src" + printf '{"name":"interactive-output","sources":["src"],"namespace":"Interactive"}\n' \ + >"$work/$implementation/rescript.json" + printf 'let value = 1\n' >"$work/$implementation/src/A.res" + printf 'let value: int\n' >"$work/$implementation/src/A.resi" + cp -R "$work/$implementation" "$work/$implementation-after-build" + cp -R "$work/$implementation" "$work/$implementation-parse-warning" + cp -R "$work/$implementation" "$work/$implementation-watch" + cp -R "$work/$implementation" "$work/$implementation-initial-failure-watch" + printf 'let value = (\n' \ + >"$work/$implementation-initial-failure-watch/src/A.res" + cp -R "$root/rewatch-ocaml/tests/basic" \ + "$work/$implementation-partial-initial-failure-watch" + printf 'let answer: int = "not an int"\n' \ + >"$work/$implementation-partial-initial-failure-watch/src/B.res" + cp -R "$work/$implementation" "$work/$implementation-warning-watch" + printf '%s\n' \ + '{"name":"interactive-output","sources":["src"],"namespace":"Interactive","package-specs":{"module":"es6","in-source":true}}' \ + >"$work/$implementation-warning-watch/rescript.json" +done + +cat >"$work/after-build-marker.sh" <<'EOF' +#!/bin/sh +printf '%s\n' AFTER_BUILD_MARKER +EOF +chmod +x "$work/after-build-marker.sh" +printf 'console.log("AFTER_BUILD_MARKER")\n' >"$work/after-build-marker.js" +cat >"$work/after-build-input.js" <<'EOF' +process.stdin.setEncoding("utf8"); +process.stdin.once("data", input => { + console.log(`AFTER_BUILD_INPUT:${input.trim()}`); +}); +EOF + +export RESCRIPT_BSC_EXE=${RESCRIPT_BSC_EXE:-$root/_build/default/compiler/bsc/rescript_compiler_main.exe} +export RESCRIPT_RUNTIME=${RESCRIPT_RUNTIME:-$root/packages/@rescript/runtime} +parse_warning_bsc="$root/_build/default/tests/rewatch_ounit_tests/rewatch_bsc_test_proxy.exe" +after_build_command="$work/after-build-marker.sh" +if $windows_posix_shell; then + RESCRIPT_BSC_EXE=$(command_path "$RESCRIPT_BSC_EXE") + RESCRIPT_RUNTIME=$(command_path "$RESCRIPT_RUNTIME") + parse_warning_bsc=$(command_path "$parse_warning_bsc") + after_build_command="node $(command_path "$work/after-build-marker.js")" +fi + +capture() { + implementation=$1 + executable=$2 + transcript="$work/$implementation.tty" + command_executable=$(command_path "$executable") + command_project=$(command_path "$work/$implementation") + if [ "$(uname -s)" = Darwin ]; then + script -qF "$transcript" env -u NO_COLOR \ + "TERM=xterm" \ + "CLICOLOR=1" \ + "CLICOLOR_FORCE=0" \ + "RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE" \ + "RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME" \ + "$executable" build "$work/$implementation" --no-timing >/dev/null + else + script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME $command_executable build $command_project --no-timing" \ + "$transcript" >/dev/null + fi + tr '\r' '\n' <"$transcript" \ + | normalize_output \ + | grep -E '^\[[123]/3\] .* (Cleaned|Parsed|Compiled) |^✅ Finished compilation in ' \ + >"$work/$implementation.phases" +} + +echo "Checking interactive build output..." +capture rust "$rust" +capture ocaml "$ocaml" + +require_spinner_frames() { + implementation=$1 + if ! grep -F $'\033[1m\033[2m[2/3]\033[0m' \ + "$work/$implementation.tty" >/dev/null; then + echo "$implementation did not render the interactive step style" >&2 + cat "$work/$implementation.tty" >&2 + exit 1 + fi + tr '\r' '\n' <"$work/$implementation.tty" \ + | normalize_output \ + >"$work/$implementation.frames" + if ! grep -E '^\[2/3\] 🧱 Parsing\.\.\. .+ [0-9]+/1' \ + "$work/$implementation.frames" >/dev/null || \ + ! grep -E '^\[3/3\] 🤺 Compiling\.\.\. .+ [0-9]+/2' \ + "$work/$implementation.frames" >/dev/null; then + echo "$implementation did not render both live spinner phases" >&2 + cat "$work/$implementation.frames" >&2 + exit 1 + fi +} + +require_spinner_frames rust +require_spinner_frames ocaml + +if ! cmp -s "$work/rust.phases" "$work/ocaml.phases"; then + echo "Interactive phase output differs" >&2 + printf '%s\n' '--- Rust phases ---' >&2 + cat "$work/rust.phases" >&2 + printf '%s\n' '--- OCaml phases ---' >&2 + cat "$work/ocaml.phases" >&2 + exit 1 +fi + +cat >"$work/expected" <<'EOF' +[1/3] 🧹 Cleaned 0/0 in 0.00s +[2/3] 🧱 Parsed 1 source files in 0.00s +[3/3] 🤺 Compiled 1 modules in 0.00s +✅ Finished compilation in 0.00s +EOF + +if ! cmp -s "$work/expected" "$work/ocaml.phases"; then + echo "Interactive phase output no longer has the expected stable shape" >&2 + cat "$work/ocaml.phases" >&2 + exit 1 +fi + +capture_parse_warning_order() { + implementation=$1 + executable=$2 + transcript="$work/$implementation-parse-warning.tty" + project="$work/$implementation-parse-warning" + command_executable=$(command_path "$executable") + command_project=$(command_path "$project") + if [ "$(uname -s)" = Darwin ]; then + script -qF "$transcript" env -u NO_COLOR \ + "TERM=xterm" \ + "CLICOLOR=1" \ + "CLICOLOR_FORCE=0" \ + "REWATCH_REAL_BSC=$RESCRIPT_BSC_EXE" \ + "REWATCH_BSC_PROXY_MODE=parse-warning" \ + "RESCRIPT_BSC_EXE=$parse_warning_bsc" \ + "RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME" \ + "$executable" build "$project" --no-timing >/dev/null + else + script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 REAL_BSC_EXE=$RESCRIPT_BSC_EXE REWATCH_REAL_BSC=$RESCRIPT_BSC_EXE REWATCH_BSC_PROXY_MODE=parse-warning RESCRIPT_BSC_EXE=$parse_warning_bsc RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME $command_executable build $command_project --no-timing" \ + "$transcript" >/dev/null + fi + tr '\r' '\n' <"$transcript" \ + | normalize_output \ + | grep -E '(^\[[123]/3\] .* Parsed |PARSE_WARNING_MARKER)' \ + >"$work/$implementation-parse-warning.order" +} + +echo "Checking interactive parser warnings..." +capture_parse_warning_order rust "$rust" +capture_parse_warning_order ocaml "$ocaml" + +if ! cmp -s "$work/rust-parse-warning.order" \ + "$work/ocaml-parse-warning.order"; then + echo "Parser warning phase order differs" >&2 + printf '%s\n' '--- Rust order ---' >&2 + cat "$work/rust-parse-warning.order" >&2 + printf '%s\n' '--- OCaml order ---' >&2 + cat "$work/ocaml-parse-warning.order" >&2 + exit 1 +fi + +if ! sed -n '1p' "$work/ocaml-parse-warning.order" \ + | grep -E '^\[2/3\] .* Parsed 1 source files in 0.00s$' >/dev/null; then + echo "Parser warnings were emitted before the completed parse phase" >&2 + cat "$work/ocaml-parse-warning.order" >&2 + exit 1 +fi + +capture_after_build_order() { + implementation=$1 + executable=$2 + transcript="$work/$implementation-after-build.tty" + project="$work/$implementation-after-build" + command_executable=$(command_path "$executable") + command_project=$(command_path "$project") + if [ "$(uname -s)" = Darwin ]; then + script -qF "$transcript" env -u NO_COLOR \ + "TERM=xterm" \ + "CLICOLOR=1" \ + "CLICOLOR_FORCE=0" \ + "RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE" \ + "RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME" \ + "$executable" build --after-build "$after_build_command" \ + "$project" --no-timing >/dev/null + else + script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME $command_executable build --after-build '$after_build_command' $command_project --no-timing" \ + "$transcript" >/dev/null + fi + tr '\r' '\n' <"$transcript" \ + | normalize_output \ + | grep -E '^(✅ Finished compilation in |AFTER_BUILD_MARKER$)' \ + | sed -E 's/in [0-9]+\.[0-9]+s$/in 0.00s/' \ + >"$work/$implementation-after-build.order" +} + +echo "Checking interactive after-build output..." +capture_after_build_order rust "$rust" +capture_after_build_order ocaml "$ocaml" + +cat >"$work/expected-after-build-order" <<'EOF' +✅ Finished compilation in 0.00s +AFTER_BUILD_MARKER +EOF + +for implementation in rust ocaml; do + if ! cmp -s "$work/expected-after-build-order" \ + "$work/$implementation-after-build.order"; then + echo "$implementation ran one-shot --after-build in the wrong phase" >&2 + cat "$work/$implementation-after-build.order" >&2 + exit 1 + fi +done + +if $windows_posix_shell; then + for implementation in rust ocaml; do + if [ "$implementation" = rust ]; then executable=$rust; else executable=$ocaml; fi + command_executable=$(command_path "$executable") + command_project=$(command_path "$work/$implementation-after-build") + input_script=$(command_path "$work/after-build-input.js") + transcript="$work/$implementation-after-build-input.tty" + printf 'from-terminal\n' | script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME $command_executable build --after-build 'node $input_script' $command_project --no-timing" \ + "$transcript" >/dev/null + if ! tr '\r' '\n' <"$transcript" \ + | grep -F 'AFTER_BUILD_INPUT:from-terminal' >/dev/null; then + echo "$implementation did not pass terminal input to --after-build" >&2 + cat "$transcript" >&2 + exit 1 + fi + done +fi + +capture_quiet_build() { + implementation=$1 + executable=$2 + transcript="$work/$implementation-quiet.tty" + command_executable=$(command_path "$executable") + command_project=$(command_path "$work/$implementation") + if [ "$(uname -s)" = Darwin ]; then + script -qF "$transcript" env -u NO_COLOR \ + "TERM=xterm" \ + "CLICOLOR=1" \ + "CLICOLOR_FORCE=0" \ + "RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE" \ + "RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME" \ + "$executable" -q build "$work/$implementation" >/dev/null + else + script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME $command_executable -q build $command_project" \ + "$transcript" >/dev/null + fi + if tr '\r' '\n' <"$transcript" \ + | grep -E '(Cleaned|Parsed|Parsing\.\.\.|Compiled|Compiling\.\.\.|Finished .*compilation)' >/dev/null; then + echo "$implementation quiet interactive build emitted progress" >&2 + cat "$transcript" >&2 + exit 1 + fi +} + +echo "Checking quiet interactive builds..." +capture_quiet_build rust "$rust" +capture_quiet_build ocaml "$ocaml" + +capture_clean() { + implementation=$1 + executable=$2 + transcript="$work/$implementation-clean.tty" + command_executable=$(command_path "$executable") + command_project=$(command_path "$work/$implementation") + if [ "$(uname -s)" = Darwin ]; then + script -qF "$transcript" env -u NO_COLOR \ + "TERM=xterm" \ + "CLICOLOR=1" \ + "CLICOLOR_FORCE=0" \ + "$executable" clean "$work/$implementation" >/dev/null + else + script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 $command_executable clean $command_project" \ + "$transcript" >/dev/null + fi + # The initial generic label is overwritten by the first package label on the + # same terminal line, so it is not part of the visible phase sequence. + tr '\r' '\n' <"$transcript" \ + | normalize_output \ + | grep -E '^\[[12]/2\] 🧹 (Cleaning|Cleaned)' \ + | awk '$0 != "[1/2] 🧹 Cleaning compiler assets..."' \ + | sed -E 's/in [0-9]+\.[0-9]+s$/in 0.00s/' \ + >"$work/$implementation-clean.phases" +} + +echo "Checking interactive clean output..." +capture_clean rust "$rust" +capture_clean ocaml "$ocaml" + +if ! cmp -s "$work/rust-clean.phases" "$work/ocaml-clean.phases"; then + echo "Interactive clean phase output differs" >&2 + printf '%s\n' '--- Rust clean phases ---' >&2 + cat "$work/rust-clean.phases" >&2 + printf '%s\n' '--- OCaml clean phases ---' >&2 + cat "$work/ocaml-clean.phases" >&2 + exit 1 +fi + +cat >"$work/expected-clean" <<'EOF' +[1/2] 🧹 Cleaning interactive-output... +[1/2] 🧹 Cleaned compiler assets in 0.00s +[2/2] 🧹 Cleaning .js files... +[2/2] 🧹 Cleaned .js files in 0.00s +EOF + +if ! cmp -s "$work/expected-clean" "$work/ocaml-clean.phases"; then + echo "Interactive clean output no longer has the expected stable shape" >&2 + cat "$work/ocaml-clean.phases" >&2 + exit 1 +fi + +capture_quiet_clean() { + implementation=$1 + executable=$2 + transcript="$work/$implementation-clean-quiet.tty" + command_executable=$(command_path "$executable") + command_project=$(command_path "$work/$implementation") + if [ "$(uname -s)" = Darwin ]; then + script -qF "$transcript" env -u NO_COLOR \ + "TERM=xterm" \ + "CLICOLOR=1" \ + "CLICOLOR_FORCE=0" \ + "$executable" -q clean "$work/$implementation" >/dev/null + else + script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 $command_executable -q clean $command_project" \ + "$transcript" >/dev/null + fi + if tr '\r' '\n' <"$transcript" | grep -E '(Cleaning|Cleaned)' >/dev/null; then + echo "$implementation quiet interactive clean emitted progress" >&2 + cat "$transcript" >&2 + exit 1 + fi +} + +echo "Checking quiet interactive cleans..." +capture_quiet_clean rust "$rust" +capture_quiet_clean ocaml "$ocaml" + +wait_for_text() { + path=$1 + pattern=$2 + count=$3 + attempts=0 + while [ "$attempts" -lt 200 ]; do + actual=$(grep -cF "$pattern" "$path" 2>/dev/null || true) + actual=${actual:-0} + if [ "$actual" -ge "$count" ]; then + return 0 + fi + attempts=$((attempts + 1)) + sleep 0.1 + done + printf 'Timed out waiting for occurrence %s of %s in %s\n' \ + "$count" "$pattern" "$path" >&2 + if [ -f "$path" ]; then cat "$path" >&2; fi + return 1 +} + +wait_for_file() { + path=$1 + attempts=0 + while [ "$attempts" -lt 200 ]; do + if [ -f "$path" ]; then return 0; fi + attempts=$((attempts + 1)) + sleep 0.1 + done + printf 'Timed out waiting for %s\n' "$path" >&2 + return 1 +} + +# Opening an existing source with shell redirection truncates it first. Some +# native watcher backends report that as a structural change, which correctly +# requests a full rebuild. Equal-length writes without truncation make these +# fixtures exercise the content-change/incremental path they are testing. +overwrite_line_in_place() { + path=$1 + line=$2 + current_size=$(wc -c <"$path" | tr -d ' ') + replacement_size=$(printf '%s\n' "$line" | wc -c | tr -d ' ') + if [ "$current_size" -ne "$replacement_size" ]; then + echo "In-place test update changed size for $path" >&2 + return 1 + fi + printf '%s\n' "$line" | dd of="$path" conv=notrunc 2>/dev/null +} + +stop_active_watch() { + rm -f "$active_watch_project/lib/watch.lock" + if ! wait_for_pid_gone "$active_script_pid"; then + echo "Timed out waiting for the interactive watcher to stop" >&2 + if [ -f "$active_watch_transcript" ]; then + cat "$active_watch_transcript" >&2 + fi + return 1 + fi + status=0 + wait "$active_script_pid" || status=$? + active_script_pid="" + active_watch_project="" + active_watch_transcript="" + return "$status" +} + +capture_watch_rebuild() { + local implementation=$1 + local executable=$2 + local project="$work/$implementation-watch" + local transcript="$work/$implementation-watch.tty" + local command_executable=$(command_path "$executable") + local command_project=$(command_path "$project") + if [ "$(uname -s)" = Darwin ]; then + script -qF "$transcript" env -u NO_COLOR \ + "TERM=xterm" \ + "CLICOLOR=1" \ + "CLICOLOR_FORCE=0" \ + "RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE" \ + "RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME" \ + "$executable" watch --clear-screen "$project" >/dev/null & + else + script -qefc \ + "env -u NO_COLOR TERM=xterm CLICOLOR=1 CLICOLOR_FORCE=0 RESCRIPT_BSC_EXE=$RESCRIPT_BSC_EXE RESCRIPT_RUNTIME=$RESCRIPT_RUNTIME $command_executable watch --clear-screen $command_project" \ + "$transcript" >/dev/null & + fi + active_script_pid=$! + active_watch_project=$project + active_watch_transcript=$transcript + if ! wait_for_text "$transcript" "Finished initial compilation" 1; then + return 1 + fi + overwrite_line_in_place "$project/src/A.res" 'let value = 2' + if ! wait_for_text "$transcript" "Finished incremental compilation" 1; then + return 1 + fi + cp "$transcript" "$work/$implementation-watch-phases.tty" + overwrite_line_in_place "$project/src/A.res" 'let value = (' + if ! wait_for_text "$transcript" "Build failed. Watching for changes..." 1; then + return 1 + fi + overwrite_line_in_place "$project/src/A.res" 'let value = 3' + if ! wait_for_text "$transcript" "Finished incremental compilation" 2; then + return 1 + fi + printf '%s\n' \ + '{"name":"interactive-output","sources":["src"],"namespace":"Interactive","package-specs":{"module":"esmodule","in-source":true,"suffix":".mjs"}}' \ + >"$project/rescript.next" + mv "$project/rescript.next" "$project/rescript.json" + if ! wait_for_text "$transcript" "Change detected. Full rebuild..." 1 || \ + ! wait_for_text "$transcript" "Finished compilation" 1; then + return 1 + fi + stop_active_watch + tr '\r' '\n' <"$work/$implementation-watch-phases.tty" \ + | normalize_output \ + | sed -E 's/in [0-9]+\.[0-9]+s/in